Files
TeslaRel410/emulator/render-bridge/GAUGE-CADENCE-NOTES.md
T
CydandClaude Fable 5 0e763fda1f BT410 5.3.113: the displays lag because the loop is slow, and the loop was slow because the flags were wrong -- authentic OPT.MAK optimizer set adopted
The operator's 'many seconds between display updates', run to ground:

MECHANISM (verified in source AND the shipped exe bytes): main passes
GetTicksPerSecond() as ApplicationManager's frame RATE, so frameDuration
is microscopic and RunMissions runs flat-out -- exactly ONE background
slot per loop frame, shipped and ours alike (ctor constant @0044f2d8 ==
1.0f, read straight out of BTL4OPT.EXE). That slot feeds a 7-task ring;
the gauge renderer gets 1/7th of slots, one ACTIVE gauge per slot, and
the screen blits once per completed wheel pass. The wheel is 136 gauges
-- and the BT_GAUGE_LOG roster dump shows all 136 are real cockpit
instruments (26 armor colormappers, leak gauges, cooling loops, weapon
clusters...): a Tesla pod shows everything at once, so the roster is
AUTHENTIC and must not be trimmed. Per-instrument latency is therefore
7 x 146 / loop_fps -- the loop rate is the only lever.

THE DEFECT: build410.sh compiled -O2 alone. The authentic release tier
(CODE/BT/OPT.MAK) is -O2 -Ot -Oc -Og -O -Ol -Z -Ob -Oe -Oi -Om -Op -Ov.
Adopting it (all 234 TUs clean, no BC4.52 optimizer ICEs) doubled the
loop: 16.7 -> ~30 fps wall on the rig. Shipped fifo throughput is still
~2x ours (11.8KB/s vs 6.4KB/s, governor-conflated) -- residual gap is an
open question pinned in GAUGE-CADENCE-NOTES.md with the operator A/B ask.

Instrumentation kept, cheap and gated: slot/wheel counters on the
[stack] line (BT_STACK_LOG), one-shot roster dump (BT_GAUGE_LOG),
tick-delta timers compile-gated BT_TICK_PROBES (OFF -- guest tick sums
proved to be trap-burst artifacts in the emulator, not costs; wall rates
are the only trustworthy measure). New: MUNGA/APPTASK.CPP shadow,
fifofps.py (true board fps from a fifodump), pod_render_bgprobe.conf.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-04 01:42:08 -05:00

104 lines
5.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Gauge / display cadence — why the cockpit instruments update slowly (2026-08-04)
Operator report: "the rendering of the displays — many seconds between
updates" on BTL4REC vs "the original." This file is the evidence chain.
All measurements on the dev rig, `pod_render_bgprobe.conf` (no per-frame
logs), DOSBox-X `cycles=max`, arena1 self-drive (BT_FORCE_THROTTLE=0.6).
## The mechanism (all verified in source AND the shipped binary)
1. **The manager runs flat-out by design.** `main` passes
`GetTicksPerSecond()` to `ApplicationManager(Scalar frame_rate)`, so
`frameDuration = 1/ticksPerSecond` — a microscopic frame budget.
Verified in the shipped exe: the ctor constant `_DAT_0044f2d8` at
file offset 0x4f0d8 of BTL4OPT.EXE is exactly `1.0f` (0x3f800000),
i.e. the shipped 4.10 does the same. Consequence: `RunMissions`
(@0044f344, structurally identical to the RP donor) finds
`Now() >= end_of_frame` after every single background pass —
**exactly one background slot per loop frame**, ours and shipped.
Measured: `bg=` grows 1001 per 1001-frame period, every period.
2. **The background slot feeds a 7-task round-robin**
(`BackgroundTasks::Execute` runs ONE task per call): RoutePacket,
ProcessEvent, AudioRenderer, GaugeRenderer, NetworkManager,
CompleteCycles, FryDeathRow. The gauge renderer gets 1/7th of slots.
3. **The gauge wheel repaints once per pass.** Each gauge-task slot =
`ProcessOneActiveGauge()` = ONE active gauge. When the active list
is exhausted the renderer enters its `copy` phase (the changed-line
blit to the display — ~10 extra slots) and only then restarts.
So per-instrument latency ≈ `7 × (wheel + copy) / loop_fps`.
4. **The wheel is 136 gauges and that is AUTHENTIC.** BT_GAUGE_LOG
roster dump: 26 ColorMapperArmor, 12 VertTwoPartBar, 10 LeakGauge,
8 TwoState/PowerSource/HorizTwoPartBar/CoolingLoop, weapon clusters,
generator clusters, myomer cluster, pilot list, message board … all
real cockpit instruments. A Tesla pod shows every instrument at
once; nothing pages out. Do NOT "fix" the roster.
So at our measured ~2533 loop fps: 7 × 146 / 30 ≈ **34 s** worst-case
per-instrument latency. That is the operator's symptom, exactly.
## The real defect found: build flags
`build410.sh` compiled with `-O2` alone. The authentic release tier
(`CODE/BT/OPT.MAK`) is:
-O2 -Ot -Oc -Og -O -Ol -Z -Ob -Oe -Oi -Om -Op -Ov
(global CSE + global register allocation, invariant code motion, copy
propagation, inline intrinsics, redundant-load suppression, loop opts).
Adopting the full set (all 234 TUs compile clean, no BC4.52 optimizer
ICEs) took the loop from **16.7 → ~30 loop fps wall** on the rig — a
~2× display-cadence improvement for free. `-w` was kept as `-w-`.
Note: RP-era MAKE.CFG uses `bcc32i` (BC5 toolchain, RP 4.11+); BT 4.10's
OPT.MAK says `BCC = bcc32` — we match 4.10.
## Measurement traps recorded (they cost hours tonight)
- **Incremental-build staging:** the link consumes `build410/lib/*.lib`;
rebuilding `engine` without `libs` ships STALE members. Also a
same-minute mtime tie made the engine step skip freshly patched TUs.
When probing: `rm` the target objs, then `engine`, `libs`, `link`.
(l4grend's obj dir is `obj/mungal4` — no underscore.)
- **Guest tick-delta profiling is unreliable in the emulator.** The SOS
clock advances in bursts at trap points, so per-stage
`Now()`-bracket sums measure where the burst LANDS, not cost:
five timed foreground stages summed 8.7 "ticks/frame" while the whole
function measured 17.0, with provably empty code between them.
Wall-clock rates (log-line arrival, fifodump growth) are the only
trustworthy measure. The tick probes are compile-gated behind
`BT_TICK_PROBES` (default OFF); the pure counters (`bg= g= p= c=` on
the `[stack]` line, BT_STACK_LOG) stay, they never touch the clock.
- **`draw_scene` rate ≠ loop rate.** The board renderer is
rate-governed by the RendererManager: 2.9 board-fps while the loop ran
33 fps. `fifofps.py` counts true board frames (action 9 records).
## Where the ours-vs-shipped gap stands
fifodump growth mid-mission: shipped ≈ 11.8 KB/s, ours ≈ 4.1 KB/s before
the flag fix, ≈ 6.4 KB/s after. Byte rate conflates the render governor
with loop rate, so treat as indicative only. Under `cycles=max` wall
time is trap-dominated; both exes drive the same VPX/serial/AWE devices.
**OPEN QUESTION for the operator:** on THIS RIG, do BTL4OPT's cockpit
instruments visibly update faster than BTL4REC's (post-flag-fix)? If
yes, the residual is ours-specific guest work and the next tool is a
DOSBox-side sampling profiler (we own the fork) — not more guest
probes. If no — the rig was always like this and the "original"
baseline was the real pod, whose identical architecture ran at real-
hardware loop rates.
## Probe inventory (all in source410, cheap, env/compile gated)
- `MUNGA/APP.CPP`: counters `bgSlots/bgTaskRuns/gaugeSlices/gaugePasses/
gaugeCopySlices` + `[stack]` print (env BT_STACK_LOG); tick-delta
stage/slot timers behind `BT_TICK_PROBES`.
- `MUNGA/APPTASK.CPP` (new shadow, from CODE/RP donor): per-ring-task
timers behind `BT_TICK_PROBES`.
- `MUNGA/GAUGREND.CPP`: wheel slice/pass counters; one-shot `[roster]`
dump (env BT_GAUGE_LOG).
- `emulator/render-bridge/fifofps.py`: true board-fps from a fifodump.
- `emulator/render-bridge/pod_render_bgprobe.conf`: clean probe conf
(BT_STACK_LOG + BT_GAUGE_LOG, no per-frame logs).