From f2c8db75bfcd1fe054a0777e1bc9f636717cd9e7 Mon Sep 17 00:00:00 2001 From: Vincent Lejeune <vljn.ovi@gmail.com> Date: Sun, 23 Aug 2015 17:13:36 +0200 Subject: [PATCH] PPU/LLVM: Do not recompile blocks --- rpcs3/Emu/Cell/PPULLVMRecompiler.cpp | 117 ++++----------------------- rpcs3/Emu/Cell/PPULLVMRecompiler.h | 19 +---- 2 files changed, 17 insertions(+), 119 deletions(-) diff --git a/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp b/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp index 6bdcf48500..fb8a2e9ef0 100644 --- a/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp +++ b/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp @@ -318,15 +318,7 @@ const Executable *RecompilationEngine::GetExecutable(u32 address, bool isFunctio return isFunction ? &executeFunc : &executeUntilReturn; } -std::pair<std::mutex, std::atomic<int> >* RecompilationEngine::GetMutexAndCounterForAddress(u32 address) { - std::lock_guard<std::mutex> lock(m_address_locks_lock); - std::unordered_map<u32, std::pair<std::mutex, std::atomic<int>> >::iterator It = m_address_locks.find(address); - if (It == m_address_locks.end()) - return nullptr; - return &(It->second); -} - -bool RecompilationEngine::isAddressCommited(u32 address) const +bool RecompilationEngine::isAddressCommited(u32 address) const { size_t offset = address * sizeof(Executable); size_t page = offset / 4096; @@ -345,7 +337,7 @@ void RecompilationEngine::commitAddress(u32 address) FunctionCachePagesCommited[page >> 3] |= (1 << (page & 7)); } -const Executable RecompilationEngine::GetCompiledExecutableIfAvailable(u32 address) +const Executable RecompilationEngine::GetCompiledExecutableIfAvailable(u32 address) { std::lock_guard<std::mutex> lock(m_address_to_function_lock); if (!isAddressCommited(address / 4)) @@ -361,22 +353,6 @@ const Executable RecompilationEngine::GetCompiledExecutableIfAvailable(u32 addre return std::get<0>(It->second); } -void RecompilationEngine::RemoveUnusedEntriesFromCache() { - auto now = std::chrono::high_resolution_clock::now(); - if (std::chrono::duration_cast<std::chrono::milliseconds>(now - m_last_cache_clear_time).count() > 10000) { - for (auto i = m_address_to_function.begin(); i != m_address_to_function.end();) { - auto tmp = i; - i++; - if (std::get<2>(tmp->second) == 0) - m_address_to_function.erase(tmp); - else - std::get<2>(tmp->second) = 0; - } - - m_last_cache_clear_time = now; - } -} - void RecompilationEngine::NotifyTrace(ExecutionTrace * execution_trace) { { std::lock_guard<std::mutex> lock(m_pending_execution_traces_lock); @@ -402,7 +378,6 @@ raw_fd_ostream & RecompilationEngine::Log() { } void RecompilationEngine::Task() { - bool is_idling = false; std::chrono::nanoseconds idling_time(0); std::chrono::nanoseconds recompiling_time(0); @@ -423,46 +398,11 @@ void RecompilationEngine::Task() { if (execution_trace) { ProcessExecutionTrace(*execution_trace); - delete execution_trace; work_done_this_iteration = true; + delete execution_trace; } if (!work_done_this_iteration) { - // TODO: Reduce the priority of the recompilation engine thread if its set to high priority - } - else { - is_idling = false; - } - - if (is_idling) { - auto recompiling_start = std::chrono::high_resolution_clock::now(); - - // Recompile the function whose CFG has changed the most since the last time it was compiled - auto candidate = (BlockEntry *)nullptr; - size_t max_diff = 0; - for (auto block : m_block_table) { - if (block->IsFunction() && block->is_compiled) { - auto diff = block->cfg.GetSize() - block->last_compiled_cfg_size; - if (diff > max_diff) { - candidate = block; - max_diff = diff; - } - } - } - - if (candidate != nullptr) { - Log() << "Recompiling: " << candidate->ToString() << "\n"; - CompileBlock(*candidate); - work_done_this_iteration = true; - } - - auto recompiling_end = std::chrono::high_resolution_clock::now(); - recompiling_time += std::chrono::duration_cast<std::chrono::nanoseconds>(recompiling_end - recompiling_start); - } - - if (!work_done_this_iteration) { - is_idling = true; - // Wait a few ms for something to happen auto idling_start = std::chrono::high_resolution_clock::now(); std::unique_lock<std::mutex> lock(mutex); @@ -583,8 +523,8 @@ void RecompilationEngine::CompileBlock(BlockEntry & block_entry) { Log() << "Compile: " << block_entry.ToString() << "\n"; Log() << "CFG: " << block_entry.cfg.ToString() << "\n"; - const std::pair<Executable, llvm::ExecutionEngine *> &compileResult = - m_compiler.Compile(fmt::format("fn_0x%08X_%u", block_entry.cfg.start_address, block_entry.revision++), block_entry.cfg, + const std::pair<Executable, llvm::ExecutionEngine *> &compileResult = + m_compiler.Compile(fmt::format("fn_0x%08X", block_entry.cfg.start_address), block_entry.cfg, block_entry.IsFunction() ? true : false /*generate_linkable_exits*/); // If entry doesn't exist, create it (using lock) @@ -597,24 +537,6 @@ void RecompilationEngine::CompileBlock(BlockEntry & block_entry) { commitAddress(block_entry.cfg.start_address / 4); } - std::unordered_map<u32, std::pair<std::mutex, std::atomic<int>> >::iterator It2 = m_address_locks.find(block_entry.cfg.start_address); - if (It2 == m_address_locks.end()) - { - std::lock_guard<std::mutex> lock(m_address_locks_lock); - (void)m_address_locks[block_entry.cfg.start_address]; - m_address_locks[block_entry.cfg.start_address].second.store(0); - } - - std::lock_guard<std::mutex> lock(m_address_locks[block_entry.cfg.start_address].first); - - int loopiteration = 0; - while (m_address_locks[block_entry.cfg.start_address].second.load() > 0) - { - std::this_thread::yield(); - if (loopiteration++ > 10000000) - return; - } - std::get<1>(m_address_to_function[block_entry.cfg.start_address]) = std::unique_ptr<llvm::ExecutionEngine>(compileResult.second); std::get<0>(m_address_to_function[block_entry.cfg.start_address]) = compileResult.first; std::get<3>(m_address_to_function[block_entry.cfg.start_address]) = m_currentId; @@ -768,25 +690,16 @@ u32 ppu_recompiler_llvm::CPUHybridDecoderRecompiler::ExecuteTillReturn(PPUThread if (context) execution_engine->m_tracer.Trace(Tracer::TraceType::ExitFromCompiledFunction, context >> 32, context & 0xFFFFFFFF); - while (PollStatus(ppu_state) == false) { - std::pair<std::mutex, std::atomic<int>> *mut = execution_engine->m_recompilation_engine->GetMutexAndCounterForAddress(ppu_state->PC); - if (mut) { - { - std::lock_guard<std::mutex> lock(mut->first); - mut->second.fetch_add(1); - } - const Executable executable = execution_engine->m_recompilation_engine->GetCompiledExecutableIfAvailable(ppu_state->PC); - if (executable) - { - auto entry = ppu_state->PC; - u32 exit = (u32)executable(ppu_state, 0); - mut->second.fetch_sub(1); - execution_engine->m_tracer.Trace(Tracer::TraceType::ExitFromCompiledBlock, entry, exit); - if (exit == 0) - return 0; - continue; - } - mut->second.fetch_add(1); + while (PollStatus(ppu_state) == false) { + const Executable executable = execution_engine->m_recompilation_engine->GetCompiledExecutableIfAvailable(ppu_state->PC); + if (executable) + { + auto entry = ppu_state->PC; + u32 exit = (u32)executable(ppu_state, 0); + execution_engine->m_tracer.Trace(Tracer::TraceType::ExitFromCompiledBlock, entry, exit); + if (exit == 0) + return 0; + continue; } execution_engine->m_tracer.Trace(Tracer::TraceType::Instruction, ppu_state->PC, 0); u32 instruction = vm::ps3::read32(ppu_state->PC); diff --git a/rpcs3/Emu/Cell/PPULLVMRecompiler.h b/rpcs3/Emu/Cell/PPULLVMRecompiler.h index 70f99a8d05..ab03bfad3e 100644 --- a/rpcs3/Emu/Cell/PPULLVMRecompiler.h +++ b/rpcs3/Emu/Cell/PPULLVMRecompiler.h @@ -1015,11 +1015,6 @@ namespace ppu_recompiler_llvm { **/ const Executable *GetExecutable(u32 address, bool isFunction); - /** - * Get a mutex for an address. Used to avoid modifying a block currently in execution. - **/ - std::pair<std::mutex, std::atomic<int> >* GetMutexAndCounterForAddress(u32 address); - /** * Get the executable for the specified address if a compiled version is * available, otherwise returns nullptr. @@ -1043,9 +1038,6 @@ namespace ppu_recompiler_llvm { /// Number of times this block was hit u32 num_hits; - /// The current revision number of this function - u32 revision; - /// Size of the CFG when it was last compiled size_t last_compiled_cfg_size; @@ -1057,15 +1049,14 @@ namespace ppu_recompiler_llvm { BlockEntry(u32 start_address, u32 function_address) : num_hits(0) - , revision(0) , last_compiled_cfg_size(0) , is_compiled(false) , cfg(start_address, function_address) { } std::string ToString() const { - return fmt::format("0x%08X (0x%08X): NumHits=%u, Revision=%u, LastCompiledCfgSize=%u, IsCompiled=%c", - cfg.start_address, cfg.function_address, num_hits, revision, last_compiled_cfg_size, is_compiled ? 'Y' : 'N'); + return fmt::format("0x%08X (0x%08X): NumHits=%u, LastCompiledCfgSize=%u, IsCompiled=%c", + cfg.start_address, cfg.function_address, num_hits, last_compiled_cfg_size, is_compiled ? 'Y' : 'N'); } bool operator == (const BlockEntry & other) const { @@ -1106,8 +1097,6 @@ namespace ppu_recompiler_llvm { /// Lock for accessing m_address_to_function. std::mutex m_address_to_function_lock; - /// Lock for modifying address mutex table - std::mutex m_address_locks_lock; int m_currentId; @@ -1126,14 +1115,10 @@ namespace ppu_recompiler_llvm { typedef std::tuple<Executable, std::unique_ptr<llvm::ExecutionEngine>, u32, u32> ExecutableStorage; /// Address to ordinal cahce. Key is address. std::unordered_map<u32, ExecutableStorage> m_address_to_function; - std::unordered_map<u32, std::pair<std::mutex, std::atomic<int> > > m_address_locks; /// The time at which the m_address_to_ordinal cache was last cleared std::chrono::high_resolution_clock::time_point m_last_cache_clear_time; - /// Remove unused entries from the m_address_to_ordinal cache - void RemoveUnusedEntriesFromCache(); - /// PPU Compiler Compiler m_compiler;