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:
parent
7a32af7a57
commit
9ac6ef6494
@ -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))
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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>&);
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user