EightBit/M6502/src/Profiler.cpp

95 lines
3.1 KiB
C++

#include "stdafx.h"
#include "Profiler.h"
Profiler::Profiler(System6502& targetProcessor, Disassembly& disassemblerTarget, Symbols& symbolsTarget, bool instructions, bool addresses)
: processor(targetProcessor),
disassembler(disassemblerTarget),
symbols(symbolsTarget),
countInstructions(instructions),
profileAddresses(addresses)
{
instructionCounts.fill(0);
addressProfiles.fill(0);
addressCounts.fill(0);
if (profileAddresses)
processor.ExecutingInstruction.connect(std::bind(&Profiler::Processor_ExecutingInstruction_ProfileAddresses, this, std::placeholders::_1));
if (countInstructions)
processor.ExecutingInstruction.connect(std::bind(&Profiler::Processor_ExecutingInstruction_CountInstructions, this, std::placeholders::_1));
if (profileAddresses)
processor.ExecutedInstruction.connect(std::bind(&Profiler::Processor_ExecutedInstruction_ProfileAddresses, this, std::placeholders::_1));
BuildAddressScopes();
}
void Profiler::Generate() {
StartingOutput.fire(EventArgs());
EmitProfileInformation();
StartingOutput.fire(EventArgs());
}
void Profiler::EmitProfileInformation() {
{
StartingLineOutput.fire(EventArgs());
// For each memory address
for (uint16_t address = 0; address < 0x10000; ++address) {
// If there are any cycles associated
auto cycles = addressProfiles[address];
if (cycles > 0) {
// Dump a profile/disassembly line
auto source = disassembler.Disassemble(address);
EmitLine.fire(ProfileLineEventArgs(source, cycles));
}
}
FinishedLineOutput.fire(EventArgs());
}
{
StartingScopeOutput.fire(EventArgs());
for (auto& scopeCycle : scopeCycles) {
auto name = scopeCycle.first;
auto cycles = scopeCycle.second;
auto namedAddress = (size_t)symbols.getAddresses().find(name)->second;
auto count = addressCounts[namedAddress];
EmitScope.fire(ProfileScopeEventArgs(name, cycles, count));
}
FinishedScopeOutput.fire(EventArgs());
}
}
void Profiler::Processor_ExecutingInstruction_ProfileAddresses(const AddressEventArgs& addressEvent) {
assert(profileAddresses);
priorCycleCount = processor.getCycles();
addressCounts[addressEvent.getAddress()]++;
}
void Profiler::Processor_ExecutingInstruction_CountInstructions(const AddressEventArgs& addressEvent) {
assert(countInstructions);
++instructionCounts[addressEvent.getCell()];
}
void Profiler::Processor_ExecutedInstruction_ProfileAddresses(const AddressEventArgs& addressEvent) {
assert(profileAddresses);
auto cycles = processor.getCycles() - priorCycleCount;
addressProfiles[addressEvent.getAddress()] += cycles;
auto addressScope = addressScopes[addressEvent.getAddress()];
if (!addressScope.empty()) {
if (scopeCycles.find(addressScope) == scopeCycles.end())
scopeCycles[addressScope] = 0;
scopeCycles[addressScope] += cycles;
}
}
void Profiler::BuildAddressScopes() {
for (auto& label : symbols.getLabels()) {
auto address = label.first;
auto key = label.second;
auto scope = symbols.getScopes().find(key);
if (scope != symbols.getScopes().end()) {
for (uint16_t i = address; i < address + scope->second; ++i) {
addressScopes[i] = key;
}
}
}
}