Implement cpu_thread::if_suspended

Use it for opportunistic guaranteed GETLLAR execution (TSX-FA).
This commit is contained in:
Nekotekina 2020-10-17 14:55:31 +03:00
parent f5c575961f
commit adf50b7c4b
4 changed files with 61 additions and 6 deletions

View File

@ -739,7 +739,7 @@ std::string cpu_thread::dump_misc() const
return fmt::format("Type: %s\n" "State: %s\n", typeid(*this).name(), state.load());
}
void cpu_thread::suspend_work::push(cpu_thread* _this) noexcept
bool cpu_thread::suspend_work::push(cpu_thread* _this, bool cancel_if_not_suspended) noexcept
{
// Can't allow pre-set wait bit (it'd be a problem)
verify(HERE), !_this || !(_this->state & cpu_flag::wait);
@ -758,6 +758,12 @@ void cpu_thread::suspend_work::push(cpu_thread* _this) noexcept
// Load current head
next = queue.load();
if (!next && cancel_if_not_suspended) [[unlikely]]
{
// Give up if not suspended
return false;
}
if (!_this && next)
{
// If _this == nullptr, it only works if this is the first workload pushed
@ -869,10 +875,11 @@ void cpu_thread::suspend_work::push(cpu_thread* _this) noexcept
}
_this->check_state();
return;
return true;
}
g_suspend_counter.notify_all();
return true;
}
void cpu_thread::stop_all() noexcept

View File

@ -136,7 +136,7 @@ public:
suspend_work* next;
// Internal method
void push(cpu_thread* _this) noexcept;
bool push(cpu_thread* _this, bool cancel_if_not_suspended = false) noexcept;
};
// Suspend all threads and execute op (may be executed by other thread than caller!)
@ -167,6 +167,21 @@ public:
}
}
// Push the workload only if threads are being suspended by suspend_all()
template <s8 Prio = 0, typename F>
static bool if_suspended(cpu_thread* _this, F op)
{
static_assert(std::is_void_v<std::invoke_result_t<F>>, "Unimplemented (must return void)");
{
suspend_work work{Prio, &op, nullptr, [](void* func, void*)
{
std::invoke(*static_cast<F*>(func));
}};
return work.push(_this, true);
}
}
// Stop all threads with cpu_flag::dbg_global_stop
static void stop_all() noexcept;

View File

@ -1189,10 +1189,27 @@ static T ppu_load_acquire_reservation(ppu_thread& ppu, u32 addr)
ppu.use_full_rdata = false;
}
for (u64 count = 0;; [&]()
for (u64 count = 0; count != umax; [&]()
{
if (ppu.state)
{
if (ppu.state & cpu_flag::pause)
{
verify(HERE), cpu_thread::if_suspended<-1>(&ppu, [&]()
{
// Guaranteed success
ppu.rtime = vm::reservation_acquire(addr, sizeof(T)) & -128;
mov_rdata(ppu.rdata, *vm::get_super_ptr<spu_rdata_t>(addr & -128));
});
// Exit loop
if ((ppu.rtime & 127) == 0)
{
count = -1;
return;
}
}
ppu.check_state();
}
else if (++count < 20) [[likely]]
@ -1275,6 +1292,10 @@ static T ppu_load_acquire_reservation(ppu_thread& ppu, u32 addr)
return static_cast<T>(rdata << data_off >> size_off);
}
}
be_t<u64> rdata;
std::memcpy(&rdata, &ppu.rdata[addr & 0x78], 8);
return static_cast<T>(rdata << data_off >> size_off);
}
extern u32 ppu_lwarx(ppu_thread& ppu, u32 addr)

View File

@ -2428,11 +2428,23 @@ bool spu_thread::process_mfc_cmd()
mov_rdata(temp, rdata);
}
for (u64 i = 0;; [&]()
for (u64 i = 0; i != umax; [&]()
{
if (state & cpu_flag::pause)
{
check_state();
verify(HERE), cpu_thread::if_suspended<-1>(this, [&]
{
// Guaranteed success
ntime = vm::reservation_acquire(addr, 128);
mov_rdata(rdata, *vm::get_super_ptr<spu_rdata_t>(addr));
});
// Exit loop
if ((ntime & 127) == 0)
{
i = -1;
return;
}
}
if (++i < 25) [[likely]]