bus-bench: decoder stand-in and mixed-load runs

Raw frames to four subscribers plus envelopes to five, at the car's rate and
at a full bus. Raw never suffered; envelope deliveries are the load, with the
knee near 40,000 deliveries/s.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DDwfd6Ki8UfG4hK6W5YpJz
This commit is contained in:
2026-10-12 22:33:44 +09:00
parent bba48efd90
commit b605c27fc0
5 changed files with 256 additions and 19 deletions
+49 -2
View File
@@ -12,6 +12,7 @@ The car's usual services (recorder, orin-status, svc-gw, svc-vision) kept runnin
```bash
scripts/bus-bench.sh ./bus-bench z27ag-20261009-163736-ign.log 20 # on the Orin
scripts/bus-mix.sh ./bus-bench z27ag-20261009-163736-ign.log 20 # after bus-bench.sh
```
Loads:
@@ -67,10 +68,56 @@ The car's broker now has `set_tcp_nodelay true` (orin-nano-env-setup `MOSQUITTO.
Clients that publish or consume raw CAN set `set_tcp_nodelay(true)` too. At once a
second (orin-status) it does not matter.
## The bus as the car will use it
`scripts/bus-mix.sh`: the raw stream (10 ms batches) to four subscribers (the decoder
plus three: svc-gw, telemetry-gw, a debug tool), and a stand-in `decoder` publishing
envelopes on one retained topic per signal, to five subscribers that each take every
signal (svc-gw, recorder, svc-nav, svc-vision, telemetry-gw). Loads keep the car's
27 CAN IDs and their rates (2–100 Hz): the capture as recorded, and played 5× faster
for a full bus. Signals per frame and a per-signal rate cap (latest value wins)
stand in for the decoder design nobody has made yet. 20 s runs.
| Load | Signals/frame | Cap | Envelopes/s | Deliveries/s (×5) | Broker CPU | Envelope latency p50 / p99 (ms) |
|---|---|---|---|---|---|---|
| car | 3 | 50 Hz | 1,600 | 8,000 | 22 % | 13 / 21 |
| car | 3 | none | 2,550 | 12,800 | 35 % | 13 / 20 |
| car | 8 | 20 Hz | 2,550 | 12,800 | 32 % | 14 / 27 |
| car | 8 | 50 Hz | 4,300 | 21,600 | 47 % | 16 / 32 |
| car | 8 | none | 6,800 | 34,000 | 51 % | 14 / 47 |
| full bus | 3 | 50 Hz | 3,100 | 15,500 | 39 % | 12 / 18 |
| full bus | 8 | 20 Hz | 3,500 | 17,300 | 44 % | 22 / 41 |
| full bus | 8 | 50 Hz | 8,100 | 40,600 | 57 % | 15 / **391** |
| full bus | 3 | none | 12,800 | 63,800 | 74 % | **636 / 1,472** |
| full bus | 8 | none | 16,300 offered | — | 75 % | **5,380 / 5,994**; decoder queue overflowing |
- **The raw stream never suffered.** All four raw subscribers got every frame in every
run, p99 ≤ 16 ms, including the runs where the envelopes collapsed.
- **Envelopes are the load.** The broker's cost follows deliveries (messages ×
subscribers). Up to ~22,000 deliveries/s it stays under half a core with p99 near
30 ms; around 40,000 the tail goes to hundreds of ms; past ~60,000 queues grow by
seconds. Mosquitto is single-threaded, so this is a ceiling, not a share.
- **Each subscriber pays too.** Parsing JSON envelopes cost each sink 14–38 % of a
core at these rates; five of them took two cores. A real subscriber that takes
everything (svc-gw) pays the same.
- Envelope loss is not measured exactly (no sequence numbers in the envelope);
the decoder's own `refused` counts what it could not even queue.
What keeps it in the comfortable range, any of which is enough at the car's rate:
1. **Cap each signal's rate in the decoder**, latest value wins. 20–50 Hz is still
10–50× OBD-II polling, and the raw stream keeps the full rate for anything that
needs it.
2. **Subscribe narrowly.** Only a consumer that shows or stores everything (svc-gw)
needs `yukart/vehicle/+`; svc-nav and svc-vision need a handful of topics.
3. **Publish slow signals on change**, with a heartbeat; temperatures and states do
not need 50 Hz.
4. **The recorder need not record decoded signals at full rate.** It records raw
frames, and decoding them again offline gives the same signals.
## Not tested
- A real CAN adapter: vcan has no bus timing, and the PCAN-USB's own reception and
timestamps are already covered by the recorder.
- Several subscribers on `yukart/can/raw` at once (recorder reads SocketCAN directly,
so expected consumers are the decoder and perhaps svc-gw).
- The broker under memory pressure, or with the GPU/vision load of later phases.
- The real decoder: signals per frame, rates and topic layout are stand-ins.