#!/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" # fio may print human notes (e.g. sync-engine warnings) before the JSON on # stdout; strip everything before the opening brace so jq always gets JSON. parse_fio() { # $1=json-file $2=testname $3=read|write sed -n '/^{/,$p' "$1" | jq -r --arg n "$2" --arg d "$3" ' .jobs[0] as $j | ($n) + "|iops=" + ($j[$d].iops | tostring) + "|" + "bw_kbps=" + ($j[$d].bw | tostring) + "|" + "p99_ms=" + (($j[$d].clat_ns.percentile["99.000000"] // 0) / 1000000 | tostring)' | while IFS='|' read -r n rest; do printf 'BENCH|%s|%s|%s\n' "$HOSTID" "$n" "$rest" done } run_fio() { # $1=testname $2=read|write $3+=fio-args local name="$1"; local dir="$2"; shift 2 fio --name="$name" --output-format=json --timeout=120 "$@" \ > "$BENCH_DIR/.fio-out.json" 2>"$BENCH_DIR/.fio-err" || { b "fio_${name}" ERROR; return; } parse_fio "$BENCH_DIR/.fio-out.json" "$name" "$dir" } # 4k random read/write (IOPS), 1M sequential read/write (MB/s); direct to skip cache run_fio randread4k read --filename="$BENCH_DIR/perf-test-file" --rw=randread --bs=4k --direct=1 --iodepth=16 --time_based --runtime="$RUNTIME" --size="$SIZE" run_fio randwrite4k write --filename="$BENCH_DIR/perf-test-file" --rw=randwrite --bs=4k --direct=1 --iodepth=16 --time_based --runtime="$RUNTIME" --size="$SIZE" run_fio seqread1m read --filename="$BENCH_DIR/perf-test-file" --rw=read --bs=1M --direct=1 --iodepth=8 --time_based --runtime="$RUNTIME" --size="$SIZE" run_fio seqwrite1m write --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"