SPU: Use optimized PPU signaling to SPU on reservation pause

This commit is contained in:
Eladash 2020-05-09 08:42:59 +03:00 committed by Ani
parent 525453794f
commit b38580bf32
2 changed files with 68 additions and 41 deletions

View File

@ -466,6 +466,7 @@ bool cpu_thread::check_state() noexcept
bool cpu_sleep_called = false; bool cpu_sleep_called = false;
bool cpu_flag_memory = false; bool cpu_flag_memory = false;
bool escape, retval;
if (!(state & cpu_flag::wait)) if (!(state & cpu_flag::wait))
{ {
@ -474,54 +475,73 @@ bool cpu_thread::check_state() noexcept
while (true) while (true)
{ {
if (state & cpu_flag::memory) // Process all flags in a single atomic op
const auto state0 = state.fetch_op([&](bs_t<cpu_flag>& flags)
{ {
if (auto& ptr = vm::g_tls_locked) bool store = false;
if (flags & cpu_flag::signal)
{ {
ptr->compare_and_swap(this, nullptr); flags -= cpu_flag::signal;
ptr = nullptr; cpu_sleep_called = false;
store = true;
} }
cpu_flag_memory = true;
state -= cpu_flag::memory;
}
if (state & (cpu_flag::exit + cpu_flag::dbg_global_stop))
{
state += cpu_flag::wait;
return true;
}
const auto [state0, escape] = state.fetch_op([&](bs_t<cpu_flag>& flags)
{
// Atomically clean wait flag and escape // Atomically clean wait flag and escape
if (!(flags & (cpu_flag::exit + cpu_flag::dbg_global_stop + cpu_flag::ret + cpu_flag::stop))) if (!(flags & (cpu_flag::exit + cpu_flag::dbg_global_stop + cpu_flag::ret + cpu_flag::stop)))
{ {
// Check pause flags which hold thread inside check_state // Check pause flags which hold thread inside check_state
if (flags & (cpu_flag::pause + cpu_flag::suspend + cpu_flag::dbg_global_pause + cpu_flag::dbg_pause)) if (flags & (cpu_flag::pause + cpu_flag::suspend + cpu_flag::dbg_global_pause + cpu_flag::dbg_pause))
{ {
return false; escape = false;
return store;
} }
flags -= cpu_flag::wait; if (flags & cpu_flag::memory)
{
// wait flag will be cleared later (optimization)
cpu_flag_memory = true;
}
else
{
AUDIT(!cpu_flag_memory);
flags -= cpu_flag::wait;
store = true;
}
retval = false;
}
else
{
cpu_flag_memory = false;
retval = true;
} }
return true; if (flags & cpu_flag::dbg_step)
}); {
flags += cpu_flag::dbg_pause;
flags -= cpu_flag::dbg_step;
store = true;
}
if (state & cpu_flag::signal && state.test_and_reset(cpu_flag::signal)) escape = true;
{ return store;
cpu_sleep_called = false; }).first;
}
if (escape) if (escape)
{ {
if (cpu_flag_memory) if (cpu_flag_memory)
{ {
cpu_mem(); cpu_mem();
if (state & (cpu_flag::pause + cpu_flag::memory)) [[unlikely]]
{
state += cpu_flag::wait;
continue;
}
} }
break; return retval;
} }
else if (!cpu_sleep_called && state0 & cpu_flag::suspend) else if (!cpu_sleep_called && state0 & cpu_flag::suspend)
{ {
@ -540,21 +560,6 @@ bool cpu_thread::check_state() noexcept
g_fxo->get<cpu_counter>()->cpu_suspend_lock.lock_unlock(); g_fxo->get<cpu_counter>()->cpu_suspend_lock.lock_unlock();
} }
} }
const auto state_ = state.load();
if (state_ & (cpu_flag::ret + cpu_flag::stop))
{
return true;
}
if (state_ & cpu_flag::dbg_step)
{
state += cpu_flag::dbg_pause;
state -= cpu_flag::dbg_step;
}
return false;
} }
void cpu_thread::notify() void cpu_thread::notify()

View File

@ -129,9 +129,30 @@ namespace vm
{ {
if (g_tls_locked && *g_tls_locked == &cpu) [[unlikely]] if (g_tls_locked && *g_tls_locked == &cpu) [[unlikely]]
{ {
if (cpu.state & cpu_flag::wait)
{
while (true)
{
g_mutex.lock_unlock();
cpu.state -= cpu_flag::wait + cpu_flag::memory;
if (g_mutex.is_lockable()) [[likely]]
{
return;
}
cpu.state += cpu_flag::wait;
}
}
return; return;
} }
if (cpu.state & cpu_flag::memory)
{
cpu.state -= cpu_flag::memory;
}
if (g_mutex.is_lockable()) [[likely]] if (g_mutex.is_lockable()) [[likely]]
{ {
// Optimistic path (hope that mutex is not exclusively locked) // Optimistic path (hope that mutex is not exclusively locked)
@ -355,7 +376,8 @@ namespace vm
for (auto lock = g_locks.cbegin(), end = lock + g_cfg.core.ppu_threads; lock != end; lock++) for (auto lock = g_locks.cbegin(), end = lock + g_cfg.core.ppu_threads; lock != end; lock++)
{ {
while (*lock) cpu_thread* ptr;
while ((ptr = *lock) && !(ptr->state & cpu_flag::wait))
{ {
_mm_pause(); _mm_pause();
} }