mirror of
https://github.com/mwpenny/portal64-still-alive.git
synced 2024-10-19 22:27:36 -04:00
Get profiler working
This commit is contained in:
parent
e50e0a32ac
commit
7e10fc5d2f
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -24,3 +24,6 @@ tools/vtf2png
|
|||
skelatool64/*.zip*
|
||||
|
||||
src/controls/controller-data.h
|
||||
|
||||
|
||||
log.txt
|
|
@ -75,8 +75,13 @@ OSTime profileTask(OSSched* scheduler, OSThread* currentThread, OSTask* task) {
|
|||
|
||||
u64 us = OS_CYCLES_TO_NSEC(result);
|
||||
|
||||
// wait for DP to be available
|
||||
while (IO_READ(DPC_STATUS_REG) & (DPC_STATUS_DMA_BUSY | DPC_STATUS_END_VALID | DPC_STATUS_START_VALID));
|
||||
|
||||
copyGfx(tmp, curr, 3);
|
||||
|
||||
osWritebackDCacheAll();
|
||||
|
||||
char message[64];
|
||||
int messageLen = sprintf(
|
||||
message,
|
||||
|
|
|
@ -330,7 +330,9 @@ static void gameProc(void* arg) {
|
|||
}
|
||||
|
||||
if (controllerGetButtonDown(0, R_JPAD)) {
|
||||
profileTask(&scheduler, &gameThread, &gGraphicsTasks[drawBufferIndex ^ 1].task.list);
|
||||
struct GraphicsTask* task = &gGraphicsTasks[drawBufferIndex];
|
||||
zeroMemory(task->framebuffer, sizeof(u16) * SCREEN_WD * SCREEN_HT);
|
||||
profileTask(&scheduler, &gameThread, &task->task.list);
|
||||
}
|
||||
timeUpdateDelta();
|
||||
soundPlayerUpdate();
|
||||
|
|
124
tools/profile_parser.js
Normal file
124
tools/profile_parser.js
Normal file
|
@ -0,0 +1,124 @@
|
|||
const fs = require('fs');
|
||||
|
||||
const lines = fs.readFileSync(process.argv[2], 'utf-8').split('\n');
|
||||
|
||||
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 symbolParserRegexp = /0x([a-f0-9]{16})\s+(\w+)/
|
||||
|
||||
function parseLine(line) {
|
||||
const match = lineParserRegexp.exec(line);
|
||||
|
||||
if (!match) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
index: parseInt(match[1]),
|
||||
command: match[2],
|
||||
w0: match[3],
|
||||
w1: match[4],
|
||||
startTime: parseFloat(match[5]),
|
||||
}
|
||||
}
|
||||
|
||||
function parseSymbolLine(line) {
|
||||
const match = symbolParserRegexp.exec(line);
|
||||
|
||||
if (!match) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
address: match[1].substring(8),
|
||||
name: match[2],
|
||||
};
|
||||
}
|
||||
|
||||
const linesParsed = lines.map(parseLine).filter(Boolean);
|
||||
|
||||
const symbolAddressMapping = new Map();
|
||||
|
||||
for (const symbolLine of symbolMapLines) {
|
||||
const parsedLine = parseSymbolLine(symbolLine);
|
||||
|
||||
if (!parsedLine) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (symbolAddressMapping.has(parsedLine.address)) {
|
||||
symbolAddressMapping.set(parsedLine.address, symbolAddressMapping.get(parsedLine.address) + ',' + parsedLine.name);
|
||||
} else {
|
||||
symbolAddressMapping.set(parsedLine.address, parsedLine.name);
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
function formatAddress(address) {
|
||||
return symbolAddressMapping.get(address) || `0x${address}`;
|
||||
}
|
||||
|
||||
function formatCommandName(command) {
|
||||
switch (command.command) {
|
||||
case 'db':
|
||||
{
|
||||
const segment = parseInt(command.w0.substring(4), 16) / 4;
|
||||
return `gsSPSegment(0x${segment}, 0x${command.w1})`;
|
||||
}
|
||||
case 'de':
|
||||
return `gsSPDisplayList(${formatAddress(command.w1)})`;
|
||||
case 'f6':
|
||||
return `gsDPFillRectangle`;
|
||||
case 'd8':
|
||||
return `gsSPPopMatrix`;
|
||||
case 'da':
|
||||
return `gsSPMatrix`;
|
||||
default:
|
||||
return `unknown 0x${command.command} 0x${command.w0}${command.w1}`;
|
||||
}
|
||||
}
|
||||
|
||||
function formatCommand(command) {
|
||||
return `${command.elapsedTime} ${formatCommandName(command)}`;
|
||||
}
|
||||
|
||||
for (const command of combinedCommands) {
|
||||
console.log(formatCommand(command));
|
||||
}
|
Loading…
Reference in a new issue