mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-03-29 22:20:48 +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
|
// Avoid notifications from lwmutex or sys_spinlock
|
||||||
if (new_data != old_data && (ppu.cia < liblv2_begin || ppu.cia >= liblv2_end))
|
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)
|
if (notify)
|
||||||
{
|
{
|
||||||
bool notified = false;
|
if (ppu.res_notify_time == vm::reservation_notifier_count_index(notify).second)
|
||||||
|
|
||||||
if (ppu.res_notify_time == (vm::reservation_acquire(notify) & -128))
|
|
||||||
{
|
{
|
||||||
ppu.state += cpu_flag::wait;
|
ppu.state += cpu_flag::wait;
|
||||||
vm::reservation_notifier_notify(notify);
|
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
|
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
|
// 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
|
||||||
if (vm::reservation_notifier_count(addr))
|
const auto [count, index] = vm::reservation_notifier_count_index(addr);
|
||||||
|
|
||||||
|
switch (count)
|
||||||
{
|
{
|
||||||
ppu.res_notify = addr;
|
case 0:
|
||||||
ppu.res_notify_time = rtime + 128;
|
{
|
||||||
|
// 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)
|
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
|
// And on failure it has some time to do something else
|
||||||
if (notify && ((addr ^ notify) & -128))
|
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;
|
ppu.state += cpu_flag::wait;
|
||||||
vm::reservation_notifier_notify(notify);
|
vm::reservation_notifier_notify(notify);
|
||||||
|
@ -446,7 +446,7 @@ waitpkg_func static void __tpause(u32 cycles, u32 cstate)
|
|||||||
|
|
||||||
namespace vm
|
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);
|
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;
|
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
|
// Ignore outdated notification request
|
||||||
}
|
}
|
||||||
@ -1388,7 +1388,7 @@ bool lv2_obj::awake(cpu_thread* thread, s32 prio)
|
|||||||
{
|
{
|
||||||
ppu->res_notify = 0;
|
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
|
// 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)
|
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)
|
// Storage efficient method to distinguish different nearby addresses (which are likely)
|
||||||
const usz index = std::popcount(raddr & -512) + ((raddr / 128) % 4) * 32;
|
constexpr u32 wait_vars_for_each = 8;
|
||||||
auto& waiter = g_resrv_waiters_count[index * 4];
|
constexpr u32 unique_address_bit_mask = 0b11;
|
||||||
return { &g_resrv_waiters_count[index * 4 + waiter.load().waiters_index % 4], &waiter };
|
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)
|
static inline u32 reservation_notifier_count(u32 raddr)
|
||||||
{
|
{
|
||||||
return reservation_notifier(raddr).first->load().waiters_count;
|
return reservation_notifier(raddr).first->load().waiters_count;
|
||||||
|
@ -947,6 +947,7 @@
|
|||||||
<ClInclude Include="Emu\Memory\vm.h" />
|
<ClInclude Include="Emu\Memory\vm.h" />
|
||||||
<ClInclude Include="Emu\Memory\vm_ptr.h" />
|
<ClInclude Include="Emu\Memory\vm_ptr.h" />
|
||||||
<ClInclude Include="Emu\Memory\vm_ref.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\Memory\vm_var.h" />
|
||||||
<ClInclude Include="Emu\RSX\rsx_methods.h" />
|
<ClInclude Include="Emu\RSX\rsx_methods.h" />
|
||||||
<ClInclude Include="Emu\RSX\rsx_utils.h" />
|
<ClInclude Include="Emu\RSX\rsx_utils.h" />
|
||||||
|
@ -1461,6 +1461,9 @@
|
|||||||
<ClInclude Include="Emu\Memory\vm_ref.h">
|
<ClInclude Include="Emu\Memory\vm_ref.h">
|
||||||
<Filter>Emu\Memory</Filter>
|
<Filter>Emu\Memory</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="Emu\Memory\vm_reservation.h">
|
||||||
|
<Filter>Emu\Memory</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="Emu\Memory\vm_var.h">
|
<ClInclude Include="Emu\Memory\vm_var.h">
|
||||||
<Filter>Emu\Memory</Filter>
|
<Filter>Emu\Memory</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user