From 9ac6ef649488d9bd9994cf22b33bc6c8fc5c20b7 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Fri, 25 Oct 2019 17:20:39 +0300 Subject: [PATCH] SPU: cleanup former OOM handling Remove cpu_flag::jit_return. It's obsolete now, and worked only in SPU ASMJIT anyway. --- rpcs3/Emu/CPU/CPUThread.cpp | 5 +- rpcs3/Emu/CPU/CPUThread.h | 3 +- rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp | 6 +- rpcs3/Emu/Cell/SPUASMJITRecompiler.h | 2 +- rpcs3/Emu/Cell/SPURecompiler.cpp | 144 ++++++------------------- rpcs3/Emu/Cell/SPURecompiler.h | 66 +----------- rpcs3/Emu/Cell/SPUThread.cpp | 12 --- 7 files changed, 46 insertions(+), 192 deletions(-) diff --git a/rpcs3/Emu/CPU/CPUThread.cpp b/rpcs3/Emu/CPU/CPUThread.cpp index c2e104293e..61fc22d281 100644 --- a/rpcs3/Emu/CPU/CPUThread.cpp +++ b/rpcs3/Emu/CPU/CPUThread.cpp @@ -30,7 +30,6 @@ void fmt_class_string::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& 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)) diff --git a/rpcs3/Emu/CPU/CPUThread.h b/rpcs3/Emu/CPU/CPUThread.h index 2a3bf0b397..1e90e82df3 100644 --- a/rpcs3/Emu/CPU/CPUThread.h +++ b/rpcs3/Emu/CPU/CPUThread.h @@ -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 diff --git a/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp b/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp index 5baa36a8f0..bb50f8e227 100644 --- a/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp @@ -45,11 +45,11 @@ void spu_recompiler::init() } } -spu_function_t spu_recompiler::compile(u64 last_reset_count, const std::vector& func, void* fn_location) +spu_function_t spu_recompiler::compile(const std::vector& 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::vectoradd(last_reset_count, fn_location, fn)) + if (!m_spurt->add(fn_location, fn)) { return nullptr; } diff --git a/rpcs3/Emu/Cell/SPUASMJITRecompiler.h b/rpcs3/Emu/Cell/SPUASMJITRecompiler.h index 05fa0292fd..b639f1aa6c 100644 --- a/rpcs3/Emu/Cell/SPUASMJITRecompiler.h +++ b/rpcs3/Emu/Cell/SPUASMJITRecompiler.h @@ -13,7 +13,7 @@ public: virtual void init() override; - virtual spu_function_t compile(u64 last_reset_count, const std::vector&, void*) override; + virtual spu_function_t compile(const std::vector&, void*) override; private: // ASMJIT runtime diff --git a/rpcs3/Emu/Cell/SPURecompiler.cpp b/rpcs3/Emu/Cell/SPURecompiler.cpp index 7d61b3f451..a825c4e8ad 100644 --- a/rpcs3/Emu/Cell/SPURecompiler.cpp +++ b/rpcs3/Emu/Cell/SPURecompiler.cpp @@ -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> 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& func) +void* spu_runtime::find(const std::vector& 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& 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& 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& 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(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>([](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& 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& func, void* fn_location) override + virtual spu_function_t compile(const std::vector& 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(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(target) - reinterpret_cast(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& func, void* fn_location) override + virtual spu_function_t compile(const std::vector& 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(::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(::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(result))) + if (!m_spurt->add(fn_location, reinterpret_cast(result))) { return nullptr; } diff --git a/rpcs3/Emu/Cell/SPURecompiler.h b/rpcs3/Emu/Cell/SPURecompiler.h index 26575dd7e4..c4b5e5d77b 100644 --- a/rpcs3/Emu/Cell/SPURecompiler.h +++ b/rpcs3/Emu/Cell/SPURecompiler.h @@ -44,10 +44,6 @@ class spu_runtime mutable cond_variable m_cond; - mutable atomic_t m_passive_locks{0}; - - atomic_t 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&); + void* find(const std::vector&); // Get func from opaque ptr static inline const std::vector& 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, (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&, void*) = 0; + virtual spu_function_t compile(const std::vector&, void*) = 0; // Compile function, handle failure void make_function(const std::vector&); diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 290dee4734..6067daab22 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -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(offset), nullptr);