ReviewOS

stacks/harness

Cold start is ~665ms against a 300ms budget, and ~455ms of it is Craft

#5
Closed chris opened this 9 days ago ·
9 days ago

PLAN.md §11 budgets 300ms from window launch to an interactive page. Measured in-process (markWindowSpawned() immediately before the spawn, the page's own probe on arrival — one process, one clock):

Phasemshow it was measured
Craft process start → window created165craft --benchmark prints ready at window creation and exits
WKWebView cold init + trivial navigation~290an 88-byte control page: 455ms total, minus the 165ms above
harness SSR render of /166 → 129curl against a warm server (improved by deferred spaces)
page parse / execute / layout~45remainder
total~665

Two things this rules out

Payload is not the lever. Lifting the stx runtime and stylesheet into cacheable assets took the page from 392,733 to 213,141 bytes — 46% smaller — and cold start did not move: 671ms inline vs 661ms externalized across six interleaved pairs. The difference is noise.

Starting the load earlier is not the lever either. --timing showed 58ms of translucency, file-drop-hook and UI-delegate setup sitting ahead of loadRequest:. Moving the load first is still correct — I/O before cosmetics — but end-to-end did not measurably improve, because WKWebView launches its WebContent process at webview creation, not at loadRequest:. Firing the load earlier shifts a wait rather than removing one.

Where that leaves it

An 88-byte page cannot beat ~455ms on this machine. The budget is a Craft and WKWebView problem before it is a harness one, and it may simply be wrong for a WKWebView app — macOS pays for WebContent and Networking XPC spin-up on first launch regardless of what is rendered.

Worth trying, roughly in order of expected return:

  1. Create the WKWebView before the window rather than after, so WebContent spin-up overlaps the ~35–46ms of window construction.
  2. Investigate whether a warmed WKProcessPool survives across launches at all.
  3. Decide whether 300ms is achievable for any WKWebView app and, if not, re-baseline the budget honestly rather than leaving it permanently red.

Reproduce with craft --timing, added in v0.0.62.

9 days ago

Both remaining experiments ran today against craft main (v0.0.66 + the activation/TLS fix, rebased locally as perf/cold-start-experiments in the craft repo):

1. WKWebView before the window — no measurable effect. Interleaved A/B, eight pairs, spawn → page-JS beacon on a ~60-byte page: median 451ms old order vs 474ms new order, inside the ±100ms run-to-run noise. The mechanism, visible in hindsight: everything before run-loop entry is serialized main-thread work whose total is order-invariant, and WebContent can't complete its handshake until the run loop services XPC — which happens at the same absolute time in either order. Same shape as the earlier load-hoisting result: the wait shifts, nothing is removed. Change discarded.

2. Warmed WKProcessPool across launches — impossible by construction. The pool is in-process state; nothing about it survives the process, and the API is deprecated. The only cross-launch warmth is OS-level (dyld/XPC caches), which every measurement already includes.

One number improved on its own: window creation is now 40–90ms by craft --benchmark (was 165ms) — current craft main is simply faster there. The floor to page-JS (~450ms) stands regardless.

3. Re-baselined. With the floor probed twice and holding, 300ms is not achievable for any WKWebView app on this machine. PLAN.md §11 now budgets < 600ms end-to-end, with the harness-controlled slice (SSR + parse/layout) budgeted < 150ms — which deferred spaces already meet at realistic profile counts (77ms at 3–5). Landed in c7ddb2d.

Sign in to comment on this issue.