Leave timing and cache placement variables out of the frontend cache key (#2211)

This commit is contained in:
Chris Tate
2026-10-25 07:25:47 -05:00
committed by GitHub
2 changed files with 46 additions and 7 deletions
+26 -1
View File
@@ -1,7 +1,7 @@
import { mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { afterEach, expect, test } from "vitest";
import { afterEach, expect, test, vi } from "vitest";
import {
LINUX_ARM64_GNU_TARGET,
nativeCodegenTarget,
@@ -23,6 +23,7 @@ function text(input: ReturnType<ReturnType<typeof fixture>["prepare"]>) {
const scratch: string[] = [];
afterEach(() => {
vi.unstubAllEnvs();
for (const path of scratch.splice(0)) rmSync(path, { recursive: true, force: true });
});
@@ -197,6 +198,30 @@ test("structurally invalid cached features cause a rebuild even with a valid dig
expect(f.loads()).toBe(2);
});
test("timing, cache placement and emission worker variables keep the frontend output", () => {
for (const name of [
"SCRIPTC_CACHE_DIR",
"SCRIPTC_CACHE_MAX_MB",
"SCRIPTC_EMIT_WORKERS",
"SCRIPTC_EMIT_WORKER_FUNCTIONS",
"SCRIPTC_TIMING",
"SCRIPTC_TEST_FRONTEND_KEY",
])
vi.stubEnv(name, undefined);
const f = fixture();
expect(f.prepare().ok).toBe(true);
vi.stubEnv("SCRIPTC_CACHE_DIR", f.cache.root);
vi.stubEnv("SCRIPTC_CACHE_MAX_MB", "8192");
vi.stubEnv("SCRIPTC_EMIT_WORKERS", "1");
vi.stubEnv("SCRIPTC_EMIT_WORKER_FUNCTIONS", "100");
vi.stubEnv("SCRIPTC_TIMING", "0");
expect(f.prepare().ok).toBe(true);
expect(f.loads()).toBe(1);
vi.stubEnv("SCRIPTC_TEST_FRONTEND_KEY", "1");
expect(f.prepare().ok).toBe(true);
expect(f.loads()).toBe(2);
});
test("serialized IR travels as bounded parts through the frontend cache", () => {
const f = fixture();
const first = f.prepare({ emitIr: true });
+20 -6
View File
@@ -211,6 +211,24 @@ function implementationIdentity(toolchain: NativeToolchain): string {
);
}
/** SCRIPTC_* variables that report on a build, place its cache or set
* backend emission parallelism. The frontend's output does not depend on
* them, so they are left out of its cache key. */
const FRONTEND_INDEPENDENT_VARIABLES = new Set([
"SCRIPTC_CACHE_DIR",
"SCRIPTC_CACHE_MAX_MB",
"SCRIPTC_EMIT_WORKERS",
"SCRIPTC_EMIT_WORKER_FUNCTIONS",
"SCRIPTC_TIMING",
]);
/** The SCRIPTC_* variables a frontend cache entry depends on, sorted by name. */
function frontendEnvironment(): [string, string | undefined][] {
return Object.entries(process.env)
.filter(([name]) => name.startsWith("SCRIPTC_") && !FRONTEND_INDEPENDENT_VARIABLES.has(name))
.sort(([a], [b]) => a.localeCompare(b));
}
function validFeatures(value: unknown): value is NativeLinkFeatures {
if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
const features = value as Record<string, unknown>;
@@ -363,9 +381,7 @@ export function prepareNativeExecutable(
implementation: implementationIdentity(toolchain),
target: toolchain.target.name,
declarations: toolchain.declarationsRoot ?? null,
environment: Object.entries(process.env)
.filter(([name]) => name.startsWith("SCRIPTC_"))
.sort(([a], [b]) => a.localeCompare(b)),
environment: frontendEnvironment(),
}),
);
const cached = readFrontendCache(cache, key, exclusions);
@@ -493,9 +509,7 @@ export function prepareNativeLibrary(
implementation: implementationIdentity(toolchain),
target: toolchain.target.name,
declarations: toolchain.declarationsRoot ?? null,
environment: Object.entries(process.env)
.filter(([name]) => name.startsWith("SCRIPTC_"))
.sort(([a], [b]) => a.localeCompare(b)),
environment: frontendEnvironment(),
}),
);
const cached = readFrontendCache(cache, key, exclusions);