mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-03-14 10:21:21 +00:00
CELL: Rewrite reservation notification postponing
This commit is contained in:
parent
729826ec40
commit
a4ea71d18f
@ -3541,49 +3541,62 @@ static bool ppu_store_reservation(ppu_thread& ppu, u32 addr, u64 reg_value)
|
||||
// Avoid notifications from lwmutex or sys_spinlock
|
||||
if (new_data != old_data && (ppu.cia < liblv2_begin || ppu.cia >= liblv2_end))
|
||||
{
|
||||
const u32 notify = ppu.res_notify;
|
||||
u32 notify = ppu.res_notify;
|
||||
|
||||
if (notify)
|
||||
{
|
||||
bool notified = false;
|
||||
|
||||
if (ppu.res_notify_time == (vm::reservation_acquire(notify) & -128))
|
||||
if (ppu.res_notify_time == vm::reservation_notifier_count_index(notify).second)
|
||||
{
|
||||
ppu.state += cpu_flag::wait;
|
||||
vm::reservation_notifier_notify(notify);
|
||||
notified = true;
|
||||
}
|
||||
|
||||
if (vm::reservation_notifier_count(addr))
|
||||
{
|
||||
if (!notified)
|
||||
{
|
||||
ppu.res_notify = addr;
|
||||
ppu.res_notify_time = rtime + 128;
|
||||
}
|
||||
else if ((addr ^ notify) & -128)
|
||||
{
|
||||
vm::reservation_notifier_notify(addr);
|
||||
ppu.res_notify = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ppu.res_notify = 0;
|
||||
notify = 0;
|
||||
}
|
||||
|
||||
static_cast<void>(ppu.test_stopped());
|
||||
ppu.res_notify = 0;
|
||||
}
|
||||
else
|
||||
|
||||
if ((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
|
||||
if (vm::reservation_notifier_count(addr))
|
||||
const auto [count, index] = vm::reservation_notifier_count_index(addr);
|
||||
|
||||
switch (count)
|
||||
{
|
||||
ppu.res_notify = addr;
|
||||
ppu.res_notify_time = rtime + 128;
|
||||
case 0:
|
||||
{
|
||||
// Nothing to do
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
if (!notify)
|
||||
{
|
||||
ppu.res_notify = addr;
|
||||
ppu.res_notify_time = index;
|
||||
break;
|
||||
}
|
||||
|
||||
// Notify both
|
||||
[[fallthrough]];
|
||||
}
|
||||
default:
|
||||
{
|
||||
if (!notify)
|
||||
{
|
||||
ppu.state += cpu_flag::wait;
|
||||
}
|
||||
|
||||
vm::reservation_notifier_notify(addr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static_cast<void>(ppu.test_stopped());
|
||||
}
|
||||
|
||||
if (addr == ppu.last_faddr)
|
||||
@ -3601,7 +3614,7 @@ 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))
|
||||
{
|
||||
if (ppu.res_notify_time == (vm::reservation_acquire(notify) & -128))
|
||||
if (ppu.res_notify_time == vm::reservation_notifier_count_index(notify).second)
|
||||
{
|
||||
ppu.state += cpu_flag::wait;
|
||||
vm::reservation_notifier_notify(notify);
|
||||
|
@ -446,7 +446,7 @@ waitpkg_func static void __tpause(u32 cycles, u32 cstate)
|
||||
|
||||
namespace vm
|
||||
{
|
||||
std::array<atomic_t<reservation_waiter_t>, 512> g_resrv_waiters_count{};
|
||||
std::array<atomic_t<reservation_waiter_t>, 1024> g_resrv_waiters_count{};
|
||||
}
|
||||
|
||||
void do_cell_atomic_128_store(u32 addr, const void* to_write);
|
||||
|
@ -1335,7 +1335,7 @@ bool lv2_obj::sleep(cpu_thread& cpu, const u64 timeout)
|
||||
{
|
||||
static_cast<ppu_thread&>(cpu).res_notify = 0;
|
||||
|
||||
if (static_cast<ppu_thread&>(cpu).res_notify_time != (vm::reservation_acquire(addr) & -128))
|
||||
if (static_cast<ppu_thread&>(cpu).res_notify_time != vm::reservation_notifier_count_index(addr).second)
|
||||
{
|
||||
// Ignore outdated notification request
|
||||
}
|
||||
@ -1388,7 +1388,7 @@ bool lv2_obj::awake(cpu_thread* thread, s32 prio)
|
||||
{
|
||||
ppu->res_notify = 0;
|
||||
|
||||
if (ppu->res_notify_time != (vm::reservation_acquire(addr) & -128))
|
||||
if (ppu->res_notify_time != vm::reservation_notifier_count_index(addr).second)
|
||||
{
|
||||
// Ignore outdated notification request
|
||||
}
|
||||
|
@ -45,14 +45,24 @@ namespace vm
|
||||
|
||||
static inline std::pair<atomic_t<reservation_waiter_t>*, atomic_t<reservation_waiter_t>*> reservation_notifier(u32 raddr)
|
||||
{
|
||||
extern std::array<atomic_t<reservation_waiter_t>, 512> g_resrv_waiters_count;
|
||||
extern std::array<atomic_t<reservation_waiter_t>, 1024> g_resrv_waiters_count;
|
||||
|
||||
// Storage efficient method to distinguish different nearby addresses (which are likely)
|
||||
const usz index = std::popcount(raddr & -512) + ((raddr / 128) % 4) * 32;
|
||||
auto& waiter = g_resrv_waiters_count[index * 4];
|
||||
return { &g_resrv_waiters_count[index * 4 + waiter.load().waiters_index % 4], &waiter };
|
||||
constexpr u32 wait_vars_for_each = 8;
|
||||
constexpr u32 unique_address_bit_mask = 0b11;
|
||||
const usz index = std::popcount(raddr & -1024) + ((raddr / 128) & unique_address_bit_mask) * 32;
|
||||
auto& waiter = g_resrv_waiters_count[index * wait_vars_for_each];
|
||||
return { &g_resrv_waiters_count[index * wait_vars_for_each + waiter.load().waiters_index % wait_vars_for_each], &waiter };
|
||||
}
|
||||
|
||||
// Returns waiter count and index
|
||||
static inline std::pair<u32, u32> reservation_notifier_count_index(u32 raddr)
|
||||
{
|
||||
const auto notifiers = reservation_notifier(raddr);
|
||||
return { notifiers.first->load().waiters_count, static_cast<u32>(notifiers.first - notifiers.second) };
|
||||
}
|
||||
|
||||
// Returns waiter count
|
||||
static inline u32 reservation_notifier_count(u32 raddr)
|
||||
{
|
||||
return reservation_notifier(raddr).first->load().waiters_count;
|
||||
|
@ -947,6 +947,7 @@
|
||||
<ClInclude Include="Emu\Memory\vm.h" />
|
||||
<ClInclude Include="Emu\Memory\vm_ptr.h" />
|
||||
<ClInclude Include="Emu\Memory\vm_ref.h" />
|
||||
<ClInclude Include="Emu\Memory\vm_reservation.h" />
|
||||
<ClInclude Include="Emu\Memory\vm_var.h" />
|
||||
<ClInclude Include="Emu\RSX\rsx_methods.h" />
|
||||
<ClInclude Include="Emu\RSX\rsx_utils.h" />
|
||||
|
@ -1461,6 +1461,9 @@
|
||||
<ClInclude Include="Emu\Memory\vm_ref.h">
|
||||
<Filter>Emu\Memory</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\Memory\vm_reservation.h">
|
||||
<Filter>Emu\Memory</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\Memory\vm_var.h">
|
||||
<Filter>Emu\Memory</Filter>
|
||||
</ClInclude>
|
||||
|
Loading…
x
Reference in New Issue
Block a user