4.0 KiB
Renderer performance probes
Measuring what a session switch costs in the running Desktop app, over CDP. The findings in #4109 were produced with these; they live here so the next measurement is a command rather than a rebuild.
They are ad-hoc tools, not a benchmark suite: they attach to a dev app you started, and they answer "how much" only for the interaction they drive.
Running
Start the dev app with the debugger open:
npm run dev -w @maka/desktop -- --remote-debugging-port=9334
Then, with a populated sidebar (about 30 rows is what the #4109 numbers used):
node scripts/perf/session-switch-commits.mjs before
node scripts/perf/session-switch-busy-js.mjs
session-switch-commits.mjs— React commits per switch, how many are full-tree renders, and how many fibers actually re-rendered. Reloads the page first, soreact-commit-probe.jsis in place before React boots.session-switch-busy-js.mjs— renderer busy JS per switch, with the top self-time entries. It reports the running build, one configuration. A before/after needs both configurations in one instance; see below.react-commit-probe.js— the in-page half: a minimal__REACT_DEVTOOLS_GLOBAL_HOOK__plus aFunction.prototype.bindwrapper that catches React creating adispatchSetState, so a commit can be attributed to thesetStatethat caused it.cdp-client.mjs— the protocol client and the row-clicking helper.
The one rule
Never compare numbers from two app launches. Restarting the app shifts these
metrics by orders of magnitude, while the spread inside a single running
instance is small. An A/B means: one instance, a globalThis switch to select
the configuration, at least three repetitions per configuration, alternating,
compared pairwise. Two runs of "before" and "after" against two launches will
produce a confident number that means nothing.
The switch is a throwaway, not a shipped affordance. Branch a worktree, put a
globalThis flag in the one place that reads it — one that restores the old
behaviour when set, so the regressed configuration is reachable without
rebuilding the defect by hand — alternate the flag inside the running instance,
then delete the worktree. Measurement discipline is ours; product code carries
none of it. A flag that reaches main is a branch nothing executes and a
defect replica that has to be maintained against the code it replicates.
Two smaller ones that cost time to rediscover:
- Clicks must be
Input.dispatchMouseEvent. A synthesisedelement.click()does not activate an AstryxSideNavItem, so the app does nothing and the measurement describes it. - Disarm the commit probe (
__MAKA_PROBE__.arm = false) before sampling. Its fiber walk otherwise shows up in the profile as the app's own work;session-switch-busy-js.mjsdoes this for you.
What these do not tell you
The commit count is unweighted, and busy JS on this workload is spread across about a thousand cheap fibers rather than concentrated in one component. A change that lowers the commit count has not necessarily lowered the time, and a change that moves the top self-time entry has not necessarily lowered anything. Read both, and read the medians.