98 lines
3.4 KiB
Bash
Executable File
98 lines
3.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# run_melee_strong_field.sh — drive the STRONG-FIELD melee A/B
|
|
# (see common_libs/tests/measure_melee_strong_field.nim).
|
|
#
|
|
# Builds ONE frozen ModularBot (from `git archive HEAD`), then runs one process
|
|
# per arm in parallel; each process owns its own Tank Royale server on an
|
|
# ephemeral port. Output: <outdir>/<arm>/run<N>.json (+ .bot.stdout.log).
|
|
#
|
|
# common_libs/tests/run_melee_strong_field.sh [outdir]
|
|
#
|
|
# Env:
|
|
# MELEE_RUNS (default 12)
|
|
# MELEE_ROUNDS (default 5)
|
|
# MELEE_ARMS (default "pattern bb_ret bb_decay")
|
|
# MELEE_FIELD (default "/tmp/tr_bots/Diamond,/tmp/tr_bots/Dookious,/tmp/tr_bots/GresSuffurd")
|
|
# WAIT_ARENA minutes to wait for foreign battles (default 45)
|
|
#
|
|
# ARENA SERIALIZATION: refuses to start (or waits) while another job's battles
|
|
# are running; never pkills a foreign process. Kills only its own process groups
|
|
# on EXIT/INT/TERM.
|
|
set -euo pipefail
|
|
|
|
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
REPO="$(cd "$HERE/../.." && pwd)"
|
|
OUTDIR="${1:-/tmp/melee_strong_field}"
|
|
RUNS="${MELEE_RUNS:-12}"
|
|
ROUNDS="${MELEE_ROUNDS:-5}"
|
|
ARMS_STR="${MELEE_ARMS:-pattern bb_ret bb_decay}"
|
|
WAIT_ARENA="${WAIT_ARENA:-45}"
|
|
export MELEE_FIELD="${MELEE_FIELD:-/tmp/tr_bots/Diamond,/tmp/tr_bots/Dookious,/tmp/tr_bots/GresSuffurd}"
|
|
BIN="$HERE/measure_melee_strong_field"
|
|
|
|
[[ -x "$BIN" ]] || { echo "ERROR: build the runner first: nim c --nimcache:/tmp/nc_j124 --path:common_libs $HERE/measure_melee_strong_field.nim" >&2; exit 1; }
|
|
|
|
# ── arena serialization (bracketed patterns: pgrep must not match itself) ────
|
|
FOREIGN='[r]un_bridge_battle.sh|[r]obocode_shim.TrBattleCapture|[r]obocode_shim.LegacyBotBridge|[M]odularBot_bin|[m]easure_melee'
|
|
foreign() { pgrep -af "$FOREIGN" 2>/dev/null | grep -v "$OUTDIR" || true; }
|
|
if [[ -n "$(foreign)" ]]; then
|
|
if (( WAIT_ARENA <= 0 )); then
|
|
echo "[driver] ERROR: arena busy with another job's battles:" >&2
|
|
foreign | sed 's/^/ /' >&2
|
|
exit 3
|
|
fi
|
|
echo "[driver] arena busy — waiting up to ${WAIT_ARENA} min:"
|
|
foreign | sed 's/^/ /'
|
|
deadline=$(( $(date +%s) + WAIT_ARENA * 60 ))
|
|
while :; do
|
|
sleep 60
|
|
if [[ -z "$(foreign)" ]]; then echo "[driver] arena free."; break; fi
|
|
if (( $(date +%s) >= deadline )); then
|
|
echo "[driver] ERROR: arena still busy after ${WAIT_ARENA} min; NOT starting." >&2
|
|
exit 3
|
|
fi
|
|
echo "[driver] still busy at $(date +%H:%M:%S)"
|
|
done
|
|
fi
|
|
|
|
mkdir -p "$OUTDIR"
|
|
echo "[driver] building frozen ModularBot…"
|
|
"$BIN" --outdir "$OUTDIR" --build-only
|
|
|
|
read -r -a ARMS <<< "$ARMS_STR"
|
|
PIDS=()
|
|
cleanup() {
|
|
local rc=$?
|
|
trap - EXIT INT TERM
|
|
for p in "${PIDS[@]:-}"; do
|
|
[[ -n "$p" ]] || continue
|
|
kill -TERM -- "-$p" 2>/dev/null || true
|
|
done
|
|
sleep 1
|
|
for p in "${PIDS[@]:-}"; do
|
|
[[ -n "$p" ]] || continue
|
|
kill -KILL -- "-$p" 2>/dev/null || true
|
|
done
|
|
pkill -f "[m]easure_melee_strong_field.*$OUTDIR" 2>/dev/null || true
|
|
exit "$rc"
|
|
}
|
|
trap cleanup EXIT INT TERM
|
|
|
|
for arm in "${ARMS[@]}"; do
|
|
echo "[driver] launching arm $arm (runs=$RUNS rounds=$ROUNDS) field=$MELEE_FIELD"
|
|
setsid "$BIN" --outdir "$OUTDIR" --arm "$arm" \
|
|
--run-start 1 --run-count "$RUNS" --rounds "$ROUNDS" \
|
|
> "$OUTDIR/$arm.driver.log" 2>&1 &
|
|
PIDS+=("$!")
|
|
sleep 3 # stagger so concurrent servers do not race for the same free port
|
|
done
|
|
|
|
echo "[driver] all arms launched; waiting…"
|
|
FAIL=0
|
|
for p in "${PIDS[@]}"; do
|
|
wait "$p" || FAIL=$((FAIL + 1))
|
|
done
|
|
PIDS=()
|
|
echo "[driver] done (failed arm processes: $FAIL)"
|
|
exit "$FAIL"
|