work on rsp profiler

This commit is contained in:
James Lambert 2023-12-10 21:34:46 -07:00
parent eae2f6d3b1
commit af2240298f
5 changed files with 117 additions and 38 deletions

View file

@ -110,4 +110,28 @@ void profileTask(OSSched* scheduler, OSThread* currentThread, OSTask* task) {
osSetEventMesg(OS_EVENT_DP, &scheduler->interruptQ, (OSMesg)RDP_DONE_MSG);
osViSetEvent(&scheduler->interruptQ, (OSMesg)VIDEO_MSG, 1);
osSetThreadPri(currentThread, GAME_PRIORITY);
}
void profileMapAddress(void* original, void* ramAddress) {
#ifdef PORTAL64_WITH_DEBUGGER
char message[64];
int messageLen = sprintf(
message,
"addr 0x%08x -> 0x%08x",
(int)original,
(int)ramAddress
);
gdbSendMessage(GDBDataTypeText, message, messageLen);
#endif
}
void profileClearAddressMap() {
#ifdef PORTAL64_WITH_DEBUGGER
char message[64];
int messageLen = sprintf(
message,
"addr clearall"
);
gdbSendMessage(GDBDataTypeText, message, messageLen);
#endif
}

View file

@ -5,5 +5,7 @@
#include <sched.h>
void profileTask(OSSched* scheduler, OSThread* currentThread, OSTask* task);
void profileMapAddress(void* original, void* ramAddress);
void profileClearAddressMap();
#endif

View file

@ -284,6 +284,7 @@ static void gameProc(void* arg) {
portalSurfaceRevert(0);
portalSurfaceCleanupQueueInit();
heapInit(_heapStart, memoryEnd);
profileClearAddressMap();
translationsLoad(gSaveData.controls.subtitleLanguage);
levelLoadWithCallbacks(levelGetQueued());
rumblePakClipInit();

View file

@ -1,6 +1,7 @@
#include "dynamic_asset_loader.h"
#include "memory.h"
#include "rom.h"
#include "../graphics/profile_task.h"
#include "../build/assets/models/dynamic_model_list.h"
#include "../build/assets/models/dynamic_animated_model_list.h"
@ -92,6 +93,8 @@ Gfx* dynamicAssetLoadModel(struct DynamicAssetModel* model, u32* pointerOffset)
*pointerOffset = 0;
}
profileMapAddress(model->model, result);
return result;
}
@ -114,6 +117,8 @@ void dynamicAssetLoadAnimatedModel(struct DynamicAnimatedAssetModel* model, stru
}
result->clipCount = model->clipCount;
profileMapAddress(result->armature->displayList, result->armature->displayList);
}
void dynamicAssetModelPreload(int index) {

View file

@ -6,6 +6,8 @@ const symbolMapLines = fs.readFileSync(process.argv[3], 'utf-8').split('\n');
const lineParserRegexp = /(\d+)\/\d+ 0x([a-f0-9]{2})([a-f0-9]{6})([a-f0-9]{8}) ms (\d+\.\d+)/
const lineMappingRegexp = /addr 0x([a-f0-9]{8}) -> 0x([a-f0-9]{8})/
const symbolParserRegexp = /0x([a-f0-9]{16})\s+(\w+)/
function parseLine(line) {
@ -37,7 +39,38 @@ function parseSymbolLine(line) {
};
}
const linesParsed = lines.map(parseLine).filter(Boolean);
const memoryMapping = new Map();
const profileBatches = [];
let lastIndex = -1;
for (const line of lines) {
const parsedLine = parseLine(line);
if (parsedLine) {
if (lastIndex != 0 && parsedLine.index == 0) {
profileBatches.push({
memoryMapping: new Map(memoryMapping),
lines: [],
})
}
const latestBatch = profileBatches[profileBatches.length - 1];
latestBatch.lines.push(parsedLine);
lastIndex = parsedLine.index;
continue
}
if (line.trim() == 'addr clearall') {
memoryMapping.clear();
}
const addrMatch = lineMappingRegexp.exec(line);
if (addrMatch) {
memoryMapping.set(addrMatch[2], addrMatch[1]);
}
}
const symbolAddressMapping = new Map();
@ -55,47 +88,57 @@ for (const symbolLine of symbolMapLines) {
}
}
const combinedCommands = [];
for (const parsedLine of linesParsed) {
const existing = combinedCommands[parsedLine.index];
if (existing) {
existing.startTime += parsedLine.startTime;
existing.total += 1;
} else {
combinedCommands[parsedLine.index] = {
...parsedLine,
total: 1,
};
function calculateAverage(batch) {
const combinedCommands = [];
for (const parsedLine of batch.lines) {
const existing = combinedCommands[parsedLine.index];
if (existing) {
existing.startTime += parsedLine.startTime;
existing.total += 1;
} else {
combinedCommands[parsedLine.index] = {
...parsedLine,
total: 1,
};
}
}
}
for (let i = 0; i < combinedCommands.length; ++i) {
const current = combinedCommands[i];
if (current) {
current.startTime /= current.total;
for (let i = 0; i < combinedCommands.length; ++i) {
const current = combinedCommands[i];
if (current) {
current.startTime /= current.total;
}
}
for (let i = 0; i + 1 < combinedCommands.length; ++i) {
const current = combinedCommands[i];
const next = combinedCommands[i + 1];
current.elapsedTime = next.startTime - current.startTime;
}
// the last command is always a pipe sync we dont care about
combinedCommands.pop();
combinedCommands.sort((a, b) => b.elapsedTime - a.elapsedTime);
batch.combinedCommands = combinedCommands;
}
for (let i = 0; i + 1 < combinedCommands.length; ++i) {
const current = combinedCommands[i];
const next = combinedCommands[i + 1];
profileBatches.forEach(calculateAverage);
current.elapsedTime = next.startTime - current.startTime;
}
function formatAddress(address, batch) {
if (batch.memoryMapping.has(address)) {
address = batch.memoryMapping.get(address);
}
// the last command is always a pipe sync we dont care about
combinedCommands.pop();
combinedCommands.sort((a, b) => b.elapsedTime - a.elapsedTime);
function formatAddress(address) {
return symbolAddressMapping.get(address) || `0x${address}`;
}
function formatCommandName(command) {
function formatCommandName(command, batch) {
switch (command.command) {
case 'db':
{
@ -103,7 +146,7 @@ function formatCommandName(command) {
return `gsSPSegment(0x${segment}, 0x${command.w1})`;
}
case 'de':
return `gsSPDisplayList(${formatAddress(command.w1)})`;
return `gsSPDisplayList(${formatAddress(command.w1, batch)})`;
case 'f6':
return `gsDPFillRectangle`;
case 'd8':
@ -115,10 +158,14 @@ function formatCommandName(command) {
}
}
function formatCommand(command) {
return `${command.elapsedTime} ${formatCommandName(command)}`;
function formatCommand(command, batch) {
return `${command.elapsedTime} ${formatCommandName(command, batch)}`;
}
for (const command of combinedCommands) {
console.log(formatCommand(command));
for (const batch of profileBatches) {
console.log('start of batch');
for (const command of batch.combinedCommands) {
console.log(formatCommand(command, batch));
}
console.log('end of batch');
}