mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-11-01 07:33:12 +08:00
The test compiles the three npm package twice, dev and release, and both cases shared one 600s budget through test.each. Release compiles the whole library into one LLVM module that scriptc-llvm-codegen optimizes and codegens in a single process on a single core: 426s of the 477s total run in the native-archive phase alone. Across sandbox lanes release measured 331, 335, 339, 345, 348, 350, 358, 428, 450, 511, 521 and 581s, so whole- box speed varies about 1.7x and the slowest lanes sat within 20s of the budget; the sanitized dev case hit 600s twice. There is no regression, the work is fixed and single-threaded. Generate the two cases in a loop so each gets its own timeout: 1200_000ms for release and for dev under SCRIPTC_SAN, and the unchanged 600_000ms else. Test names are byte-identical to the .each %s expansion, so skipUnownedTest keeps assigning each case to the same shard. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
98 lines
4.0 KiB
TypeScript
98 lines
4.0 KiB
TypeScript
import { spawnSync } from "node:child_process";
|
|
import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
|
import { join } from "node:path";
|
|
import { compileLibrary } from "@scriptc/compiler";
|
|
import { beforeEach, describe, expect, test } from "vitest";
|
|
import { skipUnownedTest } from "./shard.js";
|
|
|
|
const fixture = join(import.meta.dirname, "../library-mode/wasm");
|
|
const hasClang = spawnSync("clang", ["--version"]).status === 0;
|
|
// Release compiles the whole three.js library into one LLVM module that a
|
|
// single process optimizes and codegens on one core, which takes 5-10
|
|
// minutes; sanitized dev builds are slower still. Lanes measured 331-581s for
|
|
// release against the old 600s budget, so both get 1_200_000ms. The plain dev
|
|
// case runs at about a fifth of release and keeps 600_000ms.
|
|
function timeoutFor(optimization: "dev" | "release"): number {
|
|
return optimization === "release" || process.env["SCRIPTC_SAN"] === "1" ? 1_200_000 : 600_000;
|
|
}
|
|
// The two optimizations take similar time (about 10 minutes each under ASan):
|
|
// SCRIPTC_TEST_SHARD runs them on different shards (tests/harness/shard.ts).
|
|
// skipUnownedTest partitions a describe block's tests.
|
|
describe("three.js native library", () => {
|
|
beforeEach((context) => skipUnownedTest(context, {}));
|
|
for (const optimization of ["dev", "release"] as const) {
|
|
test.skipIf(!hasClang)(
|
|
`three.js sends animated geometry, materials and resource lifecycle to a native host in ${optimization}`,
|
|
async () => {
|
|
const directory = await mkdtemp("/tmp/scriptc-three-library-");
|
|
const sanitize = process.env["SCRIPTC_SAN"] === "1";
|
|
try {
|
|
const profile = JSON.parse(await readFile(join(fixture, "three.json"), "utf8"));
|
|
const profilePath = join(directory, "profile.json");
|
|
await writeFile(
|
|
profilePath,
|
|
JSON.stringify({
|
|
...profile,
|
|
name: "three-native-embedding",
|
|
entry: join(fixture, "three.mjs"),
|
|
optimization,
|
|
}),
|
|
);
|
|
const built = await compileLibrary({ profilePath, outDir: directory, sanitize });
|
|
if (!built.ok)
|
|
throw new Error(
|
|
built.diagnostics
|
|
.map((diagnostic) => `${diagnostic.code}: ${diagnostic.message}`)
|
|
.join("\n"),
|
|
);
|
|
const binary = join(directory, "host");
|
|
const linked = spawnSync(
|
|
"clang",
|
|
[
|
|
"-std=c11",
|
|
...(sanitize ? ["-fsanitize=address,undefined"] : []),
|
|
join(fixture, "three-native.c"),
|
|
built.archivePath,
|
|
"-lm",
|
|
"-o",
|
|
binary,
|
|
],
|
|
{ encoding: "utf8" },
|
|
);
|
|
expect(linked.status, linked.stderr).toBe(0);
|
|
const actual = spawnSync(binary, [], { encoding: "utf8", timeout: 30_000 });
|
|
expect(actual.status, actual.stderr).toBe(0);
|
|
const reference = spawnSync(
|
|
process.execPath,
|
|
[
|
|
"--no-warnings",
|
|
"--input-type=module",
|
|
"-e",
|
|
`
|
|
const events=[];
|
|
for (const name of ["vertex","surface","resource"]) globalThis[name]=(...values)=>events.push([name,...values.map(value=>Number(value.toFixed(9)))]);
|
|
const {frame,dispose}=await import(${JSON.stringify(join(fixture, "three.mjs"))});
|
|
for (const time of [0,123,2000]) frame(time,1.5);
|
|
dispose();
|
|
console.log(JSON.stringify(events));
|
|
`,
|
|
],
|
|
{ encoding: "utf8" },
|
|
);
|
|
expect(reference.status, reference.stderr).toBe(0);
|
|
const events = JSON.parse(reference.stdout);
|
|
expect(
|
|
actual.stdout
|
|
.trim()
|
|
.split("\n")
|
|
.map((line) => JSON.parse(line)),
|
|
).toEqual([...events, ...events]);
|
|
} finally {
|
|
await rm(directory, { recursive: true, force: true });
|
|
}
|
|
},
|
|
timeoutFor(optimization),
|
|
);
|
|
}
|
|
});
|