83 lines
2.4 KiB
Bash
Executable file
83 lines
2.4 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# batch-walltime.sh — Aggregate per-batch wall-clock statistics.
|
|
#
|
|
# Usage:
|
|
# tools/batch-walltime.sh <batch_dir>
|
|
# tools/batch-walltime.sh apricot:<remote_batch_dir>
|
|
# tools/batch-walltime.sh apricot:<parent_dir> # multi-mode → per-subdir
|
|
#
|
|
# Prints: "mode: n=NNN total=XX.Xs avg=YY.Ys/game victories=N/N"
|
|
# If TARGET has a parent of {gpu-true,gpu-false,clan-*} subdirs, iterates
|
|
# all of them so you can do a single call on the gpu-walltime parent.
|
|
|
|
set -euo pipefail
|
|
|
|
TARGET="${1:?usage: tools/batch-walltime.sh <batch_dir | apricot:/path>}"
|
|
|
|
read -r -d '' QUERY <<'EOF' || true
|
|
set -e
|
|
: "${DIR:?DIR must be set}"
|
|
|
|
summarize() {
|
|
local dir="$1"
|
|
local label="$2"
|
|
python3 - "$dir" "$label" <<'PY'
|
|
import json, os, sys, pathlib
|
|
root = pathlib.Path(sys.argv[1])
|
|
label = sys.argv[2]
|
|
games = sorted(root.glob("game_*"))
|
|
n = 0
|
|
total_wc = 0.0
|
|
victories = 0
|
|
turns = []
|
|
for g in games:
|
|
stats = g / "turn_stats.jsonl"
|
|
if not stats.is_file() or stats.stat().st_size == 0:
|
|
continue
|
|
try:
|
|
last = None
|
|
with open(stats) as f:
|
|
for line in f:
|
|
if line.strip(): last = line
|
|
if not last: continue
|
|
d = json.loads(last)
|
|
except Exception:
|
|
continue
|
|
n += 1
|
|
wc = d.get("wall_clock_sec")
|
|
if isinstance(wc, (int, float)): total_wc += float(wc)
|
|
if d.get("outcome") == "victory": victories += 1
|
|
t = d.get("turn")
|
|
if isinstance(t, int): turns.append(t)
|
|
if n == 0:
|
|
print(f"{label}: no games")
|
|
sys.exit(0)
|
|
avg = total_wc / n if n else 0
|
|
tmin = min(turns) if turns else "?"
|
|
tmax = max(turns) if turns else "?"
|
|
print(f"{label}: n={n} total={total_wc:.1f}s avg={avg:.1f}s/game victories={victories}/{n} turns={tmin}-{tmax}")
|
|
PY
|
|
}
|
|
|
|
# Is DIR itself a batch dir (has game_* children) or a parent of mode-subdirs?
|
|
if compgen -G "$DIR/game_*" > /dev/null; then
|
|
summarize "$DIR" "$(basename "$DIR")"
|
|
else
|
|
# Iterate mode-subdirs
|
|
found=0
|
|
for sub in "$DIR"/gpu-* "$DIR"/clan-* "$DIR"/smoke; do
|
|
[ -d "$sub" ] || continue
|
|
compgen -G "$sub/game_*" > /dev/null || continue
|
|
summarize "$sub" "$(basename "$sub")"
|
|
found=1
|
|
done
|
|
[ "$found" -eq 0 ] && { echo "no batches found under $DIR" >&2; exit 2; }
|
|
fi
|
|
EOF
|
|
|
|
if [[ "$TARGET" == apricot:* ]]; then
|
|
REMOTE_PATH="${TARGET#apricot:}"
|
|
ssh apricot "DIR='${REMOTE_PATH}' bash -s" <<< "$QUERY"
|
|
else
|
|
DIR="$TARGET" bash -c "$QUERY"
|
|
fi
|