#!/usr/bin/env bash # Raw CAN over MQTT, measured on the car Orin against a vcan0 (project-yukart decision 4). # Runs on the Orin; sudo once, to create vcan0. Prints one JSON line per run: the # sink's and the bridge's reports, and mosquitto's CPU over the run. # # usage: bus-bench.sh BUS_BENCH_BINARY CAPTURE.log [secs] # env: BATCHES batch windows in ms, 0 = one message per frame ("0 10") # FLAGS extra options for both roles, e.g. --nagle # GAP_MS cangen gap for the full-bus run (0.15: ~4500 frames/s here, past what # 500 kbit/s can carry with 8-byte frames) set -euo pipefail BIN="$1"; CAPTURE="$2"; SECS="${3:-20}" BATCHES="${BATCHES:-0 10}"; FLAGS="${FLAGS:-}" if ! ip link show vcan0 >/dev/null 2>&1; then sudo modprobe vcan sudo ip link add vcan0 type vcan fi sudo ip link set vcan0 up txqueuelen 10000 ticks() { awk '{print $14 + $15}' "/proc/$1/stat"; } HZ=$(getconf CLK_TCK) OUT=$(mktemp -d) # run NAME BATCH_MS GENERATOR...: the generator feeds vcan0 for a little over SECS seconds. run() { local name="$1" batch="$2"; shift 2 # shellcheck disable=SC2086 "$BIN" sink --secs "$SECS" $FLAGS > "$OUT/sink" 2>/dev/null & local sink=$! sleep 0.5 # shellcheck disable=SC2086 "$BIN" bridge --batch-ms "$batch" --secs $((SECS + 3)) $FLAGS > "$OUT/bridge" 2>/dev/null & local bridge=$! sleep 0.5 local broker m0 m1 t0 t1 broker=$(pgrep -x mosquitto); m0=$(ticks "$broker"); t0=$(date +%s.%N) timeout "$((SECS + 1))" "$@" >/dev/null 2>&1 || true m1=$(ticks "$broker"); t1=$(date +%s.%N) wait "$sink" "$bridge" python3 - "$name" "$batch" "$FLAGS" "$OUT" "$((m1 - m0))" "$HZ" "$t0" "$t1" <<'PY' import json, sys name, batch, flags, out, ticks, hz, t0, t1 = sys.argv[1:] r = {"run": name, "batch_ms": int(batch), "flags": flags, "sink": json.load(open(f"{out}/sink")), "bridge": json.load(open(f"{out}/bridge")), "mosquitto_cpu_pct": round(100 * int(ticks) / int(hz) / (float(t1) - float(t0)), 1)} for k in ("role",): r["sink"].pop(k); r["bridge"].pop(k) print(json.dumps(r)) PY } LOOPS=$(( (SECS + 9) / 10 + 1 )) # the capture is 10 s; loop past the run's end for batch in $BATCHES; do run "car replay" "$batch" canplayer -l "$LOOPS" -I "$CAPTURE" vcan0=can_pcan run "full bus" "$batch" cangen vcan0 -g "${GAP_MS:-0.15}" -L 8 run "flood" "$batch" cangen vcan0 -g 0 -L 8 done