Add Linux perf JIT support (/tmp/perf-$pid.map)
'perf' is the standard builtin tool for performance analysis on recent Linux kernel. Its source code is shipped within the kernel repository. 'perf' has basic support for JIT. For each process, it can read a file named /tmp/perf-$PID.map. This file contains mapping from address range to function name in the format: 41187e2a 1a EmuCode_804a33fc with the following entries: 1. beginning of the range (hexadecimal); 2. size of the range (hexadecimal); 3. name of the function. We supply the PowerPC address of the basic block as function name. Usage: DOLPHIN_PERF_DIR=/tmp dolphin-emu & perf record -F99 -p $(pgrep dolphin-emu) --call-graph dwarf perf script | stackcollapse-perf.pl | grep EmuCode__ | flamegraph.pl > profile.svg Issue: perf does not have support for region invalidation. It reads the file in postprocessing. It probably does not work very well if a JIT region is reused for another basic block: wrong results should be expected in this case. Currently, nothing is done to prevent this.
This commit is contained in:
parent
60e9301f40
commit
cdce5ace25
|
@ -9,6 +9,14 @@
|
||||||
// performance hit, it's not enabled by default, but it's useful for
|
// performance hit, it's not enabled by default, but it's useful for
|
||||||
// locating performance issues.
|
// locating performance issues.
|
||||||
|
|
||||||
|
#include <cinttypes>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <process.h>
|
||||||
|
#else
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "disasm.h"
|
#include "disasm.h"
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
@ -50,6 +58,15 @@ using namespace Gen;
|
||||||
#if defined USE_OPROFILE && USE_OPROFILE
|
#if defined USE_OPROFILE && USE_OPROFILE
|
||||||
agent = op_open_agent();
|
agent = op_open_agent();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
const char* perf_dir = getenv("DOLPHIN_PERF_DIR");
|
||||||
|
if (perf_dir && perf_dir[0])
|
||||||
|
{
|
||||||
|
std::string filename = StringFromFormat("%s/perf-%d.map",
|
||||||
|
perf_dir, getpid());
|
||||||
|
m_perf_map_file.open(filename, std::ios::trunc);
|
||||||
|
}
|
||||||
|
|
||||||
iCache.fill(JIT_ICACHE_INVALID_BYTE);
|
iCache.fill(JIT_ICACHE_INVALID_BYTE);
|
||||||
iCacheEx.fill(JIT_ICACHE_INVALID_BYTE);
|
iCacheEx.fill(JIT_ICACHE_INVALID_BYTE);
|
||||||
iCacheVMEM.fill(JIT_ICACHE_INVALID_BYTE);
|
iCacheVMEM.fill(JIT_ICACHE_INVALID_BYTE);
|
||||||
|
@ -69,6 +86,9 @@ using namespace Gen;
|
||||||
#ifdef USE_VTUNE
|
#ifdef USE_VTUNE
|
||||||
iJIT_NotifyEvent(iJVM_EVENT_TYPE_SHUTDOWN, nullptr);
|
iJIT_NotifyEvent(iJVM_EVENT_TYPE_SHUTDOWN, nullptr);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (m_perf_map_file.is_open())
|
||||||
|
m_perf_map_file.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
// This clears the JIT cache. It's called from JitCache.cpp when the JIT cache
|
// This clears the JIT cache. It's called from JitCache.cpp when the JIT cache
|
||||||
|
@ -179,6 +199,13 @@ using namespace Gen;
|
||||||
jmethod.method_name = b.blockName;
|
jmethod.method_name = b.blockName;
|
||||||
iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, (void*)&jmethod);
|
iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, (void*)&jmethod);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (m_perf_map_file.is_open())
|
||||||
|
{
|
||||||
|
m_perf_map_file << StringFromFormat(
|
||||||
|
"%" PRIx64 " %x EmuCode_%x\n",
|
||||||
|
(u64)blockCodePointers[block_num], b.codeSize, b.originalAddress);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const u8 **JitBaseBlockCache::GetCodePointers()
|
const u8 **JitBaseBlockCache::GetCodePointers()
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <bitset>
|
#include <bitset>
|
||||||
|
#include <fstream>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -119,6 +120,8 @@ class JitBaseBlockCache
|
||||||
|
|
||||||
bool m_initialized;
|
bool m_initialized;
|
||||||
|
|
||||||
|
std::ofstream m_perf_map_file;
|
||||||
|
|
||||||
bool RangeIntersect(int s1, int e1, int s2, int e2) const;
|
bool RangeIntersect(int s1, int e1, int s2, int e2) const;
|
||||||
void LinkBlockExits(int i);
|
void LinkBlockExits(int i);
|
||||||
void LinkBlock(int i);
|
void LinkBlock(int i);
|
||||||
|
|
Loading…
Reference in New Issue