mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-22 05:59:31 +08:00
60 lines
3.0 KiB
JavaScript
60 lines
3.0 KiB
JavaScript
/* Isolate whole-module propagation from frontend/native toolchain timings.
|
||
* Caller-first and parent-first chains expose depth-dependent rescanning;
|
||
* every measured run verifies the complete analysis result. */
|
||
import assert from "node:assert/strict";
|
||
import { parseArgs } from "node:util";
|
||
import { computeMayThrow } from "../packages/compiler/dist/backend/may-throw.js";
|
||
import { computeTraced } from "../packages/compiler/dist/backend/cycle-analysis.js";
|
||
import { F64, VOID } from "../packages/compiler/dist/ir/ir.js";
|
||
|
||
const { values } = parseArgs({ options: {
|
||
iterations: { type: "string", default: "5" },
|
||
sizes: { type: "string", default: "500,2000,4000,8000" },
|
||
} });
|
||
const iterations = Number(values.iterations);
|
||
const sizes = values.sizes.split(",").map(Number);
|
||
assert.ok(Number.isInteger(iterations) && iterations >= 1 && iterations <= 100, "--iterations must be an integer between 1 and 100");
|
||
assert.ok(sizes.length >= 1 && sizes.length <= 16 && sizes.every((n) => Number.isInteger(n) && n >= 1 && n <= 100_000), "--sizes must contain 1–16 integers between 1 and 100000");
|
||
const loc = { file: "chain.ts", start: 0, end: 1 };
|
||
const value = { kind: "numLit", value: 1, type: F64, loc };
|
||
const results = [];
|
||
for (const size of sizes) {
|
||
const functions = Array.from({ length: size }, (_, i) => ({
|
||
name: `fn${i}`, params: [], locals: [], returnType: VOID, loc,
|
||
body: [i === size - 1 ? { kind: "throw", value, loc }
|
||
: { kind: "exprStmt", expr: { kind: "call", callee: `fn${i + 1}`, args: [], type: VOID, loc }, loc }],
|
||
}));
|
||
const mod = { irVersion: 13, sourceFile: loc.file, entry: "fn0", functions };
|
||
const records = Array.from({ length: size }, (_, i) => ({
|
||
id: `r${i}`, fields: [{ name: "next", type: i === size - 1 ? F64 : { kind: "record", shapeId: `r${i + 1}` } }],
|
||
}));
|
||
const graph = { ...mod, records };
|
||
const workloads = [
|
||
{ name: "may-throw", run: () => computeMayThrow(mod), check: (answer) => {
|
||
assert.equal(answer.indirect, false);
|
||
assert.equal(answer.fns.size, size);
|
||
for (const fn of functions) assert.ok(answer.fns.has(fn.name), fn.name);
|
||
} },
|
||
{ name: "cycle-analysis", run: () => computeTraced(graph), check: (answer) => {
|
||
assert.equal(answer.shapes.size, 0);
|
||
assert.equal(answer.unions.size, 0);
|
||
} },
|
||
];
|
||
for (const { name, run, check } of workloads) {
|
||
const samples = [];
|
||
for (let i = -2; i < iterations; i++) {
|
||
const start = performance.now();
|
||
const answer = run();
|
||
const ms = performance.now() - start;
|
||
check(answer);
|
||
if (i >= 0) samples.push(ms);
|
||
}
|
||
const sorted = [...samples].sort((a, b) => a - b);
|
||
const middle = Math.floor(sorted.length / 2);
|
||
const median = sorted.length % 2 ? sorted[middle] : (sorted[middle - 1] + sorted[middle]) / 2;
|
||
results.push({ analysis: name, nodes: size, median_ms: median, samples_ms: samples });
|
||
process.stderr.write(`${name} ${size}: ${median.toFixed(2)} ms\n`);
|
||
}
|
||
}
|
||
console.log(JSON.stringify({ node: process.version, platform: process.platform, arch: process.arch, iterations, results }, null, 2));
|