Repository navigation
stream: per-frame air-side timing in addr3 + a hardware-clocked marker - #479
Conversation
Six bytes in every stream frame's addr3 (no receiver read it: every consumer keys on addr2 and slices the body at +24) carry the transmitter's backlog depth, capture->send_packet and its predicted TSF at the send; a periodic probe-response marker (DEVOURER_STREAM_TIMING=N) carries the host<->TSF fit state and the window's stage statistics. rxdemo fits the transmitter's clock from hardware egress pairs only and reports a one-way submit->arrival and capture->arrival latency per frame (rx.frame lat_us / c2a_us, rx.timing per marker). The producer's capture time arrives through the stdin control escape streamtx and duplex now share (opcode 4, CAPTURE_TS); the Python producers emit it with --capture-ts. Measured first (tests/probe_resp_egress_tsf_check.sh): an injected probe response is MAC-stamped with the egress TSF on Jaguar2, Jaguar3 and Kestrel but not on Jaguar1, where the 8821AU writes a counter that is neither TSF port -- hence AdapterCaps::hw_injected_mgmt_txtsf, and the hardware beacon as Jaguar1's clock carrier on a fixed channel. Both fits restart on a >50 ms discontinuity (the beacon arm pulses the TSF; a re-init zeroes it). The TX fit never reads a register on the send path: one ReadTsf per 100 ms. On air (tests/stream_timing_onair.sh, CF-924AC witness): submit->air p50 ~100-150 us on 8812CU / 8832CU / paced 8812EU, ~400 us with depth 2 on the async 8821AU; a 20 ms producer delay on every 10th record is recovered as 20.08 ms on 10% of frames; the clock survives slot hopping; svctx and duplex stamp identically. A producer that outruns the chip (8812EU on 5 GHz, 20 ms bulk-OUT stalls) pins capture->send at its clip -- a true backlog reading, documented with the harness's pacing knob. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
PR Summary by QodoAdd hardware-clocked per-frame stream timing telemetry
AI Description
Diagram
High-Level Assessment
Files changed (35)
|
Code Review by Qodo
1.
|
…ean stops - hw_injected_mgmt_txtsf only on the dies measured (8822B, 8852C); the 8821C and 8852B stay false until a cell exists. - rxdemo: no clock fit or latency on a receiver without a hardware RX stamp (hw_rx_timestamp false); addr3 read and decoded only on frames >= 24 bytes; a TSF discontinuity is caught from the second pair on, not only once the fit is ready (the TX fit likewise); beacon pairs are taken only when the live marker says a beacon carries the clock -- a Jaguar1 hardware beacon outlived its killed transmitter and poisoned the next run's fit. - streamtx/svctx/duplex: SIGINT/SIGTERM end the loop through the ordinary exit path (device stopped, timing beacon disarmed; verified zero stray beacons after a timeout-ended Jaguar1 run); no marker before the first data frame went out; the fit log no longer claims a state it cannot know, and stream.timing carries fit_unsupported. - duplex: a live SET_CHAN updates the marker's DS channel. - TimingWindow: a uniform reservoir, so a window longer than 8192 frames reports the whole window's median (selftest: 40000-frame ramp). - rx.frame gains fc0 (rxdemo + duplex); adaptive_link counts only 0x40 data frames as video, so markers and beacons never enter its sequence ledger. - The stdin control TLVs move to tools/precoder/stdin_ctl.py (stdlib only); stream.py re-exports them, adaptive_link stays numpy-free. - CLAUDE.md keeps a pointer, not a copy, of the wire details. Re-validated on air: 8812CU floor/delay/hop/corrupt/duplex, 8821AU floor (beacon clock, fit_resets 0), 8832CU floor, all PASS. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
What
Per-frame TX-side timing for the stream link, the way kestrel-air's slice header does it, on devourer's own clock (the MAC TSF):
streamtx,svctx,duplex) carries six bytes no receiver otherwise reads: backlog depth, capture→send_packet, and the transmitter's predicted TSF at the send (src/StreamTelemetry.h). FEC bodies untouched, MTU unchanged; the old addr3 contents decode as "no telemetry".DEVOURER_STREAM_TIMING=N), a probe response with the canonical SA, carries the host↔TSF fit state and the window's p50/max of stdin-read→send,send_packetwall time, capture→send and depth.stream_stdin::read_item, opcode 4CAPTURE_TS); the Python producers emit it with--capture-ts.lat_us/c2a_ustorx.frame, plusrx.timingper marker.tests/stream_timing_analyze.pysummarizes a capture.AdapterCaps::hw_injected_mgmt_txtsf,TxStats::inflight, a sharedtsf_linfit.h(timesync re-exports it).Measured, not assumed
tests/probe_resp_egress_tsf_check.sh(a constant in the timestamp field, an independent witness reading it back): an injected probe response / beacon is MAC-stamped at egress on Jaguar2 (8812BU), Jaguar3 (8812CU, 8812EU) and Kestrel (8832CU), 34–41 µs spread; not on Jaguar1 — the 8821AU writes a free-running counter that is neither TSF port (both sampled live). Its hardware TBTT beacon is stamped (3.2 µs), so that family arms the beacon as its clock carrier on a fixed channel and reports durations only while hopping. TheRxPacket.hcomment that claimed otherwise is corrected.tests/stream_timing_onair.sh, CF-924AC (8822BU) witness, 20 s runs, floor first:svctx/duplexA 20 ms producer delay on every 10th record is recovered as 20.08–20.09 ms on 9.8–10.2% of frames on every part; slot hopping (1/6/11 @ 50 ms) keeps the clock on Jaguar3; CRC-failed frames never feed the fit. Headless:
ctest85/85, the new selftests green under ASan+UBSan.The adversarial readings sit in
docs/stream-timing.mdbeside the numbers: Jaguar1's async transport shows as depth 2 and ~400 µs; the 8812EU's 20 ms bulk-OUT stalls on 5 GHz pin capture→send at its clip when the producer outruns it (a true backlog reading, hencePACE_US); a fit sampled across the Jaguar1 beacon arm reads a decaying 62 ms (hence the beacon-first order and the discontinuity reset); a duplex fed during bring-up times out every send (hence the 12 s feeder lead the ARQ harness already uses, and the fit arming on the first record).Follow-ups filed
#474 addr1 as five more bytes · #475 svctx live stdin mode · #476 CCX queue time join (and A-MPDU semantics) · #477
hw_injected_mgmt_txtsfon 8812AU/8814AU/MT7612U · #478 duplex gating its TX thread on bring-up.🤖 Generated with Claude Code