Debugger: Profiler - Added min/max/avg cycle counts per function call to profiler
This commit is contained in:
parent
20fe8bd4c7
commit
c35d6d8989
7 changed files with 73 additions and 16 deletions
|
@ -1,4 +1,5 @@
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
|
#include <limits>
|
||||||
#include "Profiler.h"
|
#include "Profiler.h"
|
||||||
#include "DebugBreakHelper.h"
|
#include "DebugBreakHelper.h"
|
||||||
#include "Debugger.h"
|
#include "Debugger.h"
|
||||||
|
@ -30,6 +31,9 @@ void Profiler::UnstackFunction()
|
||||||
{
|
{
|
||||||
if(!_functionStack.empty()) {
|
if(!_functionStack.empty()) {
|
||||||
//Return to the previous function
|
//Return to the previous function
|
||||||
|
_minCycles[_currentFunction] = std::min(_minCycles[_currentFunction], _currentCycleCount);
|
||||||
|
_maxCycles[_currentFunction] = std::max(_maxCycles[_currentFunction], _currentCycleCount);
|
||||||
|
|
||||||
_currentFunction = _functionStack.top();
|
_currentFunction = _functionStack.top();
|
||||||
_functionStack.pop();
|
_functionStack.pop();
|
||||||
|
|
||||||
|
@ -96,14 +100,18 @@ void Profiler::InternalReset()
|
||||||
_cyclesByFunction.clear();
|
_cyclesByFunction.clear();
|
||||||
_cyclesByFunctionInclusive.clear();
|
_cyclesByFunctionInclusive.clear();
|
||||||
_functionCallCount.clear();
|
_functionCallCount.clear();
|
||||||
|
_minCycles.clear();
|
||||||
|
_maxCycles.clear();
|
||||||
|
|
||||||
_cyclesByInstruction.insert(_cyclesByInstruction.end(), size + 2, 0);
|
_cyclesByInstruction.insert(_cyclesByInstruction.end(), size + 2, 0);
|
||||||
_cyclesByFunction.insert(_cyclesByFunction.end(), size + 2, 0);
|
_cyclesByFunction.insert(_cyclesByFunction.end(), size + 2, 0);
|
||||||
_cyclesByFunctionInclusive.insert(_cyclesByFunctionInclusive.end(), size + 2, 0);
|
_cyclesByFunctionInclusive.insert(_cyclesByFunctionInclusive.end(), size + 2, 0);
|
||||||
_functionCallCount.insert(_functionCallCount.end(), size + 2, 0);
|
_functionCallCount.insert(_functionCallCount.end(), size + 2, 0);
|
||||||
|
_minCycles.insert(_minCycles.end(), size + 2, std::numeric_limits<uint64_t>().max());
|
||||||
|
_maxCycles.insert(_maxCycles.end(), size + 2, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Profiler::GetProfilerData(int64_t * profilerData, ProfilerDataType type)
|
void Profiler::GetProfilerData(uint64_t * profilerData, ProfilerDataType type)
|
||||||
{
|
{
|
||||||
vector<uint64_t> *dataArray = nullptr;
|
vector<uint64_t> *dataArray = nullptr;
|
||||||
|
|
||||||
|
@ -113,6 +121,8 @@ void Profiler::GetProfilerData(int64_t * profilerData, ProfilerDataType type)
|
||||||
case ProfilerDataType::FunctionInclusive: dataArray = &_cyclesByFunctionInclusive; break;
|
case ProfilerDataType::FunctionInclusive: dataArray = &_cyclesByFunctionInclusive; break;
|
||||||
case ProfilerDataType::Instructions: dataArray = &_cyclesByInstruction; break;
|
case ProfilerDataType::Instructions: dataArray = &_cyclesByInstruction; break;
|
||||||
case ProfilerDataType::FunctionCallCount: dataArray = &_functionCallCount; break;
|
case ProfilerDataType::FunctionCallCount: dataArray = &_functionCallCount; break;
|
||||||
|
case ProfilerDataType::MinCycles: dataArray = &_minCycles; break;
|
||||||
|
case ProfilerDataType::MaxCycles: dataArray = &_maxCycles; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(profilerData, (*dataArray).data(), (*dataArray).size() * sizeof(uint64_t));
|
memcpy(profilerData, (*dataArray).data(), (*dataArray).size() * sizeof(uint64_t));
|
||||||
|
|
|
@ -11,6 +11,8 @@ enum class ProfilerDataType
|
||||||
FunctionInclusive = 1,
|
FunctionInclusive = 1,
|
||||||
Instructions = 2,
|
Instructions = 2,
|
||||||
FunctionCallCount = 3,
|
FunctionCallCount = 3,
|
||||||
|
MinCycles = 4,
|
||||||
|
MaxCycles = 5,
|
||||||
};
|
};
|
||||||
|
|
||||||
class Profiler
|
class Profiler
|
||||||
|
@ -22,6 +24,8 @@ private:
|
||||||
vector<uint64_t> _cyclesByFunction;
|
vector<uint64_t> _cyclesByFunction;
|
||||||
vector<uint64_t> _cyclesByFunctionInclusive;
|
vector<uint64_t> _cyclesByFunctionInclusive;
|
||||||
vector<uint64_t> _functionCallCount;
|
vector<uint64_t> _functionCallCount;
|
||||||
|
vector<uint64_t> _minCycles;
|
||||||
|
vector<uint64_t> _maxCycles;
|
||||||
|
|
||||||
std::stack<int32_t> _functionStack;
|
std::stack<int32_t> _functionStack;
|
||||||
std::stack<int32_t> _jsrStack;
|
std::stack<int32_t> _jsrStack;
|
||||||
|
@ -47,5 +51,5 @@ public:
|
||||||
void UnstackFunction();
|
void UnstackFunction();
|
||||||
|
|
||||||
void Reset();
|
void Reset();
|
||||||
void GetProfilerData(int64_t* profilerData, ProfilerDataType type);
|
void GetProfilerData(uint64_t* profilerData, ProfilerDataType type);
|
||||||
};
|
};
|
23
GUI.NET/Debugger/Controls/ctrlProfiler.Designer.cs
generated
23
GUI.NET/Debugger/Controls/ctrlProfiler.Designer.cs
generated
|
@ -36,6 +36,9 @@
|
||||||
this.columnHeader5 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
this.columnHeader5 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||||
this.columnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
this.columnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||||
this.colExclusiveTimePercent = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
this.colExclusiveTimePercent = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||||
|
this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||||
|
this.columnHeader6 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||||
|
this.columnHeader7 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||||
this.tableLayoutPanel1.SuspendLayout();
|
this.tableLayoutPanel1.SuspendLayout();
|
||||||
this.SuspendLayout();
|
this.SuspendLayout();
|
||||||
//
|
//
|
||||||
|
@ -76,7 +79,10 @@
|
||||||
this.columnHeader3,
|
this.columnHeader3,
|
||||||
this.columnHeader5,
|
this.columnHeader5,
|
||||||
this.columnHeader2,
|
this.columnHeader2,
|
||||||
this.colExclusiveTimePercent});
|
this.colExclusiveTimePercent,
|
||||||
|
this.columnHeader1,
|
||||||
|
this.columnHeader6,
|
||||||
|
this.columnHeader7});
|
||||||
this.tableLayoutPanel1.SetColumnSpan(this.lstFunctions, 2);
|
this.tableLayoutPanel1.SetColumnSpan(this.lstFunctions, 2);
|
||||||
this.lstFunctions.Dock = System.Windows.Forms.DockStyle.Fill;
|
this.lstFunctions.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||||
this.lstFunctions.FullRowSelect = true;
|
this.lstFunctions.FullRowSelect = true;
|
||||||
|
@ -121,6 +127,18 @@
|
||||||
this.colExclusiveTimePercent.Text = "Exclusive Time (%)";
|
this.colExclusiveTimePercent.Text = "Exclusive Time (%)";
|
||||||
this.colExclusiveTimePercent.Width = 57;
|
this.colExclusiveTimePercent.Width = 57;
|
||||||
//
|
//
|
||||||
|
// columnHeader1
|
||||||
|
//
|
||||||
|
this.columnHeader1.Text = "Avg. Cycles";
|
||||||
|
//
|
||||||
|
// columnHeader6
|
||||||
|
//
|
||||||
|
this.columnHeader6.Text = "Min. Cycles";
|
||||||
|
//
|
||||||
|
// columnHeader7
|
||||||
|
//
|
||||||
|
this.columnHeader7.Text = "Max. Cycles";
|
||||||
|
//
|
||||||
// ctrlProfiler
|
// ctrlProfiler
|
||||||
//
|
//
|
||||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||||
|
@ -144,5 +162,8 @@
|
||||||
private System.Windows.Forms.ColumnHeader columnHeader3;
|
private System.Windows.Forms.ColumnHeader columnHeader3;
|
||||||
private System.Windows.Forms.ColumnHeader columnHeader5;
|
private System.Windows.Forms.ColumnHeader columnHeader5;
|
||||||
private System.Windows.Forms.ColumnHeader colExclusiveTimePercent;
|
private System.Windows.Forms.ColumnHeader colExclusiveTimePercent;
|
||||||
|
private System.Windows.Forms.ColumnHeader columnHeader1;
|
||||||
|
private System.Windows.Forms.ColumnHeader columnHeader6;
|
||||||
|
private System.Windows.Forms.ColumnHeader columnHeader7;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,9 +15,11 @@ namespace Mesen.GUI.Debugger.Controls
|
||||||
public partial class ctrlProfiler : BaseControl
|
public partial class ctrlProfiler : BaseControl
|
||||||
{
|
{
|
||||||
public static event EventHandler OnFunctionSelected;
|
public static event EventHandler OnFunctionSelected;
|
||||||
private Int64[] _exclusiveTime;
|
private UInt64[] _exclusiveTime;
|
||||||
private Int64[] _inclusiveTime;
|
private UInt64[] _inclusiveTime;
|
||||||
private Int64[] _callCount;
|
private UInt64[] _callCount;
|
||||||
|
private UInt64[] _minCycles;
|
||||||
|
private UInt64[] _maxCycles;
|
||||||
private object _resetLock = new object();
|
private object _resetLock = new object();
|
||||||
|
|
||||||
private int _sortColumn = 5;
|
private int _sortColumn = 5;
|
||||||
|
@ -36,7 +38,7 @@ namespace Mesen.GUI.Debugger.Controls
|
||||||
if(!designMode) {
|
if(!designMode) {
|
||||||
lstFunctions.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);
|
lstFunctions.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);
|
||||||
int newWidth = Math.Max(colFunction.Width * 2, 250);
|
int newWidth = Math.Max(colFunction.Width * 2, 250);
|
||||||
colExclusiveTimePercent.Width -= (newWidth - colFunction.Width) + 30;
|
columnHeader7.Width -= (newWidth - colFunction.Width) + 30;
|
||||||
colFunction.Width = newWidth;
|
colFunction.Width = newWidth;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,6 +49,8 @@ namespace Mesen.GUI.Debugger.Controls
|
||||||
_exclusiveTime = InteropEmu.DebugGetProfilerData(ProfilerDataType.FunctionExclusive);
|
_exclusiveTime = InteropEmu.DebugGetProfilerData(ProfilerDataType.FunctionExclusive);
|
||||||
_inclusiveTime = InteropEmu.DebugGetProfilerData(ProfilerDataType.FunctionInclusive);
|
_inclusiveTime = InteropEmu.DebugGetProfilerData(ProfilerDataType.FunctionInclusive);
|
||||||
_callCount = InteropEmu.DebugGetProfilerData(ProfilerDataType.FunctionCallCount);
|
_callCount = InteropEmu.DebugGetProfilerData(ProfilerDataType.FunctionCallCount);
|
||||||
|
_minCycles = InteropEmu.DebugGetProfilerData(ProfilerDataType.MinCycles);
|
||||||
|
_maxCycles = InteropEmu.DebugGetProfilerData(ProfilerDataType.MaxCycles);
|
||||||
}
|
}
|
||||||
RefreshList();
|
RefreshList();
|
||||||
}
|
}
|
||||||
|
@ -68,7 +72,10 @@ namespace Mesen.GUI.Debugger.Controls
|
||||||
|
|
||||||
private void RefreshList()
|
private void RefreshList()
|
||||||
{
|
{
|
||||||
Int64 exclusiveTotal = _exclusiveTime.Sum();
|
UInt64 exclusiveTotal = 0;
|
||||||
|
foreach(UInt64 time in _exclusiveTime) {
|
||||||
|
exclusiveTotal += time;
|
||||||
|
}
|
||||||
|
|
||||||
int hexCount = GetMaxAddrHexSize();
|
int hexCount = GetMaxAddrHexSize();
|
||||||
|
|
||||||
|
@ -103,6 +110,9 @@ namespace Mesen.GUI.Debugger.Controls
|
||||||
item.SubItems.Add("");
|
item.SubItems.Add("");
|
||||||
item.SubItems.Add("");
|
item.SubItems.Add("");
|
||||||
item.SubItems.Add("");
|
item.SubItems.Add("");
|
||||||
|
item.SubItems.Add("");
|
||||||
|
item.SubItems.Add("");
|
||||||
|
item.SubItems.Add("");
|
||||||
} else {
|
} else {
|
||||||
item = lstFunctions.Items[itemNumber];
|
item = lstFunctions.Items[itemNumber];
|
||||||
}
|
}
|
||||||
|
@ -121,14 +131,24 @@ namespace Mesen.GUI.Debugger.Controls
|
||||||
|
|
||||||
double ratio = ((double)_inclusiveTime[i] / exclusiveTotal) *100;
|
double ratio = ((double)_inclusiveTime[i] / exclusiveTotal) *100;
|
||||||
item.SubItems[3].Text = ratio.ToString("0.00");
|
item.SubItems[3].Text = ratio.ToString("0.00");
|
||||||
item.SubItems[3].Tag = (Int64)(ratio*100);
|
item.SubItems[3].Tag = (UInt64)(ratio*100);
|
||||||
|
|
||||||
item.SubItems[4].Text = _exclusiveTime[i].ToString();
|
item.SubItems[4].Text = _exclusiveTime[i].ToString();
|
||||||
item.SubItems[4].Tag = _exclusiveTime[i];
|
item.SubItems[4].Tag = _exclusiveTime[i];
|
||||||
|
|
||||||
ratio = ((double)_exclusiveTime[i] / exclusiveTotal)*100;
|
ratio = ((double)_exclusiveTime[i] / exclusiveTotal)*100;
|
||||||
item.SubItems[5].Text = ratio.ToString("0.00");
|
item.SubItems[5].Text = ratio.ToString("0.00");
|
||||||
item.SubItems[5].Tag = (Int64)(ratio*100);
|
item.SubItems[5].Tag = (UInt64)(ratio*100);
|
||||||
|
|
||||||
|
UInt64 avgCycles = _callCount[i] == 0 ? 0 : (_inclusiveTime[i] / _callCount[i]);
|
||||||
|
item.SubItems[6].Text = avgCycles.ToString();
|
||||||
|
item.SubItems[6].Tag = avgCycles;
|
||||||
|
|
||||||
|
item.SubItems[7].Text = _minCycles[i] == UInt64.MaxValue ? "n/a" : _minCycles[i].ToString();
|
||||||
|
item.SubItems[7].Tag = _minCycles[i];
|
||||||
|
|
||||||
|
item.SubItems[8].Text = _maxCycles[i] == 0 ? "n/a" : _maxCycles[i].ToString();
|
||||||
|
item.SubItems[8].Tag = _maxCycles[i];
|
||||||
|
|
||||||
itemNumber++;
|
itemNumber++;
|
||||||
}
|
}
|
||||||
|
@ -195,8 +215,8 @@ namespace Mesen.GUI.Debugger.Controls
|
||||||
return String.Compare(((ListViewItem)x).SubItems[0].Text, ((ListViewItem)y).SubItems[0].Text);
|
return String.Compare(((ListViewItem)x).SubItems[0].Text, ((ListViewItem)y).SubItems[0].Text);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Int64 columnValueY = (Int64)((ListViewItem)y).SubItems[_columnIndex].Tag;
|
UInt64 columnValueY = (UInt64)((ListViewItem)y).SubItems[_columnIndex].Tag;
|
||||||
Int64 columnValueX = (Int64)((ListViewItem)x).SubItems[_columnIndex].Tag;
|
UInt64 columnValueX = (UInt64)((ListViewItem)x).SubItems[_columnIndex].Tag;
|
||||||
if(_sortOrder) {
|
if(_sortOrder) {
|
||||||
return (int)(columnValueY - columnValueX);
|
return (int)(columnValueY - columnValueX);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -612,7 +612,7 @@ namespace Mesen.GUI.Debugger
|
||||||
DebugState state = new DebugState();
|
DebugState state = new DebugState();
|
||||||
InteropEmu.DebugGetState(ref state);
|
InteropEmu.DebugGetState(ref state);
|
||||||
|
|
||||||
lblCyclesElapsedCount.Text = (state.CPU.CycleCount - _previousCycle).ToString();
|
lblCyclesElapsedCount.Text = ((Int64)state.CPU.CycleCount - (Int64)_previousCycle).ToString();
|
||||||
_previousCycle = state.CPU.CycleCount;
|
_previousCycle = state.CPU.CycleCount;
|
||||||
|
|
||||||
if(UpdateSplitView()) {
|
if(UpdateSplitView()) {
|
||||||
|
|
|
@ -514,9 +514,9 @@ namespace Mesen.GUI
|
||||||
}
|
}
|
||||||
|
|
||||||
[DllImport(DLLPath, EntryPoint = "DebugGetProfilerData")] private static extern void DebugGetProfilerDataWrapper(IntPtr profilerData, ProfilerDataType dataType);
|
[DllImport(DLLPath, EntryPoint = "DebugGetProfilerData")] private static extern void DebugGetProfilerDataWrapper(IntPtr profilerData, ProfilerDataType dataType);
|
||||||
public static Int64[] DebugGetProfilerData(ProfilerDataType dataType)
|
public static UInt64[] DebugGetProfilerData(ProfilerDataType dataType)
|
||||||
{
|
{
|
||||||
Int64[] profileData = new Int64[InteropEmu.DebugGetMemorySize(DebugMemoryType.PrgRom) + 2];
|
UInt64[] profileData = new UInt64[InteropEmu.DebugGetMemorySize(DebugMemoryType.PrgRom) + 2];
|
||||||
|
|
||||||
GCHandle hProfilerData = GCHandle.Alloc(profileData, GCHandleType.Pinned);
|
GCHandle hProfilerData = GCHandle.Alloc(profileData, GCHandleType.Pinned);
|
||||||
try {
|
try {
|
||||||
|
@ -1592,6 +1592,8 @@ namespace Mesen.GUI
|
||||||
FunctionInclusive = 1,
|
FunctionInclusive = 1,
|
||||||
Instructions = 2,
|
Instructions = 2,
|
||||||
FunctionCallCount = 3,
|
FunctionCallCount = 3,
|
||||||
|
MinCycles = 4,
|
||||||
|
MaxCycles = 5,
|
||||||
}
|
}
|
||||||
|
|
||||||
[Flags]
|
[Flags]
|
||||||
|
|
|
@ -118,7 +118,7 @@ extern "C"
|
||||||
DllExport void __stdcall DebugGetUninitMemoryReads(DebugMemoryType memoryType, int32_t* counts) { GetDebugger()->GetMemoryAccessCounter()->GetUninitMemoryReads(memoryType, counts); }
|
DllExport void __stdcall DebugGetUninitMemoryReads(DebugMemoryType memoryType, int32_t* counts) { GetDebugger()->GetMemoryAccessCounter()->GetUninitMemoryReads(memoryType, counts); }
|
||||||
DllExport void __stdcall DebugGetNametableChangedData(bool* ntChangedData) { GetDebugger()->GetMemoryAccessCounter()->GetNametableChangedData(ntChangedData); }
|
DllExport void __stdcall DebugGetNametableChangedData(bool* ntChangedData) { GetDebugger()->GetMemoryAccessCounter()->GetNametableChangedData(ntChangedData); }
|
||||||
|
|
||||||
DllExport void __stdcall DebugGetProfilerData(int64_t* profilerData, ProfilerDataType dataType) { GetDebugger()->GetProfiler()->GetProfilerData(profilerData, dataType); }
|
DllExport void __stdcall DebugGetProfilerData(uint64_t* profilerData, ProfilerDataType dataType) { GetDebugger()->GetProfiler()->GetProfilerData(profilerData, dataType); }
|
||||||
DllExport void __stdcall DebugResetProfiler() { GetDebugger()->GetProfiler()->Reset(); }
|
DllExport void __stdcall DebugResetProfiler() { GetDebugger()->GetProfiler()->Reset(); }
|
||||||
|
|
||||||
DllExport void __stdcall DebugSetFreezeState(uint16_t address, bool frozen) { GetDebugger()->SetFreezeState(address, frozen); }
|
DllExport void __stdcall DebugSetFreezeState(uint16_t address, bool frozen) { GetDebugger()->SetFreezeState(address, frozen); }
|
||||||
|
|
Loading…
Add table
Reference in a new issue