Mesen-X/GUI.NET/Debugger/Controls/ctrlMemoryAccessCounters.cs
Sour 1ebd943f3a Debugger: Rewrite profiler and memory counters
Improves performance when debugger enabled (10-15%), simplifies code and improves memory counters UI
2020-02-15 10:18:07 -05:00

222 lines
8 KiB
C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Mesen.GUI.Controls;
using Mesen.GUI.Forms;
using Mesen.GUI.Config;
namespace Mesen.GUI.Debugger.Controls
{
public partial class ctrlMemoryAccessCounters : BaseControl
{
private bool _sorting = false;
private UInt64 _cycleCount = 0;
private AddressCounters[] _counts = new AddressCounters[0];
private AddressCounters[] _newCounts = new AddressCounters[0];
private DebugMemoryType _memoryType = DebugMemoryType.InternalRam;
private SortType _sortType = SortType.Address;
public ctrlMemoryAccessCounters()
{
InitializeComponent();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
if(!IsDesignMode) {
InitMemoryTypeDropdown();
}
}
public void InitMemoryTypeDropdown()
{
cboMemoryType.SelectedIndexChanged -= cboMemoryType_SelectedIndexChanged;
DebugMemoryType originalValue = cboMemoryType.GetEnumValue<DebugMemoryType>();
cboMemoryType.BeginUpdate();
cboMemoryType.Items.Clear();
cboMemoryType.Items.Add(ResourceHelper.GetEnumText(DebugMemoryType.InternalRam));
if(InteropEmu.DebugGetMemorySize(DebugMemoryType.PrgRom) > 0) {
cboMemoryType.Items.Add(ResourceHelper.GetEnumText(DebugMemoryType.PrgRom));
}
if(InteropEmu.DebugGetMemorySize(DebugMemoryType.WorkRam) > 0) {
cboMemoryType.Items.Add(ResourceHelper.GetEnumText(DebugMemoryType.WorkRam));
}
if(InteropEmu.DebugGetMemorySize(DebugMemoryType.SaveRam) > 0) {
cboMemoryType.Items.Add(ResourceHelper.GetEnumText(DebugMemoryType.SaveRam));
}
if(InteropEmu.DebugGetMemorySize(DebugMemoryType.ChrRom) > 0) {
cboMemoryType.Items.Add(ResourceHelper.GetEnumText(DebugMemoryType.ChrRom));
}
if(InteropEmu.DebugGetMemorySize(DebugMemoryType.ChrRam) > 0) {
cboMemoryType.Items.Add(ResourceHelper.GetEnumText(DebugMemoryType.ChrRam));
}
cboMemoryType.Items.Add(ResourceHelper.GetEnumText(DebugMemoryType.NametableRam));
cboMemoryType.Items.Add(ResourceHelper.GetEnumText(DebugMemoryType.PaletteMemory));
cboMemoryType.SelectedIndex = 0;
cboMemoryType.SetEnumValue(originalValue);
cboMemoryType.SelectedIndexChanged += cboMemoryType_SelectedIndexChanged;
cboMemoryType.EndUpdate();
UpdateMemoryType();
}
public void RefreshData()
{
if(_sorting) {
return;
}
InteropEmu.DebugGetMemoryAccessCounts(_memoryType, ref _counts);
DebugState state = new DebugState();
InteropEmu.DebugGetState(ref state);
_cycleCount = state.CPU.CycleCount;
_sorting = true;
Task.Run(() => {
switch(_sortType) {
case SortType.Address: break;
case SortType.Value: break;
case SortType.Read: Array.Sort(_newCounts, new SortReadComparer()); break;
case SortType.ReadStamp: Array.Sort(_newCounts, new SortReadStampComparer()); break;
case SortType.Write: Array.Sort(_newCounts, new SortWriteComparer()); break;
case SortType.WriteStamp: Array.Sort(_newCounts, new SortWriteStampComparer()); break;
case SortType.Exec: Array.Sort(_newCounts, new SortExecComparer()); break;
case SortType.ExecStamp: Array.Sort(_newCounts, new SortExecStampComparer()); break;
case SortType.UninitRead: Array.Sort(_newCounts, new SortUninitComparer()); break;
}
AddressCounters[] counts = _counts;
_counts = _newCounts;
_newCounts = counts;
this.BeginInvoke((Action)(() => {
_sorting = false;
lstCounters.BeginUpdate();
lstCounters.VirtualListSize = _counts.Length;
lstCounters.EndUpdate();
}));
});
}
private void cboMemoryType_SelectedIndexChanged(object sender, EventArgs e)
{
UpdateMemoryType();
}
private void UpdateMemoryType()
{
_memoryType = cboMemoryType.GetEnumValue<DebugMemoryType>();
RefreshData();
}
private void btnReset_Click(object sender, EventArgs e)
{
InteropEmu.DebugResetMemoryAccessCounts();
RefreshData();
}
private string FormatNumber(UInt64 value)
{
if(value >= 1000000000000) {
return ((double)value / 1000000000000).ToString("0.00") + " T";
} else if(value >= 1000000000) {
return ((double)value / 1000000000).ToString("0.00") + " G";
} else if(value >= 1000000) {
return ((double)value / 1000000).ToString("0.00") + " M";
} else if(value >= 1000) {
return ((double)value / 1000).ToString("0.00") + " K";
}
return value.ToString();
}
private void lstCounters_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
{
AddressCounters counts = _counts[e.ItemIndex];
ListViewItem item = new ListViewItem("$" + counts.Address.ToString("X4"));
item.Selected = false;
item.Focused = false;
item.SubItems.Add("$" + InteropEmu.DebugGetMemoryValue(_memoryType, counts.Address).ToString("X2"));
item.SubItems.Add(FormatNumber(counts.ReadCount));
item.SubItems.Add(counts.ReadStamp > 0 ? FormatNumber(_cycleCount - counts.ReadStamp) : "n/a");
item.SubItems.Add(FormatNumber(counts.WriteCount));
item.SubItems.Add(counts.WriteStamp > 0 ? FormatNumber(_cycleCount - counts.WriteStamp) : "n/a");
item.SubItems.Add(FormatNumber(counts.ExecCount));
item.SubItems.Add(counts.ExecStamp > 0 ? FormatNumber(_cycleCount - counts.ExecStamp) : "n/a");
item.SubItems.Add(counts.UninitRead != 0 ? "☑" : "☐");
if(counts.ReadCount == 0 && counts.WriteCount == 0 && counts.ExecCount == 0) {
item.ForeColor = Color.Gray;
}
e.Item = item;
}
public void GoToAddress()
{
GoToAddress address = new GoToAddress();
address.Address = 0;
using(frmGoToLine frm = new frmGoToLine(address, 8)) {
frm.StartPosition = FormStartPosition.Manual;
Point topLeft = this.PointToScreen(new Point(0, 0));
frm.Location = new Point(topLeft.X + (this.Width - frm.Width) / 2, topLeft.Y + (this.Height - frm.Height) / 2);
if(frm.ShowDialog() == DialogResult.OK) {
int index = -1;
for(int i = 0; i < _counts.Length; i++) {
if(_counts[i].Address == address.Address) {
index = i;
break;
}
}
if(index >= 0) {
lstCounters.EnsureVisible(index);
lstCounters.SelectedIndices.Clear();
lstCounters.SelectedIndices.Add(index);
}
}
}
}
private void lstCounters_ColumnClick(object sender, ColumnClickEventArgs e)
{
_sortType = (SortType)e.Column;
RefreshData();
}
private class SortReadComparer : IComparer<AddressCounters> { public int Compare(AddressCounters a, AddressCounters b) { return a.ReadCount.CompareTo(b.ReadCount) * -2 + a.Address.CompareTo(b.Address); } }
private class SortReadStampComparer : IComparer<AddressCounters> { public int Compare(AddressCounters a, AddressCounters b) { return a.ReadStamp.CompareTo(b.ReadStamp) * -2 + a.Address.CompareTo(b.Address); } }
private class SortWriteComparer : IComparer<AddressCounters> { public int Compare(AddressCounters a, AddressCounters b) { return a.WriteCount.CompareTo(b.WriteCount) * -2 + a.Address.CompareTo(b.Address); } }
private class SortWriteStampComparer : IComparer<AddressCounters> { public int Compare(AddressCounters a, AddressCounters b) { return a.WriteStamp.CompareTo(b.WriteStamp) * -2 + a.Address.CompareTo(b.Address); } }
private class SortExecComparer : IComparer<AddressCounters> { public int Compare(AddressCounters a, AddressCounters b) { return a.ExecCount.CompareTo(b.ExecCount) * -2 + a.Address.CompareTo(b.Address); } }
private class SortExecStampComparer : IComparer<AddressCounters> { public int Compare(AddressCounters a, AddressCounters b) { return a.ExecStamp.CompareTo(b.ExecStamp) * -2 + a.Address.CompareTo(b.Address); } }
private class SortUninitComparer : IComparer<AddressCounters> { public int Compare(AddressCounters a, AddressCounters b) { return a.UninitRead.CompareTo(b.UninitRead) * -2 + a.Address.CompareTo(b.Address); } }
private enum SortType
{
Address = 0,
Value,
Read,
ReadStamp,
Write,
WriteStamp,
Exec,
ExecStamp,
UninitRead,
}
}
}