fix: a still frame's measurements are the frame's, not the viewport's
A measurement is a statistic of the window the pane is *about*, and on a pinned view -- a held event, a paused stream, an opened file -- that is the frame, not the part of it on screen. The pane followed the viewport instead, so a wheel on a latched event moved `average` and `top`: the reported "when measuring a still frame, moving the zoom makes measurements such as average or top change". Nothing about the data had changed; the user was only looking closer. The window is `RowSet::pinned_range()` while the pin frames the view and the viewport otherwise, and the choice is made in `update_measures()` -- the call site -- rather than inside `MeasureWindowReader`, because it is *booked* as well as read: that window is what the "it moved" test compares against `App::measure_window`, so a gesture inside the pin spends no recompute either, and a reader that chose its own would leave a pinned view recomputing every gesture frame for a number that cannot change. `pinned_range()` is now the one expression of the pin's extent, shared with the framing (`hold_pinned_window()`, `fit_x()`), and the reader is handed the window instead of reading the plot. Live is unchanged: there the window really moves and the statistic follows it, and the accumulator's rule about what resets the history is about neither. `UDPSCOPE_PROBE_MEASUREPIN_MS` is the guard, three legs of before/after a gesture on the row's own axis. On a latched event zoomed to a quarter (`view=[-1..1]` -> `[-0.25..0.25]`, `pin` unchanged): `same=4/4 for_same=1 pass_delta=0`, every value bit-identical -- `average=0.000000 top=0.957975 peak to peak=2.000000 amplitude=1.915950` both sides. The same on a pause taken from it. Since the key `for=` follows `pin=` now, `[measure-trace]` gained the field, so a held run reads `for==pin` with `swin` free to sit inside it. On a live view a zoom to an eighth reads `same=0/4 for_same=0 pass_delta=3 span_after=0.125000 follows=1` with the values moving -- the case the rule must not swallow. Before the fix the same probe reads `same=1/4 for_same=0 pass_delta=1 span_after=0.500000` on the held event (`top` `0.957975` -> `0.957966`) and `same=0/4 span_after=0.125000` on the pause (`top` `0.957944` -> `0.358614`). Live reads the same either way. Also fixed, found by the pause leg: pausing while an event is *held* froze an **empty** picture. `on_pause_toggled()` read `stream_at_x0()` after setting the pause state, and that accessor follows the display -- `paused` with no pause view published yet answers `-display_epoch()`, which on a held event is 0, so the cut searched the ring at edge-relative x, found nothing, and the frame bound an empty snapshot: every measurement `--`, every ruler gone (`ev=650001` on the probe's line now, `ev=0` before). The offset and the window are read first, which is the offset the axis is actually displaying. The live case is unaffected, which is why the pause probe, which pauses a live view, never saw it. Docs corrected where they asserted the old half-truth: the invariants now separate the accumulator's rule (unchanged) from the window a value is computed over (this change), the trigger/pinning file names the pin as load-bearing for both the framing and the numbers and records the pause ordering rule, `verification.md`/`probe-readings.md` describe the new probe and `pin=`, and the README and the manual say what a still frame measures. Checked: `cmake --build build --clean-first -j4` 0 errors and the documented three warnings; `make -C build test-ui` 13 ok; `make -C build test-help` green; an exit-dump run 0 Gtk-WARNING/Gtk-CRITICAL and `gtk warnings: 0`; `[measurepin-probe]`, `[pan-probe]` (`held=1`, `allowed=1`, `limited=1`), `[pause-probe]` (`event_size` non-zero exactly while paused, `axis` inside `frozen_x`, `skips` 0 live / 30 paused), `[stats-probe]` (`dn=1` across the pause), `[zoom-probe]` (`gap_px=0.0` at every step) and `[measure-probe]` + the dump's `measures window:` (all-types run `marks_in_window=4/4`, `pin=off` live) on the fast mock. `measure cost:` is unchanged in kind: `raw=37298 (0.0%)` of `covered=121704537`, 1.04 ms a pass -- the runs that read higher are the probe's own zoomed-to-a-slice windows, where the window is legitimately shorter than a bucket.
This commit is contained in:
1 parent
d91957a2fe
commit
0a209becb1
13 files changed
+719
-114
No files matched your search
+34
-14
@@ -96,20 +96,25 @@ precedent, not an exception.
|
||||
overshoot, kept by the extremes and excluded by the levels. The per-type values, the reason for
|
||||
each, and the cost of the histogram are in
|
||||
[invariants-measurements.md](invariants-measurements.md).
|
||||
`[measure-trace] mode=M view=[..] s0=S swin=[..] for=[..] passes=N <type>=<value>... marks=N
|
||||
level:V/time:V...` is a repeating line (250 ms) from the probe: the pane's numbers beside the
|
||||
*current* window and the marks actually placed, which is the only way a stale result or a mark
|
||||
that should not be drawn shows up as a number. `swin` is `view` moved onto the stream's clock by
|
||||
`s0` (`stream_at_x0()`), and `for` is the window the printed numbers were computed over, in the
|
||||
same clock -- so a reading that moved while `view` stood still is a change of `s0` (a new
|
||||
snapshot under the same mode) and not a stale pass, and only these three fields tell the two
|
||||
apart. `passes` beside them says whether a recompute answered the move. **While `mode=held`,
|
||||
`for` must equal `swin` exactly**, through any number of zooms and pans: a latched event does
|
||||
not scroll, so there is nothing for a recompute to be late for. That reading is where
|
||||
the measurements standing still under a gesture was found -- `for=[0.47..2.47]` against a
|
||||
`swin=[1.417..1.467]` with `passes` frozen, the pane describing the whole 2 s event while a 50 ms
|
||||
slice of it was on screen. The line must also never print `marks=0` while measurements with
|
||||
`show_on_plot` are on and the data is there -- that was the rulers blinking off at a mode change.
|
||||
`[measure-trace] mode=M view=[..] s0=S swin=[..] pin=[..|off] for=[..] passes=N
|
||||
<type>=<value>... marks=N level:V/time:V...` is a repeating line (250 ms) from the probe: the
|
||||
pane's numbers beside the *current* window and the marks actually placed, which is the only way a
|
||||
stale result or a mark that should not be drawn shows up as a number. `swin` is `view` moved onto
|
||||
the stream's clock by `s0` (`stream_at_x0()`), `pin` is the pin's own extent in that clock (`off`
|
||||
when nothing is pinned) and `for` is the window the printed numbers were computed over -- so a
|
||||
reading that moved while `view` stood still is a change of `s0` (a new snapshot under the same
|
||||
mode) and not a stale pass, and only these fields tell those apart. `passes` beside them says
|
||||
whether a recompute answered the move. **While the view is pinned, `for` must equal `pin` -- and
|
||||
`swin` is free to sit anywhere inside it** -- through any number of zooms and pans: a latched
|
||||
event's numbers are the *frame's*, so a gesture inside the pin changes neither them nor `passes`.
|
||||
Read the other way round it is the defect: `for` following `swin` into the zoom while the values
|
||||
move is the reported "on a still frame the measurements change when I zoom". Neither reading is
|
||||
the old "measurements stand still while the data moves", which was `for=[0.47..2.47]` against a
|
||||
`swin=[1.417..1.467]` with `passes` frozen -- the pane describing a window the plot had left.
|
||||
The line must also never print `marks=0` while measurements with `show_on_plot` are on and the
|
||||
data is there -- that was the rulers blinking off at a mode change. `pin=off` while the mode is
|
||||
`held` is not a stale reading but the window control: `apply_time_window()` unpins, and for those
|
||||
frames the view is live-framed and measuring the viewport is right.
|
||||
`measure cost: N recomputes, X ms total, Y ms each, data D ms (P%), covered=C buckets=B
|
||||
raw=R (F%), N ns/covered sample` follows it: **read it against a run with
|
||||
`UDPSCOPE_PROBE_MEASURE_MS` unset**, because a frame mean cannot attribute a cost. The last
|
||||
@@ -168,6 +173,21 @@ precedent, not an exception.
|
||||
`--square-harmonics 30` for the `0.986496` and the `0.302744`, `--square-harmonics 0` for the
|
||||
`1.000000` and the empty band.
|
||||
|
||||
- `[measurepin-probe]` (stderr, `UDPSCOPE_PROBE_MEASUREPIN_MS`) — **what window a measurement
|
||||
describes**: on a still frame the pane is about the *frame*, so a pan or a zoom changes no
|
||||
number, and on a live view the numbers still follow the window. Three legs — a latched event, a
|
||||
pause taken from it, and a live view after the trigger is switched off — each read the pane
|
||||
before and after a *gesture* written on the row's own axis (never the window control, which
|
||||
calls off the pin). The assertions, in order: the pinned legs read **`same=4/4 for_same=1
|
||||
pass_delta=0`** with `for=` still at the pin (the values bit-identical and no recompute spent on
|
||||
the gesture), and the live leg reads **`follows=1`** with `for_same=0`, `pass_delta>0` and the
|
||||
results window's span narrowed to the axis'. Its sequence is about 12 s, so
|
||||
`UDPSCOPE_EXIT_AFTER_MS=20000`; run it on the fast mock with a batch the datagram limit allows
|
||||
(`--rate 1300000 --batch 1500 --freq 1`, **not** `--batch 2000`, which is 80 kB of payload and
|
||||
dies with `Message too long`). The lines, the fields and the settle wait are in
|
||||
[probe-readings.md](probe-readings.md); the window rule itself is in
|
||||
[invariants-measurements.md](invariants-measurements.md).
|
||||
|
||||
- `[pan-probe] asked=[..] was=[..]`, `[pan-probe] after=[..] held=D asked=[..]`, then
|
||||
`[pan-probe] zoom asked=[..] after=[..] span=S window=W limited=L`
|
||||
(stderr, `UDPSCOPE_PROBE_PAN_MS`) — **`held` must be 1**: a gesture must not move a window
|
||||
|
||||
Reference in new issue
Block a user