#!/usr/bin/env bash
# ferranet vs libpnet capture comparison over a veth pair, for low-power hardware.
#
# Run ON the device (e.g. a Raspberry Pi). Needs root for veth + AF_PACKET. A flooder is pinned to
# the upper cores and the capturer to core 0, so a single capture core is the bottleneck and the
# result reflects each backend's per-core efficiency.
#
#   PIBENCH=./pibench SECS=10 SIZE=64 [SNAPLEN=128] [MBPS=100] ./pibench.sh
#
# Prints one result line per backend (ring, basic, pnet) — compare proc_cpu (% of one core),
# cpu_us/frame, and drops. Set MBPS to compare CPU load at a fixed offered rate.
set -euo pipefail

BIN="${PIBENCH:-./pibench}"
SECS="${SECS:-10}"
SIZE="${SIZE:-64}"
SNAPLEN="${SNAPLEN:-}"
A=pibench0
B=pibench1

[ -x "$BIN" ] || command -v "$BIN" >/dev/null 2>&1 || { echo "set PIBENCH to the pibench binary path"; exit 1; }

sudo ip link del "$A" 2>/dev/null || true
sudo ip link add "$A" type veth peer name "$B"
sudo ip link set "$A" up
sudo ip link set "$B" up
trap 'sudo ip link del "$A" 2>/dev/null || true' EXIT

ncpu="$(nproc)"
flood_cores="2,3"
[ "$ncpu" -lt 4 ] && flood_cores="$((ncpu - 1))"

rate=()
[ -n "${MBPS:-}" ] && rate=(--mbps "$MBPS") # cap the offered rate to compare CPU at a fixed load

run() {
  local backend="$1"
  sudo taskset -c "$flood_cores" "$BIN" flood --iface "$A" --secs "$((SECS + 3))" --size "$SIZE" "${rate[@]}" >/dev/null 2>&1 &
  local fpid=$!
  sleep 1 # ramp to steady state
  local snap=()
  [ -n "$SNAPLEN" ] && [ "$backend" = ring ] && snap=(--snaplen "$SNAPLEN")
  sudo taskset -c 0 "$BIN" capture --backend "$backend" --iface "$B" --secs "$SECS" "${snap[@]}"
  kill "$fpid" 2>/dev/null || true
  wait "$fpid" 2>/dev/null || true
}

echo "# ferranet vs libpnet | $(uname -m) ${ncpu} cores | ${SECS}s | ${SIZE}B frames | flood@${flood_cores} capture@0"
for b in ring basic pnet; do run "$b"; done
