mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-12-16 04:09:07 +00:00
Merge 11ed2c9948 into cf87f24587
This commit is contained in:
commit
0ba5d715f3
@ -2365,7 +2365,6 @@ void ppu_thread::cpu_wait(bs_t<cpu_flag> old)
|
|||||||
if (u32 addr = res_notify)
|
if (u32 addr = res_notify)
|
||||||
{
|
{
|
||||||
res_notify = 0;
|
res_notify = 0;
|
||||||
res_notify_postpone_streak = 0;
|
|
||||||
|
|
||||||
if (res_notify_time + 128 == (vm::reservation_acquire(addr) & -128))
|
if (res_notify_time + 128 == (vm::reservation_acquire(addr) & -128))
|
||||||
{
|
{
|
||||||
@ -3361,17 +3360,34 @@ static bool ppu_store_reservation(ppu_thread& ppu, u32 addr, u64 reg_value)
|
|||||||
{
|
{
|
||||||
extern atomic_t<u32> liblv2_begin, liblv2_end;
|
extern atomic_t<u32> liblv2_begin, liblv2_end;
|
||||||
|
|
||||||
u32 notify = ppu.res_notify;
|
const u32 notify = ppu.res_notify;
|
||||||
|
|
||||||
|
if (notify)
|
||||||
|
{
|
||||||
|
if (auto waiter = vm::reservation_notifier_notify(notify, ppu.res_notify_time, true))
|
||||||
|
{
|
||||||
|
ppu.state += cpu_flag::wait;
|
||||||
|
waiter->notify_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
ppu.res_notify = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Avoid notifications from lwmutex or sys_spinlock
|
// Avoid notifications from lwmutex or sys_spinlock
|
||||||
const bool is_liblv2_or_null = (ppu.cia >= liblv2_begin && ppu.cia < liblv2_end);
|
const bool is_liblv2_or_null = (ppu.cia >= liblv2_begin && ppu.cia < liblv2_end);
|
||||||
|
|
||||||
if (!is_liblv2_or_null)
|
if (!is_liblv2_or_null && (addr ^ notify) & -128)
|
||||||
{
|
{
|
||||||
// Try to postpone notification to when PPU is asleep or join notifications on the same address
|
// Try to postpone notification to when PPU is asleep or join notifications on the same address
|
||||||
// This also optimizes a mutex - won't notify after lock is aqcuired (prolonging the critical section duration), only notifies on unlock
|
// This also optimizes a mutex - won't notify after lock is aqcuired (prolonging the critical section duration), only notifies on unlock
|
||||||
const u32 count = vm::reservation_notifier_count(addr, rtime);
|
const u32 count = vm::reservation_notifier_count(addr & -128, rtime);
|
||||||
|
|
||||||
|
if (cpu_flag::wait - ppu.state)
|
||||||
|
{
|
||||||
|
ppu.state += cpu_flag::wait;
|
||||||
|
}
|
||||||
|
|
||||||
|
vm::reservation_notifier_notify(addr & -128, rtime);
|
||||||
switch (count)
|
switch (count)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
@ -3381,18 +3397,11 @@ static bool ppu_store_reservation(ppu_thread& ppu, u32 addr, u64 reg_value)
|
|||||||
}
|
}
|
||||||
case 1:
|
case 1:
|
||||||
{
|
{
|
||||||
// Postpone notifications if there is no pending one OR if there is likely a complex operation on reservation going on
|
if (!notify)
|
||||||
// Which consists of multiple used addresses
|
|
||||||
if (ppu.res_notify_postpone_streak <= 4)
|
|
||||||
{
|
{
|
||||||
if (!notify || ((notify & -128) == (addr & -128) && new_data != old_data))
|
ppu.res_notify = addr & -128;
|
||||||
{
|
ppu.res_notify_time = rtime;
|
||||||
ppu.res_notify = addr;
|
break;
|
||||||
ppu.res_notify_time = rtime;
|
|
||||||
ppu.res_notify_postpone_streak++;
|
|
||||||
notify = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify both
|
// Notify both
|
||||||
@ -3405,24 +3414,12 @@ static bool ppu_store_reservation(ppu_thread& ppu, u32 addr, u64 reg_value)
|
|||||||
ppu.state += cpu_flag::wait;
|
ppu.state += cpu_flag::wait;
|
||||||
}
|
}
|
||||||
|
|
||||||
vm::reservation_notifier_notify(addr, rtime);
|
vm::reservation_notifier_notify(addr & -128, rtime);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (notify)
|
|
||||||
{
|
|
||||||
if (auto waiter = vm::reservation_notifier_notify(notify, ppu.res_notify_time, true))
|
|
||||||
{
|
|
||||||
ppu.state += cpu_flag::wait;
|
|
||||||
waiter->notify_all();
|
|
||||||
}
|
|
||||||
|
|
||||||
ppu.res_notify = 0;
|
|
||||||
ppu.res_notify_postpone_streak = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static_cast<void>(ppu.test_stopped());
|
static_cast<void>(ppu.test_stopped());
|
||||||
|
|
||||||
if (addr == ppu.last_faddr)
|
if (addr == ppu.last_faddr)
|
||||||
@ -3450,7 +3447,6 @@ static bool ppu_store_reservation(ppu_thread& ppu, u32 addr, u64 reg_value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ppu.res_notify = 0;
|
ppu.res_notify = 0;
|
||||||
ppu.res_notify_postpone_streak = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ppu.raddr = 0;
|
ppu.raddr = 0;
|
||||||
|
|||||||
@ -267,7 +267,6 @@ public:
|
|||||||
u32 res_cached{0}; // Reservation "cached" addresss
|
u32 res_cached{0}; // Reservation "cached" addresss
|
||||||
u32 res_notify{0};
|
u32 res_notify{0};
|
||||||
u64 res_notify_time{0};
|
u64 res_notify_time{0};
|
||||||
u32 res_notify_postpone_streak{0};
|
|
||||||
|
|
||||||
union ppu_prio_t
|
union ppu_prio_t
|
||||||
{
|
{
|
||||||
|
|||||||
@ -3563,10 +3563,9 @@ void spu_thread::do_putlluc(const spu_mfc_cmd& args)
|
|||||||
|
|
||||||
do_cell_atomic_128_store(addr, _ptr<spu_rdata_t>(args.lsa & 0x3ff80));
|
do_cell_atomic_128_store(addr, _ptr<spu_rdata_t>(args.lsa & 0x3ff80));
|
||||||
|
|
||||||
// Cover all waiters (TODO: Get reservation time atomically)
|
// TODO: Implement properly (notifying previous two times)
|
||||||
const u64 rtime = vm::reservation_acquire(addr);
|
vm::reservation_notifier_notify(addr, vm::reservation_acquire(addr) - 128);
|
||||||
vm::reservation_notifier_notify(addr, rtime - 128);
|
vm::reservation_notifier_notify(addr, vm::reservation_acquire(addr) - 256);
|
||||||
vm::reservation_notifier_notify(addr, rtime - 256);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool spu_thread::do_mfc(bool can_escape, bool must_finish)
|
bool spu_thread::do_mfc(bool can_escape, bool must_finish)
|
||||||
@ -5497,8 +5496,6 @@ s64 spu_thread::get_ch_value(u32 ch)
|
|||||||
eventstat_spin_count = 0;
|
eventstat_spin_count = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lv2_obj::notify_all();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1336,16 +1336,13 @@ bool lv2_obj::sleep(cpu_thread& cpu, const u64 timeout)
|
|||||||
|
|
||||||
if (cpu.get_class() == thread_class::ppu)
|
if (cpu.get_class() == thread_class::ppu)
|
||||||
{
|
{
|
||||||
ppu_thread& ppu = static_cast<ppu_thread&>(cpu);
|
if (u32 addr = static_cast<ppu_thread&>(cpu).res_notify)
|
||||||
|
|
||||||
if (u32 addr = ppu.res_notify)
|
|
||||||
{
|
{
|
||||||
ppu.res_notify = 0;
|
static_cast<ppu_thread&>(cpu).res_notify = 0;
|
||||||
ppu.res_notify_postpone_streak = 0;
|
|
||||||
|
|
||||||
if (auto it = std::find(g_to_notify, std::end(g_to_notify), std::add_pointer_t<const void>{}); it != std::end(g_to_notify))
|
if (auto it = std::find(g_to_notify, std::end(g_to_notify), std::add_pointer_t<const void>{}); it != std::end(g_to_notify))
|
||||||
{
|
{
|
||||||
if ((*it++ = vm::reservation_notifier_notify(addr, ppu.res_notify_time, true)))
|
if ((*it++ = vm::reservation_notifier_notify(addr, static_cast<ppu_thread&>(cpu).res_notify_time, true)))
|
||||||
{
|
{
|
||||||
if (it < std::end(g_to_notify))
|
if (it < std::end(g_to_notify))
|
||||||
{
|
{
|
||||||
@ -1356,7 +1353,7 @@ bool lv2_obj::sleep(cpu_thread& cpu, const u64 timeout)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
vm::reservation_notifier_notify(addr, ppu.res_notify_time);
|
vm::reservation_notifier_notify(addr, static_cast<ppu_thread&>(cpu).res_notify_time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1392,7 +1389,6 @@ bool lv2_obj::awake(cpu_thread* thread, s32 prio)
|
|||||||
if (u32 addr = ppu->res_notify)
|
if (u32 addr = ppu->res_notify)
|
||||||
{
|
{
|
||||||
ppu->res_notify = 0;
|
ppu->res_notify = 0;
|
||||||
ppu->res_notify_postpone_streak = 0;
|
|
||||||
|
|
||||||
if (auto it = std::find(g_to_notify, std::end(g_to_notify), std::add_pointer_t<const void>{}); it != std::end(g_to_notify))
|
if (auto it = std::find(g_to_notify, std::end(g_to_notify), std::add_pointer_t<const void>{}); it != std::end(g_to_notify))
|
||||||
{
|
{
|
||||||
@ -2262,9 +2258,12 @@ void lv2_obj::notify_all() noexcept
|
|||||||
|
|
||||||
atomic_t<u64, 64>* range_lock = nullptr;
|
atomic_t<u64, 64>* range_lock = nullptr;
|
||||||
|
|
||||||
|
u32 current_raddr = 0;
|
||||||
|
|
||||||
if (cpu->get_class() == thread_class::spu)
|
if (cpu->get_class() == thread_class::spu)
|
||||||
{
|
{
|
||||||
range_lock = static_cast<spu_thread*>(cpu)->range_lock;
|
range_lock = static_cast<spu_thread*>(cpu)->range_lock;
|
||||||
|
current_raddr = static_cast<spu_thread*>(cpu)->raddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (usz i = 0, checked = 0; checked < 4 && i < total_waiters; i++)
|
for (usz i = 0, checked = 0; checked < 4 && i < total_waiters; i++)
|
||||||
@ -2273,7 +2272,7 @@ void lv2_obj::notify_all() noexcept
|
|||||||
const u64 value = waiter.load();
|
const u64 value = waiter.load();
|
||||||
u32 raddr = static_cast<u32>(value) & -128;
|
u32 raddr = static_cast<u32>(value) & -128;
|
||||||
|
|
||||||
if (vm::check_addr(raddr))
|
if (vm::check_addr(raddr) && (raddr != current_raddr || (value % 128) > 1))
|
||||||
{
|
{
|
||||||
if (((raddr >> 28) < 2 || (raddr >> 28) == 0xd))
|
if (((raddr >> 28) < 2 || (raddr >> 28) == 0xd))
|
||||||
{
|
{
|
||||||
@ -2338,9 +2337,8 @@ void lv2_obj::notify_all() noexcept
|
|||||||
{
|
{
|
||||||
if (notifies[i])
|
if (notifies[i])
|
||||||
{
|
{
|
||||||
// Cover all waiters for an address
|
vm::reservation_update(notifies[i]);
|
||||||
vm::reservation_notifier_notify(notifies[i], notifies_time[i]);
|
vm::reservation_notifier_notify(notifies[i], notifies_time[i]);
|
||||||
vm::reservation_notifier_notify(notifies[i], notifies_time[i] - 128);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -485,6 +485,7 @@ public:
|
|||||||
|
|
||||||
static void enqueue_on_top(const void* waiter)
|
static void enqueue_on_top(const void* waiter)
|
||||||
{
|
{
|
||||||
|
return;
|
||||||
g_to_notify[0] = waiter;
|
g_to_notify[0] = waiter;
|
||||||
g_to_notify[1] = nullptr;
|
g_to_notify[1] = nullptr;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -113,10 +113,7 @@ namespace vm
|
|||||||
|
|
||||||
if (ok)
|
if (ok)
|
||||||
{
|
{
|
||||||
// Notify all waiters for an address
|
|
||||||
// This is because reservation_update is often brought after the actual reservation update and not by a fused operation
|
|
||||||
reservation_notifier_notify(addr, rtime);
|
reservation_notifier_notify(addr, rtime);
|
||||||
reservation_notifier_notify(addr, rtime - 128);
|
|
||||||
|
|
||||||
if (cpu && !had_wait && cpu->test_stopped())
|
if (cpu && !had_wait && cpu->test_stopped())
|
||||||
{
|
{
|
||||||
|
|||||||
@ -42,14 +42,15 @@ namespace vm
|
|||||||
|
|
||||||
static inline atomic_t<reservation_waiter_t>* reservation_notifier(u32 raddr, u64 rtime)
|
static inline atomic_t<reservation_waiter_t>* reservation_notifier(u32 raddr, u64 rtime)
|
||||||
{
|
{
|
||||||
|
rtime = 0;
|
||||||
constexpr u32 wait_vars_for_each = 64;
|
constexpr u32 wait_vars_for_each = 64;
|
||||||
constexpr u32 unique_address_bit_mask = 0b1111;
|
constexpr u32 unique_address_bit_mask = 0b111;
|
||||||
constexpr u32 unique_rtime_bit_mask = 0b1;
|
constexpr u32 unique_rtime_bit_mask = 0b11;
|
||||||
|
|
||||||
extern std::array<atomic_t<reservation_waiter_t>, wait_vars_for_each * (unique_address_bit_mask + 1) * (unique_rtime_bit_mask + 1)> g_resrv_waiters_count;
|
extern std::array<atomic_t<reservation_waiter_t>, wait_vars_for_each * (unique_address_bit_mask + 1) * (unique_rtime_bit_mask + 1)> g_resrv_waiters_count;
|
||||||
|
|
||||||
// Storage efficient method to distinguish different nearby addresses (which are likely)
|
// Storage efficient method to distinguish different nearby addresses (which are likely)
|
||||||
const usz index = std::popcount(raddr & -2048) * (1 << 5) + ((rtime / 128) & unique_rtime_bit_mask) * (1 << 4) + ((raddr / 128) & unique_address_bit_mask);
|
const usz index = std::popcount(raddr & -1024) * (1 << 5) + ((rtime / 128) & unique_rtime_bit_mask) * (1 << 3) + ((raddr / 128) & unique_address_bit_mask);
|
||||||
return &g_resrv_waiters_count[index];
|
return &g_resrv_waiters_count[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user