mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-25 23:29:44 -06:00
JIT profiler: in block performance counter.
MemoryView: raw memory display. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@522 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
@ -9,6 +9,7 @@ protected:
|
|||||||
virtual ~DebugInterface() {}
|
virtual ~DebugInterface() {}
|
||||||
public:
|
public:
|
||||||
virtual const char *disasm(unsigned int /*address*/) {return "NODEBUGGER";}
|
virtual const char *disasm(unsigned int /*address*/) {return "NODEBUGGER";}
|
||||||
|
virtual const char *getRawMemoryString(unsigned int /*address*/){return "NODEBUGGER";}
|
||||||
virtual int getInstructionSize(int /*instruction*/) {return 1;}
|
virtual int getInstructionSize(int /*instruction*/) {return 1;}
|
||||||
|
|
||||||
virtual bool isAlive() {return true;}
|
virtual bool isAlive() {return true;}
|
||||||
|
@ -42,6 +42,25 @@ const char *PPCDebugInterface::disasm(unsigned int address)
|
|||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *PPCDebugInterface::getRawMemoryString(unsigned int address)
|
||||||
|
{
|
||||||
|
if (Core::GetState() != Core::CORE_UNINITIALIZED)
|
||||||
|
{
|
||||||
|
if (address < 0xE0000000)
|
||||||
|
{
|
||||||
|
static char str[256] ={0};
|
||||||
|
if (sprintf(str,"%08X",readMemory(address))!=8) {
|
||||||
|
PanicAlert("getRawMemoryString -> WTF! ( as read somewhere;) )");
|
||||||
|
return ":(";
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
return "No RAM";
|
||||||
|
}
|
||||||
|
static const char tmp[] = "<unknown>";
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned int PPCDebugInterface::readMemory(unsigned int address)
|
unsigned int PPCDebugInterface::readMemory(unsigned int address)
|
||||||
{
|
{
|
||||||
return Memory::ReadUnchecked_U32(address);
|
return Memory::ReadUnchecked_U32(address);
|
||||||
|
@ -12,6 +12,7 @@ class PPCDebugInterface : public DebugInterface
|
|||||||
public:
|
public:
|
||||||
PPCDebugInterface(){}
|
PPCDebugInterface(){}
|
||||||
virtual const char *disasm(unsigned int address);
|
virtual const char *disasm(unsigned int address);
|
||||||
|
virtual const char *getRawMemoryString(unsigned int address);
|
||||||
virtual int getInstructionSize(int instruction) {return 4;}
|
virtual int getInstructionSize(int instruction) {return 4;}
|
||||||
virtual bool isAlive();
|
virtual bool isAlive();
|
||||||
virtual bool isBreakpoint(unsigned int address);
|
virtual bool isBreakpoint(unsigned int address);
|
||||||
|
@ -398,6 +398,15 @@ namespace Jit64
|
|||||||
|
|
||||||
if (Profiler::g_ProfileBlocks) {
|
if (Profiler::g_ProfileBlocks) {
|
||||||
ADD(32, M(&b.runCount), Imm8(1));
|
ADD(32, M(&b.runCount), Imm8(1));
|
||||||
|
#ifdef _WIN32
|
||||||
|
b.ticCounter.QuadPart = 0;
|
||||||
|
b.ticStart.QuadPart = 0;
|
||||||
|
b.ticStop.QuadPart = 0;
|
||||||
|
#else
|
||||||
|
//TODO
|
||||||
|
#endif
|
||||||
|
// get start tic
|
||||||
|
PROFILER_QUERY_PERFORMACE_COUNTER(&b.ticStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Start up the register allocators
|
//Start up the register allocators
|
||||||
@ -416,8 +425,18 @@ namespace Jit64
|
|||||||
js.compilerPC = ops[i].address;
|
js.compilerPC = ops[i].address;
|
||||||
js.op = &ops[i];
|
js.op = &ops[i];
|
||||||
js.instructionNumber = i;
|
js.instructionNumber = i;
|
||||||
if (i == (int)size - 1)
|
if (i == (int)size - 1) {
|
||||||
js.isLastInstruction = true;
|
js.isLastInstruction = true;
|
||||||
|
if (Profiler::g_ProfileBlocks) {
|
||||||
|
// CAUTION!!! push on stack regs you use, do your stuff, then pop
|
||||||
|
PROFILER_VPUSH;
|
||||||
|
// get end tic
|
||||||
|
PROFILER_QUERY_PERFORMACE_COUNTER(&b.ticStop);
|
||||||
|
// tic counter += (end tic - start tic)
|
||||||
|
PROFILER_ADD_DIFF_LARGE_INTEGER(&b.ticCounter, &b.ticStop, &b.ticStart);
|
||||||
|
PROFILER_VPOP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// const GekkoOpInfo *info = GetOpInfo();
|
// const GekkoOpInfo *info = GetOpInfo();
|
||||||
// if (js.isLastInstruction)
|
// if (js.isLastInstruction)
|
||||||
|
@ -18,6 +18,9 @@
|
|||||||
#define _JITCACHE_H
|
#define _JITCACHE_H
|
||||||
|
|
||||||
#include "../Gekko.h"
|
#include "../Gekko.h"
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h> // -> LARGE_INTEGER
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace Jit64
|
namespace Jit64
|
||||||
{
|
{
|
||||||
@ -52,6 +55,13 @@ namespace Jit64
|
|||||||
u32 codeSize;
|
u32 codeSize;
|
||||||
u32 originalSize;
|
u32 originalSize;
|
||||||
int runCount; // for profiling.
|
int runCount; // for profiling.
|
||||||
|
#ifdef _WIN32
|
||||||
|
// we don't really need to save start and stop
|
||||||
|
// TODO (mb2): ticStart and ticStop -> "local var" mean "in block" ... low priority ;)
|
||||||
|
LARGE_INTEGER ticStart; // for profiling - time.
|
||||||
|
LARGE_INTEGER ticStop; // for profiling - time.
|
||||||
|
LARGE_INTEGER ticCounter; // for profiling - time.
|
||||||
|
#endif
|
||||||
const u8 *checkedEntry;
|
const u8 *checkedEntry;
|
||||||
bool invalid;
|
bool invalid;
|
||||||
int flags;
|
int flags;
|
||||||
|
@ -30,9 +30,9 @@ bool g_ProfileInstructions;
|
|||||||
|
|
||||||
struct BlockStat
|
struct BlockStat
|
||||||
{
|
{
|
||||||
BlockStat(int bn, int c) : blockNum(bn), cost(c) {}
|
BlockStat(int bn, u64 c) : blockNum(bn), cost(c) {}
|
||||||
int blockNum;
|
int blockNum;
|
||||||
int cost;
|
u64 cost;
|
||||||
|
|
||||||
bool operator <(const BlockStat &other) const {
|
bool operator <(const BlockStat &other) const {
|
||||||
return cost > other.cost;
|
return cost > other.cost;
|
||||||
@ -43,14 +43,25 @@ void WriteProfileResults(const char *filename) {
|
|||||||
std::vector<BlockStat> stats;
|
std::vector<BlockStat> stats;
|
||||||
stats.reserve(Jit64::GetNumBlocks());
|
stats.reserve(Jit64::GetNumBlocks());
|
||||||
u64 cost_sum = 0;
|
u64 cost_sum = 0;
|
||||||
|
#ifdef _WIN32
|
||||||
|
u64 timecost_sum = 0;
|
||||||
|
LARGE_INTEGER countsPerSec;
|
||||||
|
QueryPerformanceFrequency(&countsPerSec);
|
||||||
|
#endif
|
||||||
for (int i = 0; i < Jit64::GetNumBlocks(); i++)
|
for (int i = 0; i < Jit64::GetNumBlocks(); i++)
|
||||||
{
|
{
|
||||||
const Jit64::JitBlock *block = Jit64::GetBlock(i);
|
const Jit64::JitBlock *block = Jit64::GetBlock(i);
|
||||||
int cost = (block->originalSize / 4) * block->runCount; // rough heuristic. mem instructions should cost more.
|
u64 cost = (block->originalSize / 4) * block->runCount; // rough heuristic. mem instructions should cost more.
|
||||||
|
#ifdef _WIN32
|
||||||
|
u64 timecost = block->ticCounter.QuadPart; // Indeed ;)
|
||||||
|
#endif
|
||||||
if (block->runCount >= 1) { // Todo: tweak.
|
if (block->runCount >= 1) { // Todo: tweak.
|
||||||
stats.push_back(BlockStat(i, cost));
|
stats.push_back(BlockStat(i, cost));
|
||||||
}
|
}
|
||||||
cost_sum += cost;
|
cost_sum += cost;
|
||||||
|
#ifdef _WIN32
|
||||||
|
timecost_sum += timecost;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
sort(stats.begin(), stats.end());
|
sort(stats.begin(), stats.end());
|
||||||
@ -59,14 +70,21 @@ void WriteProfileResults(const char *filename) {
|
|||||||
PanicAlert("failed to open %s", filename);
|
PanicAlert("failed to open %s", filename);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fprintf(f, "Profile\n");
|
fprintf(f, "origAddr\tblkName\tcost\ttimeCost\tpercent\ttimePercent\tOvAllinBlkTime(ms)\tblkCodeSize\n");
|
||||||
for (unsigned int i = 0; i < stats.size(); i++)
|
for (unsigned int i = 0; i < stats.size(); i++)
|
||||||
{
|
{
|
||||||
const Jit64::JitBlock *block = Jit64::GetBlock(stats[i].blockNum);
|
const Jit64::JitBlock *block = Jit64::GetBlock(stats[i].blockNum);
|
||||||
if (block) {
|
if (block) {
|
||||||
std::string name = g_symbolDB.GetDescription(block->originalAddress);
|
std::string name = g_symbolDB.GetDescription(block->originalAddress);
|
||||||
double percent = 100 * (double)stats[i].cost / (double)cost_sum;
|
double percent = 100.0 * (double)stats[i].cost / (double)cost_sum;
|
||||||
fprintf(f, "%08x - %s - %i (%f%%)\n", block->originalAddress, name.c_str(), stats[i].cost, percent);
|
#ifdef _WIN32
|
||||||
|
double timePercent = 100.0 * (double)block->ticCounter.QuadPart / (double)timecost_sum;
|
||||||
|
fprintf(f, "%08x\t%s\t%llu\t%llu\t%llf\t%llf\t%lf\t%i\n",
|
||||||
|
block->originalAddress, name.c_str(), stats[i].cost, block->ticCounter.QuadPart, percent, timePercent, (double)block->ticCounter.QuadPart*1000.0/(double)countsPerSec.QuadPart, block->codeSize);
|
||||||
|
#else
|
||||||
|
fprintf(f, "%08x\t%s\t%llu\t???\t%llf\t???\t???\t%i\n",
|
||||||
|
block->originalAddress, name.c_str(), stats[i].cost, /*block->ticCounter.QuadPart,*/ percent, /*timePercent, (double)block->ticCounter.QuadPart*1000.0/(double)countsPerSec.QuadPart,*/ block->codeSize);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
@ -19,6 +19,34 @@
|
|||||||
#ifndef _PROFILER_H
|
#ifndef _PROFILER_H
|
||||||
#define _PROFILER_H
|
#define _PROFILER_H
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define PROFILER_QUERY_PERFORMACE_COUNTER(pt) \
|
||||||
|
LEA(32, EAX, M(pt)); PUSH(EAX); \
|
||||||
|
CALL(QueryPerformanceCounter)
|
||||||
|
// TODO: r64 way
|
||||||
|
// asm write : (u64) dt += t1-t0
|
||||||
|
#define PROFILER_ADD_DIFF_LARGE_INTEGER(pdt, pt1, pt0) \
|
||||||
|
MOV(32, R(EAX), M(pt1.LowPart)); \
|
||||||
|
SUB(32, R(EAX), M(pt0.LowPart)); \
|
||||||
|
MOV(32, R(ECX), M(pt1.HighPart)); \
|
||||||
|
SBB(32, R(ECX), M(pt0.HighPart)); \
|
||||||
|
ADD(32, R(EAX), M(pdt.LowPart)); \
|
||||||
|
MOV(32, R(EDX), M(pdt.HighPart)); \
|
||||||
|
ADC(32, R(EDX), R(ECX)); \
|
||||||
|
MOV(32, M(pdt.LowPart), R(EAX)); \
|
||||||
|
MOV(32, M(pdt.HighPart), R(EDX))
|
||||||
|
|
||||||
|
#define PROFILER_VPUSH PUSH(EAX);PUSH(ECX);PUSH(EDX)
|
||||||
|
#define PROFILER_VPOP POP(EDX);POP(ECX);POP(EAX)
|
||||||
|
#else
|
||||||
|
// TODO
|
||||||
|
#define PROFILER_QUERY_PERFORMACE_COUNTER(pt)
|
||||||
|
#define PROFILER_ADD_DIFF_LARGE_INTEGER(pdt, pt1, pt0)
|
||||||
|
#define PROFILER_VPUSH
|
||||||
|
#define PROFILER_VPOP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
namespace Profiler
|
namespace Profiler
|
||||||
{
|
{
|
||||||
extern bool g_ProfileBlocks;
|
extern bool g_ProfileBlocks;
|
||||||
|
@ -223,8 +223,9 @@ void CMemoryView::OnErase(wxEraseEvent& event)
|
|||||||
void CMemoryView::OnPaint(wxPaintEvent& event)
|
void CMemoryView::OnPaint(wxPaintEvent& event)
|
||||||
{
|
{
|
||||||
wxPaintDC dc(this);
|
wxPaintDC dc(this);
|
||||||
|
int fontSize = 8;
|
||||||
wxRect rc = GetClientRect();
|
wxRect rc = GetClientRect();
|
||||||
wxFont font(7, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_LIGHT);
|
wxFont font(fontSize, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_LIGHT);
|
||||||
dc.SetFont(font);
|
dc.SetFont(font);
|
||||||
struct branch
|
struct branch
|
||||||
{
|
{
|
||||||
@ -254,7 +255,7 @@ void CMemoryView::OnPaint(wxPaintEvent& event)
|
|||||||
dc.SetPen(nullPen);
|
dc.SetPen(nullPen);
|
||||||
dc.SetBrush(bgBrush);
|
dc.SetBrush(bgBrush);
|
||||||
dc.DrawRectangle(0, 0, 16, rc.height);
|
dc.DrawRectangle(0, 0, 16, rc.height);
|
||||||
dc.DrawRectangle(0, 0, rc.width, 5);
|
dc.DrawRectangle(0, 0, rc.width, 5+8);
|
||||||
// TODO - clean up this freaking mess!!!!!
|
// TODO - clean up this freaking mess!!!!!
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -294,6 +295,10 @@ void CMemoryView::OnPaint(wxPaintEvent& event)
|
|||||||
dc.SetBrush(currentBrush);
|
dc.SetBrush(currentBrush);
|
||||||
dc.SetTextForeground(_T("#600000"));
|
dc.SetTextForeground(_T("#600000"));
|
||||||
dc.DrawText(temp, 17, rowY1);
|
dc.DrawText(temp, 17, rowY1);
|
||||||
|
char mem[256] = {0};
|
||||||
|
strcpy(mem, debugger->getRawMemoryString(address));
|
||||||
|
dc.SetTextForeground(_T("#000080"));
|
||||||
|
dc.DrawText(wxString::FromAscii(mem), 17+fontSize*(8), rowY1);
|
||||||
dc.SetTextForeground(_T("#000000"));
|
dc.SetTextForeground(_T("#000000"));
|
||||||
|
|
||||||
if (debugger->isAlive())
|
if (debugger->isAlive())
|
||||||
@ -347,7 +352,7 @@ void CMemoryView::OnPaint(wxPaintEvent& event)
|
|||||||
dc.SetTextForeground(_T("#000000"));
|
dc.SetTextForeground(_T("#000000"));
|
||||||
}
|
}
|
||||||
|
|
||||||
dc.DrawText(wxString::FromAscii(dis2), 126, rowY1);
|
dc.DrawText(wxString::FromAscii(dis2), 17+fontSize*(8+8+8), rowY1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(dis, "blr"))
|
if (strcmp(dis, "blr"))
|
||||||
@ -359,7 +364,7 @@ void CMemoryView::OnPaint(wxPaintEvent& event)
|
|||||||
dc.SetTextForeground(_T("#8000FF"));
|
dc.SetTextForeground(_T("#8000FF"));
|
||||||
}
|
}
|
||||||
|
|
||||||
dc.DrawText(wxString::FromAscii(dis), 70, rowY1);
|
dc.DrawText(wxString::FromAscii(dis), 17+fontSize*(8+8), rowY1);
|
||||||
|
|
||||||
if (desc[0] == 0)
|
if (desc[0] == 0)
|
||||||
{
|
{
|
||||||
@ -372,7 +377,7 @@ void CMemoryView::OnPaint(wxPaintEvent& event)
|
|||||||
//UnDecorateSymbolName(desc,temp,255,UNDNAME_COMPLETE);
|
//UnDecorateSymbolName(desc,temp,255,UNDNAME_COMPLETE);
|
||||||
if (strlen(desc))
|
if (strlen(desc))
|
||||||
{
|
{
|
||||||
dc.DrawText(wxString::FromAscii(desc), 235, rowY1);
|
dc.DrawText(wxString::FromAscii(desc), 17+fontSize*(8+8+8+30), rowY1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (debugger->isBreakpoint(address))
|
if (debugger->isBreakpoint(address))
|
||||||
|
@ -70,14 +70,15 @@ CMemoryWindow::CMemoryWindow(wxWindow* parent, wxWindowID id,
|
|||||||
{
|
{
|
||||||
wxBoxSizer* sizerBig = new wxBoxSizer(wxHORIZONTAL);
|
wxBoxSizer* sizerBig = new wxBoxSizer(wxHORIZONTAL);
|
||||||
wxBoxSizer* sizerRight = new wxBoxSizer(wxVERTICAL);
|
wxBoxSizer* sizerRight = new wxBoxSizer(wxVERTICAL);
|
||||||
wxBoxSizer* sizerLeft = new wxBoxSizer(wxVERTICAL);
|
// didn't see anything usefull in the left part
|
||||||
|
//wxBoxSizer* sizerLeft = new wxBoxSizer(wxVERTICAL);
|
||||||
|
|
||||||
DebugInterface* di = new PPCDebugInterface();
|
DebugInterface* di = new PPCDebugInterface();
|
||||||
|
|
||||||
sizerLeft->Add(symbols = new wxListBox(this, IDM_SYMBOLLIST, wxDefaultPosition, wxSize(90, 100), 0, NULL, wxLB_SORT), 1, wxEXPAND);
|
//sizerLeft->Add(symbols = new wxListBox(this, IDM_SYMBOLLIST, wxDefaultPosition, wxSize(20, 100), 0, NULL, wxLB_SORT), 1, wxEXPAND);
|
||||||
memview = new CMemoryView(di, this, wxID_ANY);
|
memview = new CMemoryView(di, this, wxID_ANY);
|
||||||
sizerBig->Add(sizerLeft, 2, wxEXPAND);
|
//sizerBig->Add(sizerLeft, 1, wxEXPAND);
|
||||||
sizerBig->Add(memview, 5, wxEXPAND);
|
sizerBig->Add(memview, 20, wxEXPAND);
|
||||||
sizerBig->Add(sizerRight, 0, wxEXPAND | wxALL, 3);
|
sizerBig->Add(sizerRight, 0, wxEXPAND | wxALL, 3);
|
||||||
sizerRight->Add(buttonGo = new wxButton(this, IDM_DEBUG_GO, _T("&Go")));
|
sizerRight->Add(buttonGo = new wxButton(this, IDM_DEBUG_GO, _T("&Go")));
|
||||||
sizerRight->Add(addrbox = new wxTextCtrl(this, IDM_ADDRBOX, _T("")));
|
sizerRight->Add(addrbox = new wxTextCtrl(this, IDM_ADDRBOX, _T("")));
|
||||||
@ -85,8 +86,8 @@ CMemoryWindow::CMemoryWindow(wxWindow* parent, wxWindowID id,
|
|||||||
|
|
||||||
SetSizer(sizerBig);
|
SetSizer(sizerBig);
|
||||||
|
|
||||||
sizerLeft->SetSizeHints(this);
|
//sizerLeft->SetSizeHints(this);
|
||||||
sizerLeft->Fit(this);
|
//sizerLeft->Fit(this);
|
||||||
sizerRight->SetSizeHints(this);
|
sizerRight->SetSizeHints(this);
|
||||||
sizerRight->Fit(this);
|
sizerRight->Fit(this);
|
||||||
sizerBig->SetSizeHints(this);
|
sizerBig->SetSizeHints(this);
|
||||||
|
Reference in New Issue
Block a user