#!/usr/bin/env python3 """Check the L25 hash command and 24 m crossing across compilers and workers.""" import os import re import subprocess import time from pathlib import Path ROOT = Path(__file__).resolve().parents[4] OUT = ROOT / "Saved/Linux/l32" OUT.mkdir(parents=True, exist_ok=True) RUN_TAG = os.environ.get("VOXELFORGE_DETERMINISM_TAG", "").strip() RUN_RESUME = os.environ.get("VOXELFORGE_DETERMINISM_RESUME", "0") == "1" BINARIES = { "clang": Path(os.environ.get("VOXELFORGE_L32_CLANG_BINARY", str(OUT / "bin/VoxelForgeCoreHeadless-l32-clang-v20"))), "gcc": Path(os.environ.get("VOXELFORGE_L32_GCC_BINARY", str(OUT / "bin/VoxelForgeCoreHeadless-l32-gcc-v20"))), } HASH_PATTERN = re.compile( r"^\[Pipeline(?:FullDetailHash|WholeViewHash|LODHash|ExactQueryHash)\].*$", re.M) candidate_reference = {} rows = [] failed = False prior_elapsed = {} if RUN_RESUME and RUN_TAG: prior_log = OUT / f"determinism-{RUN_TAG}-runner.log" if prior_log.exists(): for line in prior_log.read_text(encoding="utf-8", errors="replace").splitlines(): match = re.match(r"^(\S+) elapsed=([0-9.]+)s .* PASS$", line) if match: prior_elapsed[match.group(1)] = float(match.group(2)) def run(kind, compiler, recipe, workers): global failed tag = f"-{RUN_TAG}" if RUN_TAG else "" name = f"{kind}{tag}-{compiler}-{recipe}-w{workers}" logfile = OUT / f"{name}.log" command = [ "taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--", str(BINARIES[compiler]), str(ROOT / "Standalone/data/owner_world.json"), "--world-assembler-prototype", "--stream-benchmark", "--stream-pipeline", "--stream-hash", "--force-generate", "--clip-radius=3", "--max-clip-level=8", "--far-horizon-lod8-step=0", f"--workers={workers}", f"--recipe={recipe}", ] if kind == "crossing24": command.extend(("--camera-step=24,0,0", "--region-crossing")) if RUN_RESUME and name in prior_elapsed and logfile.exists(): result = subprocess.CompletedProcess(command, 0) elapsed = prior_elapsed[name] else: started = time.monotonic() try: with logfile.open("w", encoding="utf-8") as stream: result = subprocess.run(command, stdout=stream, stderr=subprocess.STDOUT, timeout=900, check=False) except subprocess.TimeoutExpired: result = None elapsed = time.monotonic() - started text = logfile.read_text(encoding="utf-8", errors="replace") stamps = re.findall( r"^\[WorldAssemblerRecipeAudit\] requested=([^ ]+) actual=([^ ]+).*status=([^ ]+)$", text, re.M) hashes = HASH_PATTERN.findall(text) key = (kind, recipe) reference = candidate_reference.get(key) stable = reference is None or hashes == reference if reference is None and hashes: candidate_reference[key] = hashes ok = (result is not None and result.returncode == 0 and stamps == [(recipe, recipe, "PASS")] and "hash=on" in text and len(hashes) == 12 and stable) rows.append((kind, recipe, compiler, workers, elapsed, result.returncode if result else "TIMEOUT", len(hashes), ok)) print(f"{name} elapsed={elapsed:.1f}s recipe={stamps[0][1] if stamps else 'MISSING'} " f"hashes={len(hashes)} stable_across_matrix={'yes' if stable else 'no'} " f"{'PASS' if ok else 'FAIL'}", flush=True) failed |= not ok for kind in ("l25", "crossing24"): for recipe in ("surface-world", "floating-islands"): for compiler in ("clang", "gcc"): for workers in (1, 8, 12): run(kind, compiler, recipe, workers) summary = OUT / (f"determinism-{RUN_TAG}.csv" if RUN_TAG else "determinism.csv") summary.write_text( "kind,recipe,compiler,workers,elapsed_seconds,exit_code,hash_rows,status\n" + "".join(f"{kind},{recipe},{compiler},{workers},{elapsed:.3f},{code},{count}," f"{'PASS' if ok else 'FAIL'}\n" for kind, recipe, compiler, workers, elapsed, code, count, ok in rows), encoding="utf-8") print(f"[L32Determinism] runs={len(rows)} pass={sum(row[-1] for row in rows)} " f"fail={sum(not row[-1] for row in rows)} summary={summary}", flush=True) raise SystemExit(1 if failed or len(rows) != 24 else 0)