2016-12-09 00:30:41 +00:00
|
|
|
#include "stdafx.h"
|
|
|
|
#include "Profiler.h"
|
|
|
|
#include "DebugBreakHelper.h"
|
|
|
|
#include "Debugger.h"
|
2017-05-03 01:23:28 +00:00
|
|
|
#include "MemoryDumper.h"
|
2016-12-09 00:30:41 +00:00
|
|
|
|
|
|
|
Profiler::Profiler(Debugger * debugger)
|
|
|
|
{
|
|
|
|
_debugger = debugger;
|
2017-09-29 01:10:48 +00:00
|
|
|
InternalReset();
|
2016-12-09 00:30:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Profiler::ProcessCycle()
|
|
|
|
{
|
|
|
|
_cyclesByFunction[_currentFunction]++;
|
|
|
|
_cyclesByFunctionInclusive[_currentFunction]++;
|
|
|
|
_cyclesByInstruction[_currentInstruction]++;
|
|
|
|
_currentCycleCount++;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Profiler::StackFunction(int32_t instructionAddr, int32_t functionAddr)
|
|
|
|
{
|
|
|
|
if(functionAddr >= 0) {
|
2016-12-09 18:45:50 +00:00
|
|
|
_nextFunctionAddr = functionAddr;
|
2016-12-09 00:30:41 +00:00
|
|
|
_jsrStack.push(instructionAddr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Profiler::UnstackFunction()
|
|
|
|
{
|
|
|
|
if(!_functionStack.empty()) {
|
|
|
|
//Return to the previous function
|
|
|
|
_currentFunction = _functionStack.top();
|
|
|
|
_functionStack.pop();
|
|
|
|
|
|
|
|
int32_t jsrAddr = _jsrStack.top();
|
|
|
|
_jsrStack.pop();
|
|
|
|
|
|
|
|
if(jsrAddr >= 0) {
|
|
|
|
//Prevent IRQ/NMI from adding cycles to the calling function
|
|
|
|
|
|
|
|
//Add the subroutine's cycle count to the JSR instruction
|
|
|
|
_cyclesByInstruction[jsrAddr] += _currentCycleCount;
|
|
|
|
|
|
|
|
if(_currentFunction >= 0) {
|
|
|
|
//Add the subroutine's cycle count to the function's inclusive cycle count
|
|
|
|
_cyclesByFunctionInclusive[_currentFunction] += _currentCycleCount;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//Add the subroutine's cycle count to the current routine's cycle count
|
|
|
|
_currentCycleCount = _cycleCountStack.top() + _currentCycleCount;
|
|
|
|
_cycleCountStack.pop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Profiler::ProcessInstructionStart(int32_t absoluteAddr)
|
|
|
|
{
|
2016-12-09 18:45:50 +00:00
|
|
|
if(_nextFunctionAddr >= 0) {
|
|
|
|
_cycleCountStack.push(_currentCycleCount);
|
|
|
|
_functionStack.push(_currentFunction);
|
|
|
|
|
|
|
|
_currentFunction = _nextFunctionAddr;
|
|
|
|
_currentCycleCount = 0;
|
|
|
|
_functionCallCount[_nextFunctionAddr]++;
|
|
|
|
|
|
|
|
_nextFunctionAddr = -1;
|
|
|
|
}
|
|
|
|
|
2016-12-09 00:30:41 +00:00
|
|
|
if(absoluteAddr >= 0) {
|
|
|
|
_currentInstruction = absoluteAddr;
|
|
|
|
ProcessCycle();
|
|
|
|
} else {
|
|
|
|
_currentFunction = _inMemoryFunctionIndex;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Profiler::Reset()
|
|
|
|
{
|
|
|
|
DebugBreakHelper helper(_debugger);
|
2017-09-29 01:10:48 +00:00
|
|
|
InternalReset();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Profiler::InternalReset()
|
|
|
|
{
|
|
|
|
_nextFunctionAddr = -1;
|
|
|
|
_currentCycleCount = 0;
|
|
|
|
_currentInstruction = 0;
|
|
|
|
|
|
|
|
int size = _debugger->GetMemoryDumper()->GetMemorySize(DebugMemoryType::PrgRom);
|
|
|
|
_resetFunctionIndex = size;
|
|
|
|
_inMemoryFunctionIndex = size + 1;
|
|
|
|
_currentFunction = _resetFunctionIndex;
|
2016-12-09 00:30:41 +00:00
|
|
|
|
|
|
|
_cyclesByInstruction.clear();
|
|
|
|
_cyclesByFunction.clear();
|
|
|
|
_cyclesByFunctionInclusive.clear();
|
|
|
|
_functionCallCount.clear();
|
|
|
|
|
2017-09-29 01:10:48 +00:00
|
|
|
_cyclesByInstruction.insert(_cyclesByInstruction.end(), size + 2, 0);
|
|
|
|
_cyclesByFunction.insert(_cyclesByFunction.end(), size + 2, 0);
|
|
|
|
_cyclesByFunctionInclusive.insert(_cyclesByFunctionInclusive.end(), size + 2, 0);
|
|
|
|
_functionCallCount.insert(_functionCallCount.end(), size + 2, 0);
|
2016-12-09 00:30:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Profiler::GetProfilerData(int64_t * profilerData, ProfilerDataType type)
|
|
|
|
{
|
|
|
|
vector<uint64_t> *dataArray = nullptr;
|
|
|
|
|
|
|
|
switch(type) {
|
|
|
|
default:
|
|
|
|
case ProfilerDataType::FunctionExclusive: dataArray = &_cyclesByFunction; break;
|
|
|
|
case ProfilerDataType::FunctionInclusive: dataArray = &_cyclesByFunctionInclusive; break;
|
|
|
|
case ProfilerDataType::Instructions: dataArray = &_cyclesByInstruction; break;
|
|
|
|
case ProfilerDataType::FunctionCallCount: dataArray = &_functionCallCount; break;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(profilerData, (*dataArray).data(), (*dataArray).size() * sizeof(uint64_t));
|
|
|
|
}
|