#!/usr/bin/env python3 """Collect two W8 passage-tile counter profiles per owner stratum.""" from __future__ import annotations import json import re import subprocess import time from pathlib import Path ROOT = Path(__file__).resolve().parents[4] OUT = ROOT / "Saved/Linux/l118/passage-counters" DATA = ROOT / "Standalone/data/owner_world.json" BINARY = ROOT / "Saved/Linux/l118/bin/VoxelForgeCoreHeadless-l118-clang" CAMERAS = { 0: (8.0, 16.0, -372.2626953125), 1: (25.8369140625, 3.19921875, -737.0), 2: (19.166015625, -14.2001953125, -753.3740234375), 3: (-20.0625, -5.068359375, -900.353515625), } FIELDS = re.compile(r"([a-zA-Z0-9_]+)=([^ ]+)") def rows(path: Path, tag: str) -> dict[str, dict[str, str]]: result = {} for line in path.read_text(encoding="utf-8", errors="replace").splitlines(): if line.startswith(tag + " "): field = dict(FIELDS.findall(line)) result[field["key"]] = field return result def run(strate: int, replicate: int) -> dict: OUT.mkdir(parents=True, exist_ok=True) label = f"s{strate}-w8-profile{replicate}" log = OUT / f"{label}.log" camera = ",".join(f"{value:.12f}" for value in CAMERAS[strate]) + ",0,0" command = [ "taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--", "timeout", "1740s", str(BINARY), str(DATA), "--world-assembler-prototype", "--stream-benchmark", "--stream-pipeline", "--workers=8", "--clip-radius=3", "--max-clip-level=8", "--max-level=8", f"--camera={camera}", "--profile-lod-work", "--profile-passage-composer", ] started = time.monotonic() with log.open("w", encoding="utf-8") as stream: result = subprocess.run(command, cwd=ROOT, stdout=stream, stderr=subprocess.STDOUT, check=False, timeout=1740) if result.returncode: raise SystemExit(f"passage-counter profile failed: {log}; exit={result.returncode}") composer = rows(log, "[PassageComposerTile]") stages = rows(log, "[CpuTileStages]") selected = [] for key, comp in composer.items(): lod = int(key.rsplit("lod", 1)[1].rstrip(")")) if lod > 2 or int(comp["features"]) == 0: continue stage = stages.get(key) if stage is None: raise SystemExit(f"missing CpuTileStages record for {label} {key}") fallbacks = [int(value) for value in stage["sweep_exact_fallback_by_caller"].split(",")] selected.append({ "features": int(comp["features"]), "sweep_pairs": int(comp["sweep_pairs"]), "sweep_bound_pruned": int(comp.get("sweep_bound_pruned", "0")), "exact_fallbacks": sum(fallbacks), "segment_visits": int(comp["carve_segment_visits"]), }) total = {name: sum(item[name] for item in selected) for name in ("sweep_pairs", "sweep_bound_pruned", "exact_fallbacks", "segment_visits")} row = {"strate": strate, "workers": 8, "replicate": replicate, "passage_tiles_lod02": len(selected), "totals": total, "elapsed_s": round(time.monotonic() - started, 3), "log": str(log.relative_to(ROOT))} print("[L118PassageCounters] " + json.dumps(row, sort_keys=True), flush=True) return row def main() -> int: if not DATA.is_file() or not BINARY.is_file(): raise SystemExit("missing owner data or L118 Clang binary") result = [run(strate, replicate) for strate in range(4) for replicate in (1, 2)] summary = [] for strate in range(4): group = [item for item in result if item["strate"] == strate] summary.append({"strate": strate, "workers": 8, "replicates": len(group), "passage_tiles_lod02_median": sorted( row["passage_tiles_lod02"] for row in group)[len(group) // 2], "totals_mean": {name: sum(row["totals"][name] for row in group) / len(group) for name in group[0]["totals"]}}) (OUT / "summary.json").write_text( json.dumps({"runs": result, "summary": summary}, indent=2) + "\n", encoding="utf-8") return 0 if __name__ == "__main__": raise SystemExit(main())