mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-22 05:59:31 +08:00
tests/harness/effect-costs.json and effect4-costs.json were recorded on 2026-10-01 and give the fixtures' relative cost for balancedShardSelect across the 16 Effect shards of each flavor. Against the fixture times of three green main runs (38851650148, 38851726594, 38852266290), the old tables put 1,171 s of plain and 1,295 s of sanitized fixture time on the longest shard, against a mean of 1,027 and 1,111 s. scripts/ci-effect-costs.mjs refreshes both tables from Effect job logs: each fixture's plain and sanitized medians, summed in seconds, as the tables recorded before. Fixtures without a measurement keep their value, and fixtures that no longer exist are removed. With the refreshed tables, the longest shard of the same measurements carries 1,082 s (plain) and 1,144 s (sanitized).
55 lines
2.5 KiB
JavaScript
55 lines
2.5 KiB
JavaScript
#!/usr/bin/env node
|
|
// Refreshes tests/harness/effect-costs.json and tests/harness/effect4-costs.json from the logs of the Effect shards
|
|
// of green CI runs on main.
|
|
//
|
|
// Usage: node scripts/ci-effect-costs.mjs <job log> ...
|
|
//
|
|
// Each log is a downloaded "test (Linux, plain|san, Effect i/n)" job log. vitest prints every fixture test with its
|
|
// duration; for each fixture this takes the median over the logs of each flavor and stores the plain and sanitized
|
|
// medians' sum in seconds. Both flavors shard with the same table. Fixtures without a measurement in both flavors
|
|
// keep their current value; fixtures that no longer exist are removed.
|
|
import { globSync, readFileSync, writeFileSync } from "node:fs";
|
|
import { basename } from "node:path";
|
|
|
|
const suites = {
|
|
effect: {
|
|
table: new URL("../tests/harness/effect-costs.json", import.meta.url),
|
|
fixtures: new URL("../tests/fixtures/effect/", import.meta.url),
|
|
},
|
|
effect4: {
|
|
table: new URL("../tests/harness/effect4-costs.json", import.meta.url),
|
|
fixtures: new URL("../tests/fixtures/effect4/", import.meta.url),
|
|
},
|
|
};
|
|
const samples = { effect: {}, effect4: {} };
|
|
for (const log of process.argv.slice(2)) {
|
|
// Logs keep the terminal color codes (ESC [ ... m); drop them before matching.
|
|
const text = readFileSync(log, "utf8")
|
|
.replaceAll(String.fromCharCode(27), "")
|
|
.replace(/\[[0-9;]*m/g, "");
|
|
const flavor = /SCRIPTC_SAN: 1\b/.test(text) ? "san" : "plain";
|
|
for (const m of text.matchAll(
|
|
/✓ published Effect (?:4 )?\S*\/(effect4?)\/([^/\s]+\.ts) matches Node statically {2}(\d+)ms$/gm,
|
|
))
|
|
(samples[m[1]][m[2]] ??= { plain: [], san: [] })[flavor].push(Number(m[3]));
|
|
}
|
|
const median = (values) => [...values].sort((a, b) => a - b)[Math.floor(values.length / 2)];
|
|
let updated = 0;
|
|
for (const [suite, { table: path, fixtures }] of Object.entries(suites)) {
|
|
const table = JSON.parse(readFileSync(path, "utf8"));
|
|
const names = globSync("*.ts", { cwd: fixtures })
|
|
.filter((file) => !file.endsWith(".d.ts"))
|
|
.map((file) => basename(file))
|
|
.sort();
|
|
const next = {};
|
|
for (const name of names) {
|
|
const measured = samples[suite][name];
|
|
if (measured?.plain.length && measured.san.length) {
|
|
next[name] = Math.max(1, Math.round((median(measured.plain) + median(measured.san)) / 1000));
|
|
updated++;
|
|
} else if (table[name] !== undefined) next[name] = table[name];
|
|
}
|
|
writeFileSync(path, JSON.stringify(next, null, 2) + "\n");
|
|
}
|
|
console.log(`updated ${updated} fixture costs`);
|