mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-04 22:11:26 +12:00
Implement cpu_thread::if_suspended
Use it for opportunistic guaranteed GETLLAR execution (TSX-FA).
This commit is contained in:
parent
f5c575961f
commit
adf50b7c4b
4 changed files with 61 additions and 6 deletions
|
@ -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());
|
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)
|
// Can't allow pre-set wait bit (it'd be a problem)
|
||||||
verify(HERE), !_this || !(_this->state & cpu_flag::wait);
|
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
|
// Load current head
|
||||||
next = queue.load();
|
next = queue.load();
|
||||||
|
|
||||||
|
if (!next && cancel_if_not_suspended) [[unlikely]]
|
||||||
|
{
|
||||||
|
// Give up if not suspended
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!_this && next)
|
if (!_this && next)
|
||||||
{
|
{
|
||||||
// If _this == nullptr, it only works if this is the first workload pushed
|
// 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();
|
_this->check_state();
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_suspend_counter.notify_all();
|
g_suspend_counter.notify_all();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cpu_thread::stop_all() noexcept
|
void cpu_thread::stop_all() noexcept
|
||||||
|
|
|
@ -136,7 +136,7 @@ public:
|
||||||
suspend_work* next;
|
suspend_work* next;
|
||||||
|
|
||||||
// Internal method
|
// 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!)
|
// 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
|
// Stop all threads with cpu_flag::dbg_global_stop
|
||||||
static void stop_all() noexcept;
|
static void stop_all() noexcept;
|
||||||
|
|
||||||
|
|
|
@ -1189,10 +1189,27 @@ static T ppu_load_acquire_reservation(ppu_thread& ppu, u32 addr)
|
||||||
ppu.use_full_rdata = false;
|
ppu.use_full_rdata = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (u64 count = 0;; [&]()
|
for (u64 count = 0; count != umax; [&]()
|
||||||
{
|
{
|
||||||
if (ppu.state)
|
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();
|
ppu.check_state();
|
||||||
}
|
}
|
||||||
else if (++count < 20) [[likely]]
|
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);
|
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)
|
extern u32 ppu_lwarx(ppu_thread& ppu, u32 addr)
|
||||||
|
|
|
@ -2428,11 +2428,23 @@ bool spu_thread::process_mfc_cmd()
|
||||||
mov_rdata(temp, rdata);
|
mov_rdata(temp, rdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (u64 i = 0;; [&]()
|
for (u64 i = 0; i != umax; [&]()
|
||||||
{
|
{
|
||||||
if (state & cpu_flag::pause)
|
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]]
|
if (++i < 25) [[likely]]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue