Merge main

This commit is contained in:
Chris Tate
2026-10-25 18:30:23 -05:00
169 changed files with 8015 additions and 494 deletions
+20 -4
View File
@@ -16,13 +16,16 @@
* [--seeds 1,2,3] [--jobs 8] [--entry <file.ts>]... [--out <dir>]
* [--fail-on names|content]
*
* --stride and --offset sample the top-level corpus programs by number, or by
* a hash of the name of a program without one.
*
* Needs a built compiler (pnpm build). Writes <out>/results.json and prints
* a ranking of fields by the programs whose IR they change. With --fail-on,
* it exits with status 1 when some program's IR differs between orders:
* in any way (names), or beyond names and ids (content). */
import { spawn } from "node:child_process";
import { createHash } from "node:crypto";
import { mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
import { mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
import { cpus, tmpdir } from "node:os";
import { basename, join, resolve } from "node:path";
import { fileURLToPath, pathToFileURL } from "node:url";
@@ -306,12 +309,25 @@ if (values["fail-on"] !== undefined && !["names", "content"].includes(values["fa
const out = resolve(values.out);
mkdirSync(out, { recursive: true });
const seeds = values.seeds.split(",").filter(Boolean);
/** A top-level corpus program's sampling key: its number, or, for a program
* named without one, a stable hash of its name (FNV-1a). */
const programKey = (name) =>
/^\d+-/.test(name)
? Number.parseInt(name, 10)
: [...name].reduce((h, c) => Math.imul(h ^ c.charCodeAt(0), 16777619) >>> 0, 2166136261);
/** Numbered programs by number, then the named ones by name. */
const programOrder = (a, b) =>
/^\d+-/.test(a) !== /^\d+-/.test(b)
? /^\d+-/.test(a)
? -1
: 1
: programKey(a) - programKey(b) || (a < b ? -1 : a > b ? 1 : 0);
const corpus = join(root, "tests/corpus");
const programs = [
...readdirSync(corpus)
.filter((name) => /^\d+-.*\.ts$/.test(name))
.filter((name) => Number.parseInt(name, 10) % Number(values.stride) === Number(values.offset))
.sort((a, b) => Number.parseInt(a, 10) - Number.parseInt(b, 10))
.filter((name) => /^[\w-]+\.ts$/.test(name) && statSync(join(corpus, name)).isFile())
.filter((name) => programKey(name) % Number(values.stride) === Number(values.offset))
.sort(programOrder)
.slice(0, Number(values.limit))
.map((name) => join(corpus, name)),
...values.entry.map((entry) => resolve(entry)),
+22 -7
View File
@@ -7,8 +7,9 @@
* Builds an instrumented native compiler for this Linux host, runs it on the
* training builds below, and merges the raw profiles it writes into one
* sparse indexed profile. The training builds are tsc-ts (a cold `speed`
* build, then a rebuild after an edit), every seventh corpus program at the
* default optimization and a further slice in `dev`, and the runtime
* build, then a rebuild after an edit), every seventh top-level corpus
* program (by number, or by a hash of the name of a program without one) at
* the default optimization and a further slice in `dev`, and the runtime
* benchmark workloads. Run it on a quiet Linux x64 host after changes that
* move much compiler code; a stale profile only loses part of its gain. A
* refresh takes about 11 minutes on 16 cores.
@@ -126,16 +127,30 @@ async function pool(tasks) {
return passed;
}
const programNumber = (name) => Number.parseInt(name, 10);
/** A top-level corpus program's sampling key: its number, or, for a program
* named without one, a stable hash of its name (FNV-1a). */
const programKey = (name) =>
/^\d+-/.test(name)
? Number.parseInt(name, 10)
: [...name].reduce((h, c) => Math.imul(h ^ c.charCodeAt(0), 16777619) >>> 0, 2166136261);
/** Numbered programs by number, then the named ones by name. */
const programOrder = (a, b) =>
/^\d+-/.test(a) !== /^\d+-/.test(b)
? /^\d+-/.test(a)
? -1
: 1
: programKey(a) - programKey(b) || (a < b ? -1 : a > b ? 1 : 0);
const corpus = readdirSync(join(root, "tests/corpus"))
.filter((name) => /^\d+-.*\.ts$/.test(name))
.sort((a, b) => programNumber(a) - programNumber(b));
.filter(
(name) => /^[\w-]+\.ts$/.test(name) && statSync(join(root, "tests/corpus", name)).isFile(),
)
.sort(programOrder);
const training = [
...corpus
.filter((name) => programNumber(name) % 7 === 0)
.filter((name) => programKey(name) % 7 === 0)
.map((name) => ({ file: join(root, "tests/corpus", name), optimization: "release" })),
...corpus
.filter((name) => programNumber(name) % 14 === 7)
.filter((name) => programKey(name) % 14 === 7)
.map((name) => ({ file: join(root, "tests/corpus", name), optimization: "dev" })),
...readdirSync(join(root, "benchmarks/runtime/workloads"))
.filter((name) => name.endsWith(".ts"))