Debugger: Profiler - Added min/max/avg cycle counts per function call to profiler

This commit is contained in:
Sour 2019-11-03 14:37:29 -05:00
parent 20fe8bd4c7
commit c35d6d8989
7 changed files with 73 additions and 16 deletions

View file

@ -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));

View file

@ -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);
};

View file

@ -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;
}
}

View file

@ -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 {

View file

@ -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()) {

View file

@ -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]

View file

@ -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); }