Scaffolding for the canary-model rework (host-thread-per-guest-thread, opt-in, non-deterministic). No behavior change with the flag off. - XENIA_NATIVE_THREADS=1 selects the new executor; folded into the parallel spawn gate (reuses Arc<Mutex<KernelState>> + worker dispatch). - native_threads_enabled() = single source of truth for guarded branches. - run_execution_native(): Stage-0 body delegates to the iterate-4D free-run executor verbatim (native == freerun for now); Stage 1' will replace the worker set with one host thread per guest thread. - native-gate.sh: functional oracle replacing byte-goldens for the MT path — (1) lockstep golden byte-identity (flag-off safety net), (2) native render milestone (draws>0 && swaps>0), (3) native deadlock stress. GREEN 3/3 on current code. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
88 lines
3.9 KiB
Bash
Executable File
88 lines
3.9 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# native-gate.sh — functional correctness gate for the iterate-4E canary-model
|
|
# native-threads rework (host-thread-per-guest-thread, non-deterministic).
|
|
#
|
|
# Byte-identical goldens cannot gate a multi-threaded run (OS interleaving is
|
|
# nondeterministic), so this script is the REPLACEMENT oracle. It runs three
|
|
# checks and exits 0 iff all pass:
|
|
#
|
|
# 1. LOCKSTEP GOLDEN (flag-off): the deterministic default path stays
|
|
# byte-identical on sylpheed_n200m.json. This is the safety net that
|
|
# proves the native-mode work did not disturb the reference path.
|
|
# 2. NATIVE RENDER MILESTONE: native mode (XENIA_NATIVE_THREADS=1) boots far
|
|
# enough to render — draws>0 && swaps>0 in the run digest — proving the
|
|
# executor runs guest CPU + drives the GPU end-to-end without hanging.
|
|
# 3. NATIVE DEADLOCK STRESS: parallel_stress_short under XENIA_NATIVE_THREADS=1
|
|
# with --halt-on-deadlock; N back-to-back short runs with no panic/hang,
|
|
# surfacing lost-wakeups / lock-order inversions the single run misses.
|
|
#
|
|
# Usage: [SYLPHEED_ISO=...] native-gate.sh [milestone_n] [milestone_timeout_s]
|
|
# milestone_n default 200000000 (renders; matches the golden anchor)
|
|
# milestone_timeout_s default 120
|
|
#
|
|
# The binary must be built first (the caller owns the build so the OOM guardrail
|
|
# CARGO_BUILD_JOBS=4 / free-check stays explicit):
|
|
# CARGO_BUILD_JOBS=4 cargo build --release
|
|
set -u
|
|
cd "$(dirname "$0")" || exit 2
|
|
BIN=./target/release/xenia-rs
|
|
ISO_CHECK=sylpheed.iso
|
|
MN="${1:-200000000}"
|
|
MTO="${2:-120}"
|
|
DIGEST=/tmp/native-gate-digest.json
|
|
LOG=/tmp/native-gate
|
|
mkdir -p "$LOG"
|
|
fails=0
|
|
hr(){ printf '=%.0s' {1..64}; echo; }
|
|
|
|
[ -x "$BIN" ] || { echo "FAIL: build first: CARGO_BUILD_JOBS=4 cargo build --release"; exit 3; }
|
|
|
|
# ---------------------------------------------------------------- 1) golden
|
|
hr; echo "[1/3] LOCKSTEP GOLDEN — flag-off byte-identity (sylpheed_n200m)"; hr
|
|
cargo test --release -p xenia-app --test sylpheed_oracles -- \
|
|
--ignored --nocapture sylpheed_n200m >"$LOG/golden.log" 2>&1
|
|
rc=$?
|
|
if [ $rc -eq 0 ]; then echo " PASS (golden byte-identical)"; else
|
|
echo " FAIL rc=$rc — see $LOG/golden.log"; tail -20 "$LOG/golden.log"; fails=$((fails+1)); fi
|
|
|
|
# ------------------------------------------------------- 2) native milestone
|
|
hr; echo "[2/3] NATIVE RENDER MILESTONE — XENIA_NATIVE_THREADS=1, -n $MN"; hr
|
|
rm -f "$DIGEST"
|
|
XENIA_NATIVE_THREADS=1 timeout "$MTO" "$BIN" check "$ISO_CHECK" \
|
|
-n "$MN" --gpu-inline --out "$DIGEST" >"$LOG/milestone.log" 2>&1
|
|
rc=$?
|
|
pkill -x xenia-rs 2>/dev/null
|
|
if [ $rc -ne 0 ]; then
|
|
echo " FAIL emulator rc=$rc (timeout=$MTO s) — see $LOG/milestone.log"
|
|
tail -20 "$LOG/milestone.log"; fails=$((fails+1))
|
|
elif [ ! -f "$DIGEST" ]; then
|
|
echo " FAIL no digest written — see $LOG/milestone.log"; fails=$((fails+1))
|
|
else
|
|
read -r draws swaps instrs < <(python3 - "$DIGEST" <<'PY'
|
|
import json,sys
|
|
d=json.load(open(sys.argv[1]))
|
|
print(d.get("draws",0), d.get("swaps",0), d.get("instructions",0))
|
|
PY
|
|
)
|
|
echo " digest: instructions=$instrs draws=$draws swaps=$swaps"
|
|
if [ "${draws:-0}" -gt 0 ] && [ "${swaps:-0}" -gt 0 ]; then
|
|
echo " PASS (native mode renders)"
|
|
else
|
|
echo " FAIL (native mode did not render: draws=$draws swaps=$swaps)"; fails=$((fails+1)); fi
|
|
fi
|
|
|
|
# ---------------------------------------------------------- 3) native stress
|
|
hr; echo "[3/3] NATIVE DEADLOCK STRESS — parallel_stress_short (native)"; hr
|
|
XENIA_NATIVE_THREADS=1 cargo test --release -p xenia-app --test parallel_stress -- \
|
|
--nocapture parallel_stress_short >"$LOG/stress.log" 2>&1
|
|
rc=$?
|
|
if [ $rc -eq 0 ]; then
|
|
grep -o "runs=[0-9]* ok=[0-9]* failed=[0-9]*" "$LOG/stress.log" | tail -1
|
|
echo " PASS (no deadlock/panic)"
|
|
else
|
|
echo " FAIL rc=$rc — see $LOG/stress.log"; tail -20 "$LOG/stress.log"; fails=$((fails+1)); fi
|
|
|
|
hr
|
|
if [ "$fails" -eq 0 ]; then echo "NATIVE GATE: PASS (3/3)"; exit 0
|
|
else echo "NATIVE GATE: FAIL ($fails/3 checks failed)"; exit 1; fi
|