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