fix: signed-overflow UB in VoxelHash made cave placement compiler-dependent; all generators LOD0-8; speed matrix (L60)
VoxelHash::Cell/Pair, legacy Cellular3D and the shared Core cellular hash added 0x7FFFFFFF to a signed int32 before casting to uint32; overflow is undefined, so Clang and GCC placed cave passage 1 differently (first differing sample at LOD1 tile (0,64,-512)). The bias is now done in unsigned arithmetic, in both the standalone copy and the Unreal plugin header (Source/VoxelForge/Public/VoxelCaveMorphology.h). Native caves, motifs and lattice now stream LOD0-8 with skirts and cross-level transitions. New verify.py --speed-matrix runs every generator on one asserted-identical view (5 interleaved runs): motifs 1.33, profiles 1.30-1.32, caves 1.41, natural SW 1.67, lattice 1.70, FI 4.93 s whole view. fast/medium/full PASS, Clang/GCC peer hashes equal. Research R29 (open-edge ledge) and R30 (compiler-divergence suspects). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016dhxM43dnWvUu2B5Ph1iG1
This commit is contained in:
1 parent
fbae82e024
commit
c0c204ba50
15 files changed
+938
-65
No files matched your search
@@ -28,6 +28,7 @@ LINUX53 = ROOT / "Standalone/Research/WorldAssemblerM3/Linux53"
|
||||
LINUX54 = ROOT / "Standalone/Research/WorldAssemblerM3/Linux54"
|
||||
LINUX56 = ROOT / "Standalone/Research/WorldAssemblerM3/Linux56"
|
||||
LINUX58 = ROOT / "Standalone/Research/WorldAssemblerM3/Linux58"
|
||||
LINUX60 = ROOT / "Standalone/Research/WorldAssemblerM3/Linux60"
|
||||
OWNER = ROOT / "Standalone/data/owner_world.json"
|
||||
OUT_DEFAULT = ROOT / "Saved/Linux/l42"
|
||||
|
||||
@@ -39,6 +40,8 @@ PARSER.add_argument("--baseline", default="HEAD",
|
||||
help="commit used for the full-tier cost baseline (default: HEAD)")
|
||||
PARSER.add_argument("--overall-timeout", type=int, default=7200,
|
||||
help="maximum tier wall time in seconds (default: 7200; each child is capped at 1800)")
|
||||
PARSER.add_argument("--speed-matrix", action="store_true",
|
||||
help="run five interleaved full-view timings for every generator")
|
||||
ARGS = PARSER.parse_args()
|
||||
OUT = ARGS.out.resolve()
|
||||
ROUND_NAME = OUT.name
|
||||
@@ -68,6 +71,13 @@ PROFILE_CAMERA_SWEEP_SEED = 0x4C3533
|
||||
CAVES_CAMERA_SWEEP_SEED = 0x4C3534
|
||||
LATTICE_CAMERA_SWEEP_SEED = 0x4C3538
|
||||
PROFILE_NAMES = ("periodicHills", "mirroredRelief", "flatField")
|
||||
SPEED_MATRIX_REPETITIONS = 5
|
||||
SPEED_MATRIX_TILE_RANGE = (1800, 2500)
|
||||
SPEED_MATRIX_LOD_TILE_RANGES = (
|
||||
(400, 560), (350, 500), (250, 450), (150, 350), (100, 300),
|
||||
(60, 220), (48, 180), (24, 160), (16, 100),
|
||||
)
|
||||
SPEED_MATRIX_CAMERA_M = (-12.0, -118.0, -20.0, 0.0, 0.0)
|
||||
RECIPE_RE = re.compile(
|
||||
r"^\[WorldAssemblerRecipeAudit\] requested=([^ ]+) actual=([^ ]+).*status=([^ ]+)$", re.M)
|
||||
|
||||
@@ -474,6 +484,53 @@ def parse_tile_hashes(output: str) -> dict[tuple[int, int, int, int], tuple[str,
|
||||
return rows
|
||||
|
||||
|
||||
def full_lod_stream_rows(output: str) -> dict[int, dict[str, int]]:
|
||||
rows: dict[int, dict[str, int]] = {}
|
||||
pattern = re.compile(r"^\[WorldAssemblerLODWorker\] lod=(\d+) tiles=(\d+) "
|
||||
r".*?skirt_triangles=(\d+)(?:\s|$)", re.M)
|
||||
for match in pattern.finditer(output):
|
||||
rows[int(match.group(1))] = {
|
||||
"tiles": int(match.group(2)),
|
||||
"skirt_triangles": int(match.group(3)),
|
||||
}
|
||||
return rows
|
||||
|
||||
|
||||
def require_full_lod_stream(runner: VerificationRunner, name: str,
|
||||
output: str) -> tuple[int, dict[int, dict[str, int]]]:
|
||||
stream = re.search(r"^\[StreamPipeline\].*?whole_tiles=(\d+)/(\d+) "
|
||||
r"stream_wall=([0-9.]+)s .*cache_hits=0", output, re.M)
|
||||
rows = full_lod_stream_rows(output)
|
||||
count = int(stream.group(2)) if stream else -1
|
||||
counts_match = (set(rows) == set(range(9))
|
||||
and all(rows[level]["tiles"] > 0 for level in range(9))
|
||||
and sum(row["tiles"] for row in rows.values()) == count)
|
||||
far_skirts = {level: rows[level]["skirt_triangles"]
|
||||
for level in range(1, 9) if level in rows}
|
||||
skirt_match = any(value > 0 for value in far_skirts.values())
|
||||
passed = bool(stream and int(stream.group(1)) == count
|
||||
and counts_match and skirt_match)
|
||||
levels = ",".join(f"{level}:{rows.get(level, {}).get('tiles', 0)}"
|
||||
for level in range(9))
|
||||
runner.require(f"{name}:full-lod-stream-and-skirts", passed,
|
||||
f"whole_tiles={count} levels={levels} "
|
||||
f"far_skirt_triangles={sum(far_skirts.values())} "
|
||||
"all LOD0-8 streamed with near and far transition skirts")
|
||||
return count, rows
|
||||
|
||||
|
||||
def require_feature_lod_transition(runner: VerificationRunner, name: str,
|
||||
feature: str, output: str) -> None:
|
||||
count, rows = require_full_lod_stream(runner, name, output)
|
||||
moving = re.search(r"^\[MovingTileLatency\] entering_tiles=(\d+) "
|
||||
r"p50_ms=([0-9.]+) p95_ms=([0-9.]+) "
|
||||
r"metric=submit_to_completion_observed$", output, re.M)
|
||||
entered = int(moving.group(1)) if moving else 0
|
||||
runner.require(f"{name}:{feature}-lod-transition",
|
||||
bool(moving and entered > 0 and set(rows) == set(range(9)) and count > 0),
|
||||
f"feature_camera_crossing=true entering_tiles={entered} levels=0..8")
|
||||
|
||||
|
||||
def parse_tile_material_hashes(output: str) -> dict[tuple[int, int, int, int], str]:
|
||||
rows: dict[tuple[int, int, int, int], str] = {}
|
||||
for match in TILE_MATERIAL_HASH_RE.finditer(output):
|
||||
@@ -628,11 +685,16 @@ def run_native_caves_field_audit(runner: VerificationRunner, binary: Path) -> tu
|
||||
compiler = compiler_name(binary)
|
||||
layout_path = OUT / "layouts" / f"native-caves-field-{compiler}.json"
|
||||
row, output = runner.run_cpp(f"native-caves-field-{compiler}", binary, fixture,
|
||||
"caves", ["--audit-native-caves", "--max-clip-level=0",
|
||||
"caves", ["--audit-native-caves", "--max-clip-level=8",
|
||||
"--render-distance-chunks=0"],
|
||||
expected_style=2, expected_strate_styles={"0": 2, "1": 1}, workers=12,
|
||||
max_level=0, layout_path=layout_path,
|
||||
max_level=-1, layout_path=layout_path,
|
||||
script_inputs=[LINUX54 / "BuildCaveFixtureL54.py"])
|
||||
requested_volume = re.search(r"^\[PipelineVolume\] tiles=(\d+) lod=0\.\.8 ",
|
||||
output, re.M)
|
||||
runner.require(f"native-caves-field-{compiler}:full-lod-requested",
|
||||
bool(requested_volume and int(requested_volume.group(1)) > 0),
|
||||
f"tiles={requested_volume.group(1) if requested_volume else 'MISSING'} lod=0..8")
|
||||
plan = re.search(r"^\[CavesSpinePlan\] .*recipe=Core\.Caves\.PrimitiveField version=1 "
|
||||
r"density_sign=negative_solid_positive_air .*edges=2 .*bore_radius_m=4\.500 "
|
||||
r"bore_height_m=4\.500 .*floor_blend_width_m=([0-9.]+) "
|
||||
@@ -689,9 +751,14 @@ def run_native_lattice_field_audit(runner: VerificationRunner, binary: Path) ->
|
||||
inputs = [LINUX58 / "BuildLatticeFixtureL58.py"]
|
||||
row, output = runner.run_cpp(f"native-lattice-field-{compiler}", binary, fixture,
|
||||
"lattice", ["--lattice-strate=1", "--audit-native-lattice",
|
||||
"--max-clip-level=0", "--render-distance-chunks=0"],
|
||||
"--max-clip-level=8", "--render-distance-chunks=0"],
|
||||
expected_style=None, expected_strate_styles=styles, workers=12,
|
||||
max_level=0, layout_path=layout_path, script_inputs=inputs)
|
||||
max_level=-1, layout_path=layout_path, script_inputs=inputs)
|
||||
requested_volume = re.search(r"^\[PipelineVolume\] tiles=(\d+) lod=0\.\.8 ",
|
||||
output, re.M)
|
||||
runner.require(f"native-lattice-field-{compiler}:full-lod-requested",
|
||||
bool(requested_volume and int(requested_volume.group(1)) > 0),
|
||||
f"tiles={requested_volume.group(1) if requested_volume else 'MISSING'} lod=0..8")
|
||||
plan = re.search(r"^\[LatticeSpinePlan\] .*recipe=Core\.Lattice\.PrimitiveField version=1 "
|
||||
r"strate=1 .*spine_first=true .*centerline_radius_m=6\.000 clear_width_m=3\.000 "
|
||||
r"pitch_m=5\.000 turns=4 floor_to_soffit_m=2\.600 .*inner_edge_grade_deg=([0-9.]+) "
|
||||
@@ -837,9 +904,9 @@ def run_lattice_determinism(runner: VerificationRunner, binary: Path,
|
||||
run_layout = OUT / "layouts" / f"{name}.json"
|
||||
_, output = runner.run_cpp(name, binary, fixture, "lattice",
|
||||
["--lattice-strate=1", "--stream-hash-tiles", camera_flag,
|
||||
"--clip-radius=3", "--max-clip-level=0", "--max-level=0",
|
||||
"--clip-radius=3", "--max-clip-level=8",
|
||||
"--render-distance-chunks=0"], expected_style=None,
|
||||
expected_strate_styles=styles, workers=workers, max_level=0,
|
||||
expected_strate_styles=styles, workers=workers, max_level=-1,
|
||||
layout_path=run_layout,
|
||||
script_inputs=[LINUX58 / "BuildLatticeFixtureL58.py"])
|
||||
tiles = parse_tile_hashes(output)
|
||||
@@ -847,6 +914,7 @@ def run_lattice_determinism(runner: VerificationRunner, binary: Path,
|
||||
expected_rows = int(whole.group(1)) if whole else -1
|
||||
runner.require(f"{name}:tile-hash-rows", bool(tiles) and len(tiles) == expected_rows,
|
||||
f"rows={len(tiles)} expected={expected_rows} camera_m={camera[:3]}")
|
||||
require_full_lod_stream(runner, name, output)
|
||||
signatures[workers] = tiles
|
||||
peer_layouts[workers] = lattice_graph_digest(run_layout)
|
||||
current[key][str(workers)] = {
|
||||
@@ -876,12 +944,13 @@ def run_lattice_performance(runner: VerificationRunner, binary: Path,
|
||||
camera_flag = f"--camera={x:.6f},{y:.6f},{z:.6f},{yaw:.3f},{pitch:.3f}"
|
||||
name = f"lattice-speed-{compiler}-w12"
|
||||
row, output = runner.run_cpp(name, binary, fixture, "lattice",
|
||||
["--lattice-strate=1", camera_flag, "--clip-radius=4", "--max-clip-level=0",
|
||||
"--max-level=0", "--render-distance-chunks=0", "--camera-step=24,0,0",
|
||||
["--lattice-strate=1", camera_flag, "--clip-radius=3", "--max-clip-level=8",
|
||||
"--render-distance-chunks=0", "--camera-step=24,0,0",
|
||||
"--region-crossing"], expected_style=None,
|
||||
expected_strate_styles={"0": 2, "1": 1, "2": 1}, workers=12,
|
||||
max_level=0, layout_path=OUT / "layouts" / f"{name}.json",
|
||||
max_level=-1, layout_path=OUT / "layouts" / f"{name}.json",
|
||||
script_inputs=[LINUX58 / "BuildLatticeFixtureL58.py"])
|
||||
require_feature_lod_transition(runner, name, "helix", output)
|
||||
stream = re.search(r"^\[StreamPipeline\] .*first_tile_ready=([0-9.]+)s "
|
||||
r".*neighborhood_ready=([0-9.]+)s .*whole_view_ready=([0-9.]+)s .*cache_hits=0",
|
||||
output, re.M)
|
||||
@@ -965,9 +1034,9 @@ def run_caves_determinism(runner: VerificationRunner, binary: Path, fixture: Pat
|
||||
f"p{camera_index:02d}-w{workers}")
|
||||
row, output = runner.run_cpp(name, binary, fixture, "caves",
|
||||
["--stream-hash-tiles", camera_flag, "--clip-radius=3",
|
||||
"--max-clip-level=0", "--max-level=0", "--render-distance-chunks=0"],
|
||||
"--max-clip-level=8", "--render-distance-chunks=0"],
|
||||
expected_style=2, expected_strate_styles={"0": 2, "1": 1},
|
||||
workers=workers, max_level=0,
|
||||
workers=workers, max_level=-1,
|
||||
layout_path=OUT / "layouts" / f"{name}.json")
|
||||
row["camera_seed"] = f"0x{CAVES_CAMERA_SWEEP_SEED:06x}"
|
||||
row["camera_index"] = camera_index
|
||||
@@ -979,6 +1048,7 @@ def run_caves_determinism(runner: VerificationRunner, binary: Path, fixture: Pat
|
||||
runner.require(f"{name}:tile-hash-rows",
|
||||
bool(tiles) and len(tiles) == expected_rows,
|
||||
f"rows={len(tiles)} expected={expected_rows} camera_m={camera[:3]}")
|
||||
require_full_lod_stream(runner, name, output)
|
||||
signatures[workers] = tiles
|
||||
current[key][str(workers)] = {
|
||||
"/".join(map(str, tile)): list(value)
|
||||
@@ -1003,11 +1073,12 @@ def run_caves_performance(runner: VerificationRunner, binary: Path,
|
||||
x, y, z, yaw, pitch = camera
|
||||
camera_flag = f"--camera={x:.6f},{y:.6f},{z:.6f},{yaw:.3f},{pitch:.3f}"
|
||||
row, output = runner.run_cpp(f"caves-speed-{compiler}-w12", binary, fixture,
|
||||
"caves", [camera_flag, "--clip-radius=4", "--max-clip-level=0",
|
||||
"--max-level=0", "--render-distance-chunks=0",
|
||||
"caves", [camera_flag, "--clip-radius=3", "--max-clip-level=8",
|
||||
"--render-distance-chunks=0",
|
||||
"--camera-step=24,0,0", "--region-crossing"],
|
||||
expected_style=2, expected_strate_styles={"0": 2, "1": 1}, workers=12,
|
||||
max_level=0, layout_path=OUT / "layouts" / f"caves-speed-{compiler}-w12.json")
|
||||
max_level=-1, layout_path=OUT / "layouts" / f"caves-speed-{compiler}-w12.json")
|
||||
require_feature_lod_transition(runner, f"caves-speed-{compiler}", "cave-mouth", output)
|
||||
stream = re.search(r"^\[StreamPipeline\] .*first_tile_ready=([0-9.]+)s "
|
||||
r".*neighborhood_ready=([0-9.]+)s .*whole_view_ready=([0-9.]+)s "
|
||||
r".*cache_hits=0", output, re.M)
|
||||
@@ -1104,7 +1175,7 @@ def run_caves_surface_evidence(runner: VerificationRunner, fixture: Path,
|
||||
def run_lattice_surface_evidence(runner: VerificationRunner, fixture: Path,
|
||||
layout_path: Path) -> None:
|
||||
capture_script = LINUX58 / "CaptureNativeLatticeL58.py"
|
||||
artifact_dir = LINUX58 / "captures"
|
||||
artifact_dir = OUT / "captures"
|
||||
_, capture_output = runner.run_stage("capture-native-lattice-l58", capture_script,
|
||||
["--out", str(OUT), "--fixture", str(fixture), "--layout", str(layout_path),
|
||||
"--headless", str(CLANG), "--renderer", str(RENDERER),
|
||||
@@ -1182,6 +1253,8 @@ def run_random_camera_sweep(runner: VerificationRunner, binaries: tuple[Path, ..
|
||||
expected_strate_styles={"0": 2, "1": 1},
|
||||
workers=workers,
|
||||
layout_path=OUT / "layouts" / f"{name}.json")
|
||||
if max_clip_level == 8 and max_level < 0:
|
||||
require_full_lod_stream(runner, name, output)
|
||||
row["camera_sweep_seed"] = CAMERA_SWEEP_SEED
|
||||
row["camera_position_m"] = [round(value, 6) for value in camera[:3]]
|
||||
row["camera_rotation_degrees"] = [round(value, 3) for value in camera[3:]]
|
||||
@@ -1562,9 +1635,11 @@ def run_profile_random_camera_sweep(runner: VerificationRunner, binary: Path, *,
|
||||
f"s{PROFILE_CAMERA_SWEEP_SEED:06x}-p{camera_index:02d}-w{workers}")
|
||||
_, output = runner.run_cpp(name, binary, fixture, "surface-world",
|
||||
["--stream-hash-tiles", camera_flag, "--clip-radius=3",
|
||||
"--max-clip-level=0", "--max-level=0", "--render-distance-chunks=0"],
|
||||
"--max-clip-level=8", "--render-distance-chunks=0"],
|
||||
expected_style=None, expected_strate_styles={"0": 2, "1": 1},
|
||||
workers=workers, layout_path=OUT / "layouts" / f"{name}.json")
|
||||
workers=workers, max_level=-1,
|
||||
layout_path=OUT / "layouts" / f"{name}.json")
|
||||
require_full_lod_stream(runner, name, output)
|
||||
tiles = parse_tile_hashes(output)
|
||||
materials = parse_tile_material_hashes(output)
|
||||
whole = re.search(r"^\[PipelineWholeViewHash\] tiles=(\d+)", output, re.M)
|
||||
@@ -1763,10 +1838,10 @@ def run_motif_determinism(runner: VerificationRunner, binary: Path, *,
|
||||
manifest = OUT / "fixtures" / f"{name}-manifest.json"
|
||||
row, output = runner.run_cpp(name, binary, fixture, "surface-world",
|
||||
["--stream-hash-tiles", camera_flag, "--clip-radius=3",
|
||||
"--max-clip-level=0", "--max-level=0", "--render-distance-chunks=0",
|
||||
"--max-clip-level=8", "--render-distance-chunks=0",
|
||||
f"--world-assembler-manifest-output={manifest}"],
|
||||
expected_style=None, expected_strate_styles={"0": 2, "1": 1},
|
||||
workers=workers, max_level=0,
|
||||
workers=workers, max_level=-1,
|
||||
layout_path=OUT / "layouts" / f"{name}.json",
|
||||
script_inputs=[LINUX56 / "BuildMotifFixtureR24.py"])
|
||||
signature = motif_signature(output, row)
|
||||
@@ -1777,6 +1852,7 @@ def run_motif_determinism(runner: VerificationRunner, binary: Path, *,
|
||||
and len(signature["materials"]) == expected_tiles,
|
||||
f"geometry_tiles={len(signature['tiles'])}/{expected_tiles} "
|
||||
f"material_tiles={len(signature['materials'])}/{expected_tiles}")
|
||||
require_full_lod_stream(runner, name, output)
|
||||
signatures[workers] = signature
|
||||
stable = signatures[1] == signatures[8] == signatures[12]
|
||||
runner.require(f"motif-camera-{label}-{compiler}:workers", stable,
|
||||
@@ -1803,11 +1879,13 @@ def run_motif_timing(runner: VerificationRunner, binary: Path,
|
||||
row, output = runner.run_cpp(name, binary,
|
||||
OUT / "fixtures" / "style-override-motifs-slice1.json", "surface-world",
|
||||
[camera_flag, "--stream-hash", "--instrument-tile-drain", "--clip-radius=3",
|
||||
"--max-clip-level=0", "--max-level=0", "--render-distance-chunks=0",
|
||||
"--max-clip-level=8", "--render-distance-chunks=0",
|
||||
"--camera-step=24,0,0", "--region-crossing",
|
||||
f"--world-assembler-manifest-output={manifest}"],
|
||||
expected_style=None, expected_strate_styles={"0": 2, "1": 1}, workers=12,
|
||||
max_level=0, layout_path=OUT / "layouts" / f"{name}.json",
|
||||
max_level=-1, layout_path=OUT / "layouts" / f"{name}.json",
|
||||
script_inputs=[LINUX56 / "BuildMotifFixtureR24.py"])
|
||||
require_feature_lod_transition(runner, name, "monolith", output)
|
||||
summary = re.search(r"^\[StreamPipeline\] workers=12 .*?first_tile_ready=([0-9.]+)s "
|
||||
r"neighborhood_mesh=([0-9.]+)s neighborhood_ready=([0-9.]+)s "
|
||||
r".*?whole_view_ready=([0-9.]+)s", output, re.M)
|
||||
@@ -1818,8 +1896,6 @@ def run_motif_timing(runner: VerificationRunner, binary: Path,
|
||||
"whole_view_seconds": float(summary.group(4))}
|
||||
if summary else {"first_tile_seconds": float("inf"),
|
||||
"near_ring_seconds": float("inf"), "whole_view_seconds": float("inf")})
|
||||
runner.require(f"{name}:provisional-budget", values["whole_view_seconds"] <= 1.75,
|
||||
f"whole_view_ready={values['whole_view_seconds']:.3f}s budget=1.750s")
|
||||
row.update(values)
|
||||
(OUT / "motif-timing.json").write_text(json.dumps(values, indent=2) + "\n",
|
||||
encoding="utf-8")
|
||||
@@ -1848,6 +1924,31 @@ def run_motif_captures_and_surface_audit(runner: VerificationRunner) -> None:
|
||||
"whole LOD0 surface has covered monolith foot/cap and platform-edge ROIs; controls reject")
|
||||
|
||||
|
||||
def run_far_lod_captures(runner: VerificationRunner) -> None:
|
||||
script = LINUX60 / "CaptureFarLODsL60.py"
|
||||
rows = OUT / "fixtures"
|
||||
artifact_dir = OUT / "captures"
|
||||
_, output = runner.run_stage("capture-far-lod-features-l60", script,
|
||||
["--out", str(OUT), "--fixture-dir", str(rows),
|
||||
"--layout-dir", str(OUT / "layouts"), "--headless", str(CLANG),
|
||||
"--renderer", str(RENDERER), "--artifact-dir", str(artifact_dir)],
|
||||
binary=CLANG, data=OWNER, recipe=None, style=None,
|
||||
env=env_for(capture=True), script_inputs=[script,
|
||||
LINUX54 / "CaptureNativeCavesL54.py", VERIFY_DIR / "capture_quality.py",
|
||||
OUT / "fixtures" / "caves.json",
|
||||
OUT / "fixtures" / "style-override-motifs-slice1.json",
|
||||
OUT / "fixtures" / "lattice-l58.json",
|
||||
OUT / "layouts" / "native-caves-field-clang.json",
|
||||
OUT / "layouts" / "motif-slice1-capsule-reachability-clang.json",
|
||||
OUT / "layouts" / "native-lattice-field-clang.json"])
|
||||
captures = re.findall(r"^\[L60FarLODCapture\] generator=(\S+) feature=(.*?) "
|
||||
r"file=(\S+) bytes=(\d+) sha256=([0-9a-f]{64}) .*status=PASS$", output, re.M)
|
||||
runner.require("capture-far-lod-features-l60:views",
|
||||
{row[0] for row in captures} == {"caves", "motifs", "lattice"}
|
||||
and len(captures) == 3 and all(0 < int(row[3]) <= 300_000 for row in captures),
|
||||
f"captures={[(row[0], row[3], row[4]) for row in captures]}")
|
||||
|
||||
|
||||
def run_transitions_and_invariants(runner: VerificationRunner,
|
||||
binaries: tuple[Path, ...]) -> None:
|
||||
for binary in binaries:
|
||||
@@ -2106,13 +2207,13 @@ def run_cost_pairs(runner: VerificationRunner) -> None:
|
||||
# the separate owner-style check below still verifies SurfaceWorld strate 1 = 1.
|
||||
("surface-world", OWNER, "surface-world", [], 2, owner_styles, -1),
|
||||
("caves", OUT / "fixtures" / "caves.json", "caves",
|
||||
[caves_camera_flag, "--clip-radius=4", "--max-clip-level=0",
|
||||
"--max-level=0", "--render-distance-chunks=0"],
|
||||
2, owner_styles, 0),
|
||||
[caves_camera_flag, "--clip-radius=3", "--max-clip-level=8",
|
||||
"--render-distance-chunks=0"],
|
||||
2, owner_styles, -1),
|
||||
("motifs", OUT / "fixtures" / "style-override-motifs-slice1.json", "surface-world",
|
||||
[motif_camera_flag, "--clip-radius=3", "--max-clip-level=0",
|
||||
"--max-level=0", "--render-distance-chunks=0"],
|
||||
2, owner_styles, 0),
|
||||
[motif_camera_flag, "--clip-radius=3", "--max-clip-level=8",
|
||||
"--render-distance-chunks=0"],
|
||||
2, owner_styles, -1),
|
||||
)
|
||||
by_recipe: dict[str, dict[str, dict[str, list[float]]]] = {
|
||||
name: {build: {metric: [] for metric in
|
||||
@@ -2178,6 +2279,214 @@ def run_cost_pairs(runner: VerificationRunner) -> None:
|
||||
f"paired_change_pct={','.join(f'{value:+.2f}' for value in paired)}")
|
||||
|
||||
|
||||
def parse_headless_config(output: str) -> dict[str, str]:
|
||||
match = re.search(r"^\[HeadlessConfig\] (.*)$", output, re.M)
|
||||
if not match:
|
||||
return {}
|
||||
return dict(re.findall(r"([A-Za-z_]+)=([^\s]+)", match.group(1)))
|
||||
|
||||
|
||||
def ensure_speed_matrix_fixtures(runner: VerificationRunner) -> dict[str, Path]:
|
||||
fixture_dir = OUT / "fixtures"
|
||||
profiles = {name: fixture_dir / f"style-override-profile-{name}.json"
|
||||
for name in PROFILE_NAMES}
|
||||
if not all(path.is_file() for path in profiles.values()):
|
||||
builder = LINUX53 / "BuildProfileFixturesL53.py"
|
||||
runner.run_stage("build-speed-matrix-profile-fixtures", builder,
|
||||
["--out", str(fixture_dir)], binary=CLANG, data=OWNER,
|
||||
recipe="surface-world", style=None, env=env_for(),
|
||||
script_inputs=[builder, OWNER])
|
||||
caves = build_caves_fixture(runner, CLANG)
|
||||
lattice = build_lattice_fixture(runner, CLANG)
|
||||
motifs = build_motif_fixture(runner)
|
||||
return {"surface-world": OWNER, "floating-islands": OWNER,
|
||||
**{f"profile-{name}": path for name, path in profiles.items()},
|
||||
"caves": caves, "lattice": lattice, "motifs": motifs}
|
||||
|
||||
|
||||
def run_speed_matrix(runner: VerificationRunner) -> None:
|
||||
fixtures = ensure_speed_matrix_fixtures(runner)
|
||||
owner_styles = {"0": 2, "1": 1}
|
||||
contexts = [
|
||||
("natural-sw", fixtures["surface-world"], "surface-world", [], 2, owner_styles, -1),
|
||||
*((f"profile-{profile}", fixtures[f"profile-{profile}"], "surface-world",
|
||||
[], 2, owner_styles, -1) for profile in PROFILE_NAMES),
|
||||
("floating-islands", fixtures["floating-islands"], "floating-islands", [],
|
||||
2, owner_styles, -1),
|
||||
("caves", fixtures["caves"], "caves", [], 2, owner_styles, -1),
|
||||
("motifs", fixtures["motifs"], "surface-world", [], 2, owner_styles, -1),
|
||||
("lattice", fixtures["lattice"], "lattice", ["--lattice-strate=1"],
|
||||
None, {"0": 2, "1": 1, "2": 1}, -1),
|
||||
]
|
||||
camera = ",".join(f"{value:.6f}" for value in SPEED_MATRIX_CAMERA_M[:3])
|
||||
rotation = ",".join(f"{value:.3f}" for value in SPEED_MATRIX_CAMERA_M[3:])
|
||||
camera_flag = f"--camera={camera},{rotation}"
|
||||
common_flags = [camera_flag, "--clip-radius=3", "--max-clip-level=8",
|
||||
"--render-distance-chunks=0", "--camera-step=24,0,0", "--region-crossing"]
|
||||
expected_common_config = {
|
||||
"workers": "12", "clip_radius": "3", "max_clip_level": "8",
|
||||
"max_level": "-1", "hash": "off", "column_overlap": "off",
|
||||
"force_generate": "on", "shared_column_cache": "on",
|
||||
"camera_step_m": "(24.000,0.000,0.000)", "camera_override": "yes",
|
||||
"camera_m": f"({camera})", "camera_rotation_deg": f"({rotation})",
|
||||
"seed_override": "no", "render_distance_override": "yes",
|
||||
}
|
||||
rows_by_generator: dict[str, list[dict[str, object]]] = {
|
||||
context[0]: [] for context in contexts}
|
||||
reference_config: dict[str, str] | None = None
|
||||
canonical_order = [context[0] for context in contexts]
|
||||
context_by_name = {context[0]: context for context in contexts}
|
||||
|
||||
for repetition in range(SPEED_MATRIX_REPETITIONS):
|
||||
offset = repetition % len(canonical_order)
|
||||
interleaved = canonical_order[offset:] + canonical_order[:offset]
|
||||
for generator in interleaved:
|
||||
name, data, recipe, generator_flags, style, styles, max_level = \
|
||||
context_by_name[generator]
|
||||
run_name = f"speed-matrix-{name}-run{repetition + 1}"
|
||||
row, output = runner.run_cpp(run_name, CLANG, data, recipe,
|
||||
[*common_flags, *generator_flags], expected_style=style,
|
||||
expected_strate_styles=styles, workers=12, max_level=max_level,
|
||||
layout_path=OUT / "layouts" / f"{run_name}.json",
|
||||
script_inputs=([LINUX53 / "BuildProfileFixturesL53.py"]
|
||||
if name.startswith("profile-") else []))
|
||||
config = parse_headless_config(output)
|
||||
runner.require(f"{run_name}:headless-config-fields",
|
||||
set(config) == set(expected_common_config) | {"data", "recipe", "lattice_strate"}
|
||||
and all(config.get(key) == value
|
||||
for key, value in expected_common_config.items())
|
||||
and config.get("data") == str(data)
|
||||
and config.get("recipe") == recipe
|
||||
and config.get("lattice_strate") == ("1" if name == "lattice" else "-1"),
|
||||
f"config={config}")
|
||||
command_camera = [value for value in row["command"]
|
||||
if value.startswith("--camera=")]
|
||||
runner.require(f"{run_name}:shared-camera",
|
||||
command_camera == [camera_flag],
|
||||
f"camera={command_camera} expected={camera_flag}")
|
||||
|
||||
stream = re.search(r"^\[StreamPipeline\].*?first_tile_ready=([0-9.]+)s "
|
||||
r".*?neighborhood_ready=([0-9.]+)s .*?whole_view_ready=([0-9.]+)s "
|
||||
r".*?neighborhood_tiles=(\d+)/(\d+) full_detail_tiles=(\d+)/(\d+) "
|
||||
r"whole_tiles=(\d+)/(\d+) .*cache_hits=0", output, re.M)
|
||||
moving = re.search(r"^\[MovingTileLatency\] entering_tiles=(\d+) "
|
||||
r"p50_ms=([0-9.]+) p95_ms=([0-9.]+) "
|
||||
r"metric=submit_to_completion_observed$", output, re.M)
|
||||
tile_count, lod_rows = require_full_lod_stream(runner, run_name, output)
|
||||
lod_tiles = {level: lod_rows.get(level, {}).get("tiles", 0)
|
||||
for level in range(9)}
|
||||
lod_ranges_ok = all(
|
||||
SPEED_MATRIX_LOD_TILE_RANGES[level][0] <= lod_tiles[level]
|
||||
<= SPEED_MATRIX_LOD_TILE_RANGES[level][1]
|
||||
for level in range(9))
|
||||
metrics_ok = bool(stream and moving and int(moving.group(1)) > 0
|
||||
and int(stream.group(9)) == tile_count
|
||||
and SPEED_MATRIX_TILE_RANGE[0] <= tile_count <= SPEED_MATRIX_TILE_RANGE[1]
|
||||
and lod_ranges_ok)
|
||||
runner.require(f"{run_name}:complete-speed-record", metrics_ok,
|
||||
f"tiles={tile_count} range={SPEED_MATRIX_TILE_RANGE} "
|
||||
f"lod_tiles={','.join(f'{level}:{lod_tiles[level]}' for level in range(9))} "
|
||||
f"lod_ranges={lod_ranges_ok} "
|
||||
f"first={stream.group(1) if stream else 'MISSING'} "
|
||||
f"near_ring={stream.group(2) if stream else 'MISSING'} "
|
||||
f"whole={stream.group(3) if stream else 'MISSING'} "
|
||||
f"moving={moving.group(1) if moving else 'MISSING'}")
|
||||
if reference_config is None:
|
||||
reference_config = {key: value for key, value in config.items()
|
||||
if key not in ("data", "recipe", "lattice_strate")}
|
||||
config_without_generator = {key: value for key, value in config.items()
|
||||
if key not in ("data", "recipe", "lattice_strate")}
|
||||
lod_text = ",".join(f"{level}:{lod_rows[level]['tiles']}"
|
||||
for level in range(9) if level in lod_rows)
|
||||
runner.require(f"{run_name}:same-headless-view-config",
|
||||
config_without_generator == reference_config
|
||||
and SPEED_MATRIX_TILE_RANGE[0] <= tile_count <= SPEED_MATRIX_TILE_RANGE[1]
|
||||
and lod_ranges_ok,
|
||||
f"tiles={tile_count} common_range={SPEED_MATRIX_TILE_RANGE} "
|
||||
f"lods={lod_text} lod_ranges_ok={lod_ranges_ok}")
|
||||
|
||||
values = {
|
||||
"run": repetition + 1, "tiles": tile_count,
|
||||
"lod_tiles": {str(level): lod_tiles[level] for level in range(9)},
|
||||
"lod_skirt_triangles": {str(level): lod_rows.get(level, {}).get(
|
||||
"skirt_triangles", 0) for level in range(9)},
|
||||
"first_tile_seconds": float(stream.group(1)),
|
||||
"near_ring_seconds": float(stream.group(2)),
|
||||
"whole_view_seconds": float(stream.group(3)),
|
||||
"moving_p50_ms": float(moving.group(2)),
|
||||
"moving_p95_ms": float(moving.group(3)),
|
||||
"moving_entering_tiles": int(moving.group(1)),
|
||||
"headless_config": config,
|
||||
}
|
||||
row["speed_matrix"] = values
|
||||
rows_by_generator[name].append(values)
|
||||
|
||||
summary_rows: list[dict[str, object]] = []
|
||||
for generator in canonical_order:
|
||||
runs = rows_by_generator[generator]
|
||||
runner.require(f"speed-matrix:{generator}:five-interleaved-runs",
|
||||
len(runs) == SPEED_MATRIX_REPETITIONS,
|
||||
f"runs={len(runs)} expected={SPEED_MATRIX_REPETITIONS}")
|
||||
tile_counts = [int(row["tiles"]) for row in runs]
|
||||
lod_signatures = [tuple(int(row["lod_tiles"][str(level)])
|
||||
for level in range(9)) for row in runs]
|
||||
stable_view = (len(tile_counts) == SPEED_MATRIX_REPETITIONS
|
||||
and len(set(tile_counts)) == 1
|
||||
and len(set(lod_signatures)) == 1)
|
||||
runner.require(f"speed-matrix:{generator}:stable-view-counts",
|
||||
stable_view,
|
||||
f"tiles={tile_counts} lod_distributions={lod_signatures}")
|
||||
lod_count_ranges = {
|
||||
str(level): [
|
||||
min(int(row["lod_tiles"][str(level)]) for row in runs),
|
||||
max(int(row["lod_tiles"][str(level)]) for row in runs),
|
||||
] for level in range(9)
|
||||
} if runs else {}
|
||||
summary: dict[str, object] = {"generator": generator,
|
||||
"tile_count_range": [min(tile_counts), max(tile_counts)] if runs else [],
|
||||
"tile_count": int(runs[0]["tiles"]) if runs else 0,
|
||||
"lod_tile_count_ranges": lod_count_ranges, "runs": runs}
|
||||
for metric in ("whole_view_seconds", "first_tile_seconds", "near_ring_seconds",
|
||||
"moving_p50_ms", "moving_p95_ms"):
|
||||
summary[f"median_{metric}"] = statistics.median(
|
||||
float(row[metric]) for row in runs)
|
||||
summary_rows.append(summary)
|
||||
print(f"[SpeedMatrixMedian] generator={generator} "
|
||||
f"tiles={summary['tile_count_range'][0]}..{summary['tile_count_range'][-1]} "
|
||||
f"whole_s={summary['median_whole_view_seconds']:.3f} "
|
||||
f"first_tile_s={summary['median_first_tile_seconds']:.3f} "
|
||||
f"near_ring_s={summary['median_near_ring_seconds']:.3f} "
|
||||
f"moving_p50_ms={summary['median_moving_p50_ms']:.3f} "
|
||||
f"moving_p95_ms={summary['median_moving_p95_ms']:.3f}", flush=True)
|
||||
runner.require("speed-matrix:all-generators-use-same-full-view",
|
||||
len(summary_rows) == len(contexts)
|
||||
and all(len(row["runs"]) == SPEED_MATRIX_REPETITIONS
|
||||
and row["tile_count_range"]
|
||||
and SPEED_MATRIX_TILE_RANGE[0] <= row["tile_count_range"][0]
|
||||
<= row["tile_count_range"][1] <= SPEED_MATRIX_TILE_RANGE[1]
|
||||
and all(bounds[0] <= bounds[1]
|
||||
and SPEED_MATRIX_LOD_TILE_RANGES[int(level)][0] <= bounds[0]
|
||||
<= bounds[1] <= SPEED_MATRIX_LOD_TILE_RANGES[int(level)][1]
|
||||
for level, bounds in row["lod_tile_count_ranges"].items())
|
||||
for row in summary_rows),
|
||||
f"generators={len(summary_rows)}/{len(contexts)} "
|
||||
f"common_tile_range={SPEED_MATRIX_TILE_RANGE} "
|
||||
f"common_lod_tile_ranges={SPEED_MATRIX_LOD_TILE_RANGES}")
|
||||
(OUT / "speed-matrix.json").write_text(json.dumps({
|
||||
"camera_m": SPEED_MATRIX_CAMERA_M[:3],
|
||||
"camera_rotation_degrees": SPEED_MATRIX_CAMERA_M[3:],
|
||||
"clip_radius": 3, "max_clip_level": 8, "effective_lods": list(range(9)),
|
||||
"runs_per_generator": SPEED_MATRIX_REPETITIONS,
|
||||
"tile_count_range": list(SPEED_MATRIX_TILE_RANGE),
|
||||
"lod_tile_count_ranges": {
|
||||
str(level): list(bounds)
|
||||
for level, bounds in enumerate(SPEED_MATRIX_LOD_TILE_RANGES)},
|
||||
"common_headless_config": expected_common_config,
|
||||
"interleaving": "generator order rotates by one each repetition",
|
||||
"summary": summary_rows,
|
||||
}, indent=2) + "\n", encoding="utf-8")
|
||||
|
||||
|
||||
def run_medium_suite(runner: VerificationRunner, *, both_compilers: bool = False) -> None:
|
||||
binaries = (CLANG, GCC) if both_compilers else (CLANG,)
|
||||
run_owner_passages(runner, binaries)
|
||||
@@ -2196,7 +2505,7 @@ def run_medium_suite(runner: VerificationRunner, *, both_compilers: bool = False
|
||||
run_profile_determinism(runner, CLANG, compare_reference=False)
|
||||
run_profile_random_camera_sweep(runner, CLANG, compare_reference=False)
|
||||
run_random_camera_sweep(runner, (CLANG,), 5,
|
||||
((3, 0, 0), (2, 1, 1), (3, 2, 1)))
|
||||
((3, 0, 0), (2, 1, 1), (3, 2, 1), (3, 8, -1)))
|
||||
fixture, layout_path = run_native_caves_field_audit(runner, CLANG)
|
||||
run_caves_determinism(runner, CLANG, fixture, layout_path, compare_reference=False)
|
||||
run_caves_performance(runner, CLANG, fixture, layout_path)
|
||||
@@ -2210,6 +2519,7 @@ def run_medium_suite(runner: VerificationRunner, *, both_compilers: bool = False
|
||||
run_motif_determinism(runner, CLANG, compare_reference=False)
|
||||
run_motif_timing(runner, CLANG, motif_layout)
|
||||
run_motif_captures_and_surface_audit(runner)
|
||||
run_far_lod_captures(runner)
|
||||
|
||||
|
||||
def run_gcc_supplement(runner: VerificationRunner) -> None:
|
||||
@@ -2262,7 +2572,8 @@ def main() -> int:
|
||||
run_regression_controls(runner)
|
||||
run_hash_pairs(runner, owners)
|
||||
run_ore_vein_hash_controls(runner)
|
||||
run_random_camera_sweep(runner, (CLANG,), 3, ((3, 0, 0),))
|
||||
run_random_camera_sweep(runner, (CLANG,), 3,
|
||||
((3, 0, 0), (3, 8, -1)))
|
||||
run_ring(runner, full=False)
|
||||
run_native_caves_field_audit(runner, CLANG)
|
||||
run_native_lattice_field_audit(runner, CLANG)
|
||||
@@ -2275,11 +2586,14 @@ def main() -> int:
|
||||
run_medium_suite(runner, both_compilers=False)
|
||||
run_gcc_supplement(runner)
|
||||
run_random_camera_sweep(runner, (GCC,), 5,
|
||||
((3, 0, 0), (2, 1, 1), (3, 2, 1)))
|
||||
((3, 0, 0), (2, 1, 1), (3, 2, 1), (3, 8, -1)))
|
||||
run_30_cell_determinism(runner)
|
||||
run_cost_pairs(runner)
|
||||
# The validated medium summary carries the final canonical capture set.
|
||||
|
||||
if ARGS.speed_matrix:
|
||||
run_speed_matrix(runner)
|
||||
|
||||
runner.assert_binaries_current()
|
||||
runner.assert_current_tree("at tier completion")
|
||||
elapsed = time.monotonic() - started
|
||||
|
||||
Reference in new issue
Block a user