Charts and reproducible benchmarks, Makefile, expanded .gitignore
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Executable
+94
@@ -0,0 +1,94 @@
|
||||
#!/usr/bin/env bash
|
||||
# Reproducible measurements behind COMPARISON.md and the charts. Writes JSON (default docs/charts/bench.json).
|
||||
# Tools that are not installed or not usable are skipped and recorded as null, never guessed.
|
||||
# Usage: scripts/bench.sh [output.json] Environment: BENCH_RUNS (default 10)
|
||||
set -u
|
||||
cd "$(dirname "$0")/.."
|
||||
OUT=${1:-docs/charts/bench.json}
|
||||
RUNS=${BENCH_RUNS:-10}
|
||||
DOOS=$(readlink -f build/doos)
|
||||
[ -x "$DOOS" ] || { echo "bench: build first (make build)" >&2; exit 1; }
|
||||
export DOOS_HOME=$(mktemp -d)
|
||||
trap '"$DOOS" delete --yes ha >/dev/null 2>&1; rm -rf "$DOOS_HOME"' EXIT
|
||||
|
||||
have() { command -v "$1" >/dev/null 2>&1; }
|
||||
now() { date +%s%N; }
|
||||
# avg_ms LABEL CMD... -> prints average ms per run, or "null" when the command fails
|
||||
avg_ms() {
|
||||
timeout 180 "$@" >/dev/null 2>&1 || { echo null; return; } # warm-up, may pull an image
|
||||
local s e i; s=$(now)
|
||||
for i in $(seq "$RUNS"); do timeout 60 "$@" >/dev/null 2>&1 || { echo null; return; }; done
|
||||
e=$(now); awk -v s="$s" -v e="$e" -v n="$RUNS" 'BEGIN{printf "%.1f", (e-s)/1e6/n}'
|
||||
}
|
||||
note() { echo "bench: $*" >&2; }
|
||||
|
||||
# ---- setup doos containers (host mode needs nothing, image mode downloads Alpine once)
|
||||
"$DOOS" image add alpine >/dev/null 2>&1 || note "alpine image unavailable, image-mode rows will be null"
|
||||
"$DOOS" get_or_create --net none hn >/dev/null 2>&1
|
||||
"$DOOS" get_or_create hs >/dev/null 2>&1
|
||||
"$DOOS" get_or_create --image alpine --net none an >/dev/null 2>&1
|
||||
"$DOOS" get_or_create --image alpine as >/dev/null 2>&1
|
||||
"$DOOS" get_or_create --image alpine --net pasta ap >/dev/null 2>&1
|
||||
|
||||
BW_BASE="--unshare-user --unshare-pid --unshare-ipc --unshare-uts --die-with-parent --ro-bind /usr /usr --symlink usr/bin /bin --symlink usr/lib /lib --symlink usr/lib64 /lib64 --proc /proc --dev /dev"
|
||||
rows=()
|
||||
add() { rows+=("{\"id\":\"$1\",\"label\":\"$2\",\"group\":\"$3\",\"kind\":\"$4\",\"ms\":$5}"); }
|
||||
|
||||
echo "bench: startup, $RUNS runs each" >&2
|
||||
if have bwrap; then
|
||||
add bwrap_none "bubblewrap (host /usr)" none other "$(avg_ms bwrap --unshare-all $BW_BASE true)"
|
||||
add bwrap_net "bubblewrap (host /usr)" default other "$(avg_ms bwrap $BW_BASE true)"
|
||||
fi
|
||||
add doos_host_none "doos host mode" none doos "$(avg_ms "$DOOS" attach hn -- true)"
|
||||
add doos_alpine_none "doos Alpine image" none doos "$(avg_ms "$DOOS" attach an -- true)"
|
||||
add doos_host_slirp "doos host mode" default doos "$(avg_ms "$DOOS" attach hs -- true)"
|
||||
add doos_alpine_slirp "doos Alpine image" default doos "$(avg_ms "$DOOS" attach as -- true)"
|
||||
add doos_alpine_pasta "doos Alpine, pasta" default doos "$(avg_ms "$DOOS" attach ap -- true)"
|
||||
if have podman; then
|
||||
add podman_none "Podman Alpine" none other "$(avg_ms podman run --rm --network none alpine true)"
|
||||
add podman_net "Podman Alpine" default other "$(avg_ms podman run --rm alpine true)"
|
||||
fi
|
||||
if have docker; then
|
||||
add docker_none "Docker Alpine (rootful)" none other "$(avg_ms docker run --rm --network none alpine true)"
|
||||
add docker_net "Docker Alpine (rootful)" default other "$(avg_ms docker run --rm alpine true)"
|
||||
fi
|
||||
|
||||
# ---- binary sizes
|
||||
size_of() { local p; p=$(command -v "$1" 2>/dev/null) && stat -L -c %s "$p" || echo null; }
|
||||
sizes=()
|
||||
for t in bwrap crun doos docker podman; do
|
||||
if [ "$t" = doos ]; then b=$(stat -c %s "$DOOS"); else b=$(size_of "$t"); fi
|
||||
sizes+=("{\"id\":\"$t\",\"bytes\":$b}")
|
||||
done
|
||||
|
||||
# ---- cpu limit: 4 busy loops for 4 seconds, CPU seconds consumed (user+sys)
|
||||
cpu_run() {
|
||||
/usr/bin/time -f "%U %S" "$DOOS" attach "$1" -- sh -c 'for i in 1 2 3 4; do (timeout 4 sh -c "while :; do :; done" &); done; sleep 4.2' 2>&1 >/dev/null | tail -1 | awk '{printf "%.2f", $1+$2}'
|
||||
}
|
||||
echo "bench: cpu limit" >&2
|
||||
"$DOOS" get_or_create hc >/dev/null 2>&1; "$DOOS" get_or_create --cpus 0.5 hc5 >/dev/null 2>&1
|
||||
cpu_free=$(cpu_run hc); cpu_half=$(cpu_run hc5)
|
||||
"$DOOS" delete --yes hc >/dev/null 2>&1; "$DOOS" delete --yes hc5 >/dev/null 2>&1
|
||||
|
||||
ver() { "$@" 2>/dev/null | head -1 | tr -d '"\\' ; }
|
||||
json_join() { local IFS=,; echo "$*"; }
|
||||
cat > "$OUT" <<JSON
|
||||
{
|
||||
"meta": {
|
||||
"date": "$(date +%F)",
|
||||
"kernel": "$(uname -r)",
|
||||
"cpus": $(nproc),
|
||||
"runs": $RUNS,
|
||||
"doos": "$(cat VERSION)",
|
||||
"podman": "$(have podman && ver podman --version || echo none)",
|
||||
"docker": "$(have docker && ver docker --version || echo none)",
|
||||
"bubblewrap": "$(have bwrap && ver bwrap --version || echo none)",
|
||||
"src_lines": $(cat src/*.cpp src/*.hpp | wc -l),
|
||||
"shared_libs": $(ldd "$DOOS" | wc -l)
|
||||
},
|
||||
"startup": [$(json_join "${rows[@]}")],
|
||||
"sizes": [$(json_join "${sizes[@]}")],
|
||||
"cpu": {"wall_seconds": 4.2, "busy_loops": 4, "unlimited": ${cpu_free:-null}, "half_cpu": ${cpu_half:-null}}
|
||||
}
|
||||
JSON
|
||||
echo "bench: wrote $OUT" >&2
|
||||
@@ -22,6 +22,7 @@ if grep -rl $'\xe2\x80\x94' --exclude-dir=build --exclude-dir=.git . | grep -q .
|
||||
echo "em dash found, remove it first" >&2; exit 1
|
||||
fi
|
||||
|
||||
python3 docs/charts/make_charts.py
|
||||
scripts/check-docs.sh
|
||||
echo "$new" > VERSION
|
||||
cmake -S . -B build >/dev/null
|
||||
|
||||
Reference in New Issue
Block a user