2020-02-08 17:08:33 -05:00
|
|
|
#include "stdafx.h"
|
|
|
|
#include <limits>
|
|
|
|
#include "Profiler.h"
|
|
|
|
#include "DebugBreakHelper.h"
|
|
|
|
#include "Debugger.h"
|
|
|
|
#include "Console.h"
|
|
|
|
#include "MemoryDumper.h"
|
|
|
|
#include "DebugTypes.h"
|
|
|
|
|
2020-02-08 17:27:53 -05:00
|
|
|
static constexpr int32_t ResetFunctionIndex = -1;
|
|
|
|
|
2020-02-08 17:08:33 -05:00
|
|
|
Profiler::Profiler(Debugger* debugger)
|
|
|
|
{
|
|
|
|
_debugger = debugger;
|
2020-05-18 16:10:53 -04:00
|
|
|
_console = debugger->GetConsole().get();
|
2020-02-08 17:08:33 -05:00
|
|
|
InternalReset();
|
|
|
|
}
|
|
|
|
|
|
|
|
Profiler::~Profiler()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
void Profiler::StackFunction(AddressInfo &addr, StackFrameFlags stackFlag)
|
2020-02-08 17:08:33 -05:00
|
|
|
{
|
2021-03-10 11:13:28 -05:00
|
|
|
if(addr.Address >= 0) {
|
2020-02-08 17:08:33 -05:00
|
|
|
uint32_t key = addr.Address | ((uint8_t)addr.Type << 24);
|
2021-03-10 11:13:28 -05:00
|
|
|
if(_functions.find(key) == _functions.end()) {
|
2020-02-08 17:08:33 -05:00
|
|
|
_functions[key] = ProfiledFunction();
|
|
|
|
_functions[key].Address = addr;
|
|
|
|
}
|
|
|
|
|
2020-02-09 09:26:03 -05:00
|
|
|
UpdateCycles();
|
|
|
|
|
|
|
|
_stackFlags.push_back(stackFlag);
|
|
|
|
_cycleCountStack.push_back(_currentCycleCount);
|
|
|
|
_functionStack.push_back(_currentFunction);
|
|
|
|
|
2020-02-08 17:08:33 -05:00
|
|
|
ProfiledFunction& func = _functions[key];
|
|
|
|
func.CallCount++;
|
|
|
|
|
|
|
|
_currentFunction = key;
|
|
|
|
_currentCycleCount = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Profiler::UpdateCycles()
|
|
|
|
{
|
2020-05-18 16:10:53 -04:00
|
|
|
uint64_t masterClock = _console->GetMasterClock();
|
2021-03-10 11:13:28 -05:00
|
|
|
|
2020-02-08 17:08:33 -05:00
|
|
|
ProfiledFunction& func = _functions[_currentFunction];
|
|
|
|
uint64_t clockGap = masterClock - _prevMasterClock;
|
|
|
|
func.ExclusiveCycles += clockGap;
|
|
|
|
func.InclusiveCycles += clockGap;
|
2021-03-10 11:13:28 -05:00
|
|
|
|
2020-02-08 17:08:33 -05:00
|
|
|
int32_t len = (int32_t)_functionStack.size();
|
2021-03-10 11:13:28 -05:00
|
|
|
for(int32_t i = len - 1; i >= 0; i--) {
|
2020-02-08 17:08:33 -05:00
|
|
|
_functions[_functionStack[i]].InclusiveCycles += clockGap;
|
2021-03-10 11:13:28 -05:00
|
|
|
if(_stackFlags[i] != StackFrameFlags::None) {
|
2020-02-08 17:08:33 -05:00
|
|
|
//Don't apply inclusive times to stack frames before an IRQ/NMI
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_currentCycleCount += clockGap;
|
|
|
|
_prevMasterClock = masterClock;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Profiler::UnstackFunction()
|
|
|
|
{
|
2021-03-10 11:13:28 -05:00
|
|
|
if(!_functionStack.empty()) {
|
2020-02-09 09:26:03 -05:00
|
|
|
UpdateCycles();
|
|
|
|
|
2020-02-08 17:08:33 -05:00
|
|
|
//Return to the previous function
|
|
|
|
ProfiledFunction& func = _functions[_currentFunction];
|
|
|
|
func.MinCycles = std::min(func.MinCycles, _currentCycleCount);
|
|
|
|
func.MaxCycles = std::max(func.MaxCycles, _currentCycleCount);
|
|
|
|
|
|
|
|
_currentFunction = _functionStack.back();
|
|
|
|
_functionStack.pop_back();
|
|
|
|
_stackFlags.pop_back();
|
|
|
|
|
|
|
|
//Add the subroutine's cycle count to the current routine's cycle count
|
2020-02-09 09:26:03 -05:00
|
|
|
_currentCycleCount = _cycleCountStack.back() + _currentCycleCount;
|
|
|
|
_cycleCountStack.pop_back();
|
2020-02-08 17:08:33 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Profiler::Reset()
|
|
|
|
{
|
|
|
|
DebugBreakHelper helper(_debugger);
|
|
|
|
InternalReset();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Profiler::InternalReset()
|
|
|
|
{
|
2020-05-18 16:10:53 -04:00
|
|
|
_prevMasterClock = _console->GetMasterClock();
|
2020-02-08 17:08:33 -05:00
|
|
|
_currentCycleCount = 0;
|
2020-02-08 17:27:53 -05:00
|
|
|
_currentFunction = ResetFunctionIndex;
|
2020-02-09 09:26:03 -05:00
|
|
|
_functionStack.clear();
|
|
|
|
_stackFlags.clear();
|
|
|
|
_cycleCountStack.clear();
|
2021-03-10 11:13:28 -05:00
|
|
|
|
2020-02-08 17:08:33 -05:00
|
|
|
_functions.clear();
|
2020-02-08 17:27:53 -05:00
|
|
|
_functions[ResetFunctionIndex] = ProfiledFunction();
|
2021-03-10 11:13:28 -05:00
|
|
|
_functions[ResetFunctionIndex].Address = { ResetFunctionIndex, SnesMemoryType::Register };
|
2020-02-08 17:08:33 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void Profiler::GetProfilerData(ProfiledFunction* profilerData, uint32_t& functionCount)
|
|
|
|
{
|
|
|
|
DebugBreakHelper helper(_debugger);
|
2021-03-10 11:13:28 -05:00
|
|
|
|
2020-02-08 17:08:33 -05:00
|
|
|
UpdateCycles();
|
|
|
|
|
|
|
|
functionCount = 0;
|
2021-03-10 11:13:28 -05:00
|
|
|
for(auto func : _functions) {
|
2020-02-08 17:08:33 -05:00
|
|
|
profilerData[functionCount] = func.second;
|
|
|
|
functionCount++;
|
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
if(functionCount >= 100000) {
|
2020-02-08 17:08:33 -05:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|