Skip to content

Commit 01659de

Browse files
committed
chore: diagnose the retained heap test on GitHub runners
1 parent 1f131e6 commit 01659de

9 files changed

Lines changed: 42 additions & 258 deletions

File tree

‎.github/workflows/diag.yml‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
name: Diag memory test
2+
on:
3+
push:
4+
branches: [diag/memory-test-flake]
5+
jobs:
6+
diag:
7+
runs-on: ubuntu-latest
8+
strategy:
9+
fail-fast: false
10+
matrix:
11+
shard: [1, 2, 3, 4, 5, 6]
12+
steps:
13+
- uses: actions/checkout@v7
14+
- uses: pnpm/action-setup@v6
15+
- uses: actions/setup-node@v7
16+
with:
17+
node-version: 24.x
18+
cache: pnpm
19+
- run: |
20+
pnpm install --frozen-lockfile
21+
pnpm build
22+
pnpm benchmark:immer:build
23+
node --version
24+
nproc
25+
export DIAG_FILE="$RUNNER_TEMP/diag.jsonl"
26+
for i in $(seq 40); do pnpm test:benchmarks > /dev/null 2>&1 || echo "run $i failed"; done
27+
for i in $(seq 40); do node --expose-gc --test perf-testing/memory.test.mjs > /dev/null 2>&1 || echo "alone $i failed"; done
28+
node -e 'const l=require("fs").readFileSync(process.env.DIAG_FILE,"utf8").trim().split("\n").map(JSON.parse);const d=l.map(x=>x.delta).sort((a,b)=>a-b);console.log("n",d.length,"min",d[0],"max",d[d.length-1]);for(const x of l)if(Math.abs(x.delta)>8192)console.log(JSON.stringify(x))'

‎.github/workflows/nodejs.yml‎

Lines changed: 0 additions & 64 deletions
This file was deleted.

‎.github/workflows/npm-publish.yml‎

Lines changed: 0 additions & 32 deletions
This file was deleted.

‎.github/workflows/performance.yml‎

Lines changed: 0 additions & 49 deletions
This file was deleted.

‎.github/workflows/pull-request.yml‎

Lines changed: 0 additions & 40 deletions
This file was deleted.

‎.github/workflows/tests.yml‎

Lines changed: 0 additions & 34 deletions
This file was deleted.

‎.github/workflows/website.yml‎

Lines changed: 0 additions & 39 deletions
This file was deleted.

‎perf-testing/memory.mjs‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import assert from 'node:assert/strict';
22
import { Session } from 'node:inspector';
33
import { performance } from 'node:perf_hooks';
4+
import v8 from 'node:v8';
5+
const spaces = () => Object.fromEntries(v8.getHeapSpaceStatistics().map((s) => [s.space_name, s.space_used_size]));
46

57
export function allocatedBytes(node) {
68
return (
@@ -64,6 +66,7 @@ export async function measureMemory(
6466
globalThis.gc();
6567
const gcAfterRetainMs = performance.now() - gcStart;
6668
const retained = process.memoryUsage();
69+
const retainedSpaces = spaces();
6770
// Observe the contents after measurement, keeping every output live through GC.
6871
// Patches retain the last tuple per iteration. Avoid storing an output in a
6972
// separate local, which would keep it alive after clearing the holder.
@@ -74,6 +77,11 @@ export async function measureMemory(
7477
outputs.fill(null);
7578
globalThis.gc();
7679
const released = process.memoryUsage();
80+
const releasedSpaces = spaces();
81+
globalThis.gc();
82+
const released2 = process.memoryUsage();
83+
globalThis.gc();
84+
const released3 = process.memoryUsage();
7785
return {
7886
iterations,
7987
samplingInterval,
@@ -91,5 +99,6 @@ export async function measureMemory(
9199
gcAfterRetainMs,
92100
releasedHeapDeltaBytes: released.heapUsed - before.heapUsed,
93101
snapshots: { before, batchEnd, retained, released },
102+
diag: { retainedSpaces, releasedSpaces, released2: released2.heapUsed, released3: released3.heapUsed },
94103
};
95104
}

‎perf-testing/memory.test.mjs‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ test('retained-output heap excludes persistent cache growth during the pass', as
4646
},
4747
{ iterations: 16, samplingInterval: 256, warmup: 5 }
4848
);
49+
{
50+
const d = metrics.diag;
51+
const diff = Object.fromEntries(Object.keys(d.retainedSpaces).map((k) => [k, d.retainedSpaces[k] - d.releasedSpaces[k]]).filter(([, v]) => v));
52+
(await import('node:fs')).appendFileSync(process.env.DIAG_FILE ?? '/dev/null', JSON.stringify({ delta: metrics.retainedHeapDeltaBytes, r: metrics.snapshots.retained.heapUsed, rel: metrics.snapshots.released.heapUsed, rel2: d.released2, rel3: d.released3, diff }) + '\n');
53+
}
4954
assert.equal(cache.length, 65536);
5055
assert.ok(metrics.postGcHeapDeltaBytes > 400 * 1024);
5156
assert.ok(Math.abs(metrics.retainedHeapDeltaBytes) < 32 * 1024);

0 commit comments

Comments
 (0)