fix: bound the density grid, and make [notrace] a reading instead of a flood
The plotter caps a density grid at kDensityCellCap now (deps/plotter), so a 2 s window with persistence on no longer scales the image with the window: the probe's four one-signal rows read 1 044 714 cells / 4 178 856 bytes where they read 2 226 150 / 8 904 600, and a moved frame uploads 1 044 714 bytes where it uploaded 2 226 150. The probe's own legs are unchanged (on peak=1.0000, step-acquisitions peak=1.5000, step-time ratio=0.367879). The paint probe no longer counts a frame the density is drawing as *traceless*. `Renderer::draw_traces()` returns while the ink is the image, so every frame of a persistence display stages no trace: the dump read `traceless paints: 653 (637 after the first bind)` for a run whose real figure is 4 (0), and the `[notrace]` line printed for each of those frames. It is now behind UDPSCOPE_PROBE_NOTRACE -- a per-paint line is a log flood and not a reading -- while the counters it details stay in every build, and the line stays reachable for the state it was written for (a bound row that draws nothing). Docs corrected where they stated the old rule: the README, the trigger invariants, the density probe's readings, the verification list (the new variable) and the manual page behind the panel's tooltip.
This commit is contained in:
1 parent
da826f2cb5
commit
ac054a30c9
11 files changed
+131
-76
No files matched your search
@@ -1271,8 +1271,10 @@ snapshots there and then, because a trigger that has stopped firing never reache
|
|||||||
|
|
||||||
**Persistence: one image per signal, every acquisition.** The trigger panel's `Advanced` block
|
**Persistence: one image per signal, every acquisition.** The trigger panel's `Advanced` block
|
||||||
carries the *other* display of the same acquisitions, and it is not a count at all: `persistence`
|
carries the *other* display of the same acquisitions, and it is not a count at all: `persistence`
|
||||||
turns on a **phosphor density** — the plotter's screen-sized intensity image (`Plot::set_density()`,
|
turns on a **phosphor density** — the plotter's intensity image (`Plot::set_density()`, the axes rect
|
||||||
one `f32` cell per device pixel of the axes rect **per trace, in that trace's own signal colour**)
|
in device pixels **per trace, in that trace's own signal colour**, bounded by the plotter's
|
||||||
|
`kDensityCellCap`: past **262 144 cells** — a mebibyte of counts — it scales the rect down uniformly
|
||||||
|
and magnifies the image back over it with a linear filter)
|
||||||
into which every triggered acquisition is deposited, the newest included, and which is drawn *in
|
into which every triggered acquisition is deposited, the newest included, and which is drawn *in
|
||||||
place of* the traces. The current acquisition is therefore a sweep *inside* the image and fades with
|
place of* the traces. The current acquisition is therefore a sweep *inside* the image and fades with
|
||||||
the rest; no solid polyline is drawn over it, which is what a report of "the persistent image plus
|
the rest; no solid polyline is drawn over it, which is what a report of "the persistent image plus
|
||||||
@@ -1280,20 +1282,24 @@ the last acquisition, and the last one never fades in time mode" turned out to b
|
|||||||
brightness is how many acquisitions passed through it — one sweep's ink is the trace's own colour,
|
brightness is how many acquisitions passed through it — one sweep's ink is the trace's own colour,
|
||||||
and where several agree it clamps there rather than going white — so the display brightens where the
|
and where several agree it clamps there rather than going white — so the display brightens where the
|
||||||
signal is steady and dims where it only passed, **with no depth to choose and no memory that grows
|
signal is steady and dims where it only passed, **with no depth to choose and no memory that grows
|
||||||
with the acquisitions**: the cost is the screen's times the traces on it (2.2 MB over the probe's
|
with the acquisitions**: the cost is bounded, and the bound is the grid's — at most a mebibyte of
|
||||||
four one-signal rows; the default four signals in one 800x480 row are 6 MB) and a thousand
|
counts a signal, so the app's four signals hold 4 MiB between them however wide the window, and the
|
||||||
acquisitions cost the same. Each signal is a separate image, so two signals agreeing in a cell read
|
probe's four one-signal rows read `cells=1044714` (4 178 856 bytes, 1 044 714 of them uploaded on a
|
||||||
as two colours and not one blended grey. `fades by` picks how it decays: `acquisitions` (each
|
moved frame) — and a thousand acquisitions cost the same. Each signal is a separate image, so two
|
||||||
acquisition keeps the factor of what was before it, 0.5 by default — the phosphor afterglow
|
signals agreeing in a cell read as two colours and not one blended grey. `fades by` picks how it
|
||||||
schedule) or `time` (a time constant in stream seconds, so the display fades while you watch
|
decays: `acquisitions` (each acquisition keeps the factor of what was before it, 0.5 by default —
|
||||||
whatever the trigger rate). It applies in **trigger mode only** — while a captured acquisition is
|
the phosphor afterglow schedule) or `time` (a time constant in stream seconds, so the display fades
|
||||||
on screen — and it goes away with the trigger, on a pause and on an opened file, because the image
|
while you watch whatever the trigger rate). It applies in **trigger mode only** — while a captured
|
||||||
is an image *of* a stream of acquisitions. Like the invalid-span bands it reserves no layout space
|
acquisition is on screen — and it goes away with the trigger, on a pause and on an opened file,
|
||||||
and nothing on it can be picked. The `[density-probe]` run that measured it is in
|
because the image is an image *of* a stream of acquisitions. Like the invalid-span bands it reserves
|
||||||
`docs/claude/probe-readings.md`; what it costs is in the same place (`[density-probe] frame cost:`:
|
no layout space and nothing on it can be picked. The `[density-probe]` run that measured it is in
|
||||||
tick 0.74 → 9.99 ms and draw 2.09 → 20.91 ms over the same run, at four rows and 2.2 M cells a
|
`docs/claude/probe-readings.md`; what it costs is there and in the plotter's
|
||||||
frame, on llvmpipe — measured before the per-trace split, when the one image was still re-filled
|
`docs/data-and-performance.md`, where the density's own pass is priced headless at a fixed geometry —
|
||||||
per row).
|
the app's in-run A/B of it is a mean against a mean and the "before" side includes the run's own
|
||||||
|
startup frames. A 3040x1700 framebuffer with four rows of one trace and a 2 s window (the frozen
|
||||||
|
configuration: at 2x device scale that is a 1520x850 window) read **4.5 M cells a trace, 12.9 ms of
|
||||||
|
tick and 12.8 ms of draw a frame and 4.9 MB uploaded** on llvmpipe, and reads **1.0 M cells, 3.9 /
|
||||||
|
5.6 ms and 1.0 MB** at the cap.
|
||||||
|
|
||||||
**And it says what it costs.** A retained acquisition is a whole window copied out of the ring, so
|
**And it says what it costs.** A retained acquisition is a whole window copied out of the ring, so
|
||||||
the retention is bounded by two things: the depth, and **`--buffer-mb`** — persistence may hold at
|
the retention is bounded by two things: the depth, and **`--buffer-mb`** — persistence may hold at
|
||||||
|
|||||||
Vendored
+1
-1
Submodule deps/plotter updated: 1b8b55d3ee...f79a97be9b.
@@ -379,13 +379,16 @@ Part of [CLAUDE.md](../../CLAUDE.md). These are rules that cost a defect to lear
|
|||||||
- **The phosphor density is the *trace*, and that is a different display from the layers above, not a
|
- **The phosphor density is the *trace*, and that is a different display from the layers above, not a
|
||||||
mode of them.** The trigger panel's `Advanced` block offers both, and the words matter: *multiple
|
mode of them.** The trigger panel's `Advanced` block offers both, and the words matter: *multiple
|
||||||
events* is `persist_depth` (N retained acquisitions, N traces, dimmer with age) while *persistence*
|
events* is `persist_depth` (N retained acquisitions, N traces, dimmer with age) while *persistence*
|
||||||
is `TriggerConfig::density` -- the plotter's `Plot::set_density()`, a screen-sized intensity grid
|
is `TriggerConfig::density` -- the plotter's `Plot::set_density()`, an intensity grid
|
||||||
**per trace, drawn in that trace's own colour**, every acquisition deposited into it, which fades
|
**per trace, drawn in that trace's own colour**, every acquisition deposited into it, which fades
|
||||||
either by a time constant or by a per-acquisition factor. There is **no depth** on the density and
|
either by a time constant or by a per-acquisition factor. There is **no depth** on the density and
|
||||||
no per-acquisition memory: the image is `traces * columns * rows * 4` bytes, one cell per device
|
no per-acquisition memory: the image is `traces * columns * rows * 4` bytes, and both factors are
|
||||||
pixel of the row's axes for every trace the row draws (the app's default four signals in one row
|
bounded -- the grid is the row's axes rect in device pixels **up to the plotter's
|
||||||
are four grids -- 6 MB at 800x480; the probe's one-signal-per-row run is 2.2 MB over four rows), so
|
`kDensityCellCap`**, and there is one grid a trace the row draws. Four traces in a row
|
||||||
a thousand acquisitions cost what one costs. A cell's value is a number of *sweeps*: the library
|
therefore hold at most 4 MiB between them, whoever dragged the window where (the probe's
|
||||||
|
one-signal-per-row run reads `cells=1044714`, 4 178 856 bytes), so a thousand acquisitions cost
|
||||||
|
what one costs and *neither* a wide window nor a long run can make the image grow. A cell's value
|
||||||
|
is a number of *sweeps*: the library
|
||||||
deposits a cell once per trace per sweep however many of that trace's own samples crossed it
|
deposits a cell once per trace per sweep however many of that trace's own samples crossed it
|
||||||
(`[density-probe] on` reads `peak=1.0000` for one sweep; a per-hit deposit read 18) -- dwell is
|
(`[density-probe] on` reads `peak=1.0000` for one sweep; a per-hit deposit read 18) -- dwell is
|
||||||
`Style::intensity_grading`'s question, not this one's. The colour is the trace's own
|
`Style::intensity_grading`'s question, not this one's. The colour is the trace's own
|
||||||
|
|||||||
@@ -1981,27 +1981,29 @@ ring's bindings, and a reading taken there says nothing about either.
|
|||||||
```
|
```
|
||||||
[density-probe] arming on 'square', window 0.5 s, display off
|
[density-probe] arming on 'square', window 0.5 s, display off
|
||||||
[density-probe] off enabled=0 fade=acquisitions tau=1.000 factor=0.500 rows=0 traces=0 cells=0 ink=0.0 peak=0.0000 ratio=1.000000
|
[density-probe] off enabled=0 fade=acquisitions tau=1.000 factor=0.500 rows=0 traces=0 cells=0 ink=0.0 peak=0.0000 ratio=1.000000
|
||||||
[density-probe] on enabled=1 fade=acquisitions tau=1.000 factor=0.500 rows=4 traces=4 cells=2226150 ink=226786.0 peak=1.0000 ratio=1.000000
|
[density-probe] on enabled=1 fade=acquisitions tau=1.000 factor=0.500 rows=4 traces=4 cells=1044714 ink=99403.0 peak=1.0000 ratio=1.000000
|
||||||
[density-probe] step-acquisitions enabled=1 fade=acquisitions tau=1.000 factor=0.500 rows=4 traces=4 cells=2226150 ink=313971.0 peak=1.5000 ratio=1.384437
|
[density-probe] step-acquisitions enabled=1 fade=acquisitions tau=1.000 factor=0.500 rows=4 traces=4 cells=1044714 ink=149104.5 peak=1.5000 ratio=1.500000
|
||||||
[density-probe] time-before enabled=1 fade=time tau=1.000 factor=0.500 rows=4 traces=4 cells=2226150 ink=458610.1 peak=2.1359 ratio=1.000000
|
[density-probe] time-before enabled=1 fade=time tau=1.000 factor=0.500 rows=4 traces=4 cells=1044714 ink=121738.0 peak=1.2247 ratio=1.000000
|
||||||
[density-probe] step-time enabled=1 fade=time tau=1.000 factor=0.500 rows=4 traces=4 cells=2226150 ink=168713.2 peak=0.7858 ratio=0.367879
|
[density-probe] step-time enabled=1 fade=time tau=1.000 factor=0.500 rows=4 traces=4 cells=1044714 ink=44784.9 peak=0.4505 ratio=0.367879
|
||||||
[density-probe] frame cost: tick before=0.62 ms (184 frames) after=6.96 ms (23 frames) draw before=2.02 ms (177) after=6.16 ms (18)
|
[density-probe] frame cost: tick before=3.75 ms (145 frames) after=3.59 ms (24 frames) draw before=3.93 ms (125) after=3.23 ms (6)
|
||||||
[udpscope] density: frames=748 rows=4 traces=4 cells=2226150 grid_bytes=8904600 ink=489400.2 peak=2.2 upload_bytes=2226150
|
[udpscope] density: frames=918 rows=4 traces=4 cells=1044714 grid_bytes=4178856 ink=279073.5 peak=2.2 upload_bytes=1044714
|
||||||
```
|
```
|
||||||
|
|
||||||
The **phosphor density** (`Plot::set_density()`, the trigger pane's `persistence` switch): one
|
The **phosphor density** (`Plot::set_density()`, the trigger pane's `persistence` switch): the axes
|
||||||
screen-sized intensity image **per trace**, in that trace's own signal colour, every acquisition
|
rect in device pixels **up to `kDensityCellCap`** (262 144 cells, 1 MiB of counts) as an intensity
|
||||||
accumulated into it (the newest included), drawn *in place of* the traces and fading by a count or by
|
image **per trace**, in that trace's own signal colour, every acquisition accumulated into it (the
|
||||||
the clock. The numbers are the plotter's own -- `DensityGrid::ink()`/`peak()` summed and maxed over the
|
newest included), drawn *in place of* the traces and fading by a count or by the clock. Past the cap
|
||||||
traces the display is on, which is the same source the library's tests read -- and the
|
the plotter scales the rect down uniformly and magnifies the image back over it with a linear
|
||||||
probe drives the panel's **own widgets** for the switch and the fade, so what it measures is this app's
|
filter, so the number this probe reports is bounded whatever the window is. The numbers are the
|
||||||
wiring.
|
plotter's own -- `DensityGrid::ink()`/`peak()` summed and maxed over the traces the display is on,
|
||||||
|
which is the same source the library's tests read -- and the probe drives the panel's **own
|
||||||
|
widgets** for the switch and the fade, so what it measures is this app's wiring.
|
||||||
|
|
||||||
- **`off` is the display without it**: `rows=0 traces=0`, so there is no grid at all and both numbers
|
- **`off` is the display without it**: `rows=0 traces=0`, so there is no grid at all and both numbers
|
||||||
are zero. That is also the run the frame cost is read against, and it is a plain run -- the density
|
are zero. That is also the run the frame cost is read against, and it is a plain run -- the density
|
||||||
is off by default and nothing draws it.
|
is off by default and nothing draws it.
|
||||||
- **`on` is one sweep**: `traces=4` -- one grid per signal, four rows of one signal each -- and
|
- **`on` is one sweep**: `traces=4` -- one grid per signal, four rows of one signal each -- and
|
||||||
`peak=1.0000` exactly, with `ink=226786` the cells that sweep covered. A cell takes **1.0 once per
|
`peak=1.0000` exactly, with `ink=99403` the cells that sweep covered. A cell takes **1.0 once per
|
||||||
trace per sweep** however many of the trace's own samples crossed it, which is what makes a sweep's
|
trace per sweep** however many of the trace's own samples crossed it, which is what makes a sweep's
|
||||||
peak *one* rather than the eighteen a per-hit deposit read on the same run -- and what makes the
|
peak *one* rather than the eighteen a per-hit deposit read on the same run -- and what makes the
|
||||||
sweeps behind it visible at all.
|
sweeps behind it visible at all.
|
||||||
@@ -2013,23 +2015,34 @@ wiring.
|
|||||||
twice.
|
twice.
|
||||||
- **`step-time` is `1/e` by construction**: one step of `dt = tau` through the plot's own `decay_density()`,
|
- **`step-time` is `1/e` by construction**: one step of `dt = tau` through the plot's own `decay_density()`,
|
||||||
so `ratio=0.367879` is `exp(-1)`. The leg before it (`time-before`) reads the same image under the time
|
so `ratio=0.367879` is `exp(-1)`. The leg before it (`time-before`) reads the same image under the time
|
||||||
fade (`peak=2.1359`), and the pair is the reading that says the *panel's* constant reaches the grid.
|
fade (a peak between 1 and 2, `1.2247` here), and the pair is the reading that says the *panel's* constant
|
||||||
|
reaches the grid.
|
||||||
- **`frame cost:` is the A/B inside one run**: the accumulators as of the tick the display was switched on
|
- **`frame cost:` is the A/B inside one run**: the accumulators as of the tick the display was switched on
|
||||||
against the frames after it, so both means are the same stream, the same layout and the same mock. At four
|
against the frames after it, so both means are the same stream, the same layout and the same mock. The
|
||||||
rows of 573x412 cells it reads **tick 0.62 -> 6.96 ms** and **draw 2.02 -> 6.16 ms**: the per-frame
|
"before" side is a mean that **includes the run's startup frames** (the first paints are the expensive
|
||||||
conversion, upload and deposit. It is llvmpipe, and the arithmetic is the grid's -- 2.2 M cells, one byte
|
ones), so it is a high-water mark and not a steady-state mean: at four rows of ~261 000 cells each (the
|
||||||
each, every frame the time fade moves it. The *draw* mean is now below the run before the per-trace
|
cap) the pair above reads `tick 3.75 -> 3.59 ms`, i.e. the switch is *inside* the startup noise, and a
|
||||||
split (2.02 -> 6.16 against 2.09 -> 20.91): the solid traces are no longer drawn over the image, so the
|
quiet machine reading the same line before the cap read `tick 0.62 -> 9.53 ms` at 2.2 M cells. **The
|
||||||
frame draws four quads where it used to draw four quads *and* every trace.
|
reading that prices a display at a given window is the library's**, taken headless and against a fixed
|
||||||
- **`cells`/`grid_bytes` are the per-signal memory figure**: 556 537 cells and 2.2 MB *per signal*, times
|
geometry, in the plotter's `docs/data-and-performance.md`: a 3040x1700 framebuffer with four rows of one
|
||||||
the four signals here (2 226 150 cells, 8 904 600 bytes). It is the axes rect's device pixels, so it is
|
trace and a 2 s window, where the grid pass alone was **12.9 ms of tick and 12.8 ms of draw a frame and
|
||||||
the screen and the trace count and nothing the trigger has done -- and the app's default layout, four
|
4.9 MB uploaded** before the cap and **3.9 / 5.6 ms and 1.0 MB** after it, over the same frames.
|
||||||
signals in one row, is four grids for that one row.
|
- **`cells`/`grid_bytes` are the per-signal memory figure**: at most **262 144 cells and 1 048 576 bytes
|
||||||
|
*per signal***, and the four signals here read 1 044 714 cells / 4 178 856 bytes because a 1349x424 device
|
||||||
|
axes rect is already past the cap. It is the cap and the trace count, and neither the trigger nor the
|
||||||
|
window beyond the cap has anything to say about it -- the app's default layout, four signals in one row,
|
||||||
|
is four grids for that one row and 4 MiB whoever dragged the window where.
|
||||||
- **The dump's `density:` line** is captured on the last tick the display was **on**, not read at exit: the
|
- **The dump's `density:` line** is captured on the last tick the display was **on**, not read at exit: the
|
||||||
exit probe switches the trigger off before it dumps, which takes the display with it, so a dump that asked
|
exit probe switches the trigger off before it dumps, which takes the display with it, so a dump that asked
|
||||||
the plots would say `rows=0` about a run whose tail had the image up. `upload_bytes` is the **most** any
|
the plots would say `rows=0` about a run whose tail had the image up. `upload_bytes` is the **most** any
|
||||||
one frame uploaded -- one byte a cell **per trace**, over the grids that moved -- and not the last frame's,
|
one frame uploaded -- one byte a cell **per trace**, over the grids that moved -- and not the last frame's,
|
||||||
for the same reason.
|
for the same reason.
|
||||||
|
- **A frame the display is drawing is not a `[notrace]` frame.** `Renderer::draw_traces()` returns while a
|
||||||
|
density is on, so every frame of a persistence display stages no trace; the paint probe skips its
|
||||||
|
traceless accounting for those (they are the display working, not "a frame asked to draw something it had
|
||||||
|
nothing for") and the `[notrace]` line -- one per frame, and so behind `UDPSCOPE_PROBE_NOTRACE` -- is not
|
||||||
|
printed for them. A density run's `traceless paints:` therefore no longer counts them: it read `653 (637
|
||||||
|
after the first bind)` for a run whose density was up six hundred frames.
|
||||||
|
|
||||||
**Read `peak` as the display's ceiling**: with the default `full_scale` of 1.0 a cell at 1.0 is full ink
|
**Read `peak` as the display's ceiling**: with the default `full_scale` of 1.0 a cell at 1.0 is full ink
|
||||||
(the trace's own colour), so a steady display under the acquisition fade sits between 1 and 2, and a `peak`
|
(the trace's own colour), so a steady display under the acquisition fade sits between 1 and 2, and a `peak`
|
||||||
|
|||||||
@@ -115,7 +115,9 @@ precedent, not an exception.
|
|||||||
schedule in use, oldest first — halves, and `1/2^age` at that. Both lines and the two exit-dump
|
schedule in use, oldest first — halves, and `1/2^age` at that. Both lines and the two exit-dump
|
||||||
lines are in [probe-readings.md](probe-readings.md).
|
lines are in [probe-readings.md](probe-readings.md).
|
||||||
- `UDPSCOPE_PROBE_DENSITY_MS` (+ `UDPSCOPE_PROBE_DENSITY_TAU`, default 1.0 s) — the **phosphor
|
- `UDPSCOPE_PROBE_DENSITY_MS` (+ `UDPSCOPE_PROBE_DENSITY_TAU`, default 1.0 s) — the **phosphor
|
||||||
density**: one screen-sized intensity image **per trace**, in that trace's own colour, every
|
density**: an intensity image **per trace**, in that trace's own colour, the axes rect in device
|
||||||
|
pixels up to the plotter's `kDensityCellCap` (past which it scales the rect down uniformly and
|
||||||
|
magnifies the image back over it with a linear filter), every
|
||||||
triggered acquisition accumulated into it (the newest included), drawn *in place of* the traces,
|
triggered acquisition accumulated into it (the newest included), drawn *in place of* the traces,
|
||||||
fading by a per-acquisition factor or by a time constant. It states the display
|
fading by a per-acquisition factor or by a time constant. It states the display
|
||||||
**off** through the panel's own switch first, so the `off` leg is the run without it, then arms the
|
**off** through the panel's own switch first, so the `off` leg is the run without it, then arms the
|
||||||
@@ -144,6 +146,15 @@ precedent, not an exception.
|
|||||||
one run), and the exit dump's `density:` line says what the last frame it was on held. Both lines
|
one run), and the exit dump's `density:` line says what the last frame it was on held. Both lines
|
||||||
and the dump line are in [probe-readings.md](probe-readings.md).
|
and the dump line are in [probe-readings.md](probe-readings.md).
|
||||||
|
|
||||||
|
- `UDPSCOPE_PROBE_NOTRACE` (no value; **not** a scheduled probe, and off unless it is set) — the
|
||||||
|
per-paint detail behind the exit dump's `traceless paints:` counter: one `[notrace]` line for each
|
||||||
|
of the first 40 paints after the first bind that staged no trace, naming the mode, the axis the
|
||||||
|
frame was asked for and every slot's bounds. It is behind a variable because a state that draws
|
||||||
|
nothing lasts as long as it lasts, so an ungated line is one per frame for the whole time -- and it
|
||||||
|
is *not* printed for a frame a phosphor density is drawing, which stages no trace by construction
|
||||||
|
(the frame's ink is the image) and would otherwise be counted as well. The counter itself is in
|
||||||
|
every build; see [probe-readings.md](probe-readings.md).
|
||||||
|
|
||||||
- `UDPSCOPE_PROBE_TRIGRENUM_MS` — the trigger's capture must survive a **renumbering of its own
|
- `UDPSCOPE_PROBE_TRIGRENUM_MS` — the trigger's capture must survive a **renumbering of its own
|
||||||
channel**. It sets the reported geometry through the real widgets (1 s window, 10 % pre share,
|
channel**. It sets the reported geometry through the real widgets (1 s window, 10 % pre share,
|
||||||
hold-off from `--holdoff`) on the mock's *square* alone, polls for a capture to open, and then
|
hold-off from `--holdoff`) on the mock's *square* alone, polls for a capture to open, and then
|
||||||
|
|||||||
@@ -133,9 +133,10 @@
|
|||||||
|
|
||||||
<p>Two things make it different from <gui>multiple events</gui> beside it, and the panel offers
|
<p>Two things make it different from <gui>multiple events</gui> beside it, and the panel offers
|
||||||
both because they answer different questions. <em>It never runs out of room</em>: each signal's
|
both because they answer different questions. <em>It never runs out of room</em>: each signal's
|
||||||
image is the size of the plot on screen, so a display of a thousand acquisitions costs what a
|
image is sized to the plot on screen and capped, so a display of a thousand acquisitions costs
|
||||||
display of one costs — one image per signal, whatever the plot's trace slots — and there is no
|
what a display of one costs — one image per signal, whatever the plot's trace slots, and a very
|
||||||
count to choose. <em>And it fades</em>, in one of two ways — <gui>fades by</gui> picks them:</p>
|
wide window does not make it grow — and there is no count to choose. <em>And it fades</em>, in
|
||||||
|
one of two ways — <gui>fades by</gui> picks them:</p>
|
||||||
<list>
|
<list>
|
||||||
<item><p><gui>acquisitions</gui>: every acquisition keeps
|
<item><p><gui>acquisitions</gui>: every acquisition keeps
|
||||||
<gui>per acquisition</gui> of what was there before it (0.5, the default, is the schedule a
|
<gui>per acquisition</gui> of what was there before it (0.5, the default, is the schedule a
|
||||||
|
|||||||
@@ -102,8 +102,8 @@ struct LayoutState {
|
|||||||
/// for: it is what the display does with the acquisitions, and there is no second switch.
|
/// for: it is what the display does with the acquisitions, and there is no second switch.
|
||||||
///
|
///
|
||||||
/// This is the **multiple event** display -- N retained acquisitions, drawn as N traces. The
|
/// This is the **multiple event** display -- N retained acquisitions, drawn as N traces. The
|
||||||
/// phosphor density beside it is a different display with a different cost (one screen-sized
|
/// phosphor density beside it is a different display with a different cost (one bounded image a
|
||||||
/// image against N window copies), which is why it has its own four fields below and why this
|
/// trace against N window copies), which is why it has its own four fields below and why this
|
||||||
/// one keeps the key it has always had: an older file's `trigger_persistence` is still the
|
/// one keeps the key it has always had: an older file's `trigger_persistence` is still the
|
||||||
/// multiple-event depth.
|
/// multiple-event depth.
|
||||||
int persistence = 1;
|
int persistence = 1;
|
||||||
|
|||||||
+2
-1
@@ -55,7 +55,8 @@ struct TriggerConfig {
|
|||||||
|
|
||||||
/// The **phosphor density** (the plotter's `Plot::set_density()`): off by default, and trigger
|
/// The **phosphor density** (the plotter's `Plot::set_density()`): off by default, and trigger
|
||||||
/// mode only. Where `persist_depth` keeps N whole acquisitions as N traces, this accumulates
|
/// mode only. Where `persist_depth` keeps N whole acquisitions as N traces, this accumulates
|
||||||
/// every acquisition into one screen-sized intensity image -- brightness is how often a trace
|
/// every acquisition into one intensity image **per trace** (the axes rect in device pixels,
|
||||||
|
/// bounded by the plotter's `kDensityCellCap`) -- brightness is how often a trace
|
||||||
/// passed a cell, so the cost of a display of a thousand acquisitions is the cost of one, and
|
/// passed a cell, so the cost of a display of a thousand acquisitions is the cost of one, and
|
||||||
/// there is no depth to get wrong. The image is drawn behind the traces, it is unpickable and it
|
/// there is no depth to get wrong. The image is drawn behind the traces, it is unpickable and it
|
||||||
/// reserves no layout space, exactly as the invalid-span bands do.
|
/// reserves no layout space, exactly as the invalid-span bands do.
|
||||||
|
|||||||
@@ -217,7 +217,7 @@
|
|||||||
|
|
||||||
Both displays live here and they are two different things: *multiple events* keeps the
|
Both displays live here and they are two different things: *multiple events* keeps the
|
||||||
last N acquisitions as N traces, dimmer with age, while *persistence* accumulates every
|
last N acquisitions as N traces, dimmer with age, while *persistence* accumulates every
|
||||||
acquisition into an image (one screen-sized grid per trace, in that trace's own colour,
|
acquisition into an image (one grid per trace, in that trace's own colour,
|
||||||
the plotter's `Plot::set_density()`), drawn in place of the traces. The first is a
|
the plotter's `Plot::set_density()`), drawn in place of the traces. The first is a
|
||||||
count and the second is a decay, which is why neither is a mode of the other. -->
|
count and the second is a decay, which is why neither is a mode of the other. -->
|
||||||
<object class="GtkExpander" id="advanced_exp">
|
<object class="GtkExpander" id="advanced_exp">
|
||||||
|
|||||||
+39
-19
@@ -40,26 +40,46 @@ int on_render_probe(GtkGLArea*, GdkGLContext*, gpointer user) {
|
|||||||
if (s.graded_traces > 0) ++app->dbg_graded_frames;
|
if (s.graded_traces > 0) ++app->dbg_graded_frames;
|
||||||
if (s.raw_traces > 0 || s.lod_traces > 0) check_frame_ink(*app);
|
if (s.raw_traces > 0 || s.lod_traces > 0) check_frame_ink(*app);
|
||||||
if (s.raw_traces == 0 && s.lod_traces == 0) {
|
if (s.raw_traces == 0 && s.lod_traces == 0) {
|
||||||
++app->dbg_notrace_frames;
|
// **A frame the density is drawing is not a traceless one.** `Renderer::draw_traces()`
|
||||||
app->dbg_notrace_last = app->dbg_paint_n;
|
// returns while a plot's phosphor density is on -- the trace ink *is* the image -- so every
|
||||||
if (app->dbg_ever_bound) {
|
// frame of a persistence display stages no trace and would be counted here, which inflates
|
||||||
++app->dbg_notrace_after_bound;
|
// the dump's reading and (with `UDPSCOPE_PROBE_NOTRACE` set below) prints a line per frame.
|
||||||
// What the frame was asked to draw, beside what there was to draw it from: an axis
|
// That is the display working, not "what the frame was asked to draw" with nothing to draw
|
||||||
// that left the data and a trace that had nothing bound are the same picture and
|
// it from. Read off the plots, because the frame's own stats can only say no trace was
|
||||||
// different bugs, so both are named here rather than inferred from the count.
|
// drawn and not why.
|
||||||
if (app->dbg_notrace_after_bound <= 40) {
|
bool density_on = false;
|
||||||
const RowSet::Row& r = app->rows->row(0);
|
for (int i = 0; i < app->rows->row_count() && !density_on; ++i) {
|
||||||
const plot::Range ax = r.plot != nullptr ? r.plot->x_range(r.axis_x) : plot::Range{};
|
const plot::Plot* p = app->rows->row(i).plot;
|
||||||
std::fprintf(stderr, "[notrace] paint %d mode=%s axis=[%.6f..%.6f] segments=%u",
|
density_on = p != nullptr && p->density().enabled;
|
||||||
app->dbg_paint_n, display_mode_name(app->dbg_display), ax.min, ax.max,
|
}
|
||||||
s.staged_segments);
|
if (!density_on) {
|
||||||
for (int sl = 0; sl < RowSet::kSlotsPerRow; ++sl) {
|
++app->dbg_notrace_frames;
|
||||||
if (r.channel[static_cast<std::size_t>(sl)] < 0) continue;
|
app->dbg_notrace_last = app->dbg_paint_n;
|
||||||
const plot::Range b = r.slots[static_cast<std::size_t>(sl)].x_bounds();
|
if (app->dbg_ever_bound) {
|
||||||
std::fprintf(stderr, " slot%d n=%zu x=[%.6f..%.6f]", sl,
|
++app->dbg_notrace_after_bound;
|
||||||
r.slots[static_cast<std::size_t>(sl)].size(), b.min, b.max);
|
// What the frame was asked to draw, beside what there was to draw it from: an axis
|
||||||
|
// that left the data and a trace that had nothing bound are the same picture and
|
||||||
|
// different bugs, so both are named here rather than inferred from the count.
|
||||||
|
//
|
||||||
|
// **A per-paint line, so it is behind a variable** (`UDPSCOPE_PROBE_NOTRACE`), unlike
|
||||||
|
// the counters beside it: a state that draws nothing lasts as long as it lasts -- a
|
||||||
|
// `Waiting` tail, a bound row with no data -- and the line would be one per frame the
|
||||||
|
// whole time. The count in the dump is the reading; this is the detail behind it.
|
||||||
|
static const bool notrace_print = g_getenv("UDPSCOPE_PROBE_NOTRACE") != nullptr;
|
||||||
|
if (notrace_print && app->dbg_notrace_after_bound <= 40) {
|
||||||
|
const RowSet::Row& r = app->rows->row(0);
|
||||||
|
const plot::Range ax = r.plot != nullptr ? r.plot->x_range(r.axis_x) : plot::Range{};
|
||||||
|
std::fprintf(stderr, "[notrace] paint %d mode=%s axis=[%.6f..%.6f] segments=%u",
|
||||||
|
app->dbg_paint_n, display_mode_name(app->dbg_display), ax.min, ax.max,
|
||||||
|
s.staged_segments);
|
||||||
|
for (int sl = 0; sl < RowSet::kSlotsPerRow; ++sl) {
|
||||||
|
if (r.channel[static_cast<std::size_t>(sl)] < 0) continue;
|
||||||
|
const plot::Range b = r.slots[static_cast<std::size_t>(sl)].x_bounds();
|
||||||
|
std::fprintf(stderr, " slot%d n=%zu x=[%.6f..%.6f]", sl,
|
||||||
|
r.slots[static_cast<std::size_t>(sl)].size(), b.min, b.max);
|
||||||
|
}
|
||||||
|
std::fprintf(stderr, "\n");
|
||||||
}
|
}
|
||||||
std::fprintf(stderr, "\n");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -756,7 +756,7 @@ GtkWidget* build_trigger_panel(App& app) {
|
|||||||
"acquisitions are also bounded by the buffer's own size");
|
"acquisitions are also bounded by the buffer's own size");
|
||||||
app.trigger_persist_row = row_for(ui, "persistence_row", app.trigger_persist_spin);
|
app.trigger_persist_row = row_for(ui, "persistence_row", app.trigger_persist_spin);
|
||||||
|
|
||||||
// The phosphor *density*: one screen-sized image per trace, in that trace's own colour, every
|
// The phosphor *density*: one bounded image per trace, in that trace's own colour, every
|
||||||
// acquisition accumulated into it, drawn *in place of* the traces and fading by a time constant
|
// acquisition accumulated into it, drawn *in place of* the traces and fading by a time constant
|
||||||
// or by a per-acquisition factor -- the other display of the same acquisitions, and nothing like
|
// or by a per-acquisition factor -- the other display of the same acquisitions, and nothing like
|
||||||
// the multiple-event one above (an image per signal against N retained traces, and no count to
|
// the multiple-event one above (an image per signal against N retained traces, and no count to
|
||||||
@@ -772,7 +772,7 @@ GtkWidget* build_trigger_panel(App& app) {
|
|||||||
}
|
}
|
||||||
gtk_widget_set_tooltip_text(
|
gtk_widget_set_tooltip_text(
|
||||||
app.trigger_density_switch,
|
app.trigger_density_switch,
|
||||||
"accumulate every triggered acquisition into a screen-sized image per signal, in that "
|
"accumulate every triggered acquisition into an image per signal, in that "
|
||||||
"signal's own colour, drawn in place of the traces: brightness is how often a trace passed, "
|
"signal's own colour, drawn in place of the traces: brightness is how often a trace passed, "
|
||||||
"so an image of a thousand acquisitions costs what one costs. Trigger mode only, and cleared "
|
"so an image of a thousand acquisitions costs what one costs. Trigger mode only, and cleared "
|
||||||
"whenever the display leaves it");
|
"whenever the display leaves it");
|
||||||
|
|||||||
Reference in new issue
Block a user