From 90f2ac944eecc20a2580ea1913994516f53cf664 Mon Sep 17 00:00:00 2001 From: "paseo-bot[bot]" <266920839+paseo-bot[bot]@users.noreply.github.com> Date: Fri, 30 Oct 2026 15:32:36 +0000 Subject: [PATCH] test(server): probe config timing under CPU contention --- .../src/utils/paseo-config-file.test.ts | 25 +++++++++++++++++-- .../test-fixtures/config-responsiveness.ts | 19 +++++++++----- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/packages/server/src/utils/paseo-config-file.test.ts b/packages/server/src/utils/paseo-config-file.test.ts index 2e4b23ea24..7da1b8452f 100644 --- a/packages/server/src/utils/paseo-config-file.test.ts +++ b/packages/server/src/utils/paseo-config-file.test.ts @@ -1,6 +1,8 @@ import { mkdirSync, mkdtempSync, readFileSync, realpathSync, rmSync, writeFileSync } from "node:fs"; import { execFile } from "node:child_process"; import { promisify } from "node:util"; +import { Worker } from "node:worker_threads"; +import { once } from "node:events"; import { fileURLToPath } from "node:url"; import { writeFile, truncate, rm } from "node:fs/promises"; import { tmpdir } from "node:os"; @@ -62,6 +64,25 @@ async function measureConfigRead(directory: string, profile = false) { }; } +// Temporary diagnostic: keep scheduling pressure present throughout the paired +// cold reads, rather than depending on which other CI files are still running. +async function withCpuContention(action: () => Promise): Promise { + const workers = Array.from( + { length: 3 }, + () => + new Worker( + 'require("node:worker_threads").parentPort.postMessage("ready"); while (true) { Math.sqrt(Math.random()); }', + { eval: true }, + ), + ); + try { + await Promise.all(workers.map((worker) => once(worker, "message"))); + return await action(); + } finally { + await Promise.all(workers.map((worker) => worker.terminate())); + } +} + describe("paseo config file substrate", () => { let tempDir: string; @@ -138,7 +159,7 @@ describe("paseo config file substrate", () => { }); it.each( - Array.from({ length: 500 }, (_, repetition) => + Array.from({ length: 100 }, (_, repetition) => [false, true].map((profile) => ({ repetition, profile })), ).flat(), )( @@ -152,7 +173,7 @@ describe("paseo config file substrate", () => { }; await writeFile(join(tempDir, "paseo.json"), JSON.stringify(config)); const { result, blockingMs, filesystemRequests, yields, workerMessages } = - await measureConfigRead(tempDir, profile); + await withCpuContention(() => measureConfigRead(tempDir, profile)); expect(result).toEqual({ ok: true, config, revision: await statPaseoConfigPath(tempDir) }); expect(blockingMs).toBeLessThan(20); expect(filesystemRequests).toBeGreaterThan(0); diff --git a/packages/server/src/utils/test-fixtures/config-responsiveness.ts b/packages/server/src/utils/test-fixtures/config-responsiveness.ts index 495148f1d3..a27ef15f88 100644 --- a/packages/server/src/utils/test-fixtures/config-responsiveness.ts +++ b/packages/server/src/utils/test-fixtures/config-responsiveness.ts @@ -51,6 +51,11 @@ activity.disable(); process.stderr.write(`Config profiling: ${Boolean(profiler)}\n`); const profile = profiler ? (await profiler.post("Profiler.stop")).profile : null; profiler?.disconnect(); +if (spans.length > 0) { + process.stderr.write( + `Config long callbacks: ${JSON.stringify(spans.map(({ start, end, cpuMs }) => ({ wallMs: (end - start) / 1000, cpuMs })))}\n`, + ); +} if (profile && spans.length > 0) { const nodes = new Map(profile.nodes.map((node) => [node.id, node])); const parents = new Map(); @@ -62,13 +67,15 @@ if (profile && spans.length > 0) { for (const [index, id] of (profile.samples ?? []).entries()) { const delta = profile.timeDeltas?.[index] ?? 0; sampleTime += delta; - if (spans.some((span) => sampleTime >= span.start && sampleTime <= span.end)) { - samples.set(id, (samples.get(id) ?? 0) + delta); - } + const overlap = spans.reduce( + (total, span) => + total + + Math.max(0, Math.min(sampleTime, span.end) - Math.max(sampleTime - delta, span.start)), + 0, + ); + if (overlap > 0) samples.set(id, (samples.get(id) ?? 0) + overlap); } - process.stderr.write( - `Config long callbacks: ${JSON.stringify(spans.map(({ start, end, cpuMs }) => ({ wallMs: (end - start) / 1000, cpuMs })))}\n`, - ); + const hottest = [...samples] .sort((a, b) => b[1] - a[1]) .slice(0, 20)