82 lines
2.0 KiB
JavaScript
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}`,
|
|
);
|
|
}
|