tx: count only full bulk writes as submitted on the sync generations - #401
Conversation
Jaguar2 and Jaguar3 counted a frame as sent on any non-negative bulk_send_sync_ep return — but that call returns bytes submitted, so a short write (the chip got a prefix of the descriptor+frame, or a prefix of an aggregated URB whose trailing blocks are partial or absent) was reported as delivered work. The RTL8733B port already refused short writes; this aligns the siblings to the same full-write-or-nothing accounting, in both the single-frame and aggregated paths. The aggregated paths on Jaguar2/Jaguar3 now also emit the tx.agg 'sent' byte count and log a genuine short write (rc >= 0) as an error; rc < 0 stays quiet there like their single-frame paths, whose NAK-backoff contract is what makes a failure log a flood. The RTL8733B, whose single-frame path logs every failure, now logs the aggregated rc < 0 case too instead of gating the diagnostic on rc >= 0. Jaguar1's aggregated path is untouched apart from a comment: its TX is async by design, so 'ok' is URB acceptance and bytes-on-wire resolve at completion reaping — there is no submit-time byte count to hold it to. On-air check on both changed generations (tests/txagg_bench.sh, BATCH=3, MCS7): 8812BU->8812CU witness 7459 agg URBs, 8812CU->8812BU witness 10654 agg URBs — every URB sent==bytes, ok=true, delivery parity with the single-frame arm, no error-log noise. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
PR Summary by QodoTX: count only full bulk writes as submitted on sync generations
AI Description
Diagram
High-Level Assessment
Files changed (5)
|
Code Review by Qodo
1.
|
Review follow-ups on the full-write accounting: UsbTransport::tx_sync counted failed only on a libusb error rc, so a success-with-short-actual transfer — the exact case the device layers now refuse to report as sent — left TxStats claiming everything completed OK. The transport now counts it as failed with a documented sentinel last_rc (kTxShortWriteRc: libusb has no code for the case) and logs it; callers keep receiving the actual byte count, so their truncation detection is unchanged. PCIe is untouched — its ring submit has no partial-write case. tx.agg's 'sent' field is deliberately the raw rc, negative on a transport error: the sync paths emit no tx.fail event, so this is the only machine-readable carrier of the aggregated-path error code. docs/logging.md now says so explicitly instead of leaving negative values as an undocumented reading of 'bytes actually transferred'. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Follow-up from the #400 review: the RTL8733B port counted an aggregated frame as submitted only on a full bulk write, and that made its siblings the odd ones out — Jaguar2 and Jaguar3 counted
rc >= 0, butbulk_send_sync_epreturns bytes submitted, so a short write (the chip got a prefix) was reported as delivered work. In an aggregated URB that is worse: trailing blocks partial or absent, no way to say which frames aired, all of them counted.What changed
tx.aggsentbyte count and log a genuine short write (rc >= 0, truncated) as an error.rc < 0stays quiet there deliberately — their single-frame paths' NAK-backoff contract means a failure log would flood exactly when the caller is already backing off.rc >= 0— a hard transport failure reaches stderr like it does on that backend's single-frame path (the rtl8733b: port USB TX aggregation (send_packets) #400 review's finding 1).okis URB acceptance and bytes-on-wire resolve at completion reaping, so submit-time full-write accounting cannot apply there.docs/logging.md: thetx.aggrow now states the sync-generationsent/full-write semantics and the Jaguar1 async exception.Verification
ctest54/54.tests/txagg_bench.sh, BATCH=3, MCS7, 10 s floods):sent==bytes,ok=true, frames/URB 3.0, rx_hits 17100 vs 17200 single — delivery parity.What this deliberately does not do
No retry of a short-written aggregated URB: the chip holds a prefix, and resubmitting could re-air frames that did make it. Frames in a truncated URB are dropped and simply not counted — the caller's own accounting sees the loss.
🤖 Generated with Claude Code