#!/usr/bin/env bash set -euo pipefail # Quick allocator matrix for the Random Mixed benchmark family (no long soaks). # # Runs N times and prints mean/median/CV for: # - hakmem (Standard) # - hakmem (FAST PGO) if present # - system # - mimalloc (direct-link) if present # - jemalloc (LD_PRELOAD) if JEMALLOC_SO is set # - tcmalloc (LD_PRELOAD) if TCMALLOC_SO is set # # Usage: # make bench_random_mixed_system bench_random_mixed_hakmem bench_random_mixed_mi # make pgo-fast-full # optional (builds bench_random_mixed_hakmem_minimal_pgo) # export JEMALLOC_SO=/path/to/libjemalloc.so.2 # export TCMALLOC_SO=/path/to/libtcmalloc.so # scripts/run_allocator_quick_matrix.sh # # Tunables: # ITERS=20000000 WS=400 SEED=1 RUNS=10 root_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" cd "${root_dir}" profile="${HAKMEM_PROFILE:-MIXED_TINYV3_C7_SAFE}" iters="${ITERS:-20000000}" ws="${WS:-400}" seed="${SEED:-1}" runs="${RUNS:-10}" require_bin() { local b="$1" if [[ ! -x "${b}" ]]; then echo "[matrix] Missing binary: ${b}" >&2 exit 1 fi } extract_throughput() { # Reads "Throughput = 54845687 ops/s ..." and prints the integer. rg -o "Throughput = +[0-9]+ ops/s" | rg -o "[0-9]+" } stats_py=' import math,statistics,sys xs=[int(x) for x in sys.stdin.read().strip().split() if x.strip()] if not xs: sys.exit(1) xs_sorted=sorted(xs) mean=sum(xs)/len(xs) median=statistics.median(xs_sorted) stdev=statistics.pstdev(xs) if len(xs)>1 else 0.0 cv=(stdev/mean*100.0) if mean>0 else 0.0 print(f"runs={len(xs)} mean={mean/1e6:.2f}M median={median/1e6:.2f}M cv={cv:.2f}% min={min(xs)/1e6:.2f}M max={max(xs)/1e6:.2f}M") ' run_n() { local label="$1"; shift local cmd=( "$@" ) echo "" echo "== ${label} ==" for i in $(seq 1 "${runs}"); do "${cmd[@]}" 2>&1 | extract_throughput || true done | python3 -c "${stats_py}" } require_bin ./bench_random_mixed_system require_bin ./bench_random_mixed_hakmem if [[ -x ./scripts/run_mixed_10_cleanenv.sh ]]; then # IMPORTANT: hakmem must run under the same profile+cleanenv SSOT as Phase runs. # Otherwise it will silently use a different route configuration and appear "much slower". run_n "hakmem (Standard, SSOT profile=${profile})" \ env HAKMEM_PROFILE="${profile}" BENCH_BIN=./bench_random_mixed_hakmem ITERS="${iters}" WS="${ws}" RUNS=1 \ ./scripts/run_mixed_10_cleanenv.sh else run_n "hakmem (Standard, raw)" ./bench_random_mixed_hakmem "${iters}" "${ws}" "${seed}" fi if [[ -x ./bench_random_mixed_hakmem_minimal_pgo ]]; then if [[ -x ./scripts/run_mixed_10_cleanenv.sh ]]; then run_n "hakmem (FAST PGO, SSOT profile=${profile})" \ env HAKMEM_PROFILE="${profile}" BENCH_BIN=./bench_random_mixed_hakmem_minimal_pgo ITERS="${iters}" WS="${ws}" RUNS=1 \ ./scripts/run_mixed_10_cleanenv.sh else run_n "hakmem (FAST PGO, raw)" ./bench_random_mixed_hakmem_minimal_pgo "${iters}" "${ws}" "${seed}" fi else echo "" echo "== hakmem (FAST PGO) ==" echo "skipped (missing ./bench_random_mixed_hakmem_minimal_pgo; build via: make pgo-fast-full)" fi run_n "system" ./bench_random_mixed_system "${iters}" "${ws}" "${seed}" if [[ -x ./bench_random_mixed_mi ]]; then run_n "mimalloc (direct link)" ./bench_random_mixed_mi "${iters}" "${ws}" "${seed}" else echo "" echo "== mimalloc (direct link) ==" echo "skipped (missing ./bench_random_mixed_mi; build via: make bench_random_mixed_mi)" fi if [[ -n "${JEMALLOC_SO:-}" && -e "${JEMALLOC_SO}" ]]; then run_n "jemalloc (LD_PRELOAD)" env LD_PRELOAD="$(realpath "${JEMALLOC_SO}")" ./bench_random_mixed_system "${iters}" "${ws}" "${seed}" fi if [[ -n "${TCMALLOC_SO:-}" && -e "${TCMALLOC_SO}" ]]; then run_n "tcmalloc (LD_PRELOAD)" env LD_PRELOAD="$(realpath "${TCMALLOC_SO}")" ./bench_random_mixed_system "${iters}" "${ws}" "${seed}" fi