1 #include "stdafx.h"
2 #include "Profiler.h"
3 #include "DebugBreakHelper.h"
4 #include "Debugger.h"
5 #include "MemoryDumper.h"
6
Profiler(Debugger * debugger)7 Profiler::Profiler(Debugger * debugger)
8 {
9 _debugger = debugger;
10 InternalReset();
11 }
12
ProcessCycle()13 void Profiler::ProcessCycle()
14 {
15 _cyclesByFunction[_currentFunction]++;
16 _cyclesByFunctionInclusive[_currentFunction]++;
17 _cyclesByInstruction[_currentInstruction]++;
18 _currentCycleCount++;
19 }
20
StackFunction(int32_t instructionAddr,int32_t functionAddr)21 void Profiler::StackFunction(int32_t instructionAddr, int32_t functionAddr)
22 {
23 if(functionAddr >= 0) {
24 _nextFunctionAddr = functionAddr;
25 _jsrStack.push(instructionAddr);
26 }
27 }
28
UnstackFunction()29 void Profiler::UnstackFunction()
30 {
31 if(!_functionStack.empty()) {
32 //Return to the previous function
33 _currentFunction = _functionStack.top();
34 _functionStack.pop();
35
36 int32_t jsrAddr = _jsrStack.top();
37 _jsrStack.pop();
38
39 if(jsrAddr >= 0) {
40 //Prevent IRQ/NMI from adding cycles to the calling function
41
42 //Add the subroutine's cycle count to the JSR instruction
43 _cyclesByInstruction[jsrAddr] += _currentCycleCount;
44
45 if(_currentFunction >= 0) {
46 //Add the subroutine's cycle count to the function's inclusive cycle count
47 _cyclesByFunctionInclusive[_currentFunction] += _currentCycleCount;
48 }
49 }
50
51 //Add the subroutine's cycle count to the current routine's cycle count
52 _currentCycleCount = _cycleCountStack.top() + _currentCycleCount;
53 _cycleCountStack.pop();
54 }
55 }
56
ProcessInstructionStart(int32_t absoluteAddr)57 void Profiler::ProcessInstructionStart(int32_t absoluteAddr)
58 {
59 if(_nextFunctionAddr >= 0) {
60 _cycleCountStack.push(_currentCycleCount);
61 _functionStack.push(_currentFunction);
62
63 _currentFunction = _nextFunctionAddr;
64 _currentCycleCount = 0;
65 _functionCallCount[_nextFunctionAddr]++;
66
67 _nextFunctionAddr = -1;
68 }
69
70 if(absoluteAddr >= 0) {
71 _currentInstruction = absoluteAddr;
72 ProcessCycle();
73 } else {
74 _currentFunction = _inMemoryFunctionIndex;
75 }
76 }
77
Reset()78 void Profiler::Reset()
79 {
80 DebugBreakHelper helper(_debugger);
81 InternalReset();
82 }
83
InternalReset()84 void Profiler::InternalReset()
85 {
86 _nextFunctionAddr = -1;
87 _currentCycleCount = 0;
88 _currentInstruction = 0;
89
90 int size = _debugger->GetMemoryDumper()->GetMemorySize(DebugMemoryType::PrgRom);
91 _resetFunctionIndex = size;
92 _inMemoryFunctionIndex = size + 1;
93 _currentFunction = _resetFunctionIndex;
94
95 _cyclesByInstruction.clear();
96 _cyclesByFunction.clear();
97 _cyclesByFunctionInclusive.clear();
98 _functionCallCount.clear();
99
100 _cyclesByInstruction.insert(_cyclesByInstruction.end(), size + 2, 0);
101 _cyclesByFunction.insert(_cyclesByFunction.end(), size + 2, 0);
102 _cyclesByFunctionInclusive.insert(_cyclesByFunctionInclusive.end(), size + 2, 0);
103 _functionCallCount.insert(_functionCallCount.end(), size + 2, 0);
104 }
105
GetProfilerData(int64_t * profilerData,ProfilerDataType type)106 void Profiler::GetProfilerData(int64_t * profilerData, ProfilerDataType type)
107 {
108 vector<uint64_t> *dataArray = nullptr;
109
110 switch(type) {
111 default:
112 case ProfilerDataType::FunctionExclusive: dataArray = &_cyclesByFunction; break;
113 case ProfilerDataType::FunctionInclusive: dataArray = &_cyclesByFunctionInclusive; break;
114 case ProfilerDataType::Instructions: dataArray = &_cyclesByInstruction; break;
115 case ProfilerDataType::FunctionCallCount: dataArray = &_functionCallCount; break;
116 }
117
118 memcpy(profilerData, (*dataArray).data(), (*dataArray).size() * sizeof(uint64_t));
119 }
120