Files
app-flutter/docs/impl/reports/LINK-TEST-2026-10-11.md
T
mikkeli 8f4e34d956
CI / Analyze & Test (push) Successful in 10s
CI / Debug APK (push) Successful in 15s
Link test: download series (bulk sampled, warm bursts, paced) and burst-vs-idle; car results
Orin -> tablet over NCM: paced streams up to 4 MB/s are clean; unpaced
bursts and bulk hit multi-second holds that inflate the RTO to 10-16 s.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DDwfd6Ki8UfG4hK6W5YpJz
2026-10-11 16:33:55 +09:00

122 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.
---
type: report
date: 2026-10-11
---
# USB link test: plain cable vs PD hub
Does the PD hub degrade the tablet ⇄ Orin USB (NCM) link? Measured from the app
(the only place on the tablet whose sockets use the link) with the link test,
`lib/linktest.dart` + `tool/linktest_server.py`.
## Short version
- **No measurable effect of the PD hub**, with or without the charger connected.
All three setups: 0% loss at every size and rate up to 500 packets/s, the same
latencies, 0 TCP retransmits.
- **The loss seen earlier the same day did not come back.** Before these runs,
ICMP ping from the Orin lost 2.5–32% at 20 packets/s through the hub. After a
replug, the same ping sweep is 0% through the hub too. That connection was in
a bad state; the hub is not shown to be the cause. Cause unknown; worth
watching for (the soak below is the app-shaped check).
- **The link is asymmetric:** tablet → Orin ~22 MB/s, Orin → tablet 1.9–5.6 MB/s
and variable, with ~30 ms RTT under load and no loss (the Orin's gadget TX side
queues rather than drops).
- **App-shaped traffic is fine:** 30 s at 10 packets/s, longest silence ≤ 144 ms,
against a 5 s heartbeat timeout.
- **adb push through the SSH tunnel stays slow (0.14 MB/s, 223 Orin retransmits
per 20 MB) on a healthy link**, while the app's TCP over the same link runs at
5.6 MB/s with none. Specific to the adbd connection; not the hub, not routing
(`tcp_fwmark_accept=1`). Unexplained.
## Results
Link USB 2.0 high-speed in all runs. TCP: 5 s each way; UDP: 3 s per cell, RTT
p50 / p99 / max in ms.
| | Plain C-to-C | Hub + charger | Hub, no charger |
|---|---|---|---|
| UDP loss, 64 B and 1400 B, 10–500 /s | 0% | 0% | 0% |
| UDP 64 B 10/s RTT | 4.1 / 24.2 / 24.2 | 4.0 / 10.5 / 10.5 | 4.1 / 5.6 / 5.6 |
| UDP 1400 B 500/s RTT | 2.8 / 7.3 / 39.7 | 2.7 / 9.4 / 42.5 | 2.7 / 16.6 / 60.2 |
| Soak 64 B 10/s 30 s: loss, max gap | 0%, 144 ms | 0%, 135 ms | 0%, 104 ms |
| TCP Orin → tablet | 1.85 MB/s | 4.06 MB/s | 5.57 MB/s |
| TCP tablet → Orin | 21.8 MB/s | 22.4 MB/s | 22.6 MB/s |
| Orin TCP retransmits | 0 | 0 | 0 |
| ICMP ping from the Orin, 20/s, 56–1472 B | 0% | 0% | 0% |
For reference, the same test over WiFi to the Orin's LAN address: 0% loss, about
25 MB/s each way.
Raw records: `~/linktest/results.jsonl` on the car Orin; tabulate with
`python3 tool/linktest_summary.py ~/linktest/results.jsonl [label…]`.
## Running it
On the Orin: `python3 linktest_server.py` (from `tool/`, copied to `~/linktest/`).
On the tablet: **Link test** in the link bar, or remotely:
```bash
adb -s localhost:15555 shell am start -n dev.yukart.display/.MainActivity --es linktest <label>[@<host>]
```
The host defaults to the gateway's. A run takes about 75 s and reports each
result to the Orin as it goes.
## Download in the car setup (PD hub + charger)
Two identical download series (`dl:`), then a burst-vs-idle series (`bi:`). Raw
records under the labels `car-dl1`, `car-dl2`, `car-bi1`.
**Paced streams are clean.** 30 frames/s at 0.5, 1, 2 and 4 MB/s, 10 s each, in
both series: every frame arrived, the full rate was delivered, and queueing never
exceeded 44 ms. A camera-like stream up to 4 MB/s (32 Mbit/s) fits.
**Unpaced traffic is not:**
| | Series 1 | Series 2 |
|---|---|---|
| Bulk, 5 × 10 s: rate while flowing | 5.6 MB/s | 5.6 MB/s |
| Bulk: longest stall per run | 1.8, 14.0, 3.6, 0.3, 0.8 s | 0.2, 3.7, 0.8, 0.8, 14.4 s |
| Bulk: Orin retransmits | 0 | 0 |
| Burst 64 KB after 1 s idle, p50 | 17 ms | 18 ms |
| Burst 256 KB, p50 | 12.1 s | 14.1 s |
| Burst 1 MB, p50 | 14.8 s | 13.8 s |
| Burst 4 MB, p50 | 4.5 s | 4.6 s |
| Burst connection: Orin retransmits, smoothed RTT, RTO | 50, 2.35 s, 10.8 s | 49, 2.39 s, 11.0 s |
**Not idle-related.** 256 KB bursts on fresh connections, 8 each:
| Idle before each burst | p50 | Bursts over 1 s | Orin retransmits, smoothed RTT |
|---|---|---|---|
| 0 | 12.6 s | 7 of 8 | 15, 1.6 s |
| 50 ms | 61 ms | 1 of 8 | 8, 1.8 s |
| 200 ms | 14.3 s | 6 of 8 | 13, 1.8 s |
| 1 s | 56 ms | 0 of 8 | 0, 16 ms |
| 1 s, 50/s UDP keepalive | 56 ms | 0 of 8 (3 near 0.5 s) | 5, 21 ms |
| 0 (repeat) | 13.6 s | 8 of 8 | 14, 1.5 s |
**Reading.** A fresh connection's first burst is fast. Then a few segments go
missing, and the Orin measures round trips of 1.5–2.4 s on a 3 ms link: packets
are being *held* for seconds, not only dropped. The smoothed RTT and the RTO
(10–16 s) inflate, and every later burst on that connection waits out the RTO.
Bulk stalls of up to 14 s with zero retransmits are the same holding, seen
without loss. Paced traffic at ≤ 4 MB/s never triggers it.
Nothing on the Orin's side records it: no kernel messages, `tx_dropped` and
`tx_errors` 0 on `usb1`. The packets vanish or wait inside the USB layer, in the
Orin's NCM gadget or the tablet's NCM host driver; the tablet's sysfs is not
readable without root.
**Consequences:**
- Anything the Orin sends to the tablet should be **paced**, not dumped at line
rate: video at a steady frame rate is fine; a TTS utterance should stream in
chunks rather than be written in one go (the protocol already plans chunks).
- A connection that has hit this is poisoned for many seconds (inflated RTO).
The heartbeat timeout will see it as a dead link and reconnect, which resets it.
- `adb push`/`install` is exactly an unpaced bulk transfer, which explains its
0.14 MB/s.
Open: whether RNDIS instead of NCM avoids it, and whether pacing all egress on
the Orin (`tc` `fq` with `maxrate`) fixes unpaced senders too.