mirror of https://github.com/PCSX2/pcsx2.git
Perf: Support instruction-level profiling with jitdump on Linux
This commit is contained in:
parent
b3697579c0
commit
a5ed24ca88
330
common/Perf.cpp
330
common/Perf.cpp
|
@ -15,197 +15,211 @@
|
|||
|
||||
#include "common/Perf.h"
|
||||
#include "common/Pcsx2Defs.h"
|
||||
#ifdef __unix__
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include "common/Assertions.h"
|
||||
#include "common/StringUtil.h"
|
||||
|
||||
#ifdef ENABLE_VTUNE
|
||||
#include "jitprofiling.h"
|
||||
#endif
|
||||
|
||||
#include <string> // std::string
|
||||
#include <cstring> // strncpy
|
||||
#include <algorithm> // std::remove_if
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
|
||||
#ifdef __linux__
|
||||
#include <atomic>
|
||||
#include <ctime>
|
||||
#include <mutex>
|
||||
#include <elf.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/syscall.h>
|
||||
#endif
|
||||
|
||||
//#define ProfileWithPerf
|
||||
#define MERGE_BLOCK_RESULT
|
||||
//#define ProfileWithPerfJitDump
|
||||
|
||||
#ifdef ENABLE_VTUNE
|
||||
#ifdef _WIN32
|
||||
#if defined(ENABLE_VTUNE) && defined(_WIN32)
|
||||
#pragma comment(lib, "jitprofiling.lib")
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace Perf
|
||||
{
|
||||
// Warning object aren't thread safe
|
||||
InfoVector any("");
|
||||
InfoVector ee("EE");
|
||||
InfoVector iop("IOP");
|
||||
InfoVector vu("VU");
|
||||
InfoVector vif("VIF");
|
||||
Group any("");
|
||||
Group ee("EE");
|
||||
Group iop("IOP");
|
||||
Group vu0("VU0");
|
||||
Group vu1("VU1");
|
||||
Group vif("VIF");
|
||||
|
||||
// Perf is only supported on linux
|
||||
#if defined(__linux__) && (defined(ProfileWithPerf) || defined(ENABLE_VTUNE))
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of the Info object
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Info::Info(uptr x86, u32 size, const char* symbol)
|
||||
: m_x86(x86)
|
||||
, m_size(size)
|
||||
, m_dynamic(false)
|
||||
#if defined(__linux__) && defined(ProfileWithPerf)
|
||||
static std::FILE* s_map_file = nullptr;
|
||||
static bool s_map_file_opened = false;
|
||||
static std::mutex s_mutex;
|
||||
static void RegisterMethod(const void* ptr, size_t size, const char* symbol)
|
||||
{
|
||||
strncpy(m_symbol, symbol, sizeof(m_symbol));
|
||||
std::unique_lock lock(s_mutex);
|
||||
|
||||
if (!s_map_file)
|
||||
{
|
||||
if (s_map_file_opened)
|
||||
return;
|
||||
|
||||
char file[256];
|
||||
snprintf(file, std::size(file), "/tmp/perf-%d.map", getpid());
|
||||
s_map_file = std::fopen(file, "wb");
|
||||
s_map_file_opened = true;
|
||||
if (!s_map_file)
|
||||
return;
|
||||
}
|
||||
|
||||
Info::Info(uptr x86, u32 size, const char* symbol, u32 pc)
|
||||
: m_x86(x86)
|
||||
, m_size(size)
|
||||
, m_dynamic(true)
|
||||
std::fprintf(s_map_file, "%" PRIx64 " %zx %s\n", static_cast<u64>(reinterpret_cast<uintptr_t>(ptr)), size, symbol);
|
||||
std::fflush(s_map_file);
|
||||
}
|
||||
#elif defined(__linux__) && defined(ProfileWithPerfJitDump)
|
||||
enum : u32
|
||||
{
|
||||
snprintf(m_symbol, sizeof(m_symbol), "%s_0x%08x", symbol, pc);
|
||||
JIT_CODE_LOAD = 0,
|
||||
JIT_CODE_MOVE = 1,
|
||||
JIT_CODE_DEBUG_INFO = 2,
|
||||
JIT_CODE_CLOSE = 3,
|
||||
JIT_CODE_UNWINDING_INFO = 4
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct JITDUMP_HEADER
|
||||
{
|
||||
u32 magic = 0x4A695444; // JiTD
|
||||
u32 version = 1;
|
||||
u32 header_size = sizeof(JITDUMP_HEADER);
|
||||
u32 elf_mach;
|
||||
u32 pad1 = 0;
|
||||
u32 pid;
|
||||
u64 timestamp;
|
||||
u64 flags = 0;
|
||||
};
|
||||
struct JITDUMP_RECORD_HEADER
|
||||
{
|
||||
u32 id;
|
||||
u32 total_size;
|
||||
u64 timestamp;
|
||||
};
|
||||
struct JITDUMP_CODE_LOAD
|
||||
{
|
||||
JITDUMP_RECORD_HEADER header;
|
||||
u32 pid;
|
||||
u32 tid;
|
||||
u64 vma;
|
||||
u64 code_addr;
|
||||
u64 code_size;
|
||||
u64 code_index;
|
||||
// name
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
static u64 JitDumpTimestamp()
|
||||
{
|
||||
struct timespec ts = {};
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
return (static_cast<u64>(ts.tv_sec) * 1000000000ULL) + static_cast<u64>(ts.tv_nsec);
|
||||
}
|
||||
|
||||
void Info::Print(FILE* fp)
|
||||
static FILE* s_jitdump_file = nullptr;
|
||||
static bool s_jitdump_file_opened = false;
|
||||
static std::mutex s_jitdump_mutex;
|
||||
static u32 s_jitdump_record_id;
|
||||
|
||||
static void RegisterMethod(const void* ptr, size_t size, const char* symbol)
|
||||
{
|
||||
fprintf(fp, "%x %x %s\n", m_x86, m_size, m_symbol);
|
||||
}
|
||||
const u32 namelen = std::strlen(symbol) + 1;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of the InfoVector object
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
InfoVector::InfoVector(const char* prefix)
|
||||
std::unique_lock lock(s_jitdump_mutex);
|
||||
if (!s_jitdump_file)
|
||||
{
|
||||
strncpy(m_prefix, prefix, sizeof(m_prefix));
|
||||
#ifdef ENABLE_VTUNE
|
||||
m_vtune_id = iJIT_GetNewMethodID();
|
||||
#else
|
||||
m_vtune_id = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void InfoVector::print(FILE* fp)
|
||||
{
|
||||
for (auto&& it : m_v)
|
||||
it.Print(fp);
|
||||
}
|
||||
|
||||
void InfoVector::map(uptr x86, u32 size, const char* symbol)
|
||||
{
|
||||
// This function is typically used for dispatcher and recompiler.
|
||||
// Dispatchers are on a page and must always be kept.
|
||||
// Recompilers are much bigger (TODO check VIF) and are only
|
||||
// useful when MERGE_BLOCK_RESULT is defined
|
||||
#if defined(ENABLE_VTUNE) || !defined(MERGE_BLOCK_RESULT)
|
||||
u32 max_code_size = 16 * _1kb;
|
||||
#else
|
||||
u32 max_code_size = _1gb;
|
||||
#endif
|
||||
|
||||
if (size < max_code_size)
|
||||
{
|
||||
m_v.emplace_back(x86, size, symbol);
|
||||
|
||||
#ifdef ENABLE_VTUNE
|
||||
std::string name = std::string(symbol);
|
||||
|
||||
iJIT_Method_Load ml;
|
||||
|
||||
memset(&ml, 0, sizeof(ml));
|
||||
|
||||
ml.method_id = iJIT_GetNewMethodID();
|
||||
ml.method_name = (char*)name.c_str();
|
||||
ml.method_load_address = (void*)x86;
|
||||
ml.method_size = size;
|
||||
|
||||
iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, &ml);
|
||||
|
||||
//fprintf(stderr, "mapF %s: %p size %dKB\n", ml.method_name, ml.method_load_address, ml.method_size / 1024u);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void InfoVector::map(uptr x86, u32 size, u32 pc)
|
||||
{
|
||||
#ifndef MERGE_BLOCK_RESULT
|
||||
m_v.emplace_back(x86, size, m_prefix, pc);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_VTUNE
|
||||
iJIT_Method_Load_V2 ml;
|
||||
|
||||
memset(&ml, 0, sizeof(ml));
|
||||
|
||||
#ifdef MERGE_BLOCK_RESULT
|
||||
ml.method_id = m_vtune_id;
|
||||
ml.method_name = m_prefix;
|
||||
#else
|
||||
std::string name = std::string(m_prefix) + "_" + std::to_string(pc);
|
||||
ml.method_id = iJIT_GetNewMethodID();
|
||||
ml.method_name = (char*)name.c_str();
|
||||
#endif
|
||||
ml.method_load_address = (void*)x86;
|
||||
ml.method_size = size;
|
||||
|
||||
iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED_V2, &ml);
|
||||
|
||||
//fprintf(stderr, "mapB %s: %p size %d\n", ml.method_name, ml.method_load_address, ml.method_size);
|
||||
#endif
|
||||
}
|
||||
|
||||
void InfoVector::reset()
|
||||
{
|
||||
auto dynamic = std::remove_if(m_v.begin(), m_v.end(), [](Info i) { return i.m_dynamic; });
|
||||
m_v.erase(dynamic, m_v.end());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Global function
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void dump()
|
||||
if (!s_jitdump_file_opened)
|
||||
{
|
||||
char file[256];
|
||||
snprintf(file, 250, "/tmp/perf-%d.map", getpid());
|
||||
FILE* fp = fopen(file, "w");
|
||||
|
||||
any.print(fp);
|
||||
ee.print(fp);
|
||||
iop.print(fp);
|
||||
vu.print(fp);
|
||||
|
||||
if (fp)
|
||||
fclose(fp);
|
||||
snprintf(file, std::size(file), "jit-%d.dump", getpid());
|
||||
s_jitdump_file = fopen(file, "w+b");
|
||||
s_jitdump_file_opened = true;
|
||||
if (!s_jitdump_file)
|
||||
return;
|
||||
}
|
||||
|
||||
void dump_and_reset()
|
||||
void* perf_marker = mmap(nullptr, 4096, PROT_READ | PROT_EXEC, MAP_PRIVATE, fileno(s_jitdump_file), 0);
|
||||
pxAssertRel(perf_marker != MAP_FAILED, "Map perf marker");
|
||||
|
||||
JITDUMP_HEADER jh = {};
|
||||
jh.elf_mach = EM_X86_64;
|
||||
jh.pid = getpid();
|
||||
jh.timestamp = JitDumpTimestamp();
|
||||
std::fwrite(&jh, sizeof(jh), 1, s_jitdump_file);
|
||||
}
|
||||
|
||||
JITDUMP_CODE_LOAD cl = {};
|
||||
cl.header.id = JIT_CODE_LOAD;
|
||||
cl.header.total_size = sizeof(cl) + namelen + static_cast<u32>(size);
|
||||
cl.header.timestamp = JitDumpTimestamp();
|
||||
cl.pid = getpid();
|
||||
cl.tid = syscall(SYS_gettid);
|
||||
cl.vma = 0;
|
||||
cl.code_addr = static_cast<u64>(reinterpret_cast<uintptr_t>(ptr));
|
||||
cl.code_size = static_cast<u64>(size);
|
||||
cl.code_index = s_jitdump_record_id++;
|
||||
std::fwrite(&cl, sizeof(cl), 1, s_jitdump_file);
|
||||
std::fwrite(symbol, namelen, 1, s_jitdump_file);
|
||||
std::fwrite(ptr, size, 1, s_jitdump_file);
|
||||
std::fflush(s_jitdump_file);
|
||||
}
|
||||
#elif defined(ENABLE_VTUNE)
|
||||
static void RegisterMethod(const void* ptr, size_t size, const char* symbol)
|
||||
{
|
||||
dump();
|
||||
|
||||
any.reset();
|
||||
ee.reset();
|
||||
iop.reset();
|
||||
vu.reset();
|
||||
iJIT_Method_Load_V2 ml = {};
|
||||
ml.method_id = iJIT_GetNewMethodID();
|
||||
ml.method_name = const_cast<char*>(symbol);
|
||||
ml.method_load_address = ptr;
|
||||
ml.method_size = static_cast<unsigned int>(size);
|
||||
iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED_V2, &ml);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Dummy implementation
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
InfoVector::InfoVector(const char* prefix)
|
||||
: m_vtune_id(0)
|
||||
static void RegisterMethod(const void* ptr, size_t size, const char* method)
|
||||
{
|
||||
}
|
||||
void InfoVector::map(uptr x86, u32 size, const char* symbol) {}
|
||||
void InfoVector::map(uptr x86, u32 size, u32 pc) {}
|
||||
void InfoVector::reset() {}
|
||||
#endif
|
||||
|
||||
void dump() {}
|
||||
void dump_and_reset() {}
|
||||
#if (defined(__linux__) && (defined(ProfileWithPerf) || defined(ProfileWithPerfJitDump))) || defined(ENABLE_VTUNE)
|
||||
void Group::Register(const void* ptr, size_t size, const char* symbol)
|
||||
{
|
||||
char full_symbol[128];
|
||||
if (HasPrefix())
|
||||
std::snprintf(full_symbol, std::size(full_symbol), "%s_%s", m_prefix, symbol);
|
||||
else
|
||||
StringUtil::Strlcpy(full_symbol, symbol, std::size(full_symbol));
|
||||
RegisterMethod(ptr, size, full_symbol);
|
||||
}
|
||||
|
||||
void Group::RegisterPC(const void* ptr, size_t size, u32 pc)
|
||||
{
|
||||
char full_symbol[128];
|
||||
if (HasPrefix())
|
||||
std::snprintf(full_symbol, std::size(full_symbol), "%s_%08X", m_prefix, pc);
|
||||
else
|
||||
std::snprintf(full_symbol, std::size(full_symbol), "%08X", pc);
|
||||
RegisterMethod(ptr, size, full_symbol);
|
||||
}
|
||||
|
||||
void Group::RegisterKey(const void* ptr, size_t size, const char* prefix, u64 key)
|
||||
{
|
||||
char full_symbol[128];
|
||||
if (HasPrefix())
|
||||
std::snprintf(full_symbol, std::size(full_symbol), "%s_%s%016" PRIX64, m_prefix, prefix, key);
|
||||
else
|
||||
std::snprintf(full_symbol, std::size(full_symbol), "%s%016" PRIX64, prefix, key);
|
||||
RegisterMethod(ptr, size, full_symbol);
|
||||
}
|
||||
#else
|
||||
void Group::Register(const void* ptr, size_t size, const char* symbol) {}
|
||||
void Group::RegisterPC(const void* ptr, size_t size, u32 pc) {}
|
||||
void Group::RegisterKey(const void* ptr, size_t size, const char* prefix, u64 key) {}
|
||||
#endif
|
||||
} // namespace Perf
|
||||
|
|
|
@ -21,42 +21,23 @@
|
|||
|
||||
namespace Perf
|
||||
{
|
||||
|
||||
struct Info
|
||||
class Group
|
||||
{
|
||||
uptr m_x86;
|
||||
u32 m_size;
|
||||
char m_symbol[20];
|
||||
// The idea is to keep static zones that are set only
|
||||
// once.
|
||||
bool m_dynamic;
|
||||
|
||||
Info(uptr x86, u32 size, const char* symbol);
|
||||
Info(uptr x86, u32 size, const char* symbol, u32 pc);
|
||||
void Print(FILE* fp);
|
||||
};
|
||||
|
||||
class InfoVector
|
||||
{
|
||||
std::vector<Info> m_v;
|
||||
char m_prefix[20];
|
||||
unsigned int m_vtune_id;
|
||||
const char* m_prefix;
|
||||
|
||||
public:
|
||||
InfoVector(const char* prefix);
|
||||
constexpr Group(const char* prefix) : m_prefix(prefix) {}
|
||||
bool HasPrefix() const { return (m_prefix && m_prefix[0]); }
|
||||
|
||||
void print(FILE* fp);
|
||||
void map(uptr x86, u32 size, const char* symbol);
|
||||
void map(uptr x86, u32 size, u32 pc);
|
||||
void reset();
|
||||
void Register(const void* ptr, size_t size, const char* symbol);
|
||||
void RegisterPC(const void* ptr, size_t size, u32 pc);
|
||||
void RegisterKey(const void* ptr, size_t size, const char* prefix, u64 key);
|
||||
};
|
||||
|
||||
void dump();
|
||||
void dump_and_reset();
|
||||
|
||||
extern InfoVector any;
|
||||
extern InfoVector ee;
|
||||
extern InfoVector iop;
|
||||
extern InfoVector vu;
|
||||
extern InfoVector vif;
|
||||
extern Group any;
|
||||
extern Group ee;
|
||||
extern Group iop;
|
||||
extern Group vu0;
|
||||
extern Group vu1;
|
||||
extern Group vif;
|
||||
} // namespace Perf
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "GSDrawScanlineCodeGenerator.all.h"
|
||||
#include "GS/Renderers/Common/GSFunctionMap.h"
|
||||
#include "GSVertexSW.h"
|
||||
#include "common/Perf.h"
|
||||
|
||||
MULTI_ISA_UNSHARED_IMPL;
|
||||
using namespace Xbyak;
|
||||
|
@ -590,6 +591,8 @@ L("exit");
|
|||
if (isYmm)
|
||||
vzeroupper();
|
||||
ret();
|
||||
|
||||
Perf::any.RegisterKey(actual.getCode(), actual.getSize(), "GSDrawScanline_", m_sel.key);
|
||||
}
|
||||
|
||||
/// Inputs: a0=pixels, a1=left, a2[x64]=top, a3[x64]=v
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "PrecompiledHeader.h"
|
||||
#include "GSSetupPrimCodeGenerator.all.h"
|
||||
#include "GSVertexSW.h"
|
||||
#include "common/Perf.h"
|
||||
|
||||
MULTI_ISA_UNSHARED_IMPL;
|
||||
using namespace Xbyak;
|
||||
|
@ -147,6 +148,8 @@ void GSSetupPrimCodeGenerator2::Generate()
|
|||
if (isYmm)
|
||||
vzeroupper();
|
||||
ret();
|
||||
|
||||
Perf::any.RegisterKey(actual.getCode(), actual.getSize(), "GSSetupPrim_", m_sel.key);
|
||||
}
|
||||
|
||||
void GSSetupPrimCodeGenerator2::Depth_XMM()
|
||||
|
|
|
@ -307,14 +307,6 @@ RecompiledCodeReserve::~RecompiledCodeReserve()
|
|||
Release();
|
||||
}
|
||||
|
||||
void RecompiledCodeReserve::_registerProfiler()
|
||||
{
|
||||
if (m_profiler_name.empty() || !IsOk())
|
||||
return;
|
||||
|
||||
Perf::any.map((uptr)m_baseptr, m_size, m_profiler_name.c_str());
|
||||
}
|
||||
|
||||
void RecompiledCodeReserve::Assign(VirtualMemoryManagerPtr allocator, size_t offset, size_t size)
|
||||
{
|
||||
// Anything passed to the memory allocator must be page aligned.
|
||||
|
@ -329,7 +321,6 @@ void RecompiledCodeReserve::Assign(VirtualMemoryManagerPtr allocator, size_t off
|
|||
}
|
||||
|
||||
VirtualMemoryReserve::Assign(std::move(allocator), base, size);
|
||||
_registerProfiler();
|
||||
}
|
||||
|
||||
void RecompiledCodeReserve::Reset()
|
||||
|
@ -353,13 +344,3 @@ void RecompiledCodeReserve::ForbidModification()
|
|||
{
|
||||
HostSys::MemProtect(m_baseptr, m_size, PageProtectionMode().Read().Execute());
|
||||
}
|
||||
|
||||
// Sets the abbreviated name used by the profiler. Name should be under 10 characters long.
|
||||
// After a name has been set, a profiler source will be automatically registered and cleared
|
||||
// in accordance with changes in the reserve area.
|
||||
RecompiledCodeReserve& RecompiledCodeReserve::SetProfilerName(std::string name)
|
||||
{
|
||||
m_profiler_name = std::move(name);
|
||||
_registerProfiler();
|
||||
return *this;
|
||||
}
|
||||
|
|
|
@ -154,9 +154,6 @@ class RecompiledCodeReserve : public VirtualMemoryReserve
|
|||
{
|
||||
typedef VirtualMemoryReserve _parent;
|
||||
|
||||
protected:
|
||||
std::string m_profiler_name;
|
||||
|
||||
public:
|
||||
RecompiledCodeReserve(std::string name);
|
||||
~RecompiledCodeReserve();
|
||||
|
@ -164,14 +161,9 @@ public:
|
|||
void Assign(VirtualMemoryManagerPtr allocator, size_t offset, size_t size);
|
||||
void Reset();
|
||||
|
||||
RecompiledCodeReserve& SetProfilerName(std::string name);
|
||||
|
||||
void ForbidModification();
|
||||
void AllowModification();
|
||||
|
||||
operator u8*() { return m_baseptr; }
|
||||
operator const u8*() const { return m_baseptr; }
|
||||
|
||||
protected:
|
||||
void _registerProfiler();
|
||||
};
|
|
@ -283,7 +283,7 @@ static void _DynGen_Dispatchers()
|
|||
|
||||
recBlocks.SetJITCompile(iopJITCompile);
|
||||
|
||||
Perf::any.map((uptr)&iopRecDispatchers, 4096, "IOP Dispatcher");
|
||||
Perf::any.Register((void*)iopRecDispatchers, 4096, "IOP Dispatcher");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
|
@ -896,7 +896,6 @@ static void recReserve()
|
|||
return;
|
||||
|
||||
recMem = new RecompiledCodeReserve("R3000A Recompiler Cache");
|
||||
recMem->SetProfilerName("IOPrec");
|
||||
recMem->Assign(GetVmMemory().CodeMemory(), HostMemoryMap::IOPrecOffset, 32 * _1mb);
|
||||
}
|
||||
|
||||
|
@ -940,8 +939,6 @@ void recResetIOP()
|
|||
{
|
||||
DevCon.WriteLn("iR3000A Recompiler reset.");
|
||||
|
||||
Perf::iop.reset();
|
||||
|
||||
recAlloc();
|
||||
recMem->Reset();
|
||||
|
||||
|
@ -1005,9 +1002,6 @@ static void recShutdown()
|
|||
|
||||
safe_free(s_pInstCache);
|
||||
s_nInstCacheSize = 0;
|
||||
|
||||
// FIXME Warning thread unsafe
|
||||
Perf::dump();
|
||||
}
|
||||
|
||||
static void iopClearRecLUT(BASEBLOCK* base, int count)
|
||||
|
@ -1768,7 +1762,7 @@ StartRecomp:
|
|||
pxAssert(xGetPtr() - recPtr < _64kb);
|
||||
s_pCurBlockEx->x86size = xGetPtr() - recPtr;
|
||||
|
||||
Perf::iop.map(s_pCurBlockEx->fnptr, s_pCurBlockEx->x86size, s_pCurBlockEx->startpc);
|
||||
Perf::iop.RegisterPC((void*)s_pCurBlockEx->fnptr, s_pCurBlockEx->x86size, s_pCurBlockEx->startpc);
|
||||
|
||||
recPtr = xGetPtr();
|
||||
|
||||
|
|
|
@ -514,7 +514,7 @@ static void _DynGen_Dispatchers()
|
|||
|
||||
recBlocks.SetJITCompile(JITCompile);
|
||||
|
||||
Perf::any.map((uptr)&eeRecDispatchers, 4096, "EE Dispatcher");
|
||||
Perf::any.Register((void*)eeRecDispatchers, 4096, "EE Dispatcher");
|
||||
}
|
||||
|
||||
|
||||
|
@ -533,7 +533,6 @@ static void recReserve()
|
|||
return;
|
||||
|
||||
recMem = new RecompiledCodeReserve("R5900 Recompiler Cache");
|
||||
recMem->SetProfilerName("EErec");
|
||||
recMem->Assign(GetVmMemory().CodeMemory(), HostMemoryMap::EErecOffset, 64 * _1mb);
|
||||
}
|
||||
|
||||
|
@ -616,8 +615,6 @@ static void recResetRaw()
|
|||
{
|
||||
Console.WriteLn(Color_StrongBlack, "EE/iR5900-32 Recompiler Reset");
|
||||
|
||||
Perf::ee.reset();
|
||||
|
||||
EE::Profiler.Reset();
|
||||
|
||||
recAlloc();
|
||||
|
@ -655,9 +652,6 @@ static void recShutdown()
|
|||
|
||||
safe_free(s_pInstCache);
|
||||
s_nInstCacheSize = 0;
|
||||
|
||||
// FIXME Warning thread unsafe
|
||||
Perf::dump();
|
||||
}
|
||||
|
||||
void recStep()
|
||||
|
@ -743,9 +737,6 @@ static void recExecute()
|
|||
|
||||
eeCpuExecuting = false;
|
||||
|
||||
// FIXME Warning thread unsafe
|
||||
Perf::dump();
|
||||
|
||||
EE::Profiler.Print();
|
||||
}
|
||||
|
||||
|
@ -2678,7 +2669,7 @@ StartRecomp:
|
|||
iDumpBlock(s_pCurBlockEx->startpc, s_pCurBlockEx->size*4, s_pCurBlockEx->fnptr, s_pCurBlockEx->x86size);
|
||||
}
|
||||
#endif
|
||||
Perf::ee.map(s_pCurBlockEx->fnptr, s_pCurBlockEx->x86size, s_pCurBlockEx->startpc);
|
||||
Perf::ee.RegisterPC((void*)s_pCurBlockEx->fnptr, s_pCurBlockEx->x86size, s_pCurBlockEx->startpc);
|
||||
|
||||
recPtr = xGetPtr();
|
||||
|
||||
|
|
|
@ -388,7 +388,7 @@ void vtlb_dynarec_init()
|
|||
|
||||
HostSys::MemProtectStatic(m_IndirectDispatchers, PageAccess_ExecOnly());
|
||||
|
||||
Perf::any.map((uptr)m_IndirectDispatchers, __pagesize, "TLB Dispatcher");
|
||||
Perf::any.Register(m_IndirectDispatchers, __pagesize, "TLB Dispatcher");
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -31,7 +31,6 @@ alignas(__pagesize) static u8 vu1_RecDispatchers[mVUdispCacheSize];
|
|||
void mVUreserveCache(microVU& mVU)
|
||||
{
|
||||
mVU.cache_reserve = new RecompiledCodeReserve(StringUtil::StdStringFromFormat("Micro VU%u Recompiler Cache", mVU.index));
|
||||
mVU.cache_reserve->SetProfilerName(StringUtil::StdStringFromFormat("mVU%urec", mVU.index));
|
||||
|
||||
const size_t alloc_offset = mVU.index ? HostMemoryMap::mVU0recOffset : HostMemoryMap::mVU1recOffset;
|
||||
mVU.cache_reserve->Assign(GetVmMemory().CodeMemory(), alloc_offset, mVU.cacheSize * _1mb);
|
||||
|
@ -128,11 +127,6 @@ void mVUreset(microVU& mVU, bool resetReserve)
|
|||
}
|
||||
|
||||
HostSys::MemProtect(mVU.dispCache, mVUdispCacheSize, PageAccess_ExecOnly());
|
||||
|
||||
if (mVU.index)
|
||||
Perf::any.map((uptr)&mVU.dispCache, mVUdispCacheSize, "mVU1 Dispatcher");
|
||||
else
|
||||
Perf::any.map((uptr)&mVU.dispCache, mVUdispCacheSize, "mVU0 Dispatcher");
|
||||
}
|
||||
|
||||
// Free Allocated Resources
|
||||
|
|
|
@ -997,7 +997,13 @@ void* mVUcompile(microVU& mVU, u32 startPC, uptr pState)
|
|||
|
||||
perf_and_return:
|
||||
|
||||
Perf::vu.map((uptr)thisPtr, x86Ptr - thisPtr, startPC);
|
||||
if (mVU.regs().start_pc == startPC)
|
||||
{
|
||||
if (mVU.index)
|
||||
Perf::vu1.RegisterPC(thisPtr, static_cast<u32>(x86Ptr - thisPtr), startPC);
|
||||
else
|
||||
Perf::vu0.RegisterPC(thisPtr, static_cast<u32>(x86Ptr - thisPtr), startPC);
|
||||
}
|
||||
|
||||
return thisPtr;
|
||||
}
|
||||
|
|
|
@ -94,6 +94,9 @@ void mVUdispatcherAB(mV)
|
|||
|
||||
pxAssertDev(xGetPtr() < (mVU.dispCache + mVUdispCacheSize),
|
||||
"microVU: Dispatcher generation exceeded reserved cache area!");
|
||||
|
||||
Perf::any.Register(mVU.startFunct, static_cast<u32>(xGetPtr() - mVU.startFunct),
|
||||
mVU.index ? "VU1StartFunc" : "VU0StartFunc");
|
||||
}
|
||||
|
||||
// Generates the code for resuming/exit xgkick
|
||||
|
@ -134,6 +137,9 @@ void mVUdispatcherCD(mV)
|
|||
|
||||
pxAssertDev(xGetPtr() < (mVU.dispCache + mVUdispCacheSize),
|
||||
"microVU: Dispatcher generation exceeded reserved cache area!");
|
||||
|
||||
Perf::any.Register(mVU.startFunctXG, static_cast<u32>(xGetPtr() - mVU.startFunctXG),
|
||||
mVU.index ? "VU1StartFuncXG" : "VU0StartFuncXG");
|
||||
}
|
||||
|
||||
void mvuGenerateWaitMTVU(mV)
|
||||
|
@ -211,6 +217,9 @@ void mvuGenerateWaitMTVU(mV)
|
|||
|
||||
pxAssertDev(xGetPtr() < (mVU.dispCache + mVUdispCacheSize),
|
||||
"microVU: Dispatcher generation exceeded reserved cache area!");
|
||||
|
||||
Perf::any.Register(mVU.waitMTVU, static_cast<u32>(xGetPtr() - mVU.waitMTVU),
|
||||
mVU.index ? "VU1WaitMTVU" : "VU0WaitMTVU");
|
||||
}
|
||||
|
||||
void mvuGenerateCopyPipelineState(mV)
|
||||
|
@ -263,6 +272,9 @@ void mvuGenerateCopyPipelineState(mV)
|
|||
|
||||
pxAssertDev(xGetPtr() < (mVU.dispCache + mVUdispCacheSize),
|
||||
"microVU: Dispatcher generation exceeded reserved cache area!");
|
||||
|
||||
Perf::any.Register(mVU.copyPLState, static_cast<u32>(xGetPtr() - mVU.copyPLState),
|
||||
mVU.index ? "VU1CopyPLState" : "VU0CopyPLState");
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
|
|
|
@ -361,7 +361,7 @@ _vifT __fi nVifBlock* dVifCompile(nVifBlock& block, bool isFill)
|
|||
|
||||
VifUnpackSSE_Dynarec(v, block).CompileRoutine();
|
||||
|
||||
Perf::vif.map((uptr)v.recWritePtr, xGetPtr() - v.recWritePtr, block.upkType /* FIXME ideally a key*/);
|
||||
Perf::vif.RegisterPC(v.recWritePtr, xGetPtr() - v.recWritePtr, block.upkType /* FIXME ideally a key*/);
|
||||
v.recWritePtr = xGetPtr();
|
||||
|
||||
return █
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "newVif_UnpackSSE.h"
|
||||
#include "common/Perf.h"
|
||||
#include "fmt/core.h"
|
||||
|
||||
#define xMOV8(regX, loc) xMOVSSZX(regX, loc)
|
||||
|
@ -346,7 +347,6 @@ void VifUnpackSSE_Init()
|
|||
DevCon.WriteLn("Generating SSE-optimized unpacking functions for VIF interpreters...");
|
||||
|
||||
nVifUpkExec = new RecompiledCodeReserve("VIF SSE-optimized Unpacking Functions");
|
||||
nVifUpkExec->SetProfilerName("iVIF-SSE");
|
||||
nVifUpkExec->Assign(GetVmMemory().CodeMemory(), HostMemoryMap::VIFUnpackRecOffset, _1mb);
|
||||
xSetPtr(*nVifUpkExec);
|
||||
|
||||
|
@ -365,6 +365,8 @@ void VifUnpackSSE_Init()
|
|||
nVifUpkExec->GetPtr(),
|
||||
(uint)(xGetPtr() - nVifUpkExec->GetPtr())
|
||||
);
|
||||
|
||||
Perf::any.Register(nVifUpkExec->GetPtr(), xGetPtr() - nVifUpkExec->GetPtr(), "VIF Unpack");
|
||||
}
|
||||
|
||||
void VifUnpackSSE_Destroy()
|
||||
|
|
Loading…
Reference in New Issue