Files
cfw-autumn/server/scripts/analyze-worker-startup-profile.mjs

82 lines
2.0 KiB
JavaScript

import { readFileSync } from "node:fs";
const profilePath = process.argv[2] ?? "worker-startup.cpuprofile";
const profile = JSON.parse(readFileSync(profilePath, "utf8"));
const selfSamples = new Map();
for (const id of profile.samples ?? []) {
selfSamples.set(id, (selfSamples.get(id) ?? 0) + 1);
}
const childrenById = new Map();
for (const node of profile.nodes) {
childrenById.set(node.id, node.children ?? []);
}
const totalSamples = new Map();
const sumTotalSamples = (id) => {
if (totalSamples.has(id)) return totalSamples.get(id);
let total = selfSamples.get(id) ?? 0;
for (const childId of childrenById.get(id) ?? []) {
total += sumTotalSamples(childId);
}
totalSamples.set(id, total);
return total;
};
for (const node of profile.nodes) {
sumTotalSamples(node.id);
}
const elapsedMicroseconds = (profile.timeDeltas ?? []).reduce(
(sum, delta) => sum + delta,
0,
);
const formatFrame = (node) => {
const frame = node.callFrame ?? {};
const functionName = frame.functionName || "(anonymous)";
const url = frame.url || "";
const line = (frame.lineNumber ?? -1) + 1;
const column = (frame.columnNumber ?? -1) + 1;
return `${functionName} ${url}:${line}:${column}`;
};
const rows = [...profile.nodes]
.map((node) => ({
frame: formatFrame(node),
self: selfSamples.get(node.id) ?? 0,
total: totalSamples.get(node.id) ?? 0,
}))
.sort((left, right) => right.total - left.total);
const gcRow = rows.find((row) => row.frame.startsWith("(garbage collector)"));
const sampleCount = profile.samples?.length ?? 0;
const gcSamples = gcRow?.self ?? 0;
const gcRatio = sampleCount === 0 ? 0 : gcSamples / sampleCount;
console.log(
JSON.stringify(
{
profilePath,
nodes: profile.nodes.length,
samples: sampleCount,
elapsedMilliseconds: Math.round(elapsedMicroseconds / 1000),
gcSamples,
gcRatio: Number(gcRatio.toFixed(3)),
},
null,
2,
),
);
console.log("\nTop total samples:");
for (const row of rows.slice(0, 30)) {
console.log(
`${String(row.self).padStart(5)} self ${String(row.total).padStart(
5,
)} total ${row.frame}`,
);
}