Prefill & the FrameAbhinav Pangaria · for Dart
Stage 1 · measured on an M4 Pro, 24 GB, 120 Hz

Prefill makes the page stutter. Decode doesn't.

I reran the performance claims in DBR-2026-05 and DBR-2025-01 on a fifth machine. I also measured something neither paper does: how the browser feels while the model runs. When a local 7B model reads a 4,000-token page at llama.cpp's default batch size, a GPU-heavy page drops most of its frames for the whole 11 seconds. A 64-token batch fixes that for about 10% more time to first token. That fix doesn't carry over to 14B, and the data suggests it won't carry over to smaller Macs either.

Recorded, not simulated

A browser that slows down while the model reads

The page below repaints only when the benchmark's real frames did. Each replay is one measured trial: 2 seconds idle, then the prefill of a 4,000-token page, then the start of decode. Gaps in the motion are real dropped frames from the run.

bench/pages/heavy.html
— fps
Idle Prefill Decode Dropped frame (over 1.5× the idle interval) On-time frame
Machine
Page
Model
Prefill batch
Phase
idle
Frames dropped, this prefill
—
Worst frame so far
—
Whole-condition median
—
Time to first token
—

What the data says

Five findings

01 · Prefill, on GPU-heavy pages

Third-party pages stutter. Text pages don't.

Every page idles at 0% dropped with no model loaded. At the default batch, 7B prefill drops 83% of frames on WebGL Aquarium, 64% on the shader page and 30% on MotionMark Arcs. It drops 0% on BBC News and on a light page. Decode drops nothing on any GPU-heavy page.

02 · The cause is the GPU

Size of each GPU submission matters. Pauses don't.

CPU-only prefill keeps the shader page smooth (0.1%) but takes 104 s instead of 11.5 s. Pausing 16 or 50 ms between 128-token chunks still drops 34–38%. 64-token chunks are smooth with no pause at all. What matters is how long each GPU kernel holds the GPU, not whether the queue has gaps.

03 · The fix moves with the model

Batch 64 fixes 3B and 7B. It doesn't fix 14B.

On the shader page batch 64 takes 3B from 69% to 0% and 7B from 64% to 1.3%. 14B still drops 31% at 64. A fixed value safe for 14B (32 or less) costs 7B about 17% TTFT on every page, including pages that never needed it.

04 · A second engine agrees

Safari shows the same pattern at 60 Hz.

Safari drops 14.5% during 7B prefill on the shader page (p95 32 ms against a 17 ms budget). Decode drops 0%, and batch 64 brings it to 0% for 6% more TTFT. At 60 Hz each frame has twice the time budget, so the same GPU stalls miss fewer deadlines.

05 · CPU is a second resource

Falling back to the CPU is worse, not safer.

On MotionMark Multiply, a CPU-bound page, GPU inference drops 6–10%. CPU inference drops 22% in prefill and 30% in decode, and four threads still drops 18%. Anything that runs on CPU cores needs its own budget, which matches DBT-2026-09's 12%-of-a-core cap on background embedding.

And the paper's limits

Cold TTFT is 11 s, not 640 ms.

7B at 4k tokens takes 11.4 s cold and 79 ms when the page is already in the KV cache, so the 640 ms figure only fits a cached prefix. No model gets a cold 4k prefill under 900 ms here. Decode and memory pass easily. 24 GB shows no swap cliff, and Q8 prefills faster than Q2_K.

7B prefill, 4,000 tokens

Frames dropped per page

batch 512, llama.cpp defaultbatch 64

A frame is dropped when its interval is more than 1.5× the page's own idle median (8.3 ms at 120 Hz, 17 ms in Safari at 60 Hz). Each bar is the median over 5 trials of a full prefill. The numbers are requestAnimationFrame intervals, which track the page's own rendering rather than the compositor.

Why this matters for Dart

“A model that starves the compositor produces a janky browser, which testers blamed on the browser rather than the model.”DBR-2026-05

Dart's own paper names the failure. Its research agenda asks for local inference “without the browser becoming unusable while they do”. This is that failure measured, narrowed down to one phase, and given a cheap first fix.

The fix isn't the whole answer. It holds for 3B and 7B on this machine, and the 14B run suggests a base M1 or M2 behaves like this machine running a bigger model. Stage 2 starts with the fix and builds only as much scheduler as the slower machines need.