b605c27fc0
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
77 lines
3.8 KiB
Bash
Executable File
77 lines
3.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# The bus as the car will use it: raw frames to several subscribers, a decoder turning
|
||
# them into envelopes, several envelope subscribers. Runs on the car Orin against a
|
||
# vcan0, beside bus-bench.sh (which makes vcan0). Prints one JSON line per run.
|
||
#
|
||
# usage: bus-mix.sh BUS_BENCH_BINARY CAPTURE.log [secs]
|
||
# env: CASES "batch_ms signals max_hz" per run, ';'-separated (default: the matrix below)
|
||
#
|
||
# Loads keep the car's own CAN IDs and their relative rates: the capture as recorded
|
||
# (~890 frames/s), and the same capture played 5× faster (~4,450 frames/s, a full bus).
|
||
set -euo pipefail
|
||
|
||
BIN="$1"; CAPTURE="$2"; SECS="${3:-20}"
|
||
RAW_SINKS=3 # besides the decoder: svc-gw, telemetry-gw, a debug tool
|
||
ENV_SINKS=5 # svc-gw, recorder, svc-nav, svc-vision, telemetry-gw
|
||
|
||
ip link show vcan0 >/dev/null 2>&1 || { echo "vcan0 missing: run bus-bench.sh once"; exit 1; }
|
||
OUT=$(mktemp -d)
|
||
FAST="$OUT/fast.log"
|
||
awk 'NR == 1 { t0 = substr($1, 2, length($1) - 2) }
|
||
{ t = substr($1, 2, length($1) - 2); printf "(%.6f) %s %s\n", t0 + (t - t0) / 5, $2, $3 }' "$CAPTURE" > "$FAST"
|
||
|
||
ticks() { awk '{print $14 + $15}' "/proc/$1/stat"; }
|
||
HZ=$(getconf CLK_TCK)
|
||
|
||
# run NAME LOG BATCH_MS SIGNALS MAX_HZ
|
||
run() {
|
||
local name="$1" log="$2" batch="$3" signals="$4" maxhz="$5" pids=() i
|
||
rm -f "$OUT"/*.json
|
||
for i in $(seq "$RAW_SINKS"); do
|
||
"$BIN" sink --secs "$SECS" > "$OUT/raw$i.json" 2>/dev/null & pids+=($!)
|
||
done
|
||
for i in $(seq "$ENV_SINKS"); do
|
||
"$BIN" sink --topic 'yukart/bench/vehicle/+' --secs "$SECS" > "$OUT/env$i.json" 2>/dev/null & pids+=($!)
|
||
done
|
||
"$BIN" decoder --signals "$signals" --max-hz "$maxhz" --secs $((SECS + 2)) > "$OUT/decoder.json" 2>/dev/null & pids+=($!)
|
||
sleep 0.5
|
||
"$BIN" bridge --batch-ms "$batch" --secs $((SECS + 3)) > "$OUT/bridge.json" 2>/dev/null & pids+=($!)
|
||
sleep 0.5
|
||
local broker m0 m1 t0 t1 loops
|
||
loops=$(( SECS / 2 + 2 )) # the fast log lasts 2 s; enough loops either way
|
||
broker=$(pgrep -x mosquitto); m0=$(ticks "$broker"); t0=$(date +%s.%N)
|
||
timeout "$((SECS + 1))" canplayer -l "$loops" -I "$log" vcan0=can_pcan >/dev/null 2>&1 || true
|
||
m1=$(ticks "$broker"); t1=$(date +%s.%N)
|
||
wait "${pids[@]}"
|
||
python3 - "$name" "$OUT" "$((m1 - m0))" "$HZ" "$t0" "$t1" <<'PY'
|
||
import glob, json, sys
|
||
name, out, ticks, hz, t0, t1 = sys.argv[1:]
|
||
load = lambda p: json.load(open(p))
|
||
raw = [load(p) for p in sorted(glob.glob(f"{out}/raw*.json"))]
|
||
env = [load(p) for p in sorted(glob.glob(f"{out}/env*.json"))]
|
||
dec, br = load(f"{out}/decoder.json"), load(f"{out}/bridge.json")
|
||
worst = lambda xs, k: max(x["latency_ms"][k] for x in xs)
|
||
print(json.dumps({
|
||
"run": name,
|
||
"bridge": {k: br[k] for k in ("batch_ms", "frames", "messages", "refused_frames", "kernel_drops", "cpu_pct")},
|
||
"raw_sinks": {"n": len(raw), "frames_per_s": min(x["frames_per_s"] for x in raw),
|
||
"lost": sum(x["lost_frames"] for x in raw),
|
||
"p99_ms": worst(raw, "p99"), "max_ms": worst(raw, "max")},
|
||
"decoder": {k: dec[k] for k in ("signals_per_frame", "max_hz", "topics", "published_per_s", "refused", "cpu_pct")},
|
||
"envelope_sinks": {"n": len(env), "per_s": min(x["messages_per_s"] for x in env),
|
||
"p50_ms": worst(env, "p50"), "p99_ms": worst(env, "p99"), "max_ms": worst(env, "max"),
|
||
"cpu_pct_each": max(x["cpu_pct"] for x in env)},
|
||
"mosquitto_cpu_pct": round(100 * int(ticks) / int(hz) / (float(t1) - float(t0)), 1)}))
|
||
PY
|
||
}
|
||
|
||
CASES="${CASES:-10 3 0;10 8 0;10 8 20;0 8 0}"
|
||
for log in "$CAPTURE" "$FAST"; do
|
||
rate=$([ "$log" = "$FAST" ] && echo "full bus" || echo "car")
|
||
IFS=';' read -ra cases <<< "$CASES"
|
||
for c in "${cases[@]}"; do
|
||
read -r batch signals maxhz <<< "$c"
|
||
run "$rate, raw batch ${batch} ms, ${signals} signals/frame, cap ${maxhz} Hz" "$log" "$batch" "$signals" "$maxhz"
|
||
done
|
||
done
|