Files
alexion 6081e3e325 chore(vendor): import pi 1.3.0
Imported as a linear vendor commit so forge rebases do not replay the upstream root tree.

git-subtree-dir: third_party/pi

git-subtree-split: 71023aec1546d6d677a65669c5665c0927ce0dd0
2026-10-15 17:58:48 -04:00

211 lines
5.4 KiB
TypeScript

import { spawnSync } from "node:child_process";
import { writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { fileURLToPath } from "node:url";
type Mode = "tracker";
type Scenario =
| "import"
| "committed-read"
| "draft-read"
| "sparse"
| "queue"
| "sort"
| "dense"
| "unshift"
| "watch-authority-control"
| "watch-live-borrowed"
| "watch-acquire-shared"
| "watch-acquire-detached"
| "watch-acquire-staggered"
| "watch-lag"
| "watch-catch-up"
| "watch-catch-up-coalesced"
| "watch-live-immutable";
type Result = {
mode: Mode;
scenario: Scenario;
size: number;
trial: number;
queueOperations: number;
watchProfile: string | null;
watchCount: number;
watchUpdates: number;
queuedBatchReferences: number;
importMs: number;
mutateMs: number;
prepareMs: number;
serializeMs: number;
adoptMs: number;
acquireMs: number;
enqueueMs: number;
deliveryMs: number;
scenarioWorkMs: number;
opBytes: number;
operationCount: number;
checksum: number;
readyMiB: number;
sampledAcquireMiB: number;
sampledTransientMiB: number;
retainedMiB: number;
retainedOverReadyMiB: number;
postAcquireRetainedMiB: number;
postLagRetainedMiB: number;
postDeliveryRetainedMiB: number;
releasedRetainedMiB: number;
maxRssMiB: number;
};
type Failure = { mode: Mode; scenario: Scenario; trial: number; stderr: string };
const ordinaryScenarios: readonly Scenario[] = [
"import",
"committed-read",
"draft-read",
"sparse",
"queue",
"sort",
"dense",
"unshift",
];
const watchScenarios: readonly Scenario[] = [
"watch-authority-control",
"watch-live-borrowed",
"watch-acquire-shared",
"watch-acquire-detached",
"watch-acquire-staggered",
"watch-lag",
"watch-catch-up",
"watch-catch-up-coalesced",
"watch-live-immutable",
];
const modes: readonly Mode[] = ["tracker"];
const quick = process.argv.includes("--quick");
const watchOnly = process.argv.includes("--watch-only");
const ordinaryOnly = process.argv.includes("--ordinary-only");
if (watchOnly && ordinaryOnly) throw new Error("Choose at most one scenario filter");
const scenarios = watchOnly
? watchScenarios
: ordinaryOnly
? ordinaryScenarios
: [...ordinaryScenarios, ...watchScenarios];
const size = quick ? 10_000 : 100_000;
const trials = quick ? 1 : 3;
const watchCount = quick ? 4 : 8;
const watchUpdates = quick ? 20 : 100;
const root = fileURLToPath(new URL("../../../..", import.meta.url));
const worker = fileURLToPath(new URL("./benchmark.worker.ts", import.meta.url));
const results: Result[] = [];
const failures: Failure[] = [];
for (let trial = 0; trial < trials; trial++) {
for (const scenario of scenarios) {
for (const mode of modes) {
const child = spawnSync(
process.execPath,
[
"--expose-gc",
"--max-old-space-size=4096",
worker,
mode,
scenario,
String(size),
String(trial),
String(watchCount),
String(watchUpdates),
],
{ cwd: root, encoding: "utf8", timeout: 300_000, maxBuffer: 10 * 1024 * 1024 },
);
if (child.status !== 0) {
const failure = { mode, scenario, trial, stderr: child.stderr } satisfies Failure;
failures.push(failure);
console.log(JSON.stringify(failure));
} else {
const result = JSON.parse(child.stdout) as Result;
results.push(result);
console.log(JSON.stringify(result));
}
}
}
}
const average = (values: readonly number[]): number | null =>
values.length === 0 ? null : values.reduce((total, value) => total + value, 0) / values.length;
const median = (values: readonly number[]): number | null => {
if (values.length === 0) return null;
const ordered = [...values].sort((left, right) => left - right);
return ordered[Math.floor(ordered.length / 2)]!;
};
const range = (values: readonly number[]): readonly [number, number] | null =>
values.length === 0 ? null : [Math.min(...values), Math.max(...values)];
const metricNames = [
"importMs",
"mutateMs",
"prepareMs",
"serializeMs",
"adoptMs",
"acquireMs",
"enqueueMs",
"deliveryMs",
"scenarioWorkMs",
"opBytes",
"operationCount",
"readyMiB",
"sampledAcquireMiB",
"sampledTransientMiB",
"retainedMiB",
"retainedOverReadyMiB",
"postAcquireRetainedMiB",
"postLagRetainedMiB",
"postDeliveryRetainedMiB",
"releasedRetainedMiB",
"maxRssMiB",
] as const satisfies readonly (keyof Result)[];
const summary = scenarios.flatMap((scenario) =>
modes.map((mode) => {
const selected = results.filter((result) => result.mode === mode && result.scenario === scenario);
const averages: Record<string, number | null> = {};
const medians: Record<string, number | null> = {};
const ranges: Record<string, readonly [number, number] | null> = {};
for (const metric of metricNames) {
const values = selected.map((result) => result[metric]);
averages[metric] = average(values);
medians[metric] = median(values);
ranges[metric] = range(values);
}
return {
mode,
scenario,
watchProfile: selected[0]?.watchProfile ?? null,
watchCount: selected[0]?.watchCount ?? 0,
watchUpdates: selected[0]?.watchUpdates ?? 0,
averages,
medians,
ranges,
};
}),
);
const output = join(tmpdir(), "chord-delta-benchmark.json");
writeFileSync(
output,
JSON.stringify(
{ node: process.version, size, trials, watchCount, watchUpdates, results, failures, summary },
null,
2,
),
);
console.log(
JSON.stringify({
output,
node: process.version,
size,
trials,
watchCount,
watchUpdates,
failures: failures.length,
summary,
}),
);