From a7241978f6f96fc1b4a540932d7ef045d3e67cc2 Mon Sep 17 00:00:00 2001 From: robobun <117481402+robobun@users.noreply.github.com> Date: Thu, 23 Jul 2026 10:03:12 +0000 Subject: [PATCH 1/2] test: speed up 32492.test.ts and assert on bundle output Reduce rounds from 16 to 4 on debug/ASAN builds (96 spawns instead of 384) and bundle to stdout instead of --outdir so the test can assert on the actual bundle contents rather than only on exit code and wall time. Since #34009 lowered the idle-futex timeout from 10s to 100ms, a skipped shutdown wake now costs at most ~100ms, which is below the 24-way scheduling noise floor. The 16-round version no longer distinguishes a reverted Event::wake fix either, so cutting rounds does not weaken the timing guard; it remains a coarse check for multi-second stalls plus a concurrent-build smoke test with real output assertions. --- test/regression/issue/32492.test.ts | 45 +++++++++++++++-------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/test/regression/issue/32492.test.ts b/test/regression/issue/32492.test.ts index 7177e787b694..11537a5f2c1f 100644 --- a/test/regression/issue/32492.test.ts +++ b/test/regression/issue/32492.test.ts @@ -1,6 +1,6 @@ // https://github.com/oven-sh/bun/issues/32492 import { expect, test } from "bun:test"; -import { bunEnv, bunExe, tempDir } from "harness"; +import { bunEnv, bunExe, isASAN, isDebug, tempDir } from "harness"; test("concurrent bun build does not stall on worker-pool shutdown", async () => { const N_MODULES = 40; @@ -24,41 +24,42 @@ test("concurrent bun build does not stall on worker-pool shutdown", async () => const root = String(dir); const CONCURRENCY = 24; - const ROUNDS = 16; - // The regression is a fixed 10s idle-futex timeout, so a stalled build always - // exceeds 10s regardless of machine speed. A healthy build is well under a - // second; keep the threshold high so 24-way oversubscription on a slow ASAN - // shard can't trip it, while staying comfortably below the 10s floor. + // #32492 was a ~10s stall at pool shutdown when the idle-futex timeout was + // 10s. #34009 lowered that timeout to 100ms, so a skipped shutdown wake now + // costs at most ~100ms and is indistinguishable from 24-way scheduling noise. + // This test therefore acts as a coarse guard (no multi-second shutdown stall) + // plus a concurrent-build smoke test. 4 rounds x 24 builds is enough for that + // on debug/ASAN; release keeps 16 because it's cheap. + const ROUNDS = isASAN || isDebug ? 4 : 16; const STALL_MS = 9000; - const buildOnce = async (round: number, i: number) => { + const buildOnce = async (i: number) => { const entry = entries[i % entries.length]; const started = Date.now(); + // Bundle to stdout (no --outdir) so we can assert on the bundle contents + // and skip per-build output directories. The regression is in thread pool + // shutdown, which runs identically regardless of the output sink. await using proc = Bun.spawn({ - cmd: [ - bunExe(), - "build", - "--target=browser", - "--sourcemap=external", - "--packages=external", - "--outdir", - `${root}/out/d${round}_${i}`, - `./src/${entry}-entry.ts`, - ], + cmd: [bunExe(), "build", "--target=browser", "--packages=external", `./src/${entry}-entry.ts`], env: bunEnv, cwd: root, stdout: "pipe", stderr: "pipe", }); const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]); - return { ms: Date.now() - started, exitCode, stdout, stderr }; + return { entry, ms: Date.now() - started, exitCode, stdout, stderr }; }; for (let round = 0; round < ROUNDS; round++) { - const results = await Promise.all(Array.from({ length: CONCURRENCY }, (_, i) => buildOnce(round, i))); - const failed = results.find(r => r.exitCode !== 0); - if (failed) { - throw new Error(`bun build exited with ${failed.exitCode}\nstdout:\n${failed.stdout}\nstderr:\n${failed.stderr}`); + const results = await Promise.all(Array.from({ length: CONCURRENCY }, (_, i) => buildOnce(i))); + for (const r of results) { + // Assert the bundle actually walked the 40-module chain before checking + // the exit code so a failure surfaces the build output. + expect(r.stderr).toBe(""); + expect(r.stdout).toContain(`var v${N_MODULES} = ${N_MODULES};`); + expect(r.stdout).toContain("var v1 = 1 + v2;"); + expect(r.stdout).toContain(`console.log("${r.entry}", v1, f1());`); + expect(r.exitCode).toBe(0); } const slowestMs = Math.max(...results.map(r => r.ms)); expect(slowestMs).toBeLessThan(STALL_MS); From 8a451d4bdc1aa11cdaa3b34cf785e9e7a7263c8f Mon Sep 17 00:00:00 2001 From: robobun <117481402+robobun@users.noreply.github.com> Date: Thu, 23 Jul 2026 10:28:06 +0000 Subject: [PATCH 2/2] reword comment: drop the '<=100ms' bound claim Only the first futex wait in Event::wait has the 100ms timeout; later waits are indefinite (see ThreadPool.rs:1412-1416). The round reduction is justified by the empirical revert result, not by a timeout bound, so say that instead. --- test/regression/issue/32492.test.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/test/regression/issue/32492.test.ts b/test/regression/issue/32492.test.ts index 11537a5f2c1f..ae10a0fee929 100644 --- a/test/regression/issue/32492.test.ts +++ b/test/regression/issue/32492.test.ts @@ -24,12 +24,13 @@ test("concurrent bun build does not stall on worker-pool shutdown", async () => const root = String(dir); const CONCURRENCY = 24; - // #32492 was a ~10s stall at pool shutdown when the idle-futex timeout was - // 10s. #34009 lowered that timeout to 100ms, so a skipped shutdown wake now - // costs at most ~100ms and is indistinguishable from 24-way scheduling noise. - // This test therefore acts as a coarse guard (no multi-second shutdown stall) - // plus a concurrent-build smoke test. 4 rounds x 24 builds is enough for that - // on debug/ASAN; release keeps 16 because it's cheap. + // #32492 was a ~10s stall at pool shutdown when the idle-futex first-wait + // timeout was 10s. #34009 lowered that timeout to 100ms, after which the + // 16-round version of this test no longer distinguishes a reverted + // Event::wake fix on current main (verified empirically). This test is now a + // coarse guard against multi-second shutdown stalls plus a concurrent-build + // smoke test; 4 rounds x 24 builds covers that on debug/ASAN and release + // keeps 16 because it's cheap. const ROUNDS = isASAN || isDebug ? 4 : 16; const STALL_MS = 9000;