benchforge 0.1.3 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{BenchRunner-BLfGX2wQ.d.mts → BenchRunner-CSKN9zPy.d.mts} +1 -1
- package/dist/BrowserHeapSampler-BzQs0P_z.mjs +202 -0
- package/dist/BrowserHeapSampler-BzQs0P_z.mjs.map +1 -0
- package/dist/GcStats-ByEovUi1.mjs +77 -0
- package/dist/GcStats-ByEovUi1.mjs.map +1 -0
- package/dist/{HeapSampler-BX3de22o.mjs → HeapSampler-B8dtKHn1.mjs} +1 -1
- package/dist/{HeapSampler-BX3de22o.mjs.map → HeapSampler-B8dtKHn1.mjs.map} +1 -1
- package/dist/bin/benchforge.mjs +1 -1
- package/dist/index.d.mts +3 -2
- package/dist/index.mjs +1 -1
- package/dist/runners/WorkerScript.d.mts +1 -1
- package/dist/runners/WorkerScript.mjs +1 -1
- package/dist/{src-JGOI6_Sc.mjs → src-Dt_T-s_f.mjs} +27 -274
- package/dist/src-Dt_T-s_f.mjs.map +1 -0
- package/package.json +13 -3
- package/src/browser/BrowserHeapSampler.ts +24 -2
- package/src/cli/CliArgs.ts +1 -1
- package/src/cli/RunBenchCLI.ts +45 -18
- package/dist/src-JGOI6_Sc.mjs.map +0 -1
|
@@ -222,4 +222,4 @@ interface RunnerOptions {
|
|
|
222
222
|
}
|
|
223
223
|
//#endregion
|
|
224
224
|
export { MeasuredResults as a, BenchmarkSpec as i, BenchGroup as n, HeapProfile as o, BenchSuite as r, RunnerOptions as t };
|
|
225
|
-
//# sourceMappingURL=BenchRunner-
|
|
225
|
+
//# sourceMappingURL=BenchRunner-CSKN9zPy.d.mts.map
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { t as aggregateGcStats } from "./GcStats-ByEovUi1.mjs";
|
|
2
|
+
import { chromium } from "playwright";
|
|
3
|
+
|
|
4
|
+
//#region src/browser/BrowserGcStats.ts
|
|
5
|
+
/** Parse CDP trace events (MinorGC/MajorGC) into GcEvent[] */
|
|
6
|
+
function parseGcTraceEvents(traceEvents) {
|
|
7
|
+
return traceEvents.flatMap((e) => {
|
|
8
|
+
if (e.ph !== "X") return [];
|
|
9
|
+
const type = gcType(e.name);
|
|
10
|
+
if (!type) return [];
|
|
11
|
+
const durUs = e.dur ?? 0;
|
|
12
|
+
const heapBefore = e.args?.usedHeapSizeBefore ?? 0;
|
|
13
|
+
const heapAfter = e.args?.usedHeapSizeAfter ?? 0;
|
|
14
|
+
return [{
|
|
15
|
+
type,
|
|
16
|
+
pauseMs: durUs / 1e3,
|
|
17
|
+
collected: Math.max(0, heapBefore - heapAfter)
|
|
18
|
+
}];
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
function gcType(name) {
|
|
22
|
+
if (name === "MinorGC") return "scavenge";
|
|
23
|
+
if (name === "MajorGC") return "mark-compact";
|
|
24
|
+
}
|
|
25
|
+
/** Parse CDP trace events and aggregate into GcStats */
|
|
26
|
+
function browserGcStats(traceEvents) {
|
|
27
|
+
return aggregateGcStats(parseGcTraceEvents(traceEvents));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
//#endregion
|
|
31
|
+
//#region src/browser/BrowserHeapSampler.ts
|
|
32
|
+
/** Run browser benchmark, auto-detecting page API mode.
|
|
33
|
+
* Bench function (window.__bench): CLI controls iteration and timing.
|
|
34
|
+
* Lap mode (__start/__lap/__done): page controls the measured region. */
|
|
35
|
+
async function profileBrowser(params) {
|
|
36
|
+
const { url, headless = true, chromeArgs, timeout = 60 } = params;
|
|
37
|
+
const { gcStats: collectGc } = params;
|
|
38
|
+
const { samplingInterval = 32768 } = params.heapOptions ?? {};
|
|
39
|
+
const server = await chromium.launchServer({
|
|
40
|
+
headless,
|
|
41
|
+
args: chromeArgs
|
|
42
|
+
});
|
|
43
|
+
pipeChromeStderr(server);
|
|
44
|
+
const browser = await chromium.connect(server.wsEndpoint());
|
|
45
|
+
try {
|
|
46
|
+
const page = await browser.newPage();
|
|
47
|
+
page.setDefaultTimeout(timeout * 1e3);
|
|
48
|
+
const cdp = await page.context().newCDPSession(page);
|
|
49
|
+
const pageErrors = [];
|
|
50
|
+
page.on("pageerror", (err) => pageErrors.push(err.message));
|
|
51
|
+
const traceEvents = collectGc ? await startGcTracing(cdp) : [];
|
|
52
|
+
const lapMode = await setupLapMode(page, cdp, params, samplingInterval, timeout, pageErrors);
|
|
53
|
+
await page.goto(url, { waitUntil: "load" });
|
|
54
|
+
const hasBench = await page.evaluate(() => typeof globalThis.__bench === "function");
|
|
55
|
+
let result;
|
|
56
|
+
if (hasBench) {
|
|
57
|
+
lapMode.cancel();
|
|
58
|
+
lapMode.promise.catch(() => {});
|
|
59
|
+
result = await runBenchLoop(page, cdp, params, samplingInterval);
|
|
60
|
+
} else {
|
|
61
|
+
result = await lapMode.promise;
|
|
62
|
+
lapMode.cancel();
|
|
63
|
+
}
|
|
64
|
+
if (collectGc) result = {
|
|
65
|
+
...result,
|
|
66
|
+
gcStats: await collectTracing(cdp, traceEvents)
|
|
67
|
+
};
|
|
68
|
+
return result;
|
|
69
|
+
} finally {
|
|
70
|
+
await browser.close();
|
|
71
|
+
await server.close();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/** Inject __start/__lap as in-page functions, expose __done for results collection.
|
|
75
|
+
* __start/__lap are pure in-page (zero CDP overhead). First __start() triggers
|
|
76
|
+
* instrument start. __done() stops instruments and collects timing data. */
|
|
77
|
+
async function setupLapMode(page, cdp, params, samplingInterval, timeout, pageErrors) {
|
|
78
|
+
const { heapSample } = params;
|
|
79
|
+
const { promise, resolve, reject } = Promise.withResolvers();
|
|
80
|
+
let instrumentsStarted = false;
|
|
81
|
+
await page.exposeFunction("__benchInstrumentStart", async () => {
|
|
82
|
+
if (instrumentsStarted) return;
|
|
83
|
+
instrumentsStarted = true;
|
|
84
|
+
if (heapSample) await cdp.send("HeapProfiler.startSampling", heapSamplingParams(samplingInterval));
|
|
85
|
+
});
|
|
86
|
+
await page.exposeFunction("__benchCollect", async (samples, wallTimeMs) => {
|
|
87
|
+
let heapProfile;
|
|
88
|
+
if (heapSample && instrumentsStarted) heapProfile = (await cdp.send("HeapProfiler.stopSampling")).profile;
|
|
89
|
+
resolve({
|
|
90
|
+
samples,
|
|
91
|
+
heapProfile,
|
|
92
|
+
wallTimeMs
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
await page.addInitScript(injectLapFunctions);
|
|
96
|
+
const timer = setTimeout(() => {
|
|
97
|
+
const lines = [`Timed out after ${timeout}s`];
|
|
98
|
+
if (pageErrors.length) lines.push("Page JS errors:", ...pageErrors.map((e) => ` ${e}`));
|
|
99
|
+
else lines.push("Page did not call __done() or define window.__bench");
|
|
100
|
+
reject(new Error(lines.join("\n")));
|
|
101
|
+
}, timeout * 1e3);
|
|
102
|
+
return {
|
|
103
|
+
promise,
|
|
104
|
+
cancel: () => clearTimeout(timer)
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/** In-page timing functions injected via addInitScript (zero CDP overhead).
|
|
108
|
+
* __start/__lap collect timestamps, __done delegates to exposed __benchCollect. */
|
|
109
|
+
function injectLapFunctions() {
|
|
110
|
+
const g = globalThis;
|
|
111
|
+
g.__benchSamples = [];
|
|
112
|
+
g.__benchLastTime = 0;
|
|
113
|
+
g.__benchFirstStart = 0;
|
|
114
|
+
g.__start = () => {
|
|
115
|
+
const now = performance.now();
|
|
116
|
+
g.__benchLastTime = now;
|
|
117
|
+
if (!g.__benchFirstStart) {
|
|
118
|
+
g.__benchFirstStart = now;
|
|
119
|
+
return g.__benchInstrumentStart();
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
g.__lap = () => {
|
|
123
|
+
const now = performance.now();
|
|
124
|
+
g.__benchSamples.push(now - g.__benchLastTime);
|
|
125
|
+
g.__benchLastTime = now;
|
|
126
|
+
};
|
|
127
|
+
g.__done = () => {
|
|
128
|
+
const wall = g.__benchFirstStart ? performance.now() - g.__benchFirstStart : 0;
|
|
129
|
+
return g.__benchCollect(g.__benchSamples.slice(), wall);
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
function heapSamplingParams(samplingInterval) {
|
|
133
|
+
return {
|
|
134
|
+
samplingInterval,
|
|
135
|
+
includeObjectsCollectedByMajorGC: true,
|
|
136
|
+
includeObjectsCollectedByMinorGC: true
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
/** Start CDP GC tracing, returns the event collector array. */
|
|
140
|
+
async function startGcTracing(cdp) {
|
|
141
|
+
const events = [];
|
|
142
|
+
cdp.on("Tracing.dataCollected", ({ value }) => {
|
|
143
|
+
for (const e of value) events.push(e);
|
|
144
|
+
});
|
|
145
|
+
await cdp.send("Tracing.start", { traceConfig: { includedCategories: ["v8", "v8.gc"] } });
|
|
146
|
+
return events;
|
|
147
|
+
}
|
|
148
|
+
/** Bench function mode: run window.__bench in a timed iteration loop. */
|
|
149
|
+
async function runBenchLoop(page, cdp, params, samplingInterval) {
|
|
150
|
+
const { heapSample } = params;
|
|
151
|
+
const maxTime = params.maxTime ?? 642;
|
|
152
|
+
const maxIter = params.maxIterations ?? Number.MAX_SAFE_INTEGER;
|
|
153
|
+
if (heapSample) await cdp.send("HeapProfiler.startSampling", heapSamplingParams(samplingInterval));
|
|
154
|
+
const { samples, totalMs } = await page.evaluate(async ({ maxTime, maxIter }) => {
|
|
155
|
+
const bench = globalThis.__bench;
|
|
156
|
+
const samples = [];
|
|
157
|
+
const startAll = performance.now();
|
|
158
|
+
const deadline = startAll + maxTime;
|
|
159
|
+
for (let i = 0; i < maxIter && performance.now() < deadline; i++) {
|
|
160
|
+
const t0 = performance.now();
|
|
161
|
+
await bench();
|
|
162
|
+
samples.push(performance.now() - t0);
|
|
163
|
+
}
|
|
164
|
+
return {
|
|
165
|
+
samples,
|
|
166
|
+
totalMs: performance.now() - startAll
|
|
167
|
+
};
|
|
168
|
+
}, {
|
|
169
|
+
maxTime,
|
|
170
|
+
maxIter
|
|
171
|
+
});
|
|
172
|
+
let heapProfile;
|
|
173
|
+
if (heapSample) heapProfile = (await cdp.send("HeapProfiler.stopSampling")).profile;
|
|
174
|
+
return {
|
|
175
|
+
samples,
|
|
176
|
+
heapProfile,
|
|
177
|
+
wallTimeMs: totalMs
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
/** Stop CDP tracing and parse GC events into GcStats. */
|
|
181
|
+
async function collectTracing(cdp, traceEvents) {
|
|
182
|
+
const complete = new Promise((resolve) => cdp.once("Tracing.tracingComplete", () => resolve()));
|
|
183
|
+
await cdp.send("Tracing.end");
|
|
184
|
+
await complete;
|
|
185
|
+
return browserGcStats(traceEvents);
|
|
186
|
+
}
|
|
187
|
+
/** Forward Chrome's stderr to the terminal so V8 flag warnings are visible. */
|
|
188
|
+
function pipeChromeStderr(server) {
|
|
189
|
+
const proc = server.process();
|
|
190
|
+
const pipe = (stream) => stream?.on("data", (chunk) => {
|
|
191
|
+
for (const line of chunk.toString().split("\n")) {
|
|
192
|
+
const text = line.trim();
|
|
193
|
+
if (text) process.stderr.write(`[chrome] ${text}\n`);
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
pipe(proc.stdout);
|
|
197
|
+
pipe(proc.stderr);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
//#endregion
|
|
201
|
+
export { profileBrowser, profileBrowser as profileBrowserHeap };
|
|
202
|
+
//# sourceMappingURL=BrowserHeapSampler-BzQs0P_z.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BrowserHeapSampler-BzQs0P_z.mjs","names":[],"sources":["../src/browser/BrowserGcStats.ts","../src/browser/BrowserHeapSampler.ts"],"sourcesContent":["import {\n aggregateGcStats,\n type GcEvent,\n type GcStats,\n} from \"../runners/GcStats.ts\";\n\n/** CDP trace event from Tracing.dataCollected */\nexport interface TraceEvent {\n cat: string;\n name: string;\n ph: string;\n dur?: number; // microseconds\n args?: Record<string, any>;\n}\n\n/** Parse CDP trace events (MinorGC/MajorGC) into GcEvent[] */\nexport function parseGcTraceEvents(traceEvents: TraceEvent[]): GcEvent[] {\n return traceEvents.flatMap(e => {\n if (e.ph !== \"X\") return [];\n const type = gcType(e.name);\n if (!type) return [];\n const durUs = e.dur ?? 0;\n const heapBefore: number = e.args?.usedHeapSizeBefore ?? 0;\n const heapAfter: number = e.args?.usedHeapSizeAfter ?? 0;\n return [\n {\n type,\n pauseMs: durUs / 1000,\n collected: Math.max(0, heapBefore - heapAfter),\n },\n ];\n });\n}\n\nfunction gcType(name: string): GcEvent[\"type\"] | undefined {\n if (name === \"MinorGC\") return \"scavenge\";\n if (name === \"MajorGC\") return \"mark-compact\";\n return undefined;\n}\n\n/** Parse CDP trace events and aggregate into GcStats */\nexport function browserGcStats(traceEvents: TraceEvent[]): GcStats {\n return aggregateGcStats(parseGcTraceEvents(traceEvents));\n}\n","import {\n type BrowserServer,\n type CDPSession,\n chromium,\n type Page,\n} from \"playwright\";\nimport type {\n HeapProfile,\n HeapSampleOptions,\n} from \"../heap-sample/HeapSampler.ts\";\nimport type { GcStats } from \"../runners/GcStats.ts\";\nimport { browserGcStats, type TraceEvent } from \"./BrowserGcStats.ts\";\n\nexport interface BrowserProfileParams {\n url: string;\n heapSample?: boolean;\n heapOptions?: HeapSampleOptions;\n gcStats?: boolean;\n headless?: boolean;\n chromeArgs?: string[];\n timeout?: number; // seconds\n maxTime?: number; // ms, bench function iteration time limit\n maxIterations?: number; // exact iteration count (bench function mode)\n}\n\nexport interface BrowserProfileResult {\n heapProfile?: HeapProfile;\n gcStats?: GcStats;\n /** Wall-clock ms (lap mode: first start to done, bench function: total loop) */\n wallTimeMs?: number;\n /** Per-iteration timing samples (ms) from bench function or lap mode */\n samples?: number[];\n}\n\ninterface LapModeHandle {\n promise: Promise<BrowserProfileResult>;\n cancel: () => void;\n}\n\n/** Run browser benchmark, auto-detecting page API mode.\n * Bench function (window.__bench): CLI controls iteration and timing.\n * Lap mode (__start/__lap/__done): page controls the measured region. */\nexport async function profileBrowser(\n params: BrowserProfileParams,\n): Promise<BrowserProfileResult> {\n const { url, headless = true, chromeArgs, timeout = 60 } = params;\n const { gcStats: collectGc } = params;\n const { samplingInterval = 32768 } = params.heapOptions ?? {};\n\n const server = await chromium.launchServer({ headless, args: chromeArgs });\n pipeChromeStderr(server);\n const browser = await chromium.connect(server.wsEndpoint());\n try {\n const page = await browser.newPage();\n page.setDefaultTimeout(timeout * 1000);\n const cdp = await page.context().newCDPSession(page);\n\n const pageErrors: string[] = [];\n page.on(\"pageerror\", err => pageErrors.push(err.message));\n\n const traceEvents = collectGc ? await startGcTracing(cdp) : [];\n const lapMode = await setupLapMode(\n page,\n cdp,\n params,\n samplingInterval,\n timeout,\n pageErrors,\n );\n\n await page.goto(url, { waitUntil: \"load\" });\n const hasBench = await page.evaluate(\n () => typeof (globalThis as any).__bench === \"function\",\n );\n\n let result: BrowserProfileResult;\n if (hasBench) {\n lapMode.cancel();\n lapMode.promise.catch(() => {}); // suppress unused rejection\n result = await runBenchLoop(page, cdp, params, samplingInterval);\n } else {\n result = await lapMode.promise;\n lapMode.cancel();\n }\n\n if (collectGc) {\n result = { ...result, gcStats: await collectTracing(cdp, traceEvents) };\n }\n return result;\n } finally {\n await browser.close();\n await server.close();\n }\n}\n\n/** Inject __start/__lap as in-page functions, expose __done for results collection.\n * __start/__lap are pure in-page (zero CDP overhead). First __start() triggers\n * instrument start. __done() stops instruments and collects timing data. */\nasync function setupLapMode(\n page: Page,\n cdp: CDPSession,\n params: BrowserProfileParams,\n samplingInterval: number,\n timeout: number,\n pageErrors: string[],\n): Promise<LapModeHandle> {\n const { heapSample } = params;\n const { promise, resolve, reject } =\n Promise.withResolvers<BrowserProfileResult>();\n let instrumentsStarted = false;\n\n await page.exposeFunction(\"__benchInstrumentStart\", async () => {\n if (instrumentsStarted) return;\n instrumentsStarted = true;\n if (heapSample) {\n await cdp.send(\n \"HeapProfiler.startSampling\",\n heapSamplingParams(samplingInterval),\n );\n }\n });\n\n await page.exposeFunction(\n \"__benchCollect\",\n async (samples: number[], wallTimeMs: number) => {\n let heapProfile: HeapProfile | undefined;\n if (heapSample && instrumentsStarted) {\n const result = await cdp.send(\"HeapProfiler.stopSampling\");\n heapProfile = result.profile as unknown as HeapProfile;\n }\n resolve({ samples, heapProfile, wallTimeMs });\n },\n );\n\n await page.addInitScript(injectLapFunctions);\n\n const timer = setTimeout(() => {\n const lines = [`Timed out after ${timeout}s`];\n if (pageErrors.length) {\n lines.push(\"Page JS errors:\", ...pageErrors.map(e => ` ${e}`));\n } else {\n lines.push(\"Page did not call __done() or define window.__bench\");\n }\n reject(new Error(lines.join(\"\\n\")));\n }, timeout * 1000);\n\n return { promise, cancel: () => clearTimeout(timer) };\n}\n\n/** In-page timing functions injected via addInitScript (zero CDP overhead).\n * __start/__lap collect timestamps, __done delegates to exposed __benchCollect. */\nfunction injectLapFunctions(): void {\n const g = globalThis as any;\n g.__benchSamples = [];\n g.__benchLastTime = 0;\n g.__benchFirstStart = 0;\n\n g.__start = () => {\n const now = performance.now();\n g.__benchLastTime = now;\n if (!g.__benchFirstStart) {\n g.__benchFirstStart = now;\n return g.__benchInstrumentStart();\n }\n };\n\n g.__lap = () => {\n const now = performance.now();\n g.__benchSamples.push(now - g.__benchLastTime);\n g.__benchLastTime = now;\n };\n\n g.__done = () => {\n const wall = g.__benchFirstStart\n ? performance.now() - g.__benchFirstStart\n : 0;\n return g.__benchCollect(g.__benchSamples.slice(), wall);\n };\n}\n\nfunction heapSamplingParams(samplingInterval: number) {\n return {\n samplingInterval,\n includeObjectsCollectedByMajorGC: true,\n includeObjectsCollectedByMinorGC: true,\n };\n}\n\n/** Start CDP GC tracing, returns the event collector array. */\nasync function startGcTracing(cdp: CDPSession): Promise<TraceEvent[]> {\n const events: TraceEvent[] = [];\n cdp.on(\"Tracing.dataCollected\", ({ value }) => {\n for (const e of value) events.push(e as unknown as TraceEvent);\n });\n await cdp.send(\"Tracing.start\", {\n traceConfig: { includedCategories: [\"v8\", \"v8.gc\"] },\n });\n return events;\n}\n\n/** Bench function mode: run window.__bench in a timed iteration loop. */\nasync function runBenchLoop(\n page: Page,\n cdp: CDPSession,\n params: BrowserProfileParams,\n samplingInterval: number,\n): Promise<BrowserProfileResult> {\n const { heapSample } = params;\n const maxTime = params.maxTime ?? 642;\n const maxIter = params.maxIterations ?? Number.MAX_SAFE_INTEGER;\n\n if (heapSample) {\n await cdp.send(\n \"HeapProfiler.startSampling\",\n heapSamplingParams(samplingInterval),\n );\n }\n\n const { samples, totalMs } = await page.evaluate(\n async ({ maxTime, maxIter }) => {\n const bench = (globalThis as any).__bench;\n const samples: number[] = [];\n const startAll = performance.now();\n const deadline = startAll + maxTime;\n for (let i = 0; i < maxIter && performance.now() < deadline; i++) {\n const t0 = performance.now();\n await bench();\n samples.push(performance.now() - t0);\n }\n return { samples, totalMs: performance.now() - startAll };\n },\n { maxTime, maxIter },\n );\n\n let heapProfile: HeapProfile | undefined;\n if (heapSample) {\n const result = await cdp.send(\"HeapProfiler.stopSampling\");\n heapProfile = result.profile as unknown as HeapProfile;\n }\n\n return { samples, heapProfile, wallTimeMs: totalMs };\n}\n\n/** Stop CDP tracing and parse GC events into GcStats. */\nasync function collectTracing(\n cdp: CDPSession,\n traceEvents: TraceEvent[],\n): Promise<GcStats> {\n const complete = new Promise<void>(resolve =>\n cdp.once(\"Tracing.tracingComplete\", () => resolve()),\n );\n await cdp.send(\"Tracing.end\");\n await complete;\n return browserGcStats(traceEvents);\n}\n\n/** Forward Chrome's stderr to the terminal so V8 flag warnings are visible. */\nfunction pipeChromeStderr(server: BrowserServer): void {\n const proc = server.process();\n const pipe = (stream: NodeJS.ReadableStream | null) =>\n stream?.on(\"data\", (chunk: Buffer) => {\n for (const line of chunk.toString().split(\"\\n\")) {\n const text = line.trim();\n if (text) process.stderr.write(`[chrome] ${text}\\n`);\n }\n });\n pipe(proc.stdout);\n pipe(proc.stderr);\n}\n\nexport { profileBrowser as profileBrowserHeap };\n"],"mappings":"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"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
//#region src/runners/GcStats.ts
|
|
2
|
+
/** Parse a single --trace-gc-nvp stderr line */
|
|
3
|
+
function parseGcLine(line) {
|
|
4
|
+
if (!line.includes("pause=")) return void 0;
|
|
5
|
+
const fields = parseNvpFields(line);
|
|
6
|
+
if (!fields.gc) return void 0;
|
|
7
|
+
const int = (k) => Number.parseInt(fields[k] || "0", 10);
|
|
8
|
+
const type = parseGcType(fields.gc);
|
|
9
|
+
const pauseMs = Number.parseFloat(fields.pause || "0");
|
|
10
|
+
const allocated = int("allocated");
|
|
11
|
+
const promoted = int("promoted");
|
|
12
|
+
const survived = int("new_space_survived") || int("survived");
|
|
13
|
+
const startSize = int("start_object_size");
|
|
14
|
+
const endSize = int("end_object_size");
|
|
15
|
+
const collected = startSize > endSize ? startSize - endSize : 0;
|
|
16
|
+
if (Number.isNaN(pauseMs)) return void 0;
|
|
17
|
+
return {
|
|
18
|
+
type,
|
|
19
|
+
pauseMs,
|
|
20
|
+
allocated,
|
|
21
|
+
collected,
|
|
22
|
+
promoted,
|
|
23
|
+
survived
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/** Parse name=value pairs from trace-gc-nvp line */
|
|
27
|
+
function parseNvpFields(line) {
|
|
28
|
+
const fields = {};
|
|
29
|
+
const matches = line.matchAll(/(\w+)=([^\s,]+)/g);
|
|
30
|
+
for (const [, key, value] of matches) fields[key] = value;
|
|
31
|
+
return fields;
|
|
32
|
+
}
|
|
33
|
+
/** Map V8 gc type codes to our types */
|
|
34
|
+
function parseGcType(gcField) {
|
|
35
|
+
if (gcField === "s" || gcField === "scavenge") return "scavenge";
|
|
36
|
+
if (gcField === "mc" || gcField === "ms" || gcField === "mark-compact") return "mark-compact";
|
|
37
|
+
if (gcField === "mmc" || gcField === "minor-mc" || gcField === "minor-ms") return "minor-ms";
|
|
38
|
+
return "unknown";
|
|
39
|
+
}
|
|
40
|
+
/** Aggregate GC events into summary stats */
|
|
41
|
+
function aggregateGcStats(events) {
|
|
42
|
+
let scavenges = 0;
|
|
43
|
+
let markCompacts = 0;
|
|
44
|
+
let gcPauseTime = 0;
|
|
45
|
+
let totalCollected = 0;
|
|
46
|
+
let hasNodeFields = false;
|
|
47
|
+
let totalAllocated = 0;
|
|
48
|
+
let totalPromoted = 0;
|
|
49
|
+
let totalSurvived = 0;
|
|
50
|
+
for (const e of events) {
|
|
51
|
+
if (e.type === "scavenge" || e.type === "minor-ms") scavenges++;
|
|
52
|
+
else if (e.type === "mark-compact") markCompacts++;
|
|
53
|
+
gcPauseTime += e.pauseMs;
|
|
54
|
+
totalCollected += e.collected;
|
|
55
|
+
if (e.allocated != null) {
|
|
56
|
+
hasNodeFields = true;
|
|
57
|
+
totalAllocated += e.allocated;
|
|
58
|
+
totalPromoted += e.promoted ?? 0;
|
|
59
|
+
totalSurvived += e.survived ?? 0;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
scavenges,
|
|
64
|
+
markCompacts,
|
|
65
|
+
totalCollected,
|
|
66
|
+
gcPauseTime,
|
|
67
|
+
...hasNodeFields && {
|
|
68
|
+
totalAllocated,
|
|
69
|
+
totalPromoted,
|
|
70
|
+
totalSurvived
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
//#endregion
|
|
76
|
+
export { parseGcLine as n, aggregateGcStats as t };
|
|
77
|
+
//# sourceMappingURL=GcStats-ByEovUi1.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GcStats-ByEovUi1.mjs","names":[],"sources":["../src/runners/GcStats.ts"],"sourcesContent":["/** GC statistics aggregated from V8 trace events.\n * Node (--trace-gc-nvp) provides all fields.\n * Browser (CDP Tracing) provides counts, collected, and pause only. */\nexport interface GcStats {\n scavenges: number;\n markCompacts: number;\n totalCollected: number; // bytes freed\n gcPauseTime: number; // total pause time (ms)\n totalAllocated?: number; // bytes allocated (Node only)\n totalPromoted?: number; // bytes promoted to old gen (Node only)\n totalSurvived?: number; // bytes survived in young gen (Node only)\n}\n\n/** Single GC event. Node provides all fields; browser provides type, pauseMs, collected. */\nexport interface GcEvent {\n type: \"scavenge\" | \"mark-compact\" | \"minor-ms\" | \"unknown\";\n pauseMs: number;\n collected: number;\n allocated?: number; // Node only\n promoted?: number; // Node only\n survived?: number; // Node only\n}\n\n/** Parse a single --trace-gc-nvp stderr line */\nexport function parseGcLine(line: string): GcEvent | undefined {\n // V8 format: [pid:addr:gen] N ms: pause=X gc=s ... allocated=N promoted=N ...\n if (!line.includes(\"pause=\")) return undefined;\n\n const fields = parseNvpFields(line);\n if (!fields.gc) return undefined;\n\n const int = (k: string) => Number.parseInt(fields[k] || \"0\", 10);\n const type = parseGcType(fields.gc);\n const pauseMs = Number.parseFloat(fields.pause || \"0\");\n const allocated = int(\"allocated\");\n const promoted = int(\"promoted\");\n // V8 uses \"new_space_survived\" not \"survived\"\n const survived = int(\"new_space_survived\") || int(\"survived\");\n // Calculate collected from start/end object size if available\n const startSize = int(\"start_object_size\");\n const endSize = int(\"end_object_size\");\n const collected = startSize > endSize ? startSize - endSize : 0;\n\n if (Number.isNaN(pauseMs)) return undefined;\n\n return { type, pauseMs, allocated, collected, promoted, survived };\n}\n\n/** Parse name=value pairs from trace-gc-nvp line */\nfunction parseNvpFields(line: string): Record<string, string> {\n const fields: Record<string, string> = {};\n // Format: \"key=value, key=value, ...\" or \"key=value key=value\"\n const matches = line.matchAll(/(\\w+)=([^\\s,]+)/g);\n for (const [, key, value] of matches) {\n fields[key] = value;\n }\n return fields;\n}\n\n/** Map V8 gc type codes to our types */\nfunction parseGcType(gcField: string): GcEvent[\"type\"] {\n // V8 uses: s=scavenge, mc=mark-compact, mmc=minor-mc (young gen mark-compact)\n if (gcField === \"s\" || gcField === \"scavenge\") return \"scavenge\";\n if (gcField === \"mc\" || gcField === \"ms\" || gcField === \"mark-compact\")\n return \"mark-compact\";\n if (gcField === \"mmc\" || gcField === \"minor-mc\" || gcField === \"minor-ms\")\n return \"minor-ms\";\n return \"unknown\";\n}\n\n/** Aggregate GC events into summary stats */\nexport function aggregateGcStats(events: GcEvent[]): GcStats {\n let scavenges = 0;\n let markCompacts = 0;\n let gcPauseTime = 0;\n let totalCollected = 0;\n let hasNodeFields = false;\n let totalAllocated = 0;\n let totalPromoted = 0;\n let totalSurvived = 0;\n\n for (const e of events) {\n if (e.type === \"scavenge\" || e.type === \"minor-ms\") scavenges++;\n else if (e.type === \"mark-compact\") markCompacts++;\n gcPauseTime += e.pauseMs;\n totalCollected += e.collected;\n if (e.allocated != null) {\n hasNodeFields = true;\n totalAllocated += e.allocated;\n totalPromoted += e.promoted ?? 0;\n totalSurvived += e.survived ?? 0;\n }\n }\n\n return {\n scavenges,\n markCompacts,\n totalCollected,\n gcPauseTime,\n ...(hasNodeFields && { totalAllocated, totalPromoted, totalSurvived }),\n };\n}\n\n/** @return GcStats with all counters zeroed */\nexport function emptyGcStats(): GcStats {\n return { scavenges: 0, markCompacts: 0, totalCollected: 0, gcPauseTime: 0 };\n}\n"],"mappings":";;AAwBA,SAAgB,YAAY,MAAmC;AAE7D,KAAI,CAAC,KAAK,SAAS,SAAS,CAAE,QAAO;CAErC,MAAM,SAAS,eAAe,KAAK;AACnC,KAAI,CAAC,OAAO,GAAI,QAAO;CAEvB,MAAM,OAAO,MAAc,OAAO,SAAS,OAAO,MAAM,KAAK,GAAG;CAChE,MAAM,OAAO,YAAY,OAAO,GAAG;CACnC,MAAM,UAAU,OAAO,WAAW,OAAO,SAAS,IAAI;CACtD,MAAM,YAAY,IAAI,YAAY;CAClC,MAAM,WAAW,IAAI,WAAW;CAEhC,MAAM,WAAW,IAAI,qBAAqB,IAAI,IAAI,WAAW;CAE7D,MAAM,YAAY,IAAI,oBAAoB;CAC1C,MAAM,UAAU,IAAI,kBAAkB;CACtC,MAAM,YAAY,YAAY,UAAU,YAAY,UAAU;AAE9D,KAAI,OAAO,MAAM,QAAQ,CAAE,QAAO;AAElC,QAAO;EAAE;EAAM;EAAS;EAAW;EAAW;EAAU;EAAU;;;AAIpE,SAAS,eAAe,MAAsC;CAC5D,MAAM,SAAiC,EAAE;CAEzC,MAAM,UAAU,KAAK,SAAS,mBAAmB;AACjD,MAAK,MAAM,GAAG,KAAK,UAAU,QAC3B,QAAO,OAAO;AAEhB,QAAO;;;AAIT,SAAS,YAAY,SAAkC;AAErD,KAAI,YAAY,OAAO,YAAY,WAAY,QAAO;AACtD,KAAI,YAAY,QAAQ,YAAY,QAAQ,YAAY,eACtD,QAAO;AACT,KAAI,YAAY,SAAS,YAAY,cAAc,YAAY,WAC7D,QAAO;AACT,QAAO;;;AAIT,SAAgB,iBAAiB,QAA4B;CAC3D,IAAI,YAAY;CAChB,IAAI,eAAe;CACnB,IAAI,cAAc;CAClB,IAAI,iBAAiB;CACrB,IAAI,gBAAgB;CACpB,IAAI,iBAAiB;CACrB,IAAI,gBAAgB;CACpB,IAAI,gBAAgB;AAEpB,MAAK,MAAM,KAAK,QAAQ;AACtB,MAAI,EAAE,SAAS,cAAc,EAAE,SAAS,WAAY;WAC3C,EAAE,SAAS,eAAgB;AACpC,iBAAe,EAAE;AACjB,oBAAkB,EAAE;AACpB,MAAI,EAAE,aAAa,MAAM;AACvB,mBAAgB;AAChB,qBAAkB,EAAE;AACpB,oBAAiB,EAAE,YAAY;AAC/B,oBAAiB,EAAE,YAAY;;;AAInC,QAAO;EACL;EACA;EACA;EACA;EACA,GAAI,iBAAiB;GAAE;GAAgB;GAAe;GAAe;EACtE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HeapSampler-
|
|
1
|
+
{"version":3,"file":"HeapSampler-B8dtKHn1.mjs","names":[],"sources":["../src/heap-sample/HeapSampler.ts"],"sourcesContent":["import { Session } from \"node:inspector/promises\";\n\nexport interface HeapSampleOptions {\n samplingInterval?: number; // bytes between samples, default 32768\n stackDepth?: number; // max stack frames, default 64\n includeMinorGC?: boolean; // keep objects collected by minor GC, default true\n includeMajorGC?: boolean; // keep objects collected by major GC, default true\n}\n\nexport interface ProfileNode {\n callFrame: {\n functionName: string;\n url: string;\n lineNumber: number;\n columnNumber?: number;\n };\n selfSize: number;\n children?: ProfileNode[];\n}\n\nexport interface HeapProfile {\n head: ProfileNode;\n samples?: number[]; // sample IDs (length = number of samples taken)\n}\n\nconst defaultOptions: Required<HeapSampleOptions> = {\n samplingInterval: 32768,\n stackDepth: 64,\n includeMinorGC: true,\n includeMajorGC: true,\n};\n\n/** Run a function while sampling heap allocations, return profile */\nexport async function withHeapSampling<T>(\n options: HeapSampleOptions,\n fn: () => Promise<T> | T,\n): Promise<{ result: T; profile: HeapProfile }> {\n const opts = { ...defaultOptions, ...options };\n const session = new Session();\n session.connect();\n\n try {\n await startSampling(session, opts);\n const result = await fn();\n const profile = await stopSampling(session);\n return { result, profile };\n } finally {\n session.disconnect();\n }\n}\n\n/** Start heap sampling, falling back if include-collected params aren't supported */\nasync function startSampling(\n session: Session,\n opts: Required<HeapSampleOptions>,\n): Promise<void> {\n const { samplingInterval, stackDepth } = opts;\n const base = { samplingInterval, stackDepth };\n const params = {\n ...base,\n includeObjectsCollectedByMinorGC: opts.includeMinorGC,\n includeObjectsCollectedByMajorGC: opts.includeMajorGC,\n };\n\n try {\n await session.post(\"HeapProfiler.startSampling\", params);\n } catch {\n console.warn(\n \"HeapProfiler: include-collected params not supported, falling back\",\n );\n await session.post(\"HeapProfiler.startSampling\", base);\n }\n}\n\nasync function stopSampling(session: Session): Promise<HeapProfile> {\n const { profile } = await session.post(\"HeapProfiler.stopSampling\");\n return profile as HeapProfile;\n}\n"],"mappings":";;;AAyBA,MAAM,iBAA8C;CAClD,kBAAkB;CAClB,YAAY;CACZ,gBAAgB;CAChB,gBAAgB;CACjB;;AAGD,eAAsB,iBACpB,SACA,IAC8C;CAC9C,MAAM,OAAO;EAAE,GAAG;EAAgB,GAAG;EAAS;CAC9C,MAAM,UAAU,IAAI,SAAS;AAC7B,SAAQ,SAAS;AAEjB,KAAI;AACF,QAAM,cAAc,SAAS,KAAK;AAGlC,SAAO;GAAE,QAFM,MAAM,IAAI;GAER,SADD,MAAM,aAAa,QAAQ;GACjB;WAClB;AACR,UAAQ,YAAY;;;;AAKxB,eAAe,cACb,SACA,MACe;CACf,MAAM,EAAE,kBAAkB,eAAe;CACzC,MAAM,OAAO;EAAE;EAAkB;EAAY;CAC7C,MAAM,SAAS;EACb,GAAG;EACH,kCAAkC,KAAK;EACvC,kCAAkC,KAAK;EACxC;AAED,KAAI;AACF,QAAM,QAAQ,KAAK,8BAA8B,OAAO;SAClD;AACN,UAAQ,KACN,qEACD;AACD,QAAM,QAAQ,KAAK,8BAA8B,KAAK;;;AAI1D,eAAe,aAAa,SAAwC;CAClE,MAAM,EAAE,YAAY,MAAM,QAAQ,KAAK,4BAA4B;AACnE,QAAO"}
|
package/dist/bin/benchforge.mjs
CHANGED
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as MeasuredResults, i as BenchmarkSpec, n as BenchGroup, r as BenchSuite, t as RunnerOptions } from "./BenchRunner-
|
|
1
|
+
import { a as MeasuredResults, i as BenchmarkSpec, n as BenchGroup, r as BenchSuite, t as RunnerOptions } from "./BenchRunner-CSKN9zPy.mjs";
|
|
2
2
|
import { Alignment } from "table";
|
|
3
3
|
import { Argv, InferredOptionTypes } from "yargs";
|
|
4
4
|
import * as node_http0 from "node:http";
|
|
@@ -308,8 +308,9 @@ declare const cliOptions: {
|
|
|
308
308
|
};
|
|
309
309
|
readonly "chrome-args": {
|
|
310
310
|
readonly type: "string";
|
|
311
|
+
readonly array: true;
|
|
311
312
|
readonly requiresArg: true;
|
|
312
|
-
readonly describe: "extra Chromium flags
|
|
313
|
+
readonly describe: "extra Chromium flags";
|
|
313
314
|
};
|
|
314
315
|
};
|
|
315
316
|
/** @return yargs with standard benchmark options */
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as timeSection, B as parseCliArgs, C as adaptiveSection, D as gcStatsSection, E as gcSection, F as generateHtmlReport, G as truncate, H as formatBytes, I as formatDateWithTimezone, J as loadCaseData, K as isStatefulVariant, L as prepareHtmlData, M as formatConvergence, N as filterMatrix, O as optSection, P as parseMatrixFilter, R as exportPerfettoTrace, S as reportMatrixResults, T as cpuSection, U as integer, V as reportResults, W as timeMs, Y as loadCasesModule, _ as runDefaultMatrixBench, a as cliToMatrixOptions, b as gcStatsColumns, c as exportReports, d as matrixToReportGroups, f as parseBenchArgs, g as runDefaultBench, h as runBenchmarks, i as benchExports, j as totalTimeSection, k as runsSection, l as hasField, m as reportOptStatus, n as getBaselineVersion, o as defaultMatrixReport, p as printHeapReports, q as runMatrix, r as getCurrentGitVersion, s as defaultReport, t as formatGitVersion, u as matrixBenchExports, v as runMatrixSuite, w as buildGenericSections, x as heapTotalColumn, y as gcPauseColumn, z as defaultCliArgs } from "./src-
|
|
1
|
+
import { A as timeSection, B as parseCliArgs, C as adaptiveSection, D as gcStatsSection, E as gcSection, F as generateHtmlReport, G as truncate, H as formatBytes, I as formatDateWithTimezone, J as loadCaseData, K as isStatefulVariant, L as prepareHtmlData, M as formatConvergence, N as filterMatrix, O as optSection, P as parseMatrixFilter, R as exportPerfettoTrace, S as reportMatrixResults, T as cpuSection, U as integer, V as reportResults, W as timeMs, Y as loadCasesModule, _ as runDefaultMatrixBench, a as cliToMatrixOptions, b as gcStatsColumns, c as exportReports, d as matrixToReportGroups, f as parseBenchArgs, g as runDefaultBench, h as runBenchmarks, i as benchExports, j as totalTimeSection, k as runsSection, l as hasField, m as reportOptStatus, n as getBaselineVersion, o as defaultMatrixReport, p as printHeapReports, q as runMatrix, r as getCurrentGitVersion, s as defaultReport, t as formatGitVersion, u as matrixBenchExports, v as runMatrixSuite, w as buildGenericSections, x as heapTotalColumn, y as gcPauseColumn, z as defaultCliArgs } from "./src-Dt_T-s_f.mjs";
|
|
2
2
|
import { o as average } from "./TimingUtils-ClclVQ7E.mjs";
|
|
3
3
|
|
|
4
4
|
export { adaptiveSection, average, benchExports, buildGenericSections, cliToMatrixOptions, cpuSection, defaultCliArgs, defaultMatrixReport, defaultReport, exportPerfettoTrace, exportReports, filterMatrix, formatBytes, formatConvergence, formatDateWithTimezone, formatGitVersion, gcPauseColumn, gcSection, gcStatsColumns, gcStatsSection, generateHtmlReport, getBaselineVersion, getCurrentGitVersion, hasField, heapTotalColumn, integer, isStatefulVariant, loadCaseData, loadCasesModule, matrixBenchExports, matrixToReportGroups, optSection, parseBenchArgs, parseCliArgs, parseMatrixFilter, prepareHtmlData, printHeapReports, reportMatrixResults, reportOptStatus, reportResults, runBenchmarks, runDefaultBench, runDefaultMatrixBench, runMatrix, runMatrixSuite, runsSection, timeMs, timeSection, totalTimeSection, truncate };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as MeasuredResults, i as BenchmarkSpec, o as HeapProfile, t as RunnerOptions } from "../BenchRunner-
|
|
1
|
+
import { a as MeasuredResults, i as BenchmarkSpec, o as HeapProfile, t as RunnerOptions } from "../BenchRunner-CSKN9zPy.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/runners/CreateRunner.d.ts
|
|
4
4
|
type KnownRunner = "basic";
|
|
@@ -18,7 +18,7 @@ process.on("message", async (message) => {
|
|
|
18
18
|
logTiming("Runner created in", getElapsed(start));
|
|
19
19
|
const benchStart = getPerfNow();
|
|
20
20
|
if (message.options.heapSample) {
|
|
21
|
-
const { withHeapSampling } = await import("../HeapSampler-
|
|
21
|
+
const { withHeapSampling } = await import("../HeapSampler-B8dtKHn1.mjs");
|
|
22
22
|
const { result: results, profile: heapProfile } = await withHeapSampling({
|
|
23
23
|
samplingInterval: message.options.heapInterval,
|
|
24
24
|
stackDepth: message.options.heapDepth
|