Passage visits -78..-89% near-ready; composer worker time back to baseline on Tunnel Network; v239 is 2-4% faster than v236 in 7/8 cells but still +4.3..+13.3% near-ready vs assembler/world. Surface World composer time equals baseline yet near-ready is +4-6%: unexplained. 16/16 seeds, fast tier, Clang/GCC green. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016dhxM43dnWvUu2B5Ph1iG1
114 lines
5.5 KiB
Python
114 lines
5.5 KiB
Python
#!/usr/bin/env python3
|
|
"""Compare assembler/world and v236 composer/classifier phase counters."""
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import re
|
|
import subprocess
|
|
import time
|
|
from collections import defaultdict
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parents[4]
|
|
OUT = ROOT / "Saved/Linux/l136/census"
|
|
DATA = ROOT / "Standalone/data/owner_world.json"
|
|
BINARIES = {
|
|
"assembler-world": ROOT / "Saved/Linux/l130/bin/VoxelForgeCoreHeadless-l130-clang",
|
|
"v236": ROOT / "Saved/Linux/l135/bin/VoxelForgeCoreHeadless-clang-l135",
|
|
"v239": ROOT / "Saved/Linux/l136/bin/VoxelForgeCoreHeadless-l136-clang",
|
|
}
|
|
STAMPS = {
|
|
"assembler-world": "8b3e7bfb4cde2b408ab940925eab973d8375d6b719774d6f72f64ee72b526c35",
|
|
"v236": "8dc4294ce0250a591ee4515471c3c547e796ffa4346ab44f0ae1740bbc3797f5",
|
|
"v239": "ebe6b32a7cd96c5aa69c6dc64ae6b9c6ff4bc18bc484efc5148611c48723c28f",
|
|
}
|
|
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 field(line: str) -> dict[str, str]:
|
|
return dict(FIELDS.findall(line))
|
|
|
|
|
|
def run(strate: int, version: str) -> dict:
|
|
OUT.mkdir(parents=True, exist_ok=True)
|
|
log = OUT / f"{version}-s{strate}.log"
|
|
camera = ",".join(f"{value:.12f}" for value in CAMERAS[strate]) + ",0,0"
|
|
command = ["taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--",
|
|
"timeout", "1740s", str(BINARIES[version]), 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",
|
|
"--stream-scheduler-policy=3"]
|
|
started = time.monotonic()
|
|
with log.open("w", encoding="utf-8") as output:
|
|
result = subprocess.run(command, cwd=ROOT, stdout=output,
|
|
stderr=subprocess.STDOUT, check=False, timeout=1740)
|
|
content = log.read_text(encoding="utf-8", errors="replace")
|
|
stamp_match = re.search(r"^\[VoxelForgeSourceStamp\] sha256=([0-9a-f]+)$", content, re.M)
|
|
if result.returncode or stamp_match is None or stamp_match.group(1) != STAMPS[version]:
|
|
raise SystemExit(f"census failed/stamp mismatch: {log}, exit={result.returncode}, stamp={stamp_match}")
|
|
lod: dict[int, dict] = defaultdict(lambda: defaultdict(float))
|
|
for line in content.splitlines():
|
|
if line.startswith("[WorldAssemblerLODClassification] "):
|
|
values = field(line)
|
|
target = lod[int(values["lod"])]
|
|
for name in ("tiles", "all_air", "all_solid", "mixed", "unclassified",
|
|
"tile_skips", "density_point_calls", "field_eval_sample_points",
|
|
"proof_air_cells", "proof_solid_cells"):
|
|
target[name] = int(values.get(name, "0"))
|
|
target["field_eval_ms_est"] = float(values.get("field_eval_ms_est", "0"))
|
|
elif line.startswith("[PassageComposerTile] "):
|
|
values = field(line)
|
|
level = int(re.search(r"lod(\d+)\)", values["key"]).group(1))
|
|
target = lod[level]
|
|
target["composer_tiles"] += 1
|
|
for name in ("samples", "field_calls", "native_cave_samples", "native_field_calls",
|
|
"room_candidates", "edge_candidates", "features", "route_candidates",
|
|
"passage_iterations", "carve_segment_visits"):
|
|
target[name] += int(values.get(name, "0"))
|
|
target["composer_worker_ms"] += float(values.get("worker_ms", "0"))
|
|
plan = re.search(r"^\[WorldAssemblerPlanTiming\] total_ms=([0-9.]+)", content, re.M)
|
|
cave = re.search(r"^\[CavernPlannerV1\].* plan_ms=([0-9.]+)", content, re.M)
|
|
pipeline = re.search(r"^\[WorldAssemblerTilePipeline\] (.*)$", content, re.M)
|
|
pipeline_fields = field(pipeline.group(1)) if pipeline else {}
|
|
result_row = {
|
|
"strate": strate, "version": version, "source_stamp": stamp_match.group(1),
|
|
"plan_ms": float(plan.group(1)) if plan else None,
|
|
"cave_plan_ms": float(cave.group(1)) if cave else None,
|
|
"tile_pipeline": {key: (float(value) if "." in value else int(value))
|
|
for key, value in pipeline_fields.items()
|
|
if re.fullmatch(r"-?\d+(?:\.\d+)?", value)},
|
|
"lod": {str(key): dict(values) for key, values in sorted(lod.items())},
|
|
"wall_s": round(time.monotonic() - started, 3),
|
|
"log": str(log.relative_to(ROOT)),
|
|
}
|
|
print("[L136CensusRun] " + json.dumps(result_row, sort_keys=True), flush=True)
|
|
return result_row
|
|
|
|
|
|
def main() -> int:
|
|
if any(not path.is_file() for path in (DATA, *BINARIES.values())):
|
|
raise SystemExit("missing census fixture or binary")
|
|
rows = []
|
|
for strate in range(4):
|
|
for version in BINARIES:
|
|
rows.append(run(strate, version))
|
|
(OUT / "runs-partial.json").write_text(json.dumps(rows, indent=2) + "\n")
|
|
summary = {"status": "PASS", "rows": rows,
|
|
"notes": [
|
|
"classifier milliseconds and composer worker milliseconds are cumulative counters, not exclusive wall time",
|
|
"assembler/world predates native cave field counters; field sample fields are only comparable where emitted",
|
|
]}
|
|
(OUT / "summary.json").write_text(json.dumps(summary, indent=2) + "\n")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|