1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-23 03:02:53 +01:00

SPU: cleanup former OOM handling

Remove cpu_flag::jit_return.
It's obsolete now, and worked only in SPU ASMJIT anyway.
This commit is contained in:
Nekotekina 2019-10-25 17:20:39 +03:00
parent 7a32af7a57
commit 9ac6ef6494
7 changed files with 46 additions and 192 deletions

View File

@ -30,7 +30,6 @@ void fmt_class_string<cpu_flag>::format(std::string& out, u64 arg)
case cpu_flag::ret: return "ret";
case cpu_flag::signal: return "sig";
case cpu_flag::memory: return "mem";
case cpu_flag::jit_return: return "JIT";
case cpu_flag::dbg_global_pause: return "G-PAUSE";
case cpu_flag::dbg_global_stop: return "G-EXIT";
case cpu_flag::dbg_pause: return "PAUSE";
@ -423,7 +422,7 @@ bool cpu_thread::check_state() noexcept
state -= cpu_flag::memory;
}
if (state & (cpu_flag::exit + cpu_flag::jit_return + cpu_flag::dbg_global_stop))
if (state & (cpu_flag::exit + cpu_flag::dbg_global_stop))
{
state += cpu_flag::wait;
return true;
@ -432,7 +431,7 @@ bool cpu_thread::check_state() noexcept
const auto [state0, escape] = state.fetch_op([&](bs_t<cpu_flag>& flags)
{
// Atomically clean wait flag and escape
if (!(flags & (cpu_flag::exit + cpu_flag::jit_return + 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
if (flags & (cpu_flag::pause + cpu_flag::suspend + cpu_flag::dbg_global_pause + cpu_flag::dbg_pause))

View File

@ -15,7 +15,6 @@ enum class cpu_flag : u32
signal, // Thread received a signal (HLE)
memory, // Thread must unlock memory mutex
jit_return, // JIT compiler event (forced return)
dbg_global_pause, // Emulation paused
dbg_global_stop, // Emulation stopped
dbg_pause, // Thread paused
@ -66,7 +65,7 @@ public:
// Test stopped state
bool is_stopped() const
{
return !!(state & (cpu_flag::stop + cpu_flag::exit + cpu_flag::jit_return + cpu_flag::dbg_global_stop));
return !!(state & (cpu_flag::stop + cpu_flag::exit + cpu_flag::dbg_global_stop));
}
// Test paused state

View File

@ -45,11 +45,11 @@ void spu_recompiler::init()
}
}
spu_function_t spu_recompiler::compile(u64 last_reset_count, const std::vector<u32>& func, void* fn_location)
spu_function_t spu_recompiler::compile(const std::vector<u32>& func, void* fn_location)
{
if (!fn_location)
{
fn_location = m_spurt->find(last_reset_count, func);
fn_location = m_spurt->find(func);
}
if (fn_location == spu_runtime::g_dispatcher)
@ -892,7 +892,7 @@ spu_function_t spu_recompiler::compile(u64 last_reset_count, const std::vector<u
LOG_FATAL(SPU, "Failed to build a function");
}
if (!m_spurt->add(last_reset_count, fn_location, fn))
if (!m_spurt->add(fn_location, fn))
{
return nullptr;
}

View File

@ -13,7 +13,7 @@ public:
virtual void init() override;
virtual spu_function_t compile(u64 last_reset_count, const std::vector<u32>&, void*) override;
virtual spu_function_t compile(const std::vector<u32>&, void*) override;
private:
// ASMJIT runtime

View File

@ -400,7 +400,7 @@ void spu_cache::initialize()
{
compiler->init();
if (compiler->compile(0, {}, nullptr) && spu_runtime::g_interpreter)
if (compiler->compile({}, nullptr) && spu_runtime::g_interpreter)
{
LOG_SUCCESS(SPU, "SPU Runtime: built interpreter.");
@ -447,9 +447,6 @@ void spu_cache::initialize()
for (std::size_t i = 0; i < compilers.size(); i++) thread_queue.emplace_back("Worker " + std::to_string(i), [&, compiler = compilers[i].get()]()
{
// Register SPU runtime user
spu_runtime::passive_lock _passive_lock(compiler->get_runtime());
// Fake LS
std::vector<be_t<u32>> ls(0x10000);
@ -482,7 +479,7 @@ void spu_cache::initialize()
LOG_ERROR(SPU, "[0x%05x] SPU Analyser failed, %u vs %u", func2[0], func2.size() - 1, size0 - 1);
}
if (!compiler->compile(0, func, nullptr))
if (!compiler->compile(func, nullptr))
{
// Likely, out of JIT memory. Signal to prevent further building.
fail_flag |= 1;
@ -523,8 +520,6 @@ void spu_cache::initialize()
if (fail_flag)
{
LOG_ERROR(SPU, "SPU Runtime: Cache building failed (too much data). SPU Cache will be disabled.");
spu_runtime::passive_lock _passive_lock(compilers[0]->get_runtime());
compilers[0]->get_runtime().reset(0);
return;
}
@ -607,12 +602,11 @@ spu_runtime::spu_runtime()
}
}
bool spu_runtime::add(u64 last_reset_count, void* _where, spu_function_t compiled)
bool spu_runtime::add(void* _where, spu_function_t compiled)
{
writer_lock lock(*this);
// Check reset count (makes where invalid)
if (!_where || last_reset_count != m_reset_count)
if (!_where)
{
return false;
}
@ -957,16 +951,10 @@ spu_function_t spu_runtime::rebuild_ubertrampoline(u32 id_inst)
return beg->second;
}
void* spu_runtime::find(u64 last_reset_count, const std::vector<u32>& func)
void* spu_runtime::find(const std::vector<u32>& func)
{
writer_lock lock(*this);
// Check reset count
if (last_reset_count != m_reset_count)
{
return nullptr;
}
//
const u32 _off = 1 + (func[0] / 4) * (false);
@ -979,11 +967,6 @@ void* spu_runtime::find(u64 last_reset_count, const std::vector<u32>& func)
while (!found->second)
{
m_cond.wait(m_mutex);
if (last_reset_count != m_reset_count)
{
return nullptr;
}
}
// Already compiled
@ -1010,12 +993,6 @@ void* spu_runtime::find(u64 last_reset_count, const std::vector<u32>& func)
while (!fn_location->second)
{
m_cond.wait(m_mutex);
// If reset count changed, fn_location is invalidated; also requires return
if (last_reset_count != m_reset_count)
{
return nullptr;
}
}
return g_dispatcher;
@ -1027,14 +1004,7 @@ void* spu_runtime::find(u64 last_reset_count, const std::vector<u32>& func)
spu_function_t spu_runtime::find(const u32* ls, u32 addr) const
{
const u64 reset_count = m_reset_count;
reader_lock lock(*this);
if (reset_count != m_reset_count)
{
return nullptr;
}
reader_lock lock(this->m_mutex);
const auto upper = m_pic_map.upper_bound({ls + addr / 4, (0x40000 - addr) / 4});
@ -1083,53 +1053,6 @@ spu_function_t spu_runtime::make_branch_patchpoint() const
return reinterpret_cast<spu_function_t>(raw);
}
u64 spu_runtime::reset(std::size_t last_reset_count)
{
writer_lock lock(*this);
if (last_reset_count != m_reset_count || !m_reset_count.compare_and_swap_test(last_reset_count, last_reset_count + 1))
{
// Probably already reset
return m_reset_count;
}
// Notify SPU threads
idm::select<named_thread<spu_thread>>([](u32, cpu_thread& cpu)
{
if (!cpu.state.test_and_set(cpu_flag::jit_return))
{
cpu.notify();
}
});
// Reset function map (may take some time)
m_map.clear();
m_pic_map.clear();
// Wait for threads to catch on jit_return flag
while (m_passive_locks)
{
busy_wait();
}
// Reinitialize (TODO)
jit_runtime::finalize();
jit_runtime::initialize();
return ++m_reset_count;
}
void spu_runtime::handle_return(spu_thread* _spu)
{
// Wait until the runtime becomes available
writer_lock lock(*this);
// Reset stack mirror
std::memset(_spu->stack_mirror.data(), 0xff, sizeof(spu_thread::stack_mirror));
// Reset the flag
_spu->state -= cpu_flag::jit_return;
}
spu_recompiler_base::spu_recompiler_base()
{
result.reserve(8192);
@ -1141,15 +1064,7 @@ spu_recompiler_base::~spu_recompiler_base()
void spu_recompiler_base::make_function(const std::vector<u32>& data)
{
for (u64 reset_count = m_spurt->get_reset_count();;)
{
if (LIKELY(compile(reset_count, data, nullptr)))
{
break;
}
reset_count = m_spurt->reset(reset_count);
}
compile(data, nullptr);
}
void spu_recompiler_base::dispatch(spu_thread& spu, void*, u8* rip)
@ -4238,16 +4153,16 @@ public:
}
}
virtual spu_function_t compile(u64 last_reset_count, const std::vector<u32>& func, void* fn_location) override
virtual spu_function_t compile(const std::vector<u32>& func, void* fn_location) override
{
if (func.empty() && last_reset_count == 0 && m_interp_magn)
if (func.empty() && m_interp_magn)
{
return compile_interpreter();
}
if (!fn_location)
{
fn_location = m_spurt->find(last_reset_count, func);
fn_location = m_spurt->find(func);
}
if (fn_location == spu_runtime::g_dispatcher)
@ -4830,7 +4745,7 @@ public:
// Register function pointer
const spu_function_t fn = reinterpret_cast<spu_function_t>(m_jit.get_engine().getPointerToFunction(main_func));
if (!m_spurt->add(last_reset_count, fn_location, fn))
if (!m_spurt->add(fn_location, fn))
{
return nullptr;
}
@ -8364,9 +8279,9 @@ struct spu_llvm
LOG_ERROR(SPU, "[0x%05x] SPU Analyser failed, %u vs %u", func2[0], func2.size() - 1, size0 - 1);
}
if (const auto target = compiler->compile(0, func, parg->first))
if (const auto target = compiler->compile(func, parg->first))
{
// Redirect old function
// Redirect old function (TODO: patch in multiple places)
const s64 rel = reinterpret_cast<u64>(target) - reinterpret_cast<u64>(parg->second) - 5;
union
@ -8421,11 +8336,11 @@ struct spu_fast : public spu_recompiler_base
}
}
virtual spu_function_t compile(u64 last_reset_count, const std::vector<u32>& func, void* fn_location) override
virtual spu_function_t compile(const std::vector<u32>& func, void* fn_location) override
{
if (!fn_location)
{
fn_location = m_spurt->find(last_reset_count, func);
fn_location = m_spurt->find(func);
}
if (fn_location == spu_runtime::g_dispatcher)
@ -8446,7 +8361,7 @@ struct spu_fast : public spu_recompiler_base
}
// Allocate executable area with necessary size
const auto result = jit_runtime::alloc(8 + 1 + 9 + (::size32(func) - 1) * (16 + 16) + 36 + 47, 16);
const auto result = jit_runtime::alloc(16 + 1 + 9 + (::size32(func) - 1) * (16 + 16) + 36 + 47, 16);
if (!result)
{
@ -8458,13 +8373,14 @@ struct spu_fast : public spu_recompiler_base
u8* raw = result;
// 8-byte NOP for patching
*raw++ = 0x0f;
*raw++ = 0x1f;
*raw++ = 0x84;
*raw++ = 0x00;
*raw++ = 0x00;
*raw++ = 0x00;
// 8-byte intruction for patching
// Update block_hash: mov [r13 + spu_thread::m_block_hash], 0xffff
*raw++ = 0x49;
*raw++ = 0xc7;
*raw++ = 0x45;
*raw++ = ::narrow<s8>(::offset32(&spu_thread::block_hash));
*raw++ = 0xff;
*raw++ = 0xff;
*raw++ = 0x00;
*raw++ = 0x00;
@ -8509,6 +8425,16 @@ struct spu_fast : public spu_recompiler_base
// trap
//*raw++ = 0xcc;
// Update block_hash: mov [r13 + spu_thread::m_block_hash], 0xfffe
*raw++ = 0x49;
*raw++ = 0xc7;
*raw++ = 0x45;
*raw++ = ::narrow<s8>(::offset32(&spu_thread::block_hash));
*raw++ = 0xfe;
*raw++ = 0xff;
*raw++ = 0x00;
*raw++ = 0x00;
// Secondary prologue: sub rsp,0x28
*raw++ = 0x48;
*raw++ = 0x83;
@ -8713,7 +8639,7 @@ struct spu_fast : public spu_recompiler_base
*raw++ = 0x28;
*raw++ = 0xc3;
if (!m_spurt->add(last_reset_count, fn_location, reinterpret_cast<spu_function_t>(result)))
if (!m_spurt->add(fn_location, reinterpret_cast<spu_function_t>(result)))
{
return nullptr;
}

View File

@ -44,10 +44,6 @@ class spu_runtime
mutable cond_variable m_cond;
mutable atomic_t<u64> m_passive_locks{0};
atomic_t<u64> m_reset_count{0};
struct func_compare
{
// Comparison function for SPU programs
@ -93,7 +89,7 @@ public:
}
// Add compiled function and generate trampoline if necessary
bool add(u64 last_reset_count, void* where, spu_function_t compiled);
bool add(void* where, spu_function_t compiled);
private:
spu_function_t rebuild_ubertrampoline(u32 id_inst);
@ -102,7 +98,7 @@ private:
public:
// Return opaque pointer for add()
void* find(u64 last_reset_count, const std::vector<u32>&);
void* find(const std::vector<u32>&);
// Get func from opaque ptr
static inline const std::vector<u32>& get_func(void* _where)
@ -116,18 +112,6 @@ public:
// Generate a patchable trampoline to spu_recompiler_base::branch
spu_function_t make_branch_patchpoint() const;
// reset() arg retriever, for race avoidance (can result in double reset)
u64 get_reset_count() const
{
return m_reset_count.load();
}
// Remove all compiled function and free JIT memory
u64 reset(std::size_t last_reset_count);
// Handle cpu_flag::jit_return
void handle_return(spu_thread* _spu);
// All dispatchers (array allocated in jit memory)
static std::array<atomic_t<spu_function_t>, (1 << 20)>* const g_dispatcher;
@ -146,26 +130,7 @@ public:
// Interpreter entry point
static spu_function_t g_interpreter;
struct passive_lock
{
spu_runtime& _this;
passive_lock(const passive_lock&) = delete;
passive_lock(spu_runtime& _this)
: _this(_this)
{
std::lock_guard lock(_this.m_mutex);
_this.m_passive_locks++;
}
~passive_lock()
{
_this.m_passive_locks--;
}
};
// Exclusive lock within passive_lock scope
// Exclusive lock
struct writer_lock
{
spu_runtime& _this;
@ -176,14 +141,11 @@ public:
writer_lock(spu_runtime& _this)
: _this(_this)
{
// Temporarily release the passive lock
_this.m_passive_locks--;
_this.m_mutex.lock();
}
~writer_lock()
{
_this.m_passive_locks++;
_this.m_mutex.unlock();
if (notify)
@ -192,26 +154,6 @@ public:
}
}
};
struct reader_lock
{
const spu_runtime& _this;
reader_lock(const reader_lock&) = delete;
reader_lock(const spu_runtime& _this)
: _this(_this)
{
_this.m_passive_locks--;
_this.m_mutex.lock_shared();
}
~reader_lock()
{
_this.m_passive_locks++;
_this.m_mutex.unlock_shared();
}
};
};
// SPU Recompiler instance base class
@ -373,7 +315,7 @@ public:
virtual void init() = 0;
// Compile function (may fail)
virtual spu_function_t compile(u64 last_reset_count, const std::vector<u32>&, void*) = 0;
virtual spu_function_t compile(const std::vector<u32>&, void*) = 0;
// Compile function, handle failure
void make_function(const std::vector<u32>&);

View File

@ -1145,24 +1145,12 @@ void spu_thread::cpu_task()
if (jit)
{
// Register SPU runtime user
spu_runtime::passive_lock _passive_lock(jit->get_runtime());
while (true)
{
if (UNLIKELY(state))
{
if (check_state())
{
if (state & cpu_flag::jit_return)
{
// Handle jit_return as a special case
jit->get_runtime().handle_return(this);
continue;
}
break;
}
}
spu_runtime::g_gateway(*this, vm::_ptr<u8>(offset), nullptr);