wip(assembler): round L2 -- the cross-platform hash check can fail; FP contraction changes the world

Clang -ffp-contract=on/fast and GCC's default (fast) all change the density hash on the L1 view;
contraction off reproduces L1 (= Windows S13) at W1/W12. Seed sweep: 48 FloatingIslands seeds and
14 effective SurfaceWorld seeds (34 of 48 fell on a seed-independent cube) match across Clang/GCC
and W1/W12. Standalone gains --seed/--recipe/--render-distance-chunks (viewer + headless) and a
Windows replay script. Linux standalone workers get 32 MiB pthread stacks (TLS is 17.3 MiB/thread),
so no external stack limit is needed. No Core or world-output change; MSVC compile unverified.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Fr0zkaandClaude Opus 5.5 committed 2026-10-19 18:18:34 +02:00
1 parent 1276fd11e3
commit 303b7b9f24
17 files changed
+1401 -13

No files matched your search

@@ -0,0 +1,164 @@
#!/usr/bin/env python3
"""Run the deterministic Linux2 seed/compiler/worker matrix under the owner limits."""
import csv
import re
import subprocess
import sys
import time
from pathlib import Path
ROOT = Path.cwd()
ROUND = ROOT / "Standalone/Research/WorldAssemblerM3/Linux2"
LOG_DIR = ROOT / "Saved/Linux"
MEASURE = ROUND / "MeasureProcess.py"
DATA = ROOT / "Standalone/data/owner_world.json"
BINARIES = {
"clang19": ROOT / "Standalone/bin/linux/VoxelForgeCoreHeadless-clang19-l2-off",
"gcc14": ROOT / "Standalone/bin/linux/VoxelForgeCoreHeadless-gcc14-l2-off",
}
CAMERAS = {
"surface-world": "0,-35,-487.94,0,-22",
"floating-islands": "0,0,-32,0,-22",
}
HASH_RE = re.compile(
r"\[PipelineWholeViewHash\] tiles=(\d+) density=0x([0-9a-f]+) "
r"mesh=0x([0-9a-f]+) payload=0x([0-9a-f]+) topology=0x([0-9a-f]+)"
)
VOLUME_RE = re.compile(
r"\[PipelineVolume\] tiles=(\d+) lod=(\d+)\.\.(\d+) "
r"min_voxel=\((-?\d+),(-?\d+),(-?\d+)\) "
r"max_voxel=\((-?\d+),(-?\d+),(-?\d+)\)"
)
READY_RE = re.compile(r"\[StreamPipeline\].*whole_view_ready=([0-9.]+)s")
RESOURCE_RE = re.compile(r"\[ProcessResources\] exit_code=(-?\d+) wall_s=([0-9.]+) peak_rss_kib=(\d+)")
def main() -> int:
if not (1 <= len(sys.argv) <= 2):
raise SystemExit("usage: RunSeedSweep.py [budget-seconds; default 1800]")
budget_seconds = int(sys.argv[1]) if len(sys.argv) == 2 else 1800
seeds = [int(line.strip()) for line in (ROUND / "seeds.txt").read_text().splitlines() if line.strip()]
if len(seeds) != 48 or len(set(seeds)) != len(seeds):
raise SystemExit("seeds.txt must contain 48 unique signed int32 seeds")
missing = [str(path) for path in [MEASURE, DATA, *BINARIES.values()] if not path.is_file()]
if missing:
raise SystemExit("missing sweep input/build: " + ", ".join(missing))
LOG_DIR.mkdir(parents=True, exist_ok=True)
output_path = ROUND / "seed_hashes.csv"
fields = [
"seed", "recipe", "compiler", "workers", "tiles", "lod_min", "lod_max",
"min_x", "min_y", "min_z", "max_x", "max_y", "max_z",
"density_hash", "mesh_hash", "payload_hash", "topology_hash",
"whole_view_ready_s", "wall_s", "peak_rss_kib", "exit_code", "status",
]
started = time.monotonic()
total = len(seeds) * len(CAMERAS) * len(BINARIES) * 2
print(f"Sweep: {len(seeds)} seeds × 2 recipes × 2 compilers × W1/W12 = {total} runs; budget={budget_seconds}s", flush=True)
with output_path.open("w", newline="") as csv_file:
writer = csv.DictWriter(csv_file, fieldnames=fields)
writer.writeheader()
for seed in seeds:
for recipe, camera in CAMERAS.items():
for compiler, binary in BINARIES.items():
for workers in (1, 12):
remaining = budget_seconds - (time.monotonic() - started)
if remaining <= 0:
print("Sweep exceeded its 30 minute budget; stopping.", file=sys.stderr, flush=True)
return 124
stem = f"linux2-seed-{seed}-{recipe}-{compiler}-w{workers}"
log_path = LOG_DIR / f"{stem}.log"
args = [
str(binary), str(DATA), f"--seed={seed}", f"--recipe={recipe}",
"--render-distance-chunks=0", f"--workers={workers}",
"--world-assembler-prototype", "--stream-benchmark", "--stream-pipeline",
"--stream-hash", "--force-generate", "--clip-radius=1",
"--max-clip-level=0", f"--camera={camera}", "--far-horizon-lod8-step=0",
]
command = [
"taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--",
"python3", str(MEASURE), *args,
]
with log_path.open("w") as log_file:
log_file.write("[SweepCommand] " + " ".join(command) + "\n")
log_file.flush()
try:
result = subprocess.run(
command, cwd=ROOT, stdout=log_file, stderr=subprocess.STDOUT,
timeout=min(900, max(1, remaining)), check=False,
)
exit_code = result.returncode
except subprocess.TimeoutExpired:
exit_code = 124
log_file.write("\n[SweepTimeout] run reached its allotted limit\n")
output = log_path.read_text(errors="replace")
volume = VOLUME_RE.search(output)
hashes = HASH_RE.search(output)
ready = READY_RE.search(output)
resources = RESOURCE_RE.search(output)
passed = exit_code == 0 and volume and hashes and ready and resources
row = {
"seed": seed, "recipe": recipe, "compiler": compiler, "workers": workers,
"tiles": "", "lod_min": "", "lod_max": "",
"min_x": "", "min_y": "", "min_z": "", "max_x": "", "max_y": "", "max_z": "",
"density_hash": "", "mesh_hash": "", "payload_hash": "", "topology_hash": "",
"whole_view_ready_s": "", "wall_s": "", "peak_rss_kib": "",
"exit_code": exit_code, "status": "PASS" if passed else "FAIL",
}
if passed:
row.update({
"tiles": hashes.group(1),
"lod_min": volume.group(2), "lod_max": volume.group(3),
"min_x": volume.group(4), "min_y": volume.group(5), "min_z": volume.group(6),
"max_x": volume.group(7), "max_y": volume.group(8), "max_z": volume.group(9),
"density_hash": "0x" + hashes.group(2), "mesh_hash": "0x" + hashes.group(3),
"payload_hash": "0x" + hashes.group(4), "topology_hash": "0x" + hashes.group(5),
"whole_view_ready_s": ready.group(1), "wall_s": resources.group(2),
"peak_rss_kib": resources.group(3),
})
writer.writerow(row)
csv_file.flush()
completed = sum(1 for _ in output_path.open()) - 1
elapsed = time.monotonic() - started
print(f"[{completed}/{total}] seed={seed} recipe={recipe} compiler={compiler} W{workers} "
f"tiles={row['tiles']} wall={row['wall_s']}s status={row['status']} "
f"elapsed={elapsed:.1f}s", flush=True)
if not passed:
print(f"Run failed; details: {log_path}", file=sys.stderr, flush=True)
return exit_code or 1
rows = list(csv.DictReader(output_path.open(newline="")))
keys = ("density_hash", "mesh_hash", "payload_hash", "topology_hash")
checks = []
for seed in seeds:
for recipe in CAMERAS:
for workers in (1, 12):
pair = [r for r in rows if int(r["seed"]) == seed and r["recipe"] == recipe
and int(r["workers"]) == workers]
equal = len(pair) == 2 and all(pair[0][key] == pair[1][key] for key in keys)
checks.append((seed, recipe, workers, equal))
worker_checks = []
for seed in seeds:
for recipe in CAMERAS:
for compiler in BINARIES:
pair = [r for r in rows if int(r["seed"]) == seed and r["recipe"] == recipe
and r["compiler"] == compiler]
equal = len(pair) == 2 and all(pair[0][key] == pair[1][key] for key in keys)
worker_checks.append((seed, recipe, compiler, equal))
summary_path = ROUND / "seed_sweep_summary.txt"
mismatch_count = sum(not equal for _, _, _, equal in checks)
worker_mismatch_count = sum(not equal for _, _, _, equal in worker_checks)
summary_path.write_text(
f"runs={len(rows)} seeds={len(seeds)} recipes={len(CAMERAS)} compilers={len(BINARIES)} "
f"workers=1,12 cross_compiler_comparisons={len(checks)} cross_compiler_mismatches={mismatch_count} "
f"cross_worker_comparisons={len(worker_checks)} cross_worker_mismatches={worker_mismatch_count} "
f"elapsed_s={time.monotonic()-started:.3f}\n"
)
print(summary_path.read_text(), end="", flush=True)
return 0 if mismatch_count == 0 and worker_mismatch_count == 0 else 3
if __name__ == "__main__":
raise SystemExit(main())