Files
PFVCluster/proxmox/perf/bench/bench-run.sh
T
mrcharles 02bdeae9e7 feat(perf): standardized fleet benchmark artifact (fio/iperf3) [#709]
bench-run.sh: identical test shape everywhere (4k rand rw, 1M seq rw,
direct IO, grep-able BENCH| lines) - runs in guests, LXCs, containers.
install-bench.sh for Debian guests/LXCs; Dockerfile for registry image;
lxc-bench-setup.sh stands up the host-side bench LXC (proxmox = no docker).

Ticket: https://projects.knownelement.com/issues/709
2026-09-03 07:21:27 -05:00

70 lines
3.1 KiB
Bash

#!/bin/bash
# bench-run.sh — standardized fleet benchmark (fio + iperf3). [#709]
# Same tool, same shape, everywhere: Proxmox LXCs, guests, containers.
# Non-destructive: fio writes only its own files under BENCH_DIR.
#
# Usage:
# BENCH_DIR=/path bench-run.sh # storage bench on /path (default /var/tmp)
# IPERF_SERVER=host bench-run.sh # + network test to that iperf3 server
# bench-run.sh --server # run as iperf3 server (one shot)
# Output: one "BENCH|key|value" line per metric (grep-friendly), plus meta.
set -u
RUNTIME="${BENCH_RUNTIME:-20}"
SIZE="${BENCH_SIZE:-1G}"
BENCH_DIR="${BENCH_DIR:-/var/tmp}"
STAMP="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
HOSTID="$(hostname -s)"
b() { printf 'BENCH|%s|%s|%s\n' "$HOSTID" "$1" "$2"; }
if [ "${1:-}" = "--server" ]; then
exec iperf3 -s -1
fi
command -v fio >/dev/null 2>&1 || { echo "ERROR: fio not installed (see install-bench.sh)" >&2; exit 1; }
mkdir -p "$BENCH_DIR"
b meta stamp "$STAMP"
b meta path "$BENCH_DIR"
b meta runtime "$RUNTIME"
b meta size "$SIZE"
run_fio() { # $1=testname $2=fio-args...
local name="$1"; shift
fio --name="$name" --output-format=json --timeout=120 "$@" \
> "$BENCH_DIR/.fio-out.json" 2>"$BENCH_DIR/.fio-err" || {
b "fio_${name}" ERROR; return; }
if command -v jq >/dev/null 2>&1; then
while IFS='|' read -r n rest; do
printf 'BENCH|%s|%s|%s\n' "$HOSTID" "$n" "$rest"
done < <(jq -r --arg n "$name" '
.jobs[0] as $j |
($n) + "|iops=" + ($j.read.iops // $j.write.iops | tostring) + "|" +
"bw_kbps=" + (($j.read.bw // $j.write.bw) | tostring) + "|" +
"p99_ms=" + (($j.read.clat_ns.percentile["99.000000"] // $j.write.clat_ns.percentile["99.000000"] // 0) / 1000000 | tostring)' \
"$BENCH_DIR/.fio-out.json")
else
# no jq: minimal grep fallback
grep -oE '"(iops|bw)":[0-9.]+' "$BENCH_DIR/.fio-out.json" | head -2 | while IFS=: read -r k v; do
b "fio_${name}_${k}" "$v"
done
fi
}
# 4k random read/write (IOPS), 1M sequential read/write (MB/s); direct to skip cache
run_fio randread4k --filename="$BENCH_DIR/perf-test-file" --rw=randread --bs=4k --direct=1 --iodepth=16 --time_based --runtime="$RUNTIME" --size="$SIZE"
run_fio randwrite4k --filename="$BENCH_DIR/perf-test-file" --rw=randwrite --bs=4k --direct=1 --iodepth=16 --time_based --runtime="$RUNTIME" --size="$SIZE"
run_fio seqread1m --filename="$BENCH_DIR/perf-test-file" --rw=read --bs=1M --direct=1 --iodepth=8 --time_based --runtime="$RUNTIME" --size="$SIZE"
run_fio seqwrite1m --filename="$BENCH_DIR/perf-test-file" --rw=write --bs=1M --direct=1 --iodepth=8 --time_based --runtime="$RUNTIME" --size="$SIZE"
rm -f "$BENCH_DIR/.fio-out.json" "$BENCH_DIR/.fio-err"
# network: only when a server is provided
if [ -n "${IPERF_SERVER:-}" ] && command -v iperf3 >/dev/null 2>&1; then
NET=$(iperf3 -c "$IPERF_SERVER" -t 10 -P 4 -J 2>/dev/null | jq -r '.end.sum_received.bits_per_second' 2>/dev/null)
[ -n "$NET" ] && b iperf3_rx_bps "$NET"
fi
b meta end "$STAMP"