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;