diff --git a/proxmox/perf/bench/Dockerfile b/proxmox/perf/bench/Dockerfile new file mode 100644 index 0000000..1f14244 --- /dev/null +++ b/proxmox/perf/bench/Dockerfile @@ -0,0 +1,15 @@ +# perfbench container — #709. Same toolset as the fleet LXC/guest installer. +# Build: docker build -t git.knownelement.com/reachableceo/perfbench:1.0 . +FROM debian:12-slim + +RUN apt-get update -qq && apt-get install -y -qq --no-install-recommends \ + fio iperf3 jq ca-certificates \ + && rm -rf /var/lib/apt/lists/* + +COPY bench-run.sh /usr/local/bin/bench-run.sh +RUN chmod +x /usr/local/bin/bench-run.sh + +# storage bench: mount the path to test at /mnt/bench +# network bench: run as server: docker run ... bench-run.sh --server +ENV BENCH_DIR=/mnt/bench +ENTRYPOINT ["/usr/local/bin/bench-run.sh"] diff --git a/proxmox/perf/bench/bench-run.sh b/proxmox/perf/bench/bench-run.sh new file mode 100644 index 0000000..185f8fb --- /dev/null +++ b/proxmox/perf/bench/bench-run.sh @@ -0,0 +1,69 @@ +#!/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" diff --git a/proxmox/perf/bench/install-bench.sh b/proxmox/perf/bench/install-bench.sh new file mode 100644 index 0000000..c6899fe --- /dev/null +++ b/proxmox/perf/bench/install-bench.sh @@ -0,0 +1,9 @@ +#!/bin/bash +# install-bench.sh — install the #709 benchmark toolset (fio + iperf3 + jq) +# on a Debian-based guest or LXC. Idempotent. Not for Proxmox hosts directly: +# on hosts, create the bench LXC (see lxc-bench-setup.sh) and run this inside. +set -eu +export DEBIAN_FRONTEND=noninteractive +apt-get update -qq +apt-get install -y -qq fio iperf3 jq >/dev/null +echo "bench toolset installed: fio=$(fio --version 2>/dev/null | awk '{print $3}') iperf3=$(iperf3 --version 2>/dev/null | awk 'NR==1{print $2}')" diff --git a/proxmox/perf/bench/lxc-bench-setup.sh b/proxmox/perf/bench/lxc-bench-setup.sh new file mode 100644 index 0000000..12242a5 --- /dev/null +++ b/proxmox/perf/bench/lxc-bench-setup.sh @@ -0,0 +1,59 @@ +#!/bin/bash +# lxc-bench-setup.sh — run ON a Proxmox host: stand up the #709 bench LXC +# (Proxmox cannot run docker; this is the host-side packaging of the same +# toolset) and optionally bench a storage path through it. +# +# Usage (from workstation, via tests/remote.sh prox-file): +# lxc-bench-setup.sh [--ctid N] [--store /mnt/path] [--keep] +# --store PATH bind-mount host PATH into the LXC at /mnt/bench and bench it +# --keep leave the LXC running (default: destroyed after the run) +set -eu + +CTID="${BENCH_CTID:-30099}" +STORE="" +KEEP=0 +while [ $# -gt 0 ]; do + case "$1" in + --ctid) CTID="$2"; shift 2 ;; + --store) STORE="$2"; shift 2 ;; + --keep) KEEP=1; shift ;; + *) echo "unknown arg $1" >&2; exit 1 ;; + esac +done + +cleanup() { + if [ "$KEEP" != 1 ] && pct status "$CTID" >/dev/null 2>&1; then + pct stop "$CTID" >/dev/null 2>&1 || true + pct destroy "$CTID" >/dev/null 2>&1 || true + fi +} +trap cleanup EXIT + +# template: fetch the standard Debian 12 LXC template if missing +TPL=$(pveam list local 2>/dev/null | grep -oE 'local:vztmpl/[a-z0-9-]*debian-12-standard[^ ]*\.tar\.zst' | head -1 || true) +if [ -z "$TPL" ]; then + pveam update >/dev/null + pveam download local debian-12-standard_12.7-1_amd64.tar.zst >/dev/null + TPL=$(pveam list local | grep -oE 'local:vztmpl/[a-z0-9-]*debian-12-standard[^ ]*\.tar\.zst' | head -1) +fi +echo "[bench-lxc] template: $TPL" + +MP=() +if [ -n "$STORE" ]; then + MP=(-mp0 "$STORE,mp=/mnt/bench") +fi + +pct create "$CTID" "$TPL" --hostname perfbench --memory 1024 --cores 2 \ + --rootfs local-lvm:8 --net0 name=eth0,bridge=vmbr0,ip=dhcp \ + --unprivileged 1 --features nesting=0 "${MP[@]}" >/dev/null +pct start "$CTID" +sleep 5 + +# toolset in (same installer the guests use; piped in, nothing fetched from outside) +pct exec "$CTID" -- bash -c "export DEBIAN_FRONTEND=noninteractive; apt-get update -qq >/dev/null; apt-get install -y -qq fio iperf3 jq >/dev/null" + +BDIR="/mnt/bench" +[ -z "$STORE" ] && BDIR="/var/tmp" +echo "[bench-lxc] benching $BDIR on CT $CTID" +pct exec "$CTID" -- env BENCH_DIR="$BDIR" bash -s < "$(dirname "$0")/bench-run.sh" +echo "[bench-lxc] done"