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 <limits>
|
||||
#include "Profiler.h"
|
||||
#include "DebugBreakHelper.h"
|
||||
#include "Debugger.h"
|
||||
|
@ -30,6 +31,9 @@ void Profiler::UnstackFunction()
|
|||
{
|
||||
if(!_functionStack.empty()) {
|
||||
//Return to the previous function
|
||||
_minCycles[_currentFunction] = std::min(_minCycles[_currentFunction], _currentCycleCount);
|
||||
_maxCycles[_currentFunction] = std::max(_maxCycles[_currentFunction], _currentCycleCount);
|
||||
|
||||
_currentFunction = _functionStack.top();
|
||||
_functionStack.pop();
|
||||
|
||||
|
@ -96,14 +100,18 @@ void Profiler::InternalReset()
|
|||
_cyclesByFunction.clear();
|
||||
_cyclesByFunctionInclusive.clear();
|
||||
_functionCallCount.clear();
|
||||
_minCycles.clear();
|
||||
_maxCycles.clear();
|
||||
|
||||
_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);
|
||||
_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;
|
||||
|
||||
|
@ -113,6 +121,8 @@ void Profiler::GetProfilerData(int64_t * profilerData, ProfilerDataType type)
|
|||
case ProfilerDataType::FunctionInclusive: dataArray = &_cyclesByFunctionInclusive; break;
|
||||
case ProfilerDataType::Instructions: dataArray = &_cyclesByInstruction; 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));
|
||||
|
|
|
@ -11,6 +11,8 @@ enum class ProfilerDataType
|
|||
FunctionInclusive = 1,
|
||||
Instructions = 2,
|
||||
FunctionCallCount = 3,
|
||||
MinCycles = 4,
|
||||
MaxCycles = 5,
|
||||
};
|
||||
|
||||
class Profiler
|
||||
|
@ -22,6 +24,8 @@ private:
|
|||
vector<uint64_t> _cyclesByFunction;
|
||||
vector<uint64_t> _cyclesByFunctionInclusive;
|
||||
vector<uint64_t> _functionCallCount;
|
||||
vector<uint64_t> _minCycles;
|
||||
vector<uint64_t> _maxCycles;
|
||||
|
||||
std::stack<int32_t> _functionStack;
|
||||
std::stack<int32_t> _jsrStack;
|
||||
|
@ -47,5 +51,5 @@ public:
|
|||
void UnstackFunction();
|
||||
|
||||
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.columnHeader2 = ((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.SuspendLayout();
|
||||
//
|
||||
|
@ -76,7 +79,10 @@
|
|||
this.columnHeader3,
|
||||
this.columnHeader5,
|
||||
this.columnHeader2,
|
||||
this.colExclusiveTimePercent});
|
||||
this.colExclusiveTimePercent,
|
||||
this.columnHeader1,
|
||||
this.columnHeader6,
|
||||
this.columnHeader7});
|
||||
this.tableLayoutPanel1.SetColumnSpan(this.lstFunctions, 2);
|
||||
this.lstFunctions.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.lstFunctions.FullRowSelect = true;
|
||||
|
@ -121,6 +127,18 @@
|
|||
this.colExclusiveTimePercent.Text = "Exclusive Time (%)";
|
||||
this.colExclusiveTimePercent.Width = 57;
|
||||
//
|
||||
// columnHeader1
|
||||
//
|
||||
this.columnHeader1.Text = "Avg. Cycles";
|
||||
//
|
||||
// columnHeader6
|
||||
//
|
||||
this.columnHeader6.Text = "Min. Cycles";
|
||||
//
|
||||
// columnHeader7
|
||||
//
|
||||
this.columnHeader7.Text = "Max. Cycles";
|
||||
//
|
||||
// ctrlProfiler
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
|
@ -144,5 +162,8 @@
|
|||
private System.Windows.Forms.ColumnHeader columnHeader3;
|
||||
private System.Windows.Forms.ColumnHeader columnHeader5;
|
||||
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 static event EventHandler OnFunctionSelected;
|
||||
private Int64[] _exclusiveTime;
|
||||
private Int64[] _inclusiveTime;
|
||||
private Int64[] _callCount;
|
||||
private UInt64[] _exclusiveTime;
|
||||
private UInt64[] _inclusiveTime;
|
||||
private UInt64[] _callCount;
|
||||
private UInt64[] _minCycles;
|
||||
private UInt64[] _maxCycles;
|
||||
private object _resetLock = new object();
|
||||
|
||||
private int _sortColumn = 5;
|
||||
|
@ -36,7 +38,7 @@ namespace Mesen.GUI.Debugger.Controls
|
|||
if(!designMode) {
|
||||
lstFunctions.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);
|
||||
int newWidth = Math.Max(colFunction.Width * 2, 250);
|
||||
colExclusiveTimePercent.Width -= (newWidth - colFunction.Width) + 30;
|
||||
columnHeader7.Width -= (newWidth - colFunction.Width) + 30;
|
||||
colFunction.Width = newWidth;
|
||||
}
|
||||
}
|
||||
|
@ -47,6 +49,8 @@ namespace Mesen.GUI.Debugger.Controls
|
|||
_exclusiveTime = InteropEmu.DebugGetProfilerData(ProfilerDataType.FunctionExclusive);
|
||||
_inclusiveTime = InteropEmu.DebugGetProfilerData(ProfilerDataType.FunctionInclusive);
|
||||
_callCount = InteropEmu.DebugGetProfilerData(ProfilerDataType.FunctionCallCount);
|
||||
_minCycles = InteropEmu.DebugGetProfilerData(ProfilerDataType.MinCycles);
|
||||
_maxCycles = InteropEmu.DebugGetProfilerData(ProfilerDataType.MaxCycles);
|
||||
}
|
||||
RefreshList();
|
||||
}
|
||||
|
@ -68,7 +72,10 @@ namespace Mesen.GUI.Debugger.Controls
|
|||
|
||||
private void RefreshList()
|
||||
{
|
||||
Int64 exclusiveTotal = _exclusiveTime.Sum();
|
||||
UInt64 exclusiveTotal = 0;
|
||||
foreach(UInt64 time in _exclusiveTime) {
|
||||
exclusiveTotal += time;
|
||||
}
|
||||
|
||||
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("");
|
||||
} else {
|
||||
item = lstFunctions.Items[itemNumber];
|
||||
}
|
||||
|
@ -121,14 +131,24 @@ namespace Mesen.GUI.Debugger.Controls
|
|||
|
||||
double ratio = ((double)_inclusiveTime[i] / exclusiveTotal) *100;
|
||||
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].Tag = _exclusiveTime[i];
|
||||
|
||||
ratio = ((double)_exclusiveTime[i] / exclusiveTotal)*100;
|
||||
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++;
|
||||
}
|
||||
|
@ -195,8 +215,8 @@ namespace Mesen.GUI.Debugger.Controls
|
|||
return String.Compare(((ListViewItem)x).SubItems[0].Text, ((ListViewItem)y).SubItems[0].Text);
|
||||
}
|
||||
} else {
|
||||
Int64 columnValueY = (Int64)((ListViewItem)y).SubItems[_columnIndex].Tag;
|
||||
Int64 columnValueX = (Int64)((ListViewItem)x).SubItems[_columnIndex].Tag;
|
||||
UInt64 columnValueY = (UInt64)((ListViewItem)y).SubItems[_columnIndex].Tag;
|
||||
UInt64 columnValueX = (UInt64)((ListViewItem)x).SubItems[_columnIndex].Tag;
|
||||
if(_sortOrder) {
|
||||
return (int)(columnValueY - columnValueX);
|
||||
} else {
|
||||
|
|
|
@ -612,7 +612,7 @@ namespace Mesen.GUI.Debugger
|
|||
DebugState state = new DebugState();
|
||||
InteropEmu.DebugGetState(ref state);
|
||||
|
||||
lblCyclesElapsedCount.Text = (state.CPU.CycleCount - _previousCycle).ToString();
|
||||
lblCyclesElapsedCount.Text = ((Int64)state.CPU.CycleCount - (Int64)_previousCycle).ToString();
|
||||
_previousCycle = state.CPU.CycleCount;
|
||||
|
||||
if(UpdateSplitView()) {
|
||||
|
|
|
@ -514,9 +514,9 @@ namespace Mesen.GUI
|
|||
}
|
||||
|
||||
[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);
|
||||
try {
|
||||
|
@ -1592,6 +1592,8 @@ namespace Mesen.GUI
|
|||
FunctionInclusive = 1,
|
||||
Instructions = 2,
|
||||
FunctionCallCount = 3,
|
||||
MinCycles = 4,
|
||||
MaxCycles = 5,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
|
|
|
@ -118,7 +118,7 @@ extern "C"
|
|||
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 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 DebugSetFreezeState(uint16_t address, bool frozen) { GetDebugger()->SetFreezeState(address, frozen); }
|
||||
|
|
Loading…
Add table
Reference in a new issue