This commit is contained in:
Ani 2025-12-15 16:25:48 +03:00 committed by GitHub
commit 0ba5d715f3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 42 additions and 53 deletions

View File

@ -2365,7 +2365,6 @@ void ppu_thread::cpu_wait(bs_t<cpu_flag> old)
if (u32 addr = res_notify)
{
res_notify = 0;
res_notify_postpone_streak = 0;
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;
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
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
// 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)
{
case 0:
@ -3381,18 +3397,11 @@ static bool ppu_store_reservation(ppu_thread& ppu, u32 addr, u64 reg_value)
}
case 1:
{
// Postpone notifications if there is no pending one OR if there is likely a complex operation on reservation going on
// Which consists of multiple used addresses
if (ppu.res_notify_postpone_streak <= 4)
if (!notify)
{
if (!notify || ((notify & -128) == (addr & -128) && new_data != old_data))
{
ppu.res_notify = addr;
ppu.res_notify_time = rtime;
ppu.res_notify_postpone_streak++;
notify = 0;
break;
}
ppu.res_notify = addr & -128;
ppu.res_notify_time = rtime;
break;
}
// Notify both
@ -3405,24 +3414,12 @@ static bool ppu_store_reservation(ppu_thread& ppu, u32 addr, u64 reg_value)
ppu.state += cpu_flag::wait;
}
vm::reservation_notifier_notify(addr, rtime);
vm::reservation_notifier_notify(addr & -128, rtime);
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());
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_postpone_streak = 0;
}
ppu.raddr = 0;

View File

@ -267,7 +267,6 @@ public:
u32 res_cached{0}; // Reservation "cached" addresss
u32 res_notify{0};
u64 res_notify_time{0};
u32 res_notify_postpone_streak{0};
union ppu_prio_t
{

View File

@ -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));
// Cover all waiters (TODO: Get reservation time atomically)
const u64 rtime = vm::reservation_acquire(addr);
vm::reservation_notifier_notify(addr, rtime - 128);
vm::reservation_notifier_notify(addr, rtime - 256);
// TODO: Implement properly (notifying previous two times)
vm::reservation_notifier_notify(addr, vm::reservation_acquire(addr) - 128);
vm::reservation_notifier_notify(addr, vm::reservation_acquire(addr) - 256);
}
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;
}
}
lv2_obj::notify_all();
}
else
{

View File

@ -1336,16 +1336,13 @@ bool lv2_obj::sleep(cpu_thread& cpu, const u64 timeout)
if (cpu.get_class() == thread_class::ppu)
{
ppu_thread& ppu = static_cast<ppu_thread&>(cpu);
if (u32 addr = ppu.res_notify)
if (u32 addr = static_cast<ppu_thread&>(cpu).res_notify)
{
ppu.res_notify = 0;
ppu.res_notify_postpone_streak = 0;
static_cast<ppu_thread&>(cpu).res_notify = 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 ((*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))
{
@ -1356,7 +1353,7 @@ bool lv2_obj::sleep(cpu_thread& cpu, const u64 timeout)
}
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)
{
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))
{
@ -2262,9 +2258,12 @@ void lv2_obj::notify_all() noexcept
atomic_t<u64, 64>* range_lock = nullptr;
u32 current_raddr = 0;
if (cpu->get_class() == thread_class::spu)
{
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++)
@ -2273,7 +2272,7 @@ void lv2_obj::notify_all() noexcept
const u64 value = waiter.load();
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))
{
@ -2338,9 +2337,8 @@ void lv2_obj::notify_all() noexcept
{
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] - 128);
}
}
}

View File

@ -485,6 +485,7 @@ public:
static void enqueue_on_top(const void* waiter)
{
return;
g_to_notify[0] = waiter;
g_to_notify[1] = nullptr;
}

View File

@ -113,10 +113,7 @@ namespace vm
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 - 128);
if (cpu && !had_wait && cpu->test_stopped())
{

View File

@ -42,14 +42,15 @@ namespace vm
static inline atomic_t<reservation_waiter_t>* reservation_notifier(u32 raddr, u64 rtime)
{
rtime = 0;
constexpr u32 wait_vars_for_each = 64;
constexpr u32 unique_address_bit_mask = 0b1111;
constexpr u32 unique_rtime_bit_mask = 0b1;
constexpr u32 unique_address_bit_mask = 0b111;
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;
// 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];
}