CPU: Improve suspend_all g_suspend_counter handling

Increase in two stages, giving more chances to use it.
Second stage is when all wait flags have been seen.
This commit is contained in:
Nekotekina 2020-11-09 22:53:32 +03:00
parent 083397a555
commit cdaa8cb5c4
2 changed files with 30 additions and 32 deletions

View file

@ -587,10 +587,19 @@ bool cpu_thread::check_state() noexcept
{ {
bool store = false; bool store = false;
if (flags & cpu_flag::pause && !(flags & cpu_flag::wait)) if (flags & cpu_flag::pause)
{ {
// Save value before state is saved and cpu_flag::wait is observed // Save value before state is saved and cpu_flag::wait is observed
susp_ctr = g_suspend_counter; susp_ctr = g_suspend_counter;
if (susp_ctr & 1 && flags & cpu_flag::wait)
{
susp_ctr = -1;
}
}
else
{
susp_ctr = -1;
} }
if (flags & cpu_flag::temp) [[unlikely]] if (flags & cpu_flag::temp) [[unlikely]]
@ -705,29 +714,16 @@ bool cpu_thread::check_state() noexcept
// If only cpu_flag::pause was set, wait on suspend counter instead // If only cpu_flag::pause was set, wait on suspend counter instead
if (state0 & cpu_flag::pause) if (state0 & cpu_flag::pause)
{ {
if (state0 & cpu_flag::wait)
{
// Otherwise, value must be reliable because cpu_flag::wait hasn't been observed yet
susp_ctr = -1;
}
// Hard way
if (susp_ctr == umax) [[unlikely]]
{
g_fxo->get<cpu_counter>()->cpu_suspend_lock.lock_unlock();
continue;
}
// Wait for current suspend_all operation // Wait for current suspend_all operation
for (u64 i = 0;; i++) for (u64 i = 0;; i++)
{ {
if (i < 20) if (i < 20 || susp_ctr & 1)
{ {
busy_wait(300); busy_wait(300);
} }
else else if (g_suspend_counter.load() >> 1 >= susp_ctr >> 1)
{ {
g_suspend_counter.wait(susp_ctr); g_suspend_counter.wait(susp_ctr, -2);
} }
if (!(state & cpu_flag::pause)) if (!(state & cpu_flag::pause))
@ -907,6 +903,8 @@ bool cpu_thread::suspend_work::push(cpu_thread* _this, bool cancel_if_not_suspen
_mm_pause(); _mm_pause();
} }
g_suspend_counter++;
// Extract queue and reverse element order (FILO to FIFO) (TODO: maybe leave order as is?) // Extract queue and reverse element order (FILO to FIFO) (TODO: maybe leave order as is?)
auto* head = queue.exchange(nullptr); auto* head = queue.exchange(nullptr);
@ -959,11 +957,8 @@ bool cpu_thread::suspend_work::push(cpu_thread* _this, bool cancel_if_not_suspen
} }
} }
// Not sure if needed, may be overkill. Some workloads may execute instructions with non-temporal hint. // Finalization (second increment)
_mm_sfence(); verify(HERE), g_suspend_counter++ & 1;
// Finalization
g_suspend_counter++;
// Exact bitset for flag pause removal // Exact bitset for flag pause removal
std::memcpy(ctr->cpu_copy_bits, copy2, sizeof(copy2)); std::memcpy(ctr->cpu_copy_bits, copy2, sizeof(copy2));

View file

@ -1996,18 +1996,22 @@ void spu_thread::do_dma_transfer(spu_thread* _this, const spu_mfc_cmd& args, u8*
{ {
if (_cpu->state & cpu_flag::pause) if (_cpu->state & cpu_flag::pause)
{ {
cpu_thread::if_suspended<0>(_cpu, {dst, dst + 64, &res}, [&] const bool ok = cpu_thread::if_suspended<0>(_cpu, {dst, dst + 64, &res}, [&]
{ {
std::memcpy(dst, src, size0); std::memcpy(dst, src, size0);
res += 128; res += 128;
}); });
// Exit loop and function if (ok)
i = -1; {
bits = nullptr; // Exit loop and function
return; i = -1;
bits = nullptr;
return;
}
} }
else if (++i < 10)
if (++i < 10)
{ {
busy_wait(500); busy_wait(500);
} }
@ -2941,18 +2945,17 @@ bool spu_thread::process_mfc_cmd()
{ {
auto& sdata = *vm::get_super_ptr<spu_rdata_t>(addr); auto& sdata = *vm::get_super_ptr<spu_rdata_t>(addr);
cpu_thread::if_suspended<0>(this, {}, [&] const bool ok = cpu_thread::if_suspended<0>(this, {&ntime}, [&]
{ {
// Guaranteed success // Guaranteed success
ntime = vm::reservation_acquire(addr, 128); ntime = vm::reservation_acquire(addr, 128);
mov_rdata_nt(rdata, sdata); mov_rdata_nt(rdata, sdata);
}); });
_mm_mfence();
// Exit loop // Exit loop
if ((ntime & 127) == 0) if (ok && (ntime & 127) == 0)
{ {
_mm_mfence();
i = -1; i = -1;
return; return;
} }