From e15b293fc4ad4a8ae4728f3e2a55f8017fbbb37a Mon Sep 17 00:00:00 2001 From: Ani Date: Mon, 15 Dec 2025 12:36:47 +0100 Subject: [PATCH] Revert "SPU: Restore postponed LR notifications (with tweaks)" This reverts commit 05648428715b9f1f54707290eb9fc1b1a124744e. --- rpcs3/Emu/Cell/PPUThread.cpp | 54 ++++++++++++++----------------- rpcs3/Emu/Cell/PPUThread.h | 1 - rpcs3/Emu/Cell/SPUThread.cpp | 9 ++---- rpcs3/Emu/Cell/lv2/lv2.cpp | 20 ++++++------ rpcs3/Emu/Cell/lv2/sys_sync.h | 1 + rpcs3/Emu/Memory/vm.cpp | 3 -- rpcs3/Emu/Memory/vm_reservation.h | 7 ++-- 7 files changed, 42 insertions(+), 53 deletions(-) diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index a9bef5e640..8dc7112c6a 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -2365,7 +2365,6 @@ void ppu_thread::cpu_wait(bs_t 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 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(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; diff --git a/rpcs3/Emu/Cell/PPUThread.h b/rpcs3/Emu/Cell/PPUThread.h index 97c705aed5..322cc13ebe 100644 --- a/rpcs3/Emu/Cell/PPUThread.h +++ b/rpcs3/Emu/Cell/PPUThread.h @@ -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 { diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 2673685bb2..69846b30af 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -3563,10 +3563,9 @@ void spu_thread::do_putlluc(const spu_mfc_cmd& args) do_cell_atomic_128_store(addr, _ptr(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 { diff --git a/rpcs3/Emu/Cell/lv2/lv2.cpp b/rpcs3/Emu/Cell/lv2/lv2.cpp index c405b98a2c..284768d8bb 100644 --- a/rpcs3/Emu/Cell/lv2/lv2.cpp +++ b/rpcs3/Emu/Cell/lv2/lv2.cpp @@ -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(cpu); - - if (u32 addr = ppu.res_notify) + if (u32 addr = static_cast(cpu).res_notify) { - ppu.res_notify = 0; - ppu.res_notify_postpone_streak = 0; + static_cast(cpu).res_notify = 0; if (auto it = std::find(g_to_notify, std::end(g_to_notify), std::add_pointer_t{}); 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(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(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{}); it != std::end(g_to_notify)) { @@ -2262,9 +2258,12 @@ void lv2_obj::notify_all() noexcept atomic_t* range_lock = nullptr; + u32 current_raddr = 0; + if (cpu->get_class() == thread_class::spu) { range_lock = static_cast(cpu)->range_lock; + current_raddr = static_cast(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(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); } } } diff --git a/rpcs3/Emu/Cell/lv2/sys_sync.h b/rpcs3/Emu/Cell/lv2/sys_sync.h index 0aff5e1e7a..7dea0fed63 100644 --- a/rpcs3/Emu/Cell/lv2/sys_sync.h +++ b/rpcs3/Emu/Cell/lv2/sys_sync.h @@ -485,6 +485,7 @@ public: static void enqueue_on_top(const void* waiter) { + return; g_to_notify[0] = waiter; g_to_notify[1] = nullptr; } diff --git a/rpcs3/Emu/Memory/vm.cpp b/rpcs3/Emu/Memory/vm.cpp index 6181c2c6bb..1d89617ea4 100644 --- a/rpcs3/Emu/Memory/vm.cpp +++ b/rpcs3/Emu/Memory/vm.cpp @@ -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()) { diff --git a/rpcs3/Emu/Memory/vm_reservation.h b/rpcs3/Emu/Memory/vm_reservation.h index d21a593959..ec5c122f91 100644 --- a/rpcs3/Emu/Memory/vm_reservation.h +++ b/rpcs3/Emu/Memory/vm_reservation.h @@ -42,14 +42,15 @@ namespace vm static inline atomic_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, 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]; }