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

5.4 KiB
Raw Blame History

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).