mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-30 05:02:58 +00:00
test(server): trace recurring config responsiveness failures
This commit is contained in:
@@ -24,6 +24,8 @@ export async function measureMainThreadWork<T>(label: string, action: () => T |
|
||||
let previousCpu = threadCpuUsage();
|
||||
let probe: ReturnType<typeof setInterval>;
|
||||
let drain: ReturnType<typeof setImmediate>;
|
||||
const types = new Map<number, string>();
|
||||
const stacks = new Map<number, string>();
|
||||
const callbacks = new Map<number, { wall: number; cpu: NodeJS.CpuUsage }>();
|
||||
const record = (wallMs: number, cpu: NodeJS.CpuUsage) => {
|
||||
const cpuMs = (cpu.user + cpu.system) / 1_000;
|
||||
@@ -46,6 +48,10 @@ export async function measureMainThreadWork<T>(label: string, action: () => T |
|
||||
gc.observe({ entryTypes: ["gc"] });
|
||||
const activity = createHook({
|
||||
init(_id, type) {
|
||||
if (label === "project config main-thread work") {
|
||||
types.set(_id, type);
|
||||
stacks.set(_id, new Error().stack ?? "");
|
||||
}
|
||||
if (type.startsWith("FSREQ")) filesystemRequests++;
|
||||
if (!draining && type === "Immediate") yields++;
|
||||
if (type === "WORKER") workerEvents++;
|
||||
@@ -60,7 +66,13 @@ export async function measureMainThreadWork<T>(label: string, action: () => T |
|
||||
const start = callbacks.get(id);
|
||||
if (!start) return;
|
||||
callbacks.delete(id);
|
||||
record(performance.now() - start.wall, threadCpuUsage(start.cpu));
|
||||
const wall = performance.now() - start.wall;
|
||||
record(wall, threadCpuUsage(start.cpu));
|
||||
if (wall > 10 && label === "project config main-thread work") {
|
||||
process.stderr.write(
|
||||
JSON.stringify({ wall, type: types.get(id), stack: stacks.get(id) }) + "\n",
|
||||
);
|
||||
}
|
||||
},
|
||||
}).enable();
|
||||
const sample = () => {
|
||||
|
||||
@@ -111,20 +111,23 @@ describe("paseo config file substrate", () => {
|
||||
expect(blockingMs).toBeLessThan(20);
|
||||
});
|
||||
|
||||
it("keeps main-thread work below 20ms while admitting large configs", async () => {
|
||||
const config = {
|
||||
scripts: Object.fromEntries(
|
||||
Array.from({ length: 7_000 }, (_, i) => [`script${i}`, { command: "echo hi" }]),
|
||||
),
|
||||
worktree: { setup: "npm ci" },
|
||||
};
|
||||
await writeFile(join(tempDir, "paseo.json"), JSON.stringify(config));
|
||||
const { result, blockingMs, filesystemRequests, yields } = await measureConfigRead(tempDir);
|
||||
expect(result).toEqual({ ok: true, config, revision: await statPaseoConfigPath(tempDir) });
|
||||
expect(blockingMs).toBeLessThan(20);
|
||||
expect(filesystemRequests).toBeGreaterThan(0);
|
||||
expect(yields).toBeGreaterThan(0);
|
||||
});
|
||||
it.each(Array.from({ length: 25 }, (_, i) => i))(
|
||||
"keeps main-thread work below 20ms while admitting large configs (%i)",
|
||||
async () => {
|
||||
const config = {
|
||||
scripts: Object.fromEntries(
|
||||
Array.from({ length: 7_000 }, (_, i) => [`script${i}`, { command: "echo hi" }]),
|
||||
),
|
||||
worktree: { setup: "npm ci" },
|
||||
};
|
||||
await writeFile(join(tempDir, "paseo.json"), JSON.stringify(config));
|
||||
const { result, blockingMs, filesystemRequests, yields } = await measureConfigRead(tempDir);
|
||||
expect(result).toEqual({ ok: true, config, revision: await statPaseoConfigPath(tempDir) });
|
||||
expect(blockingMs).toBeLessThan(20);
|
||||
expect(filesystemRequests).toBeGreaterThan(0);
|
||||
expect(yields).toBeGreaterThan(0);
|
||||
},
|
||||
);
|
||||
|
||||
it("rejects a 32MiB config with main-thread work below 20ms", async () => {
|
||||
await writeFile(
|
||||
|
||||
Reference in New Issue
Block a user