From e18c233c1e37cc0cba79d85345dae6460e2bc37f Mon Sep 17 00:00:00 2001 From: Brooklyn Nicholson Date: Thu, 21 May 2026 17:14:21 -0500 Subject: [PATCH] docs(desktop): correct leak-typing numbers on a real session MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Re-ran the leak harness on a populated session (Phaser thread) for both unpatched and patched builds. The original 'listener leak' was transient warm-up cost, not a steady-state leak — both versions show 0 listener growth/round in steady state. The load-bearing number is forced layouts per character: unpatched (HEAD~2): 7.02 layouts/char patched (HEAD): 2.35 layouts/char (3× fewer) The patches reduce per-char forced-layout work to Blink's natural floor. Document node count and heap are flat in both builds. --- apps/desktop/scripts/profile-typing-lag.md | 41 ++++++++++++---------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/apps/desktop/scripts/profile-typing-lag.md b/apps/desktop/scripts/profile-typing-lag.md index d157a8ff610..51b18b54d4d 100644 --- a/apps/desktop/scripts/profile-typing-lag.md +++ b/apps/desktop/scripts/profile-typing-lag.md @@ -58,31 +58,34 @@ makes the path slow. ### Leak counters — `leak-typing.mjs` -Types N chars, clears, force-GCs, captures `Performance.getMetrics` deltas. -Reveals leaked event listeners, heap drift, document node growth, and -forced-layout counts. +Types N chars per round, clears, force-GCs, captures +`Performance.getMetrics` deltas. Reveals leaked event listeners, heap +drift, document node growth, and forced-layout counts. ```bash -node apps/desktop/scripts/leak-typing.mjs --rounds=6 --chars=200 --cps=50 +# After clicking into a real session (e.g. via click-session.mjs): +node apps/desktop/scripts/leak-typing.mjs --rounds=8 --chars=200 --cps=50 ``` -Before patches (real run on this branch's previous tip): -``` -heapUsedMB Δ/round=+0.06 /char=+0.0003 -jsListeners Δ/round=+34.75 /char=+0.1737 ← LEAK -layoutCount Δ/round=+453.00 /char=+2.27 -``` +**Real-session numbers (Phaser thread, 8 rounds × 200 chars):** -After patches: -``` -heapUsedMB Δ/round=+0.00 /char=+0.0000 -jsListeners Δ/round=+0.00 /char=+0.0000 ← fixed -layoutCount Δ/round=+476.00 /char=+2.38 -``` +| | unpatched (HEAD~2) | patched (HEAD) | +|---|---|---| +| jsListeners growth/round | +0 | +0 | +| DOM nodes growth/round | +0 | +0 | +| heap growth/round | ~0 (V8 housekeeping) | ~0 | +| **forced layouts/char** | **7.02** | **2.35** (3× fewer) | -The listener leak is gone. The forced-layout count is unchanged because -~2 layouts/char is what Blink naturally does when a contentEditable grows -1px per character; not a JS-driven flush. +The forced-layout count is the load-bearing number — typing into a real +session was triggering ~7 layouts per character on the unpatched build +(scrollHeight reads + per-px CSS var writes + FadeText scrollWidth reads +all stacking up). After the patches it's down to ~2.35/char, which is +Blink's natural cost for a 1px/char-growing contentEditable and can't +be lowered further without architectural changes. + +The initial "+35 listeners/round leak" I called out on the first +unpatched run turned out to be transient warm-up (popovers initializing, +etc.); steady-state listener growth was 0 both before and after. ### CPU profile + heap snapshot — `profile-typing.mjs`