Skip to content

Commit

Permalink
SPU: Add alerted mode reservation status monitoring
Browse files Browse the repository at this point in the history
  • Loading branch information
elad335 committed Dec 7, 2021
1 parent 6730dc1 commit 53e2ba9
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 30 deletions.
18 changes: 12 additions & 6 deletions Utilities/Thread.h
Expand Up @@ -276,8 +276,8 @@ class thread_ctrl final
}

// Wait for both thread sync var and provided atomic var
template <atomic_wait::op Op = atomic_wait::op::eq, typename T, typename U>
static inline void wait_on(T& wait, U old, u64 usec = -1)
template <uint Max, typename Func>
static inline void wait_on_custom(Func&& setter, u64 usec = -1)
{
auto _this = g_tls_this_thread;

Expand All @@ -286,13 +286,19 @@ class thread_ctrl final
return;
}

atomic_wait::list<3> list{};
list.set<0, Op>(wait, old);
list.set<1>(_this->m_sync, 0, 4 + 1);
list.set<2>(_this->m_taskq, nullptr);
atomic_wait::list<Max + 2> list{};
list.set<Max>(_this->m_sync, 0, 4 + 1);
list.set<Max + 1>(_this->m_taskq, nullptr);
setter(list);
list.wait(atomic_wait_timeout{usec <= 0xffff'ffff'ffff'ffff / 1000 ? usec * 1000 : 0xffff'ffff'ffff'ffff});
}

template <atomic_wait::op Op = atomic_wait::op::eq, typename T, typename U>
static inline void wait_on(T& wait, U old, u64 usec = -1)
{
wait_on_custom<1>([&]<typename L>(L& list){ list.set<0, Op>(wait, old); }, usec);
}

// Exit.
[[noreturn]] static void emergency_exit(std::string_view reason);

Expand Down
77 changes: 55 additions & 22 deletions rpcs3/Emu/Cell/SPUThread.cpp
Expand Up @@ -4022,40 +4022,45 @@ s64 spu_thread::get_ch_value(u32 ch)

spu_function_logger logger(*this, "MFC Events read");

if (mask1 & SPU_EVENT_LR && raddr)
{
if (mask1 != SPU_EVENT_LR && mask1 != SPU_EVENT_LR + SPU_EVENT_TM)
{
// Combining LR with other flags needs another solution
fmt::throw_exception("Not supported: event mask 0x%x", mask1);
}
state += cpu_flag::wait;

for (; !events.count; events = get_events(mask1, false, true))
using resrv_ptr = std::add_pointer_t<decltype(rdata)>;

resrv_ptr resrv_mem{};
std::shared_ptr<utils::shm> rdata_shm;

if (raddr && mask1 & SPU_EVENT_LR)
{
if (auto area = vm::get(vm::any, raddr))
{
const auto old = state.add_fetch(cpu_flag::wait);
// Ensure possesion over reservation memory so it won't be deallocated
auto [base_addr, shm_] = area->peek(raddr);

if (is_stopped(old))
if (shm_)
{
return -1;
const u32 data_offs = raddr - base_addr;
rdata_shm = std::move(shm_);
vm::writer_lock{}, resrv_mem = reinterpret_cast<resrv_ptr>(rdata_shm->map_self() + data_offs);
}

if (is_paused(old))
else
{
// Ensure reservation data won't change while paused for debugging purposes
check_state();
continue;
raddr = 0;
}

vm::reservation_notifier(raddr).wait(rtime, -128, atomic_wait_timeout{100'000});
}
else
{
raddr = 0;
}

check_state();
return events.events & mask1;
if (!raddr)
{
set_events(SPU_EVENT_LR);
}
}

for (; !events.count; events = get_events(mask1, true, true))
for (; !events.count; events = get_events(mask1 & ~SPU_EVENT_LR, true, true))
{
const auto old = state.add_fetch(cpu_flag::wait);
const auto old = +state;

if (is_stopped(old))
{
Expand All @@ -4064,7 +4069,35 @@ s64 spu_thread::get_ch_value(u32 ch)

if (is_paused(old))
{
// Ensure spu_thread::rdata's stagnancy while the thread is paused for debugging purposes
check_state();
state += cpu_flag::wait;
continue;
}

// Optimized check
if (raddr && (!vm::check_addr(raddr) || rtime != vm::reservation_acquire(raddr) || !cmp_rdata(rdata, *resrv_mem))))
{
raddr = 0;
set_events(SPU_EVENT_LR);
continue;
}

if (g_cfg.core.spu_alerted_rdata_check)
{
// Optimized for wake-up speed when simple writes are the cause of reservation loss
// Benefit is rare, as you need many threads to experience it + the game also needs to use STW-alike instructions to invalidate reservation
continue;
}

if (raddr)
{
thread_ctrl::wait_on_custom<2>([&]<typename T>(T& list)
{
list.set<0>(state, old);
list.set<1>(vm::reservation_notifier(raddr), rtime, -128);
}, 100);

continue;
}

Expand Down
3 changes: 1 addition & 2 deletions rpcs3/Emu/Memory/vm.cpp
Expand Up @@ -1422,10 +1422,9 @@ namespace vm
return {addr, nullptr};
}

// Special case
if (m_common)
{
return {addr, nullptr};
return {this->addr, m_common};
}

// Range check
Expand Down
1 change: 1 addition & 0 deletions rpcs3/Emu/system_config.h
Expand Up @@ -46,6 +46,7 @@ struct cfg_root : cfg::node
cfg::_bool spu_verification{ this, "SPU Verification", true }; // Should be enabled
cfg::_bool spu_cache{ this, "SPU Cache", true };
cfg::_bool spu_prof{ this, "SPU Profiler", false };
cfg::_bool spu_alerted_rdata_check{ this, "SPU Alerted Reservation Check", false, true }; // Do not use if unsure, refer to SPUThread.cpp for explenation
cfg::uint<0, 16> mfc_transfers_shuffling{ this, "MFC Commands Shuffling Limit", 0 };
cfg::uint<0, 10000> mfc_transfers_timeout{ this, "MFC Commands Timeout", 0, true };
cfg::_bool mfc_shuffling_in_steps{ this, "MFC Commands Shuffling In Steps", false, true };
Expand Down

0 comments on commit 53e2ba9

Please sign in to comment.