docs: the five reseq probe cases as this build measures them, plus the overflow counter's reading

Re-measured all four recorded cases and added a fifth for the re-plan path,
which needs 100 kS/s: at 10 kS/s the ring already covers 838 s, so no window
the control can reach moves time_stride and the window probe re-plans nothing.
Also notes that `stale` is 0 by construction while resequencing is on, and that
the reservation cap is counted in packets, so its sample cost scales with the
batch.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Martino FerrariandClaude Opus 4.6 committed 2026-10-09 06:52:31 +02:00
1 parent d2d4b7f204
commit 210d124814
3 files changed
+111 -48

No files matched your search

+58 -32
View File
@@ -201,58 +201,84 @@ as distinct from the fault injection below, which exercises ingest:
- `--quiet-at S` freezes `sine` at its held value from stream second `S` onwards, so it stops
crossing zero: the dropout trigger's input.
- `UDPSCOPE_PROBE_RESEQ_MS` — one mid-run reading of the resequencing path. Four cases,
**run each as its own process** — four back to back starve the mock past its 2 s silence
- `UDPSCOPE_PROBE_RESEQ_MS` — one mid-run reading of the resequencing path. Five cases,
**run each as its own process** — five back to back starve the mock past its 2 s silence
timeout and every case then reads a reconnect instead of what it was testing. Common
conditions for all four: the mock at `--rate 10000 --batch 100 --freq 5`, udpscope with
conditions for the first four: the mock at `--rate 10000 --batch 100 --freq 5`, udpscope with
no extra options, under `xvfb-run` with
`UDPSCOPE_EXIT_AFTER_MS=8000 UDPSCOPE_ENABLE_ALL_MS=600 UDPSCOPE_EXIT_DUMP=1
UDPSCOPE_PROBE_RESEQ_MS=5000`.
UDPSCOPE_PROBE_RESEQ_MS=5000`. Delete `~/.config/udpscope/127.0.0.1_8000.toml` first: a
session left by an earlier run restores its math channel, and five channels instead of four
change `channels=`, `span=` and every count derived from them.
| case | mock extra flags | key reading |
| --- | --- | --- |
| **base** | *(none)* | every counter 0; proves the machinery costs nothing |
| **reorder** | `--reorder-every 10` | `reseq=51` (mid-run) / `102` (dump); `holes=0`; resequencing inside the window leaves no reservation |
| **late** | `--reorder-every 10 --reorder-delay-ms 50` | `holes=42 bands=42 bands_repaired=42 nan_slots=0`; every band is the faint, repaired tier |
| **mixed** | `--drop-every 20 --reorder-every 10 --reorder-delay-ms 50` | `bands=42 bands_repaired=20 nan_slots=2300`; all three band states at once |
| **late** | `--reorder-every 10 --reorder-delay-ms 50` | `bands_repaired` one short of `bands` with `nan_slots=100`; the band still solid is the one hole whose late packet is in flight, and it is the *only* unrepaired one |
| **mixed** | `--drop-every 20 --reorder-every 10 --reorder-delay-ms 50` | `bands=43 bands_repaired=20 nan_slots=2200`; all three band states at once |
| **re-plan** | `--rate 100000` with the `mixed` flags, and `UDPSCOPE_PROBE_WINDOW_MS=4000 UDPSCOPE_PROBE_RESEQ_MS=6000 UDPSCOPE_EXIT_AFTER_MS=9000` | four `buffer rebuilt` lines before the reading, then `bands=64 bands_repaired=16 nan_slots=7800`: **a band is still only marked repaired when its own slots hold values**. A `bands_repaired == bands` beside a non-zero `nan_slots` here is the hole table and the producer's `tick_` surviving a re-plan that reset `produced()` — a band marked settled over samples that are all still NaN. The non-zero `overflows` is this case too: 100 kS/s with a 50 ms reorder delay keeps about 50 packets in flight against 64 slots |
Full measured readings (probe line first, then exit-dump; `bands_repaired` was added after the
original probe and any earlier reading without it is obsolete):
The re-plan case needs `--rate 100000`, not the other four's 10 000: at 10 kS/s the ring
already covers 838 s, so no window the control can reach moves `time_stride`,
`set_target_span()` returns without rebuilding, and the window probe reports `decim=1`
throughout — it re-plans nothing. At 100 kS/s the ring covers 83.9 s and the probe's
500 ms → 500 s → 120 s → 600 s → 60 s walk crosses the boundary four times.
Full measured readings (probe line first, then exit-dump):
```
=== base mock: none
[reseq-probe] reseq=0 late=0 stale=0 holes=0 hole_slots=0 backfilled=0 open_holes=0 bands=0
bands_repaired=0 nan_slots=0 scanned=44000 trigger_in_hole=0
[udpscope] frames=1024 packets=1025 gaps=0 channels=4 span=838.861s stride=1 reseq=0 late=0
stale=0 holes=0 hole_slots=0 backfilled=0
[udpscope] channel 0 'sine' stored=95200 published=95000
[reseq-probe] reseq=0 late=0 stale=0 overflows=0 holes=0 hole_slots=0 backfilled=0 open_holes=0
bands=0 bands_repaired=0 nan_slots=0 scanned=44200 trigger_in_hole=0
[udpscope] frames=1032 packets=1033 gaps=0 channels=4 span=838.861s stride=1 reseq=0 late=0
stale=0 overflows=0 holes=0 hole_slots=0 backfilled=0
[udpscope] channel 0 'sine' stored=95700 published=95400
=== reorder mock: --reorder-every 10
[reseq-probe] reseq=51 late=0 stale=0 holes=0 hole_slots=0 backfilled=0 open_holes=0 bands=0
bands_repaired=0 nan_slots=0 scanned=44000 trigger_in_hole=0
[udpscope] frames=1028 packets=1029 gaps=0 channels=4 span=838.861s stride=1 reseq=102 late=0
stale=0 holes=0 hole_slots=0 backfilled=0
[udpscope] channel 0 'sine' stored=95400 published=95100
[reseq-probe] reseq=51 late=0 stale=0 overflows=0 holes=0 hole_slots=0 backfilled=0
open_holes=0 bands=0 bands_repaired=0 nan_slots=0 scanned=44200
trigger_in_hole=0
[udpscope] frames=1027 packets=1028 gaps=0 channels=4 span=838.861s stride=1 reseq=102 late=0
stale=0 overflows=0 holes=0 hole_slots=0 backfilled=0
[udpscope] channel 0 'sine' stored=95300 published=95100
=== late mock: --reorder-every 10 --reorder-delay-ms 50
[reseq-probe] reseq=142 late=48 stale=0 holes=42 hole_slots=4200 backfilled=16800 open_holes=42
bands=42 bands_repaired=42 nan_slots=0 scanned=44000 trigger_in_hole=0
[udpscope] frames=1026 packets=1027 gaps=100 channels=4 span=838.861s stride=1 reseq=288
late=100 stale=0 holes=94 hole_slots=9400 backfilled=37600
[udpscope] channel 0 'sine' stored=95700 published=95500
[reseq-probe] reseq=157 late=46 stale=0 overflows=0 holes=40 hole_slots=4000 backfilled=15600
open_holes=40 bands=40 bands_repaired=39 nan_slots=100 scanned=44000
trigger_in_hole=0
[udpscope] frames=1027 packets=1028 gaps=98 channels=4 span=838.861s stride=1 reseq=296
late=98 stale=0 overflows=0 holes=91 hole_slots=9100 backfilled=36400
[udpscope] channel 0 'sine' stored=95300 published=95000
=== mixed mock: --drop-every 20 --reorder-every 10 --reorder-delay-ms 50
[reseq-probe] reseq=163 late=24 stale=0 holes=43 hole_slots=4300 backfilled=8000 open_holes=43
bands=42 bands_repaired=20 nan_slots=2300 scanned=44100 trigger_in_hole=0
[udpscope] frames=974 packets=975 gaps=101 channels=4 span=838.861s stride=1 reseq=314 late=50
stale=0 holes=94 hole_slots=9400 backfilled=18400
[udpscope] channel 0 'sine' stored=95100 published=94900
[reseq-probe] reseq=159 late=25 stale=0 overflows=0 holes=43 hole_slots=4300 backfilled=8400
open_holes=43 bands=43 bands_repaired=20 nan_slots=2200 scanned=44100
trigger_in_hole=0
[udpscope] frames=978 packets=981 gaps=101 channels=4 span=838.861s stride=1 reseq=309 late=50
stale=0 overflows=0 holes=94 hole_slots=9400 backfilled=18400
[udpscope] channel 0 'sine' stored=95400 published=95400
=== re-plan mock: --rate 100000 --drop-every 20 --reorder-every 10 --reorder-delay-ms 50
[reseq-probe] reseq=4374 late=72 stale=0 overflows=36 holes=315 hole_slots=31136
backfilled=26800 open_holes=64 bands=64 bands_repaired=16 nan_slots=7800
scanned=156600 trigger_in_hole=0
[udpscope] frames=8949 packets=8953 gaps=614 channels=4 span=83.886s stride=1 reseq=8028
late=144 stale=0 overflows=36 holes=603 hole_slots=59936 backfilled=55600
[udpscope] channel 0 'sine' stored=588600 published=584600
```
The `mixed` case's `open_holes=43` against `bands=42` is correct: the 43rd hole has scrolled
out of the visible window, and `build_invalid_spans()` drops a span outside the window rather
than pinning it to the edge. The per-field reference is in
[probe-readings.md](probe-readings.md).
The `late` case's `bands_repaired` is one short of `bands` with `nan_slots=100` — exactly one
packet's worth of slots at stride 1 — because the probe fires 50 ms-delayed releases into a
window that always has one in flight. An earlier recording of this case read
`bands_repaired=42 nan_slots=0`; both are healthy, and which one a run gets is where the
probe's instant falls relative to the newest release. A `bands_repaired` *above* the count of
holes whose slots hold values is the defect, in either direction.
`holes` far above `open_holes` in the re-plan case is the two bounds working: a re-plan clears
the table (the old entries address a buffer that is gone) and `kMaxHoles` caps what survives
at 64. The `mixed` case's `open_holes=43` against `bands=43` has no such spread because
nothing re-planned. The per-field reference is in [probe-readings.md](probe-readings.md).
The mock also carries three **fault injections** that no probe schedules, because what they exercise
is the ingest rather than the UI. The first: `--time-glitch-at <stream seconds> --time-glitch-by <seconds>` makes