1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-25 20:22:30 +01:00

CELL: More efficient reservation notificatins

This commit is contained in:
Elad Ashkenazi 2024-06-29 22:00:19 +03:00
parent c71edc0719
commit f948a80242
4 changed files with 42 additions and 18 deletions

View File

@ -3256,6 +3256,8 @@ const auto ppu_stcx_accurate_tx = build_function_asm<u64(*)(u32 raddr, u64 rtime
#endif
});
extern atomic_t<u8>& get_resrv_waiters_count(u32 raddr);
template <typename T>
static bool ppu_store_reservation(ppu_thread& ppu, u32 addr, u64 reg_value)
{
@ -3500,19 +3502,30 @@ static bool ppu_store_reservation(ppu_thread& ppu, u32 addr, u64 reg_value)
if (notify)
{
vm::reservation_notifier(notify).notify_all();
bool notified = false;
if (ppu.res_notify_time == (vm::reservation_acquire(notify) & -128))
{
vm::reservation_notifier(notify).notify_all();
notified = true;
}
if (!notified || (addr ^ notify) & -128)
{
res.notify_all();
}
ppu.res_notify = 0;
}
if (!notify)
else
{
// 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
ppu.res_notify = addr;
}
else if ((addr ^ notify) & -128)
{
res.notify_all();
if (get_resrv_waiters_count(addr))
{
ppu.res_notify = addr;
ppu.res_notify_time = rtime + 128;
}
}
}
@ -3531,7 +3544,11 @@ static bool ppu_store_reservation(ppu_thread& ppu, u32 addr, u64 reg_value)
// And on failure it has some time to do something else
if (notify && ((addr ^ notify) & -128))
{
vm::reservation_notifier(notify).notify_all();
if (ppu.res_notify_time == (vm::reservation_acquire(notify) & -128))
{
vm::reservation_notifier(notify).notify_all();
}
ppu.res_notify = 0;
}

View File

@ -262,7 +262,8 @@ public:
u64 rtime{0};
alignas(64) std::byte rdata[128]{}; // Reservation data
bool use_full_rdata{};
u32 res_notify{};
u32 res_notify{0};
u64 res_notify_time{0};
union ppu_prio_t
{

View File

@ -446,10 +446,10 @@ waitpkg_func static void __tpause(u32 cycles, u32 cstate)
static std::array<atomic_t<u8>, 128> g_resrv_waiters_count;
static inline atomic_t<u8>& get_resrv_waiters_count(u32 raddr)
extern atomic_t<u8>& get_resrv_waiters_count(u32 raddr)
{
// Storage efficient method to distinguish different nearby addresses (which are likely)
return g_resrv_waiters_count[std::popcount(raddr) + ((raddr / 128) % 4) * 32];
return g_resrv_waiters_count[std::popcount(raddr & -512) + ((raddr / 128) % 4) * 32];
}
void do_cell_atomic_128_store(u32 addr, const void* to_write);

View File

@ -1333,9 +1333,12 @@ bool lv2_obj::sleep(cpu_thread& cpu, const u64 timeout)
{
static_cast<ppu_thread&>(cpu).res_notify = 0;
const usz notify_later_idx = std::basic_string_view<const void*>{g_to_notify, std::size(g_to_notify)}.find_first_of(std::add_pointer_t<const void>{});
if (notify_later_idx != umax)
if (static_cast<ppu_thread&>(cpu).res_notify_time != (vm::reservation_acquire(addr) & -128))
{
// Ignore outdated notification request
}
else if (usz notify_later_idx = std::basic_string_view<const void*>{g_to_notify, std::size(g_to_notify)}.find_first_of(std::add_pointer_t<const void>{});
notify_later_idx != umax)
{
g_to_notify[notify_later_idx] = &vm::reservation_notifier(addr);
@ -1384,9 +1387,12 @@ bool lv2_obj::awake(cpu_thread* thread, s32 prio)
{
ppu->res_notify = 0;
const usz notify_later_idx = std::basic_string_view<const void*>{g_to_notify, std::size(g_to_notify)}.find_first_of(std::add_pointer_t<const void>{});
if (notify_later_idx != umax)
if (ppu->res_notify_time != (vm::reservation_acquire(addr) & -128))
{
// Ignore outdated notification request
}
else if (usz notify_later_idx = std::basic_string_view<const void*>{g_to_notify, std::size(g_to_notify)}.find_first_of(std::add_pointer_t<const void>{});
notify_later_idx != umax)
{
g_to_notify[notify_later_idx] = &vm::reservation_notifier(addr);