mirror of
https://github.com/MoleskiCoder/EightBitNet.git
synced 2025-03-31 04:30:58 +00:00
Add instruction counters to 6502 profiler
This commit is contained in:
parent
607e93daad
commit
b62620d306
9
M6502/CycleCountedEventArgs.cs
Normal file
9
M6502/CycleCountedEventArgs.cs
Normal file
@ -0,0 +1,9 @@
|
||||
namespace EightBit
|
||||
{
|
||||
public class CycleCountedEventArgs(long cycles, long count) : EventArgs
|
||||
{
|
||||
public long Cycles { get; } = cycles;
|
||||
|
||||
public long Count { get; } = count;
|
||||
}
|
||||
}
|
@ -95,8 +95,11 @@ namespace M6502.Test
|
||||
this.profiler.FinishedLineOutput += this.Profiler_FinishedLineOutput;
|
||||
this.profiler.StartingScopeOutput += this.Profiler_StartingScopeOutput;
|
||||
this.profiler.FinishedScopeOutput += this.Profiler_FinishedScopeOutput;
|
||||
this.profiler.StartingInstructionOutput += this.Profiler_StartingInstructionOutput;
|
||||
this.profiler.FinishedInstructionOutput += this.Profiler_FinishedInstructionOutput;
|
||||
this.profiler.EmitLine += this.Profiler_EmitLine;
|
||||
this.profiler.EmitScope += this.Profiler_EmitScope;
|
||||
this.profiler.EmitInstruction += this.Profiler_EmitInstruction;
|
||||
}
|
||||
|
||||
this.Poke(0x00, 0x4c);
|
||||
@ -203,7 +206,7 @@ namespace M6502.Test
|
||||
|
||||
private void Profiler_EmitScope(object? sender, ProfileScopeEventArgs e)
|
||||
{
|
||||
var proportion = (double)e.Cycles / this.profiler.TotalCycleCount;
|
||||
var proportion = (double)e.Cycles / this.profiler.TotalCycles;
|
||||
var scope = this.symbols.LookupScopeByID(e.ID);
|
||||
Debug.Assert(scope != null);
|
||||
Console.Out.Write(string.Format(CultureInfo.InvariantCulture, "\t[{0:P2}][{1:d9}][{2:d9}]\t{3}\n", proportion, e.Cycles, e.Count, scope.Name));
|
||||
@ -211,10 +214,16 @@ namespace M6502.Test
|
||||
|
||||
private void Profiler_EmitLine(object? sender, ProfileLineEventArgs e)
|
||||
{
|
||||
var proportion = (double)e.Cycles / this.profiler.TotalCycleCount;
|
||||
var proportion = (double)e.Cycles / this.profiler.TotalCycles;
|
||||
Console.Out.Write(string.Format(CultureInfo.InvariantCulture, "\t[{0:P2}][{1:d9}][{2:d9}]\t{3}\n", proportion, e.Cycles, e.Count, e.Source));
|
||||
}
|
||||
|
||||
private void Profiler_EmitInstruction(object? sender, ProfileInstructionEventArgs e)
|
||||
{
|
||||
var proportion = (double)e.Cycles / this.profiler.TotalCycles;
|
||||
Console.Out.Write(string.Format(CultureInfo.InvariantCulture, "\t[{0:P2}][{1:d9}][{2:d9}]\t{3:X2}\n", proportion, e.Cycles, e.Count, e.Instruction));
|
||||
}
|
||||
|
||||
private void Profiler_FinishedScopeOutput(object? sender, EventArgs e)
|
||||
{
|
||||
Console.Out.Write("Finished profiler scope output...\n");
|
||||
@ -244,5 +253,15 @@ namespace M6502.Test
|
||||
{
|
||||
Console.Out.Write("Starting profiler output...\n");
|
||||
}
|
||||
|
||||
private void Profiler_FinishedInstructionOutput(object? sender, EventArgs e)
|
||||
{
|
||||
Console.Out.Write("Finished instruction output...\n");
|
||||
}
|
||||
|
||||
private void Profiler_StartingInstructionOutput(object? sender, EventArgs e)
|
||||
{
|
||||
Console.Out.Write("Starting instruction output...\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
11
M6502/ProfileInstructionEventArgs.cs
Normal file
11
M6502/ProfileInstructionEventArgs.cs
Normal file
@ -0,0 +1,11 @@
|
||||
namespace EightBit
|
||||
{
|
||||
public class ProfileInstructionEventArgs(byte instruction, long cycles, long count) : EventArgs
|
||||
{
|
||||
public byte Instruction { get; } = instruction;
|
||||
|
||||
public long Cycles { get; } = cycles;
|
||||
|
||||
public long Count { get; } = count;
|
||||
}
|
||||
}
|
@ -1,11 +1,7 @@
|
||||
namespace EightBit
|
||||
{
|
||||
public class ProfileLineEventArgs(string source, int cycles, int count) : EventArgs
|
||||
public class ProfileLineEventArgs(string source, long cycles, long count) : CycleCountedEventArgs(cycles, count)
|
||||
{
|
||||
public string Source { get; } = source;
|
||||
|
||||
public int Cycles { get; } = cycles;
|
||||
|
||||
public int Count { get; } = count;
|
||||
}
|
||||
}
|
@ -1,11 +1,7 @@
|
||||
namespace EightBit
|
||||
{
|
||||
public class ProfileScopeEventArgs(int id, int cycles, int count) : EventArgs
|
||||
public class ProfileScopeEventArgs(int id, long cycles, long count) : CycleCountedEventArgs(cycles, count)
|
||||
{
|
||||
public int ID { get; } = id;
|
||||
|
||||
public int Cycles { get; } = cycles;
|
||||
|
||||
public int Count { get; } = count;
|
||||
}
|
||||
}
|
@ -4,17 +4,22 @@
|
||||
|
||||
public sealed class Profiler
|
||||
{
|
||||
private readonly int[] instructionCounts = new int[0x100];
|
||||
private readonly int[] addressProfiles = new int[0x10000];
|
||||
private readonly int[] addressCounts = new int[0x10000];
|
||||
private readonly long[] instructionCounts = new long[0x100];
|
||||
private readonly long[] instructionCycles = new long[0x100];
|
||||
private readonly long[] addressCycles = new long[0x10000];
|
||||
private readonly long[] addressCounts = new long[0x10000];
|
||||
|
||||
private readonly Dictionary<int, int> scopeCycles = []; // ID -> Cycles
|
||||
private readonly Dictionary<int, long> scopeCycles = []; // ID -> Cycles
|
||||
|
||||
private readonly M6502 processor;
|
||||
private readonly Disassembler disassembler;
|
||||
private readonly Files.Symbols.Parser symbols;
|
||||
|
||||
private ushort executingAddress;
|
||||
private byte executingInstruction;
|
||||
|
||||
private long totalCycles = -1;
|
||||
private bool totalCyclesValid;
|
||||
|
||||
public Profiler(M6502 processor, Disassembler disassembler, Files.Symbols.Parser symbols, bool activate)
|
||||
{
|
||||
@ -43,14 +48,30 @@
|
||||
|
||||
public event EventHandler<ProfileLineEventArgs>? EmitLine;
|
||||
|
||||
public event EventHandler<EventArgs>? StartingInstructionOutput;
|
||||
|
||||
public event EventHandler<EventArgs>? FinishedInstructionOutput;
|
||||
|
||||
public event EventHandler<ProfileInstructionEventArgs>? EmitInstruction;
|
||||
|
||||
public event EventHandler<EventArgs>? StartingScopeOutput;
|
||||
|
||||
public event EventHandler<EventArgs>? FinishedScopeOutput;
|
||||
|
||||
public event EventHandler<ProfileScopeEventArgs>? EmitScope;
|
||||
|
||||
public long TotalCycleCount { get; private set; }
|
||||
|
||||
public long TotalCycles
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.totalCycles;
|
||||
}
|
||||
private set
|
||||
{
|
||||
Debug.Assert(!this.totalCyclesValid);
|
||||
this.totalCycles = value;
|
||||
}
|
||||
}
|
||||
public void Generate()
|
||||
{
|
||||
this.OnStartingOutput();
|
||||
@ -66,31 +87,16 @@
|
||||
|
||||
private void EmitProfileInformation()
|
||||
{
|
||||
this.OnStartingLineOutput();
|
||||
try
|
||||
{
|
||||
// For each memory address
|
||||
for (var i = 0; i < 0x10000; ++i)
|
||||
{
|
||||
// If there are any cycles associated
|
||||
var cycles = this.addressProfiles[i];
|
||||
if (cycles > 0)
|
||||
{
|
||||
var count = this.addressCounts[i];
|
||||
Debug.Assert(count > 0);
|
||||
var address = (ushort)i;
|
||||
this.TotalCycles = this.instructionCycles.Sum();
|
||||
this.totalCyclesValid = true;
|
||||
|
||||
// Dump a profile/disassembly line
|
||||
var source = this.disassembler.Disassemble(address);
|
||||
this.OnEmitLine(source, cycles, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.OnFinishedLineOutput();
|
||||
}
|
||||
this.EmitProfileLineInformation();
|
||||
this.EmitProfileScopeInformation();
|
||||
this.EmitProfileInstructionInformation();
|
||||
}
|
||||
|
||||
private void EmitProfileScopeInformation()
|
||||
{
|
||||
this.OnStartingScopeOutput();
|
||||
try
|
||||
{
|
||||
@ -108,10 +114,66 @@
|
||||
}
|
||||
}
|
||||
|
||||
private void EmitProfileLineInformation()
|
||||
{
|
||||
this.OnStartingLineOutput();
|
||||
try
|
||||
{
|
||||
// For each memory address
|
||||
for (var i = 0; i < 0x10000; ++i)
|
||||
{
|
||||
// If there are any cycles associated
|
||||
var cycles = this.addressCycles[i];
|
||||
if (cycles > 0)
|
||||
{
|
||||
var count = this.addressCounts[i];
|
||||
Debug.Assert(count > 0);
|
||||
var address = (ushort)i;
|
||||
|
||||
// Dump a profile/disassembly line
|
||||
var source = this.disassembler.Disassemble(address);
|
||||
this.OnEmitLine(source, cycles, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.OnFinishedLineOutput();
|
||||
}
|
||||
}
|
||||
|
||||
private void EmitProfileInstructionInformation()
|
||||
{
|
||||
this.OnStartingInstructionOutput();
|
||||
try
|
||||
{
|
||||
// For each instruction
|
||||
for (var i = 0; i < 0x100; ++i)
|
||||
{
|
||||
// If there are any cycles associated
|
||||
var cycles = this.instructionCycles[i];
|
||||
if (cycles > 0)
|
||||
{
|
||||
var count = this.instructionCounts[i];
|
||||
Debug.Assert(count > 0);
|
||||
var instruction = (byte)i;
|
||||
|
||||
// Emit an instruction event
|
||||
this.OnEmitInstruction(instruction, cycles, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.OnFinishedInstructionOutput();
|
||||
}
|
||||
}
|
||||
|
||||
private void Processor_RaisingSYNC(object? sender, EventArgs e)
|
||||
{
|
||||
// Everything needs this
|
||||
this.executingAddress = this.processor.Bus.Address.Word;
|
||||
this.executingInstruction = this.processor.Bus.Peek(this.executingAddress);
|
||||
|
||||
++this.addressCounts[this.executingAddress];
|
||||
++this.instructionCounts[this.processor.Bus.Data];
|
||||
@ -120,9 +182,9 @@
|
||||
private void Processor_ExecutedInstruction(object? sender, EventArgs e)
|
||||
{
|
||||
var cycles = this.processor.Cycles;
|
||||
this.TotalCycleCount += cycles;
|
||||
|
||||
this.addressProfiles[this.executingAddress] += cycles;
|
||||
this.addressCycles[this.executingAddress] += cycles;
|
||||
this.instructionCycles[this.executingInstruction] += cycles;
|
||||
|
||||
var scope = this.symbols.LookupScopeByAddress(this.executingAddress);
|
||||
if (scope != null)
|
||||
@ -154,6 +216,16 @@
|
||||
this.FinishedLineOutput?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
private void OnStartingInstructionOutput()
|
||||
{
|
||||
this.StartingInstructionOutput?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
private void OnFinishedInstructionOutput()
|
||||
{
|
||||
this.FinishedInstructionOutput?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
private void OnStartingScopeOutput()
|
||||
{
|
||||
this.StartingScopeOutput?.Invoke(this, EventArgs.Empty);
|
||||
@ -164,14 +236,19 @@
|
||||
this.FinishedScopeOutput?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
private void OnEmitLine(string source, int cycles, int count)
|
||||
private void OnEmitLine(string source, long cycles, long count)
|
||||
{
|
||||
this.EmitLine?.Invoke(this, new ProfileLineEventArgs(source, cycles, count));
|
||||
}
|
||||
|
||||
private void OnEmitScope(int id, int cycles, int count)
|
||||
private void OnEmitScope(int id, long cycles, long count)
|
||||
{
|
||||
this.EmitScope?.Invoke(this, new ProfileScopeEventArgs(id, cycles, count));
|
||||
}
|
||||
|
||||
private void OnEmitInstruction(byte instruction, long cycles, long count)
|
||||
{
|
||||
this.EmitInstruction?.Invoke(this, new ProfileInstructionEventArgs(instruction, cycles, count));
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user