mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-03-29 22:20:48 +00:00
PPU/LLVM: Remove lock in GetCompiledExecutableIfAvailable
This should increase performance a lot in some case.
This commit is contained in:
parent
667cb64c29
commit
ecb3d93918
@ -254,7 +254,7 @@ RecompilationEngine::RecompilationEngine()
|
|||||||
, m_last_cache_clear_time(std::chrono::high_resolution_clock::now())
|
, m_last_cache_clear_time(std::chrono::high_resolution_clock::now())
|
||||||
, m_compiler(*this, CPUHybridDecoderRecompiler::ExecuteFunction, CPUHybridDecoderRecompiler::ExecuteTillReturn, CPUHybridDecoderRecompiler::PollStatus) {
|
, m_compiler(*this, CPUHybridDecoderRecompiler::ExecuteFunction, CPUHybridDecoderRecompiler::ExecuteTillReturn, CPUHybridDecoderRecompiler::PollStatus) {
|
||||||
|
|
||||||
FunctionCache = (Executable *)memory_helper::reserve_memory(VIRTUAL_INSTRUCTION_COUNT * sizeof(Executable));
|
FunctionCache = (ExecutableStorageType *)memory_helper::reserve_memory(VIRTUAL_INSTRUCTION_COUNT * sizeof(ExecutableStorageType));
|
||||||
// Each char can store 8 page status
|
// Each char can store 8 page status
|
||||||
FunctionCachePagesCommited = (char *)malloc(VIRTUAL_INSTRUCTION_COUNT / (8 * PAGE_SIZE));
|
FunctionCachePagesCommited = (char *)malloc(VIRTUAL_INSTRUCTION_COUNT / (8 * PAGE_SIZE));
|
||||||
memset(FunctionCachePagesCommited, 0, VIRTUAL_INSTRUCTION_COUNT / (8 * PAGE_SIZE));
|
memset(FunctionCachePagesCommited, 0, VIRTUAL_INSTRUCTION_COUNT / (8 * PAGE_SIZE));
|
||||||
@ -263,15 +263,15 @@ RecompilationEngine::RecompilationEngine()
|
|||||||
}
|
}
|
||||||
|
|
||||||
RecompilationEngine::~RecompilationEngine() {
|
RecompilationEngine::~RecompilationEngine() {
|
||||||
m_address_to_function.clear();
|
m_executable_storage.clear();
|
||||||
join();
|
join();
|
||||||
memory_helper::free_reserved_memory(FunctionCache, VIRTUAL_INSTRUCTION_COUNT * sizeof(Executable));
|
memory_helper::free_reserved_memory(FunctionCache, VIRTUAL_INSTRUCTION_COUNT * sizeof(ExecutableStorageType));
|
||||||
free(FunctionCachePagesCommited);
|
free(FunctionCachePagesCommited);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RecompilationEngine::isAddressCommited(u32 address) const
|
bool RecompilationEngine::isAddressCommited(u32 address) const
|
||||||
{
|
{
|
||||||
size_t offset = address * sizeof(Executable);
|
size_t offset = address * sizeof(ExecutableStorageType);
|
||||||
size_t page = offset / 4096;
|
size_t page = offset / 4096;
|
||||||
// Since bool is stored in char, the char index is page / 8 (or page >> 3)
|
// Since bool is stored in char, the char index is page / 8 (or page >> 3)
|
||||||
// and we shr the value with the remaining bits (page & 7)
|
// and we shr the value with the remaining bits (page & 7)
|
||||||
@ -280,7 +280,7 @@ bool RecompilationEngine::isAddressCommited(u32 address) const
|
|||||||
|
|
||||||
void RecompilationEngine::commitAddress(u32 address)
|
void RecompilationEngine::commitAddress(u32 address)
|
||||||
{
|
{
|
||||||
size_t offset = address * sizeof(Executable);
|
size_t offset = address * sizeof(ExecutableStorageType);
|
||||||
size_t page = offset / 4096;
|
size_t page = offset / 4096;
|
||||||
memory_helper::commit_page_memory((u8*)FunctionCache + page * 4096, 4096);
|
memory_helper::commit_page_memory((u8*)FunctionCache + page * 4096, 4096);
|
||||||
// Reverse of isAddressCommited : we set the (page & 7)th bit of (page / 8) th char
|
// Reverse of isAddressCommited : we set the (page & 7)th bit of (page / 8) th char
|
||||||
@ -288,20 +288,15 @@ void RecompilationEngine::commitAddress(u32 address)
|
|||||||
FunctionCachePagesCommited[page >> 3] |= (1 << (page & 7));
|
FunctionCachePagesCommited[page >> 3] |= (1 << (page & 7));
|
||||||
}
|
}
|
||||||
|
|
||||||
const Executable RecompilationEngine::GetCompiledExecutableIfAvailable(u32 address)
|
const Executable RecompilationEngine::GetCompiledExecutableIfAvailable(u32 address) const
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(m_address_to_function_lock);
|
|
||||||
if (!isAddressCommited(address / 4))
|
if (!isAddressCommited(address / 4))
|
||||||
commitAddress(address / 4);
|
|
||||||
if (!Ini.LLVMExclusionRange.GetValue())
|
|
||||||
return FunctionCache[address / 4];
|
|
||||||
std::unordered_map<u32, ExecutableStorage>::iterator It = m_address_to_function.find(address);
|
|
||||||
if (It == m_address_to_function.end())
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
u32 id = std::get<3>(It->second);
|
u32 id = FunctionCache[address / 4].second;
|
||||||
if (id >= Ini.LLVMMinId.GetValue() && id <= Ini.LLVMMaxId.GetValue())
|
if (Ini.LLVMExclusionRange.GetValue() &&
|
||||||
|
(id >= Ini.LLVMMinId.GetValue() && id <= Ini.LLVMMaxId.GetValue()))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return std::get<0>(It->second);
|
return FunctionCache[address / 4].first;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RecompilationEngine::NotifyBlockStart(u32 address) {
|
void RecompilationEngine::NotifyBlockStart(u32 address) {
|
||||||
@ -464,26 +459,25 @@ void RecompilationEngine::CompileBlock(BlockEntry & block_entry) {
|
|||||||
if (!AnalyseBlock(block_entry))
|
if (!AnalyseBlock(block_entry))
|
||||||
return;
|
return;
|
||||||
Log() << "Compile: " << block_entry.ToString() << "\n";
|
Log() << "Compile: " << block_entry.ToString() << "\n";
|
||||||
const std::pair<Executable, llvm::ExecutionEngine *> &compileResult =
|
|
||||||
m_compiler.Compile(fmt::format("fn_0x%08X", block_entry.address), block_entry.address, block_entry.instructionCount);
|
|
||||||
|
|
||||||
// If entry doesn't exist, create it (using lock)
|
|
||||||
std::unordered_map<u32, ExecutableStorage>::iterator It = m_address_to_function.find(block_entry.address);
|
|
||||||
if (It == m_address_to_function.end())
|
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(m_address_to_function_lock);
|
// We create a lock here so that data are properly stored at the end of the function.
|
||||||
std::get<1>(m_address_to_function[block_entry.address]) = nullptr;
|
/// Lock for accessing compiler
|
||||||
|
std::mutex local_mutex;
|
||||||
|
std::unique_lock<std::mutex> lock(local_mutex);
|
||||||
|
|
||||||
|
const std::pair<Executable, llvm::ExecutionEngine *> &compileResult =
|
||||||
|
m_compiler.Compile(fmt::format("fn_0x%08X", block_entry.address), block_entry.address, block_entry.instructionCount);
|
||||||
|
|
||||||
if (!isAddressCommited(block_entry.address / 4))
|
if (!isAddressCommited(block_entry.address / 4))
|
||||||
commitAddress(block_entry.address / 4);
|
commitAddress(block_entry.address / 4);
|
||||||
}
|
|
||||||
|
|
||||||
std::get<1>(m_address_to_function[block_entry.address]) = std::unique_ptr<llvm::ExecutionEngine>(compileResult.second);
|
m_executable_storage.push_back(std::unique_ptr<llvm::ExecutionEngine>(compileResult.second));
|
||||||
std::get<0>(m_address_to_function[block_entry.address]) = compileResult.first;
|
Log() << "Associating " << (void*)(uint64_t)block_entry.address << " with ID " << m_currentId << "\n";
|
||||||
std::get<3>(m_address_to_function[block_entry.address]) = m_currentId;
|
FunctionCache[block_entry.address / 4] = std::make_pair(compileResult.first, m_currentId);
|
||||||
Log() << "Associating " << (void*)(uint64_t)block_entry.address << " with ID " << m_currentId << "\n";
|
m_currentId++;
|
||||||
m_currentId++;
|
block_entry.is_compiled = true;
|
||||||
block_entry.is_compiled = true;
|
}
|
||||||
FunctionCache[block_entry.address / 4] = compileResult.first;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<RecompilationEngine> RecompilationEngine::GetInstance() {
|
std::shared_ptr<RecompilationEngine> RecompilationEngine::GetInstance() {
|
||||||
|
@ -786,7 +786,7 @@ namespace ppu_recompiler_llvm {
|
|||||||
* Get the executable for the specified address if a compiled version is
|
* Get the executable for the specified address if a compiled version is
|
||||||
* available, otherwise returns nullptr.
|
* available, otherwise returns nullptr.
|
||||||
**/
|
**/
|
||||||
const Executable GetCompiledExecutableIfAvailable(u32 address);
|
const Executable GetCompiledExecutableIfAvailable(u32 address) const;
|
||||||
|
|
||||||
/// Notify the recompilation engine about a newly detected block start.
|
/// Notify the recompilation engine about a newly detected block start.
|
||||||
void NotifyBlockStart(u32 address);
|
void NotifyBlockStart(u32 address);
|
||||||
@ -855,15 +855,16 @@ namespace ppu_recompiler_llvm {
|
|||||||
/// Block table
|
/// Block table
|
||||||
std::unordered_map<u32, BlockEntry> m_block_table;
|
std::unordered_map<u32, BlockEntry> m_block_table;
|
||||||
|
|
||||||
/// Lock for accessing m_address_to_function.
|
|
||||||
std::mutex m_address_to_function_lock;
|
|
||||||
|
|
||||||
int m_currentId;
|
int m_currentId;
|
||||||
|
|
||||||
// Store pointer to every compiled function/block.
|
/// (function, id).
|
||||||
// We need to map every instruction in PS3 Ram so it's a big table
|
typedef std::pair<Executable, u32> ExecutableStorageType;
|
||||||
// But a lot of it won't be accessed. Fortunatly virtual memory help here...
|
|
||||||
Executable *FunctionCache;
|
/// Virtual memory allocated array.
|
||||||
|
/// Store pointer to every compiled function/block and a unique Id.
|
||||||
|
/// We need to map every instruction in PS3 Ram so it's a big table
|
||||||
|
/// But a lot of it won't be accessed. Fortunatly virtual memory help here...
|
||||||
|
ExecutableStorageType* FunctionCache;
|
||||||
|
|
||||||
// Bitfield recording page status in FunctionCache reserved memory.
|
// Bitfield recording page status in FunctionCache reserved memory.
|
||||||
char *FunctionCachePagesCommited;
|
char *FunctionCachePagesCommited;
|
||||||
@ -871,10 +872,8 @@ namespace ppu_recompiler_llvm {
|
|||||||
bool isAddressCommited(u32) const;
|
bool isAddressCommited(u32) const;
|
||||||
void commitAddress(u32);
|
void commitAddress(u32);
|
||||||
|
|
||||||
/// (function, module containing function, times hit, id).
|
/// vector storing all exec engine
|
||||||
typedef std::tuple<Executable, std::unique_ptr<llvm::ExecutionEngine>, u32, u32> ExecutableStorage;
|
std::vector<std::unique_ptr<llvm::ExecutionEngine> > m_executable_storage;
|
||||||
/// Address to ordinal cahce. Key is address.
|
|
||||||
std::unordered_map<u32, ExecutableStorage> m_address_to_function;
|
|
||||||
|
|
||||||
/// The time at which the m_address_to_ordinal cache was last cleared
|
/// 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;
|
std::chrono::high_resolution_clock::time_point m_last_cache_clear_time;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user