perf: a frozen frame is not re-rendered sixty times a second

The tick queued a GL render unconditionally. In `Held` and `Paused` the rows
are bound to an immutable snapshot on a pinned axis, so a frame in which none
of the picture's own terms moved is the same frame again. The gate keys on a
coarse signature of what a frozen view can be re-framed by, opens for
`kSettleRenders` frames on a change because the figure lays out per render, and
has a floor that renders anyway every few ticks. The layout editor is excluded:
its buttons are placed from the last frame's rects, so a skipped frame there is
a stale widget rather than a stale picture. `skips=` in the probe dump is the
reading.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Martino FerrariandClaude Opus 4.6 committed 2026-10-13 14:50:55 +02:00
1 parent 84c158ff21
commit be71a1d4bb
5 files changed
+130 -4

No files matched your search

+37
View File
@@ -344,6 +344,43 @@ array of per-node structs was measured and bought **nothing** — at six nodes t
L1-resident either way. It was kept because a node's state belonging on one cache line is the
right shape for a graph that grows, not because it showed up.
### What the ingest filter and a still frame cost
Two costs that are paid once per *wire sample* and once per *tick* respectively, and so are the
largest two the application has that are not proportional to anything the user asked for.
**The ingest filter's group test.** Decimation at ingest is an average, never a stride, so the
filter reads every sample by design — and the test for "is this sample the last of its group"
was a modulo: `tick % period == period - 1`, once per channel per sample, plus once more for the
shared clock. `Partition::time_stride` is chosen at *runtime* (`plan_partition()` doubles it from
1 until the window fits), so that modulo is not a compile-time strength reduction but a real
64-bit `div` — and the code's own comment claimed the opposite. Both factors are powers of two
(every per-channel `stride[i]` is 1 by design), so the period minus one is a **mask** and the test
is `(tick & mask) == mask`. The masks are built where the accumulators are sized, keyed on the
partition, so a re-plan cannot leave them addressing the previous partition's groups; the
reserved-hole path got the same treatment, because a hole's samples go through the same
accumulators and the two phases have to agree sample for sample. The shared clock's test is now
computed once per sample and reused by the time ring, the channel loop and the math push — it was
three tests of the same thing.
**A frozen frame.** The tick queued a GL render unconditionally, sixty times a second, for the
whole life of the process. In `Held` and `Paused` that is the same picture again: the rows are
bound to an immutable snapshot on a pinned axis and the producer is feeding the live ring, not the
series on screen. On llvmpipe, or on a battery, re-drawing a frozen event at 60 Hz is the entire
cost of the application. The gate is now two parts, and the second is what makes the first safe to
keep coarse: a *signature* of what a frozen view can be re-framed by — a new snapshot, a pan or
zoom (the group's range, where both the gestures and the pin write), a row added or removed —
which renders the moment it changes, and a **floor** that renders anyway every four ticks (~15 Hz),
so anything the signature does not name is late rather than lost. A gate that can only be opened by
a list of state is a gate that goes wrong the first time the list is one item short. A change opens
the gate for three frames rather than one, because the figure lays itself out per *render* and its
left gutter is a monotone floor that takes two passes to converge. The layout editor is excluded
outright: its buttons are placed from the rects the last frame was laid out with, so there a
skipped frame is a stale *widget* and not just a stale picture. Interaction needs none of this —
`PlotArea` queues its own render from the pointer, scroll and drag handlers, so a crosshair and a
cursor drag stay immediate whatever the gate decides. `[pause-probe]`'s `skips=` field reports it,
cumulative: 0 on the live line, non-zero on the paused one.
### Statistics
**Statistics** under the measurements list adds a second line to every measurement: `n`, the