From 28e8232edaab14c64fc080527f255e4fe063fd63 Mon Sep 17 00:00:00 2001 From: bitkyc08-arch Date: Sat, 22 Aug 2026 00:47:51 +0900 Subject: [PATCH 1/2] feat(scripts): Bun.gc relief evaluation harness (SIGUSR2 child GC channel + matched-arm cells) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase A of the GC-relief plan: evaluate the 260731 allocator-residual gate on Bun 1.4 before any production hook. The retention-harness child gains a SIGUSR2 handler that runs Bun.gc(true) in the measured process and reports a timestamped {type:"gc",durationMs} receipt (inert for the locked 7h protocol, which never sends SIGUSR2). bun-gc-relief-eval.ts orchestrates matched control/gc arms with SEPARATE rss-retention and latency cell types so the RSS criterion is never contaminated by probe traffic; latency cells use a post-intervention probe stream as the p99 oracle. Note: Bun.spawn handle.kill() does not deliver SIGUSR2 on Bun 1.4 — process.kill(pid) is used deliberately. Smoke-verified end to end (OCX_GC_EVAL_SMOKE=1): GC receipts flow, report.json written. Real 3-run evidence lands with the macmini-cf measurement pass. Unit: devlog/_plan/260822_260822-bun14-followup-memory/020 --- scripts/bun-gc-relief-eval.ts | 294 +++++++++++++++++++ scripts/macos-rss-retention-harness-child.ts | 22 ++ 2 files changed, 316 insertions(+) create mode 100644 scripts/bun-gc-relief-eval.ts diff --git a/scripts/bun-gc-relief-eval.ts b/scripts/bun-gc-relief-eval.ts new file mode 100644 index 0000000000..a96bd4da8d --- /dev/null +++ b/scripts/bun-gc-relief-eval.ts @@ -0,0 +1,294 @@ +/** + * Bun.gc(true) relief evaluation (devlog/_plan/260822_260822-bun14-followup-memory/020 Phase A). + * + * Evaluates the 260731 allocator-residual gate on Bun 1.4: does one full GC + * inside the measured proxy return post-load RSS growth, and does it cost + * request latency? Two SEPARATE cell types keep the criteria uncontaminated: + * + * - rss cells: load stream -> intervention -> process IDLE through +5s/+60s + * samples (criterion a evidence). + * - latency cells: load stream -> intervention -> identical POST-INTERVENTION + * probe stream in both arms; probe p99 is criterion c's oracle. + * + * Arms: control (matched idle wait) vs gc (SIGUSR2 to the child, which runs + * Bun.gc(true) in-process and reports {type:"gc",at,durationMs} on stdout). + * + * This orchestrator reuses macos-rss-retention-harness-child.ts (the real + * startServer proxy) and an inline SSE fixture upstream. It is NOT the locked + * 7h retention protocol; runs are short and labeled. Smoke mode + * (OCX_GC_EVAL_SMOKE=1) shortens durations for pipeline verification only. + * + * Usage: bun scripts/bun-gc-relief-eval.ts + */ +import { mkdirSync, writeFileSync } from "node:fs"; +import { join } from "node:path"; + +const SMOKE = process.env.OCX_GC_EVAL_SMOKE === "1"; +const RUNS = SMOKE ? 1 : 3; +const LOAD_TURNS = SMOKE ? 3 : 30; +const EVENTS = SMOKE ? 20 : 200; +const EVENT_BYTES = 65_536; +const PROBE_TURNS = SMOKE ? 3 : 20; +const POST_WAIT_1_MS = 5_000; +const POST_WAIT_2_MS = SMOKE ? 10_000 : 60_000; +const READY_TIMEOUT_MS = 15_000; + +const outDir = process.argv[2]; +if (!outDir) throw new Error("usage: bun scripts/bun-gc-relief-eval.ts "); +mkdirSync(outDir, { recursive: true }); + +type Arm = "control" | "gc"; +type CellKind = "rss" | "latency"; + +function frame(event: string | null, data: unknown): Uint8Array { + const payload = typeof data === "string" ? data : JSON.stringify(data); + return new TextEncoder().encode( + (event ? "event: " + event + "\n" : "") + "data: " + payload + "\n\n", + ); +} + +/** Minimal Responses-shaped SSE fixture (mirrors the retention-harness fixture). */ +function startFixture(): { url: string; stop(): Promise } { + let serial = 0; + const server = Bun.serve({ + hostname: "127.0.0.1", + port: 0, + async fetch(request) { + if (request.method !== "POST" || new URL(request.url).pathname !== "/v1/responses") { + return new Response("not found", { status: 404 }); + } + await request.json().catch(() => ({})); + const id = ++serial; + let n = 0; + return new Response(new ReadableStream({ + pull(controller) { + let bytes: Uint8Array; + let done = false; + if (n === 0) { + bytes = frame("response.created", { + type: "response.created", + response: { id: "fixture-" + id, status: "in_progress", output: [] }, + }); + } else if (n <= EVENTS) { + bytes = frame("response.output_text.delta", { + type: "response.output_text.delta", + output_index: 0, + content_index: 0, + item_id: "msg-" + id, + delta: "x".repeat(EVENT_BYTES), + }); + } else if (n === EVENTS + 1) { + bytes = frame("response.output_item.done", { + type: "response.output_item.done", + output_index: 0, + item: { id: "msg-" + id, type: "message", status: "completed", role: "assistant", content: [] }, + }); + } else if (n === EVENTS + 2) { + bytes = frame("response.completed", { + type: "response.completed", + response: { id: "fixture-" + id, status: "completed", output: [] }, + }); + } else { + bytes = frame(null, "[DONE]"); + done = true; + } + controller.enqueue(bytes); + n++; + if (done) controller.close(); + }, + }), { headers: { "content-type": "text/event-stream" } }); + }, + }); + return { + url: server.url.toString().replace(/\/$/, ""), + stop: () => server.stop(true), + }; +} + +type ChildHandle = { + port: number; + pid: number; + kill(signal: NodeJS.Signals): void; + nextGcReceipt(): Promise<{ at: number; durationMs: number }>; + rss(): number; + stop(): Promise; +}; + +async function startChild(upstreamUrl: string, dir: string): Promise { + const home = join(dir, "opencodex-home"); + const codexHome = join(dir, "codex-home"); + mkdirSync(home, { recursive: true }); + mkdirSync(codexHome, { recursive: true }); + const child = Bun.spawn([ + process.execPath, + join(import.meta.dir, "macos-rss-retention-harness-child.ts"), + home, + codexHome, + upstreamUrl, + join(dir, "child-series.jsonl"), + "off", + ], { stdout: "pipe", stderr: Bun.file(join(dir, "child.stderr.log")) }); + + let port = 0; + let readyResolve!: () => void; + const ready = new Promise(resolve => { readyResolve = resolve; }); + let gcWaiter: ((receipt: { at: number; durationMs: number }) => void) | null = null; + + const reader = child.stdout.getReader(); + const drain = (async () => { + const decoder = new TextDecoder(); + let buffer = ""; + for (;;) { + const part = await reader.read(); + if (part.done) break; + buffer += decoder.decode(part.value, { stream: true }); + const lines = buffer.split(/\r?\n/); + buffer = lines.pop() ?? ""; + for (const line of lines) { + try { + const value = JSON.parse(line) as { type?: string; port?: number; at?: number; durationMs?: number }; + if (value.type === "ready" && value.port) { port = value.port; readyResolve(); } + if (value.type === "gc" && gcWaiter && typeof value.at === "number" && typeof value.durationMs === "number") { + const w = gcWaiter; gcWaiter = null; w({ at: value.at, durationMs: value.durationMs }); + } + } catch { /* startup noise */ } + } + } + })(); + + await Promise.race([ + ready, + child.exited.then(() => { throw new Error("child exited before ready"); }), + Bun.sleep(READY_TIMEOUT_MS).then(() => { throw new Error("readiness timeout"); }), + ]); + + return { + port, + pid: child.pid, + // Bun.spawn's handle.kill() does not deliver SIGUSR2 reliably on Bun 1.4 + // (verified: handle.kill silently no-ops while process.kill(pid) arrives); + // signal through the OS instead. + kill: signal => process.kill(child.pid, signal), + nextGcReceipt: () => new Promise((resolve, reject) => { + gcWaiter = resolve; + setTimeout(() => { if (gcWaiter) { gcWaiter = null; reject(new Error("gc receipt timeout")); } }, 10_000); + }), + rss: () => { + const out = Bun.spawnSync(["ps", "-o", "rss=", "-p", String(child.pid)]); + return Number.parseInt(out.stdout.toString().trim(), 10) * 1024; + }, + stop: async () => { + child.kill("SIGTERM"); + await Promise.race([child.exited, Bun.sleep(5_000)]); + child.kill("SIGKILL"); + await drain.catch(() => {}); + }, + }; +} + +async function oneTurn(base: string, label: string, turn: number): Promise { + const started = performance.now(); + const response = await fetch(base + "/v1/responses", { + method: "POST", + headers: { "content-type": "application/json", "x-opencodex-api-key": "fixture-admission" }, + body: JSON.stringify({ model: "fixture/fixture-model", input: label + "-" + turn, stream: true }), + }); + if (response.status !== 200 || !response.body) throw new Error("HTTP " + response.status); + const reader = response.body.getReader(); + for (;;) { + const part = await reader.read(); + if (part.done) break; + } + return performance.now() - started; +} + +function quantile(sorted: number[], q: number): number { + if (sorted.length === 0) return Number.NaN; + const pos = (sorted.length - 1) * q; + const lo = Math.floor(pos); + const hi = Math.ceil(pos); + return sorted[lo]! + (sorted[hi]! - sorted[lo]!) * (pos - lo); +} + +type CellResult = Record; + +async function runCell(kind: CellKind, arm: Arm, runIndex: number): Promise { + const dir = join(outDir, kind + "-" + arm + "-run" + runIndex); + mkdirSync(dir, { recursive: true }); + const fixture = startFixture(); + const child = await startChild(fixture.url, dir); + const base = "http://127.0.0.1:" + child.port; + try { + // Load stream (identical in both arms). + for (let turn = 0; turn < LOAD_TURNS; turn++) await oneTurn(base, kind + "-load", turn); + const rssAfterLoad = child.rss(); + + // Intervention. + let gcReceipt: { at: number; durationMs: number } | null = null; + if (arm === "gc") { + const receipt = child.nextGcReceipt(); + child.kill("SIGUSR2"); + gcReceipt = await receipt; + } else { + await Bun.sleep(50); // matched (small) intervention window + } + + if (kind === "rss") { + // Idle through both samples: pure criterion-(a) evidence. + await Bun.sleep(POST_WAIT_1_MS); + const rssPlus5s = child.rss(); + await Bun.sleep(POST_WAIT_2_MS - POST_WAIT_1_MS); + const rssPlus60s = child.rss(); + return { + kind, arm, runIndex, smoke: SMOKE, + rssAfterLoad, rssPlus5s, rssPlus60s, + gcDurationMs: gcReceipt?.durationMs ?? null, + recoveredByPlus60s: rssAfterLoad - rssPlus60s, + }; + } + + // latency cell: post-intervention probe stream is the oracle. + const latencies: number[] = []; + for (let turn = 0; turn < PROBE_TURNS; turn++) latencies.push(await oneTurn(base, "probe", turn)); + latencies.sort((a, b) => a - b); + return { + kind, arm, runIndex, smoke: SMOKE, + probeTurns: PROBE_TURNS, + p50Ms: quantile(latencies, 0.5), + p99Ms: quantile(latencies, 0.99), + maxMs: latencies[latencies.length - 1], + gcDurationMs: gcReceipt?.durationMs ?? null, + rssNonNormative: child.rss(), + }; + } finally { + await child.stop(); + await fixture.stop(); + } +} + +const results: CellResult[] = []; +for (let run = 0; run < RUNS; run++) { + for (const kind of ["rss", "latency"] as const) { + for (const arm of ["control", "gc"] as const) { + const cell = await runCell(kind, arm, run); + results.push(cell); + console.log(JSON.stringify(cell)); + } + } +} + +const report = { + smoke: SMOKE, + bunVersion: Bun.version, + bunRevision: Bun.revision, + platform: process.platform, + arch: process.arch, + at: new Date().toISOString(), + runs: RUNS, + loadTurns: LOAD_TURNS, + events: EVENTS, + eventBytes: EVENT_BYTES, + results, +}; +writeFileSync(join(outDir, "report.json"), JSON.stringify(report, null, 2)); +console.log("report: " + join(outDir, "report.json")); diff --git a/scripts/macos-rss-retention-harness-child.ts b/scripts/macos-rss-retention-harness-child.ts index eeb59d3167..e47ed7c193 100644 --- a/scripts/macos-rss-retention-harness-child.ts +++ b/scripts/macos-rss-retention-harness-child.ts @@ -65,6 +65,28 @@ process.stdout.write(JSON.stringify({ watchdogIncluded: true, }) + "\n"); +/** + * GC control channel (devlog/_plan/260822_260822-bun14-followup-memory/020): + * SIGUSR2 runs a full collection INSIDE the measured process and reports a + * timestamped receipt with the measured pause on the same stdout JSONL channel + * as "ready". The locked 7h retention protocol never sends SIGUSR2, so this is + * inert for existing runs; only the GC-relief evaluation orchestrator uses it. + */ +process.on("SIGUSR2", () => { + const t0 = Bun.nanoseconds(); + try { + Bun.gc(true); + const durationMs = (Bun.nanoseconds() - t0) / 1e6; + process.stdout.write(JSON.stringify({ type: "gc", at: Date.now(), durationMs }) + "\n"); + } catch (error) { + process.stdout.write(JSON.stringify({ + type: "gc-error", + at: Date.now(), + message: error instanceof Error ? error.message : String(error), + }) + "\n"); + } +}); + await new Promise((resolve) => { let closing = false; From 3ee558a23877f43ebd6e7532c57af61e353b283c Mon Sep 17 00:00:00 2001 From: bitkyc08-arch Date: Sat, 22 Aug 2026 01:03:15 +0900 Subject: [PATCH 2/2] =?UTF-8?q?devlog:=20GC-relief=20Phase=20A=20verdict?= =?UTF-8?q?=20FAIL=20on=20Bun=201.4=20=E2=80=94=20260731=20gate=20stands,?= =?UTF-8?q?=20Phase=20B=20not=20implemented?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Real 3-run matched-arm evaluation on two darwin/arm64 hosts (local + macmini-cf, both Bun 1.4.0): recoveredByPlus60s in the GC arm is indistinguishable from control idle drift (<0.1% of the ~300MB post-load RSS; less than control on 4/6 runs). Criterion (a) of the 260731 allocator-residual gate fails decisively; GC pause 3.9-4.6ms recorded. Production Bun.gc(true) relief stays banned; the Phase B design is retained as documentation for a future runtime that changes page-return behavior. Evidence JSONs committed under evidence/. --- .../020_watchdog_gc_relief.md | 38 +++++ .../evidence/gc-eval-local-darwin-arm64.json | 152 ++++++++++++++++++ .../gc-eval-macmini-darwin-arm64.json | 152 ++++++++++++++++++ 3 files changed, 342 insertions(+) create mode 100644 devlog/_plan/260822_260822-bun14-followup-memory/evidence/gc-eval-local-darwin-arm64.json create mode 100644 devlog/_plan/260822_260822-bun14-followup-memory/evidence/gc-eval-macmini-darwin-arm64.json diff --git a/devlog/_plan/260822_260822-bun14-followup-memory/020_watchdog_gc_relief.md b/devlog/_plan/260822_260822-bun14-followup-memory/020_watchdog_gc_relief.md index 9ba054d4be..0cee356dcc 100644 --- a/devlog/_plan/260822_260822-bun14-followup-memory/020_watchdog_gc_relief.md +++ b/devlog/_plan/260822_260822-bun14-followup-memory/020_watchdog_gc_relief.md @@ -99,3 +99,41 @@ attached — goalplan c3 satisfied by construction. + +## Phase A verdict (2026-08-22): FAIL — Phase B not implemented + +Real runs (smoke:false), 3 fresh-process runs per arm per cell type, Bun 1.4.0 +darwin/arm64 on BOTH hosts (local dev Mac + macmini-cf). Evidence: +evidence/gc-eval-local-darwin-arm64.json, evidence/gc-eval-macmini-darwin-arm64.json. + +### Criterion (a): ≥50% of post-load RSS growth gone by +60s after one GC + +| host | arm | rssAfterLoad (3 runs) | recoveredByPlus60s (3 runs) | +|---|---|---|---| +| macmini-cf | control | 305.0 / 302.2 / 354.8 MB | +0.25 / +0.23 / +0.26 MB | +| macmini-cf | gc | 330.6 / 316.4 / 311.1 MB | −0.03 / +0.13 / +0.15 MB | +| local | control | 329.1 / 304.1 / 325.9 MB | +0.21 / +0.23 / +0.23 MB | +| local | gc | 332.5 / 324.1 / 334.1 MB | +0.13 / +0.11 / +0.10 MB | + +GC recovery is indistinguishable from control idle drift (<0.1% of load-height +RSS on every run; the GC arm recovered LESS than control on 4 of 6 runs). +Bun 1.4's shared-allocator Bun.gc(true) does NOT return the post-load RSS +plateau on darwin — same qualitative result as the 1.3.x finding that produced +the 260731 gate. Criterion (a) FAIL, decisively, on both hosts. + +### Criterion (c): latency (informational, gate already failed) + +GC pause (child-reported): 3.9–4.6 ms across all runs. Probe p99 deltas within +noise (macmini 79.6→81.1/78.3/79.2 ms; local one outlier 84.1 vs 69.8 ms +control). No acceptance computed — (a) already fails the gate. + +### Consequence + +- The 260731 ban on production threshold/idle Bun.gc(true) STANDS on Bun 1.4. +- Phase B (config-gated watchdog relief, idle gate, lastReliefAt, wiring chain) + is NOT implemented. The design remains in this doc for a future Bun release + that changes allocator page-return behavior; re-run this harness first. +- The RSS plateau after SSE load is allocator page retention, not JS-heap + garbage — consistent with the 260731 analysis; process recycling remains the + operational lever. + diff --git a/devlog/_plan/260822_260822-bun14-followup-memory/evidence/gc-eval-local-darwin-arm64.json b/devlog/_plan/260822_260822-bun14-followup-memory/evidence/gc-eval-local-darwin-arm64.json new file mode 100644 index 0000000000..bfd2591130 --- /dev/null +++ b/devlog/_plan/260822_260822-bun14-followup-memory/evidence/gc-eval-local-darwin-arm64.json @@ -0,0 +1,152 @@ +{ + "smoke": false, + "bunVersion": "1.4.0", + "bunRevision": "34cbb9a40b4bd1bd767d134a7065e66c2432a676", + "platform": "darwin", + "arch": "arm64", + "at": "2026-08-21T16:02:16.941Z", + "runs": 3, + "loadTurns": 30, + "events": 200, + "eventBytes": 65536, + "results": [ + { + "kind": "rss", + "arm": "control", + "runIndex": 0, + "smoke": false, + "rssAfterLoad": 329072640, + "rssPlus5s": 329121792, + "rssPlus60s": 328859648, + "gcDurationMs": null, + "recoveredByPlus60s": 212992 + }, + { + "kind": "rss", + "arm": "gc", + "runIndex": 0, + "smoke": false, + "rssAfterLoad": 332513280, + "rssPlus5s": 332660736, + "rssPlus60s": 332382208, + "gcDurationMs": 4.322166, + "recoveredByPlus60s": 131072 + }, + { + "kind": "latency", + "arm": "control", + "runIndex": 0, + "smoke": false, + "probeTurns": 20, + "p50Ms": 66.84818750000704, + "p99Ms": 69.78122875000263, + "maxMs": 69.89625000000524, + "gcDurationMs": null, + "rssNonNormative": 358809600 + }, + { + "kind": "latency", + "arm": "gc", + "runIndex": 0, + "smoke": false, + "probeTurns": 20, + "p50Ms": 66.28095900000335, + "p99Ms": 69.86663276999433, + "maxMs": 70.19816699999501, + "gcDurationMs": 4.599541, + "rssNonNormative": 333365248 + }, + { + "kind": "rss", + "arm": "control", + "runIndex": 1, + "smoke": false, + "rssAfterLoad": 304119808, + "rssPlus5s": 304185344, + "rssPlus60s": 303890432, + "gcDurationMs": null, + "recoveredByPlus60s": 229376 + }, + { + "kind": "rss", + "arm": "gc", + "runIndex": 1, + "smoke": false, + "rssAfterLoad": 324059136, + "rssPlus5s": 324190208, + "rssPlus60s": 323944448, + "gcDurationMs": 4.1755, + "recoveredByPlus60s": 114688 + }, + { + "kind": "latency", + "arm": "control", + "runIndex": 1, + "smoke": false, + "probeTurns": 20, + "p50Ms": 66.12091649998911, + "p99Ms": 70.72656152000272, + "maxMs": 71.06291700000293, + "gcDurationMs": null, + "rssNonNormative": 366297088 + }, + { + "kind": "latency", + "arm": "gc", + "runIndex": 1, + "smoke": false, + "probeTurns": 20, + "p50Ms": 66.67666649997409, + "p99Ms": 68.93200429000456, + "maxMs": 68.9802090000012, + "gcDurationMs": 4.379583, + "rssNonNormative": 360906752 + }, + { + "kind": "rss", + "arm": "control", + "runIndex": 2, + "smoke": false, + "rssAfterLoad": 325877760, + "rssPlus5s": 325926912, + "rssPlus60s": 325648384, + "gcDurationMs": null, + "recoveredByPlus60s": 229376 + }, + { + "kind": "rss", + "arm": "gc", + "runIndex": 2, + "smoke": false, + "rssAfterLoad": 334053376, + "rssPlus5s": 334233600, + "rssPlus60s": 333955072, + "gcDurationMs": 4.560834, + "recoveredByPlus60s": 98304 + }, + { + "kind": "latency", + "arm": "control", + "runIndex": 2, + "smoke": false, + "probeTurns": 20, + "p50Ms": 67.00995850001345, + "p99Ms": 71.89010472996858, + "maxMs": 72.32308299996657, + "gcDurationMs": null, + "rssNonNormative": 347078656 + }, + { + "kind": "latency", + "arm": "gc", + "runIndex": 2, + "smoke": false, + "probeTurns": 20, + "p50Ms": 66.42141650000121, + "p99Ms": 84.07492050000349, + "maxMs": 85.31870800000615, + "gcDurationMs": 4.345833, + "rssNonNormative": 319455232 + } + ] +} \ No newline at end of file diff --git a/devlog/_plan/260822_260822-bun14-followup-memory/evidence/gc-eval-macmini-darwin-arm64.json b/devlog/_plan/260822_260822-bun14-followup-memory/evidence/gc-eval-macmini-darwin-arm64.json new file mode 100644 index 0000000000..baf054f1c6 --- /dev/null +++ b/devlog/_plan/260822_260822-bun14-followup-memory/evidence/gc-eval-macmini-darwin-arm64.json @@ -0,0 +1,152 @@ +{ + "smoke": false, + "bunVersion": "1.4.0", + "bunRevision": "34cbb9a40b4bd1bd767d134a7065e66c2432a676", + "platform": "darwin", + "arch": "arm64", + "at": "2026-08-21T16:02:06.458Z", + "runs": 3, + "loadTurns": 30, + "events": 200, + "eventBytes": 65536, + "results": [ + { + "kind": "rss", + "arm": "control", + "runIndex": 0, + "smoke": false, + "rssAfterLoad": 305037312, + "rssPlus5s": 305086464, + "rssPlus60s": 304791552, + "gcDurationMs": null, + "recoveredByPlus60s": 245760 + }, + { + "kind": "rss", + "arm": "gc", + "runIndex": 0, + "smoke": false, + "rssAfterLoad": 330563584, + "rssPlus5s": 330711040, + "rssPlus60s": 330596352, + "gcDurationMs": 4.067541, + "recoveredByPlus60s": -32768 + }, + { + "kind": "latency", + "arm": "control", + "runIndex": 0, + "smoke": false, + "probeTurns": 20, + "p50Ms": 75.82177049999154, + "p99Ms": 79.6427512700003, + "maxMs": 79.90070800000103, + "gcDurationMs": null, + "rssNonNormative": 354353152 + }, + { + "kind": "latency", + "arm": "gc", + "runIndex": 0, + "smoke": false, + "probeTurns": 20, + "p50Ms": 76.33122900000308, + "p99Ms": 81.13658803999365, + "maxMs": 81.63145899999654, + "gcDurationMs": 4.23, + "rssNonNormative": 330596352 + }, + { + "kind": "rss", + "arm": "control", + "runIndex": 1, + "smoke": false, + "rssAfterLoad": 302235648, + "rssPlus5s": 302301184, + "rssPlus60s": 302006272, + "gcDurationMs": null, + "recoveredByPlus60s": 229376 + }, + { + "kind": "rss", + "arm": "gc", + "runIndex": 1, + "smoke": false, + "rssAfterLoad": 316375040, + "rssPlus5s": 316522496, + "rssPlus60s": 316243968, + "gcDurationMs": 4.252875, + "recoveredByPlus60s": 131072 + }, + { + "kind": "latency", + "arm": "control", + "runIndex": 1, + "smoke": false, + "probeTurns": 20, + "p50Ms": 76.29347899998538, + "p99Ms": 79.48590976999724, + "maxMs": 79.50983399999677, + "gcDurationMs": null, + "rssNonNormative": 324976640 + }, + { + "kind": "latency", + "arm": "gc", + "runIndex": 1, + "smoke": false, + "probeTurns": 20, + "p50Ms": 75.3432090000133, + "p99Ms": 78.32939928999403, + "maxMs": 78.33808399998816, + "gcDurationMs": 4.057542, + "rssNonNormative": 334856192 + }, + { + "kind": "rss", + "arm": "control", + "runIndex": 2, + "smoke": false, + "rssAfterLoad": 354811904, + "rssPlus5s": 354877440, + "rssPlus60s": 354549760, + "gcDurationMs": null, + "recoveredByPlus60s": 262144 + }, + { + "kind": "rss", + "arm": "gc", + "runIndex": 2, + "smoke": false, + "rssAfterLoad": 311148544, + "rssPlus5s": 311279616, + "rssPlus60s": 311001088, + "gcDurationMs": 3.892, + "recoveredByPlus60s": 147456 + }, + { + "kind": "latency", + "arm": "control", + "runIndex": 2, + "smoke": false, + "probeTurns": 20, + "p50Ms": 75.67283349999343, + "p99Ms": 79.54803673004673, + "maxMs": 79.55712500005029, + "gcDurationMs": null, + "rssNonNormative": 342310912 + }, + { + "kind": "latency", + "arm": "gc", + "runIndex": 2, + "smoke": false, + "probeTurns": 20, + "p50Ms": 75.90585399998236, + "p99Ms": 79.18780874996737, + "maxMs": 79.45112499996321, + "gcDurationMs": 3.921584, + "rssNonNormative": 375390208 + } + ] +} \ No newline at end of file