core: outside-influence fast path for swept samples (L138, output = v236)
Column-cache census matches assembler/world (the L77 share rise was relative, not more calls). Reuses the TN predicate and skips relief/mouth/shell work for stamped samples outside the 1.053 m influence. vs assembler/world: whole view -0.5..-4.0% on all layers; near-ready Surface World +0.3/+1.7, Floating Islands -4.3/+2.9, Tunnel Network -2.5/+2.9, Vertical Shafts +4.7/+3.3 (A/A ±1%). 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
This commit is contained in:
1 parent
98c2c8e1c5
commit
fa4417aad0
7 files changed
+545
-5
No files matched your search
@@ -0,0 +1,103 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Summarize per-tile cache counters from the five L137 paired timing runs."""
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import re
|
||||
import statistics
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[4]
|
||||
SOURCE = ROOT / "Saved/Linux/l137/timing/final-design1"
|
||||
OUT = ROOT / "Saved/Linux/l138/prechange/column-cache-counts.json"
|
||||
STAMPS = {
|
||||
"assembler-world": "4499fb2a8a4ede7d6cbc68d1b794f104658cdaae93ed9cacbc91fe7ff3fc3621",
|
||||
"l137": "7913d019d968de2dbaea2282b90fa8ff41b53f996c022e9e6fed92712cb40ecf",
|
||||
}
|
||||
FIELDS = re.compile(r"([a-zA-Z0-9_]+)=([^ ]+)")
|
||||
METRICS = (
|
||||
"column_point_calls", "column_local_hits", "column_local_misses",
|
||||
"column_conflict_misses", "column_shared_hits", "column_formula_evaluations",
|
||||
)
|
||||
|
||||
|
||||
def read_run(strate: int, workers: int, version: str, replicate: int) -> dict:
|
||||
path = SOURCE / f"s{strate}-w{workers}-{version}-measured{replicate}.log"
|
||||
if not path.is_file():
|
||||
raise SystemExit(f"missing pre-change L137 run: {path}")
|
||||
text = path.read_text(encoding="utf-8", errors="replace")
|
||||
stamp = re.search(r"^\[VoxelForgeSourceStamp\] sha256=([0-9a-f]+)$", text, re.M)
|
||||
if stamp is None or stamp.group(1) != STAMPS[version]:
|
||||
raise SystemExit(f"unexpected source stamp in {path}")
|
||||
rows = {}
|
||||
for line in text.splitlines():
|
||||
if not line.startswith("[WorldAssemblerLODCostDetail] "):
|
||||
continue
|
||||
fields = dict(FIELDS.findall(line))
|
||||
rows[int(fields["lod"])] = fields
|
||||
if set(rows) != set(range(9)):
|
||||
raise SystemExit(f"incomplete LOD counters in {path}: {sorted(rows)}")
|
||||
return {"path": str(path.relative_to(ROOT)), "rows": rows}
|
||||
|
||||
|
||||
def summarize(runs: list[dict], lods: range) -> dict:
|
||||
per_run = []
|
||||
for run in runs:
|
||||
selected = [run["rows"][lod] for lod in lods]
|
||||
tile_count = sum(int(row["tiles"]) for row in selected)
|
||||
per_run.append({
|
||||
"tiles": tile_count,
|
||||
**{metric: sum(int(row[metric]) for row in selected) / tile_count
|
||||
for metric in METRICS},
|
||||
})
|
||||
return {
|
||||
"tiles_per_run": statistics.mean(row["tiles"] for row in per_run),
|
||||
"mean_per_tile": {
|
||||
metric: statistics.mean(row[metric] for row in per_run)
|
||||
for metric in METRICS
|
||||
},
|
||||
"run_range_per_tile": {
|
||||
metric: [min(row[metric] for row in per_run),
|
||||
max(row[metric] for row in per_run)]
|
||||
for metric in METRICS
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def main() -> int:
|
||||
result = {
|
||||
"source": "five measured L137 L80 runs per version, worker count, and stratum",
|
||||
"pre_change_stamps": STAMPS,
|
||||
"cells": [],
|
||||
}
|
||||
for strate in range(4):
|
||||
for workers in (8, 12):
|
||||
versions = {
|
||||
version: [read_run(strate, workers, version, replicate)
|
||||
for replicate in range(1, 6)]
|
||||
for version in STAMPS
|
||||
}
|
||||
item = {"strate": strate, "workers": workers}
|
||||
for window, lods in (("near_lod0_2", range(3)), ("whole_lod0_8", range(9))):
|
||||
item[window] = {
|
||||
version: summarize(runs, lods)
|
||||
for version, runs in versions.items()
|
||||
}
|
||||
item[window]["candidate_minus_baseline_per_tile"] = {
|
||||
metric: (item[window]["l137"]["mean_per_tile"][metric]
|
||||
- item[window]["assembler-world"]["mean_per_tile"][metric])
|
||||
for metric in METRICS
|
||||
}
|
||||
item["logs"] = {
|
||||
version: [run["path"] for run in runs]
|
||||
for version, runs in versions.items()
|
||||
}
|
||||
result["cells"].append(item)
|
||||
OUT.parent.mkdir(parents=True, exist_ok=True)
|
||||
OUT.write_text(json.dumps(result, indent=2) + "\n", encoding="utf-8")
|
||||
print(f"[L138PrechangeCacheCounts] cells={len(result['cells'])} output={OUT.relative_to(ROOT)}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,49 @@
|
||||
# Linux138 — final cave planner speed pass
|
||||
|
||||
Source stamp: `9aade4e6cb33e86c36b89440644d9ef5d440288fb6ff0af03af128291c95f93f`.
|
||||
|
||||
## Result
|
||||
|
||||
The suspected column-cache regression is not present in the measured counters. Calls and formula evaluations per tile match `assembler/world`; the small miss deltas change sign between W8 and W12. The L77 `CachedColumn` and shared `TryRead` increases were normalized sample-share changes, not evidence of more cache calls.
|
||||
|
||||
I removed repeated route identity checks and added a fast path for prepared sweep samples that are stamped outside all passage influence. The path preserves the sample's flat distance in the union and skips wall/floor shell work whose bounds are positive. The speed bar is still missed on several near-ready cells, especially Vertical Shafts. No version bump or baseline update was needed: output audits remained green.
|
||||
|
||||
## Before-change cache census
|
||||
|
||||
Means per near-ready LOD0–2 tile, averaged across the five measured L137 L80 runs per worker count. Each cell is `assembler/world / L137 candidate`.
|
||||
|
||||
| Stratum / workers | Point calls | Local hits | Local misses | Shared hits | Formula evaluations |
|
||||
|---|---:|---:|---:|---:|---:|
|
||||
| Surface World / W8 | 6529.395 / 6529.396 | 5712.251 / 5720.303 | 817.144 / 809.092 | 570.207 / 562.158 | 246.937 / 246.934 |
|
||||
| Surface World / W12 | 6529.395 / 6529.396 | 5642.386 / 5641.558 | 887.009 / 887.838 | 639.976 / 640.851 | 247.033 / 246.987 |
|
||||
|
||||
Floating Islands, Tunnel Network, and Vertical Shafts had zero generic heightfield column calls and cache hits/misses per near-ready tile in both binaries. Floating Islands' separate local/shared cache counters were also zero in its profiled LOD0–2 tiles. The shared `TryRead` path is reached on local misses: W8 had about 8 fewer misses per tile on the candidate, while W12 had 0.83 more. Cache code, key, and window are unchanged versus `assembler/world` in `WorldAssemblerInternal.h`, `SharedColumnCache.h`, and `FloatingIslandsInternal.h`.
|
||||
|
||||
L77 reports each function's share of sampled worker ticks. A higher share can result when other work takes a smaller share; it is not a cache-call counter. The before-change census is in `Saved/Linux/l138/prechange/column-cache-counts.json`; the separate Floating Islands counters are in `Saved/Linux/l138/prechange/island-cache/summary.json`.
|
||||
|
||||
## Change and timing
|
||||
|
||||
`ShapeWorldInternal.h` now reuses the already-computed Tunnel Network stratum predicate in the passage loop. For a swept sample with no exact contribution, it adds the same flat outside distance to the union, then skips relief, mouth, wall, and shell calculations. The influence bound is 1.053 m (0.75 m shell + 0.21 m relief + 0.083 m corner support + 0.01 m guard); the stamped sentinel is one subvoxel beyond it.
|
||||
|
||||
Final L80 used one warm-up and five interleaved runs per binary, at W8/W12 across all four strata. The quiet-host gate passed at load 1.34 and 98.9% CPU idle. Deltas are candidate medians versus `assembler/world`; the L137 A/A noise floor is ±1%.
|
||||
|
||||
| Stratum | Near-ready W8 / W12 | Whole-view W8 / W12 |
|
||||
|---|---:|---:|
|
||||
| Surface World | +0.34% / +1.72% | −0.48% / −0.93% |
|
||||
| Floating Islands | −4.34% / +2.87% | −3.11% / −1.50% |
|
||||
| Tunnel Network | −2.54% / +2.86% | −3.96% / −1.73% |
|
||||
| Vertical Shafts | +4.66% / +3.25% | −1.73% / −2.06% |
|
||||
|
||||
Only Surface World W8 is within ±1% near-ready. The per-LOD worker totals show LOD2 down 24–39% on Floating Islands, Tunnel Network, and Vertical Shafts, but Vertical Shafts LOD0/1 are up 5–22%; that remaining work keeps its near-ready medians outside the bar. Tunnel Network W8 is the closest of its two near-ready cells.
|
||||
|
||||
## Checks
|
||||
|
||||
- Fast tier: PASS, 273 checks, 286.0 s.
|
||||
- Composed sweep: PASS, 16/16 seeds, with passage, seam, shell, mouth-profile, naturalness, ripple, and blocked-route controls.
|
||||
- Clang/GCC W1/W8/W12: PASS, all 13 determinism hash lines match.
|
||||
- Linux `VFHostEditor` Development: PASS, 5 actions, 38.19 s with `-NoUBA -MaxParallelActions=4`; no `prlimit`.
|
||||
- The full verification tier and Windows UE build were not run. No Unreal `Source/` files changed.
|
||||
|
||||
The first fast-tier invocation used the verifier's default `l42` output directory and refused its stale binary. I reran it with `--out Saved/Linux/l138`; the final-source run passed.
|
||||
|
||||
Build, fast-tier, seed, determinism, cache-census, and timing logs are under `Saved/Linux/l138/`; the final timing matrix is `Saved/Linux/l138/timing/summary.json`. Changes are uncommitted.
|
||||
@@ -0,0 +1,74 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Compare L138 Clang/GCC composed hashes at W1, W8, and W12."""
|
||||
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/l138/determinism"
|
||||
DATA = ROOT / "Standalone/data/regression/owner_world_2strate_l61.json"
|
||||
BINARIES = {
|
||||
"clang": ROOT / "Saved/Linux/l138/bin/VoxelForgeCoreHeadless-l138-clang",
|
||||
"gcc": ROOT / "Saved/Linux/l138/bin/VoxelForgeCoreHeadless-l138-gcc",
|
||||
}
|
||||
STAMP = "9aade4e6cb33e86c36b89440644d9ef5d440288fb6ff0af03af128291c95f93f"
|
||||
CAMERA = "-4.688214,38.662384,-505.781342,-28.446,0"
|
||||
HASH_RE = re.compile(
|
||||
r"^\[Pipeline(?:FullDetailHash|WholeViewHash|MaterialHash|LODHash|ExactQueryHash)\].*$",
|
||||
re.M)
|
||||
STAMP_RE = re.compile(r"^\[VoxelForgeSourceStamp\] sha256=([0-9a-f]+)$", re.M)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
if any(not path.is_file() for path in (DATA, *BINARIES.values())):
|
||||
raise SystemExit("missing L138 determinism binary or owner fixture")
|
||||
OUT.mkdir(parents=True, exist_ok=True)
|
||||
rows = []
|
||||
reference: tuple[str, ...] | None = None
|
||||
for compiler, binary in BINARIES.items():
|
||||
for workers in (1, 8, 12):
|
||||
name = f"determinism-{compiler}-w{workers}"
|
||||
log = OUT / f"{name}.log"
|
||||
command = ["taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--",
|
||||
"timeout", "1740s", str(binary), str(DATA),
|
||||
"--world-assembler-prototype", "--stream-benchmark", "--stream-pipeline",
|
||||
f"--workers={workers}", "--clip-radius=3", "--max-clip-level=0",
|
||||
"--max-level=0", f"--camera={CAMERA}", "--stream-hash-tiles",
|
||||
"--force-generate", "--recipe=surface-world", "--render-distance-chunks=0",
|
||||
"--landmark-chamber-demo", "--ore-veins-demo"]
|
||||
started = time.monotonic()
|
||||
with log.open("w", encoding="utf-8") as output:
|
||||
proc = subprocess.run(command, cwd=ROOT, stdout=output,
|
||||
stderr=subprocess.STDOUT, check=False, timeout=1740)
|
||||
content = log.read_text(encoding="utf-8", errors="replace")
|
||||
stamp = STAMP_RE.search(content)
|
||||
hashes = tuple(HASH_RE.findall(content))
|
||||
passed = (proc.returncode == 0 and stamp is not None
|
||||
and stamp.group(1) == STAMP and len(hashes) >= 4)
|
||||
if reference is None and passed:
|
||||
reference = hashes
|
||||
elif reference is not None:
|
||||
passed = passed and hashes == reference
|
||||
row = {"compiler": compiler, "workers": workers, "exit": proc.returncode,
|
||||
"stamp": stamp.group(1) if stamp else None, "hash_lines": len(hashes),
|
||||
"hashes_match_first": hashes == reference, "passed": bool(passed),
|
||||
"elapsed_s": round(time.monotonic() - started, 3),
|
||||
"log": str(log.relative_to(ROOT))}
|
||||
rows.append(row)
|
||||
print("[L138DeterminismRun] " + json.dumps(row, sort_keys=True), flush=True)
|
||||
if not passed:
|
||||
(OUT / "summary.json").write_text(json.dumps(
|
||||
{"status": "FAIL", "stamp": STAMP, "runs": rows}, indent=2) + "\n")
|
||||
raise SystemExit(f"determinism mismatch; see {log}")
|
||||
(OUT / "summary.json").write_text(json.dumps(
|
||||
{"status": "PASS", "stamp": STAMP, "runs": rows}, indent=2) + "\n")
|
||||
print(f"[L138DeterminismSummary] runs={len(rows)} stamp={STAMP} status=PASS")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,151 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Run five interleaved L80 timings for assembler/world and the L138 candidate."""
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import statistics
|
||||
import subprocess
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[4]
|
||||
OUT = ROOT / "Saved/Linux/l138/timing"
|
||||
DATA = ROOT / "Standalone/data/owner_world.json"
|
||||
BINARIES = {
|
||||
"assembler-world": (
|
||||
ROOT / "Saved/Linux/l137/bin/VoxelForgeCoreHeadless-l137-aa-a",
|
||||
"4499fb2a8a4ede7d6cbc68d1b794f104658cdaae93ed9cacbc91fe7ff3fc3621"),
|
||||
"l138": (
|
||||
ROOT / "Saved/Linux/l138/bin/VoxelForgeCoreHeadless-l138-clang",
|
||||
"9aade4e6cb33e86c36b89440644d9ef5d440288fb6ff0af03af128291c95f93f"),
|
||||
}
|
||||
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),
|
||||
}
|
||||
PIPELINE = re.compile(r"^\[StreamPipeline\] (.*)$", re.M)
|
||||
FIELDS = re.compile(r"([a-zA-Z0-9_]+)=([^ ]+)")
|
||||
NEAR = re.compile(
|
||||
r"^\[WorldAssemblerNearLODReady\] lods=0-2 tiles=(\d+)/(\d+) cold_ready_s=([0-9.]+)$",
|
||||
re.M)
|
||||
STAMP = re.compile(r"^\[VoxelForgeSourceStamp\] sha256=([0-9a-f]+)$", re.M)
|
||||
|
||||
|
||||
def run(strate: int, workers: int, version: str, phase: str, replicate: int) -> dict:
|
||||
OUT.mkdir(parents=True, exist_ok=True)
|
||||
binary, expected_stamp = BINARIES[version]
|
||||
camera = ",".join(f"{value:.12f}" for value in CAMERAS[strate]) + ",0,0"
|
||||
label = f"s{strate}-w{workers}-{version}-{phase}{replicate}"
|
||||
log = OUT / f"{label}.log"
|
||||
command = [
|
||||
"taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--",
|
||||
"timeout", "1740s", str(binary), str(DATA), "--world-assembler-prototype",
|
||||
"--stream-benchmark", "--stream-pipeline", f"--workers={workers}",
|
||||
"--clip-radius=3", "--max-clip-level=8", "--max-level=8",
|
||||
f"--camera={camera}", "--profile-lod-work", "--stream-scheduler-policy=3",
|
||||
]
|
||||
started = time.monotonic()
|
||||
with log.open("w", encoding="utf-8") as output:
|
||||
proc = subprocess.run(command, cwd=ROOT, stdout=output,
|
||||
stderr=subprocess.STDOUT, check=False, timeout=1740)
|
||||
content = log.read_text(encoding="utf-8", errors="replace")
|
||||
pipeline, near, stamp = PIPELINE.search(content), NEAR.search(content), STAMP.search(content)
|
||||
if (proc.returncode or pipeline is None or near is None or stamp is None
|
||||
or stamp.group(1) != expected_stamp):
|
||||
raise SystemExit(f"L80 timing failed or stamp mismatch: {log}; exit={proc.returncode}")
|
||||
fields = dict(FIELDS.findall(pipeline.group(1)))
|
||||
row = {
|
||||
"strate": strate, "workers": workers, "version": version,
|
||||
"phase": phase, "replicate": replicate, "source_stamp": stamp.group(1),
|
||||
"lod02_ready_s": float(near.group(3)),
|
||||
"whole_view_ready_s": float(fields["whole_view_ready"].removesuffix("s")),
|
||||
"whole_tiles": int(fields["whole_tiles"].split("/")[0]),
|
||||
"wall_s": round(time.monotonic() - started, 3),
|
||||
"log": str(log.relative_to(ROOT)),
|
||||
}
|
||||
print("[L138FinalTimingRun] " + json.dumps(row, sort_keys=True), flush=True)
|
||||
return row
|
||||
|
||||
|
||||
def quiet_machine() -> tuple[float, float]:
|
||||
load_1m = os.getloadavg()[0]
|
||||
|
||||
def totals() -> tuple[int, int]:
|
||||
fields = Path("/proc/stat").read_text().splitlines()[0].split()
|
||||
values = [int(value) for value in fields[1:]]
|
||||
return sum(values), values[3] + values[4]
|
||||
|
||||
before = totals()
|
||||
time.sleep(2.0)
|
||||
after = totals()
|
||||
idle = 100.0 * (after[1] - before[1]) / max(1, after[0] - before[0])
|
||||
return load_1m, idle
|
||||
|
||||
|
||||
def main() -> int:
|
||||
if any(not path.is_file() for path in [DATA, *(entry[0] for entry in BINARIES.values())]):
|
||||
raise SystemExit("missing L138 timing input")
|
||||
OUT.mkdir(parents=True, exist_ok=True)
|
||||
load_1m, idle = quiet_machine()
|
||||
(OUT / "machine-load-before.txt").write_text(
|
||||
f"1-minute load: {load_1m:.2f}\n2-second CPU idle: {idle:.1f}%\n")
|
||||
print(f"[L138FinalTimingGate] load_1m={load_1m:.2f} cpu_idle_2s={idle:.1f}%", flush=True)
|
||||
if load_1m >= 1.5 or idle < 97.0:
|
||||
raise SystemExit("timing refused: machine is above the L80 quiet-load gate")
|
||||
|
||||
rows = []
|
||||
for strate in range(4):
|
||||
for workers in (8, 12):
|
||||
for version in BINARIES:
|
||||
run(strate, workers, version, "warmup", 0)
|
||||
for replicate in range(1, 6):
|
||||
order = tuple(BINARIES) if replicate % 2 else tuple(reversed(BINARIES))
|
||||
for version in order:
|
||||
rows.append(run(strate, workers, version, "measured", replicate))
|
||||
(OUT / "runs-partial.json").write_text(
|
||||
json.dumps(rows, indent=2) + "\n", encoding="utf-8")
|
||||
|
||||
measured = [row for row in rows if row["phase"] == "measured"]
|
||||
summary = []
|
||||
for strate in range(4):
|
||||
for workers in (8, 12):
|
||||
group = [row for row in measured
|
||||
if row["strate"] == strate and row["workers"] == workers]
|
||||
entry = {"strate": strate, "workers": workers, "replicates_per_version": 5}
|
||||
medians = {
|
||||
version: {
|
||||
key: statistics.median(row[key] for row in group
|
||||
if row["version"] == version)
|
||||
for key in ("lod02_ready_s", "whole_view_ready_s")
|
||||
}
|
||||
for version in BINARIES
|
||||
}
|
||||
entry["medians"] = medians
|
||||
for key in ("lod02_ready_s", "whole_view_ready_s"):
|
||||
entry[f"l138_vs_assembler-world_{key}_delta_pct"] = round(
|
||||
100.0 * (medians["l138"][key] / medians["assembler-world"][key] - 1.0), 2)
|
||||
entry[f"{key}_paired_deltas_pct"] = [
|
||||
round(100.0 * (
|
||||
next(row[key] for row in group
|
||||
if row["version"] == "l138" and row["replicate"] == replicate)
|
||||
/ next(row[key] for row in group
|
||||
if row["version"] == "assembler-world"
|
||||
and row["replicate"] == replicate) - 1.0), 3)
|
||||
for replicate in range(1, 6)
|
||||
]
|
||||
summary.append(entry)
|
||||
(OUT / "summary.json").write_text(json.dumps({
|
||||
"a_a_noise_floor_pct": 1.0,
|
||||
"timing_protocol": "one warmup per binary, five interleaved runs, W8/W12, all four strata",
|
||||
"runs": rows,
|
||||
"summary": summary,
|
||||
}, indent=2) + "\n", encoding="utf-8")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,80 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Count pre-change Floating Islands cache calls from L137 binaries."""
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import re
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[4]
|
||||
OUT = ROOT / "Saved/Linux/l138/prechange/island-cache"
|
||||
DATA = ROOT / "Standalone/data/owner_world.json"
|
||||
BINARIES = {
|
||||
"assembler-world": (
|
||||
ROOT / "Saved/Linux/l137/profile-bin/VoxelForgeCoreHeadless-l137-profile-base",
|
||||
"4499fb2a8a4ede7d6cbc68d1b794f104658cdaae93ed9cacbc91fe7ff3fc3621"),
|
||||
"l137": (
|
||||
ROOT / "Saved/Linux/l137/profile-bin/VoxelForgeCoreHeadless-l137-profile-head",
|
||||
"dcf2ffa55fd6d62b3c7faf76229c3b99c635868dc1b694fc6e8f39e738775a4e"),
|
||||
}
|
||||
CAMERAS = {
|
||||
1: (25.8369140625, 3.19921875, -737.0),
|
||||
}
|
||||
STAMP = re.compile(r"^\[VoxelForgeSourceStamp\] sha256=([0-9a-f]+)$", re.M)
|
||||
TILE = re.compile(r"^\[CpuTileStages\] key=\([^)]*,lod(\d+)\).*", re.M)
|
||||
FIELDS = re.compile(r"([a-zA-Z0-9_]+)=([^ ]+)")
|
||||
CACHE_FIELDS = (
|
||||
"fi_local_hit", "fi_local_miss", "fi_local_conflicts",
|
||||
"fi_shared_hit", "fi_shared_miss", "fi_shared_computes",
|
||||
"fi_shared_conflicts",
|
||||
)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
OUT.mkdir(parents=True, exist_ok=True)
|
||||
rows = []
|
||||
for workers in (8, 12):
|
||||
for version, (binary, expected_stamp) in BINARIES.items():
|
||||
camera = ",".join(f"{value:.12f}" for value in CAMERAS[1]) + ",0,0"
|
||||
log = OUT / f"s1-w{workers}-{version}.log"
|
||||
command = [
|
||||
"taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--",
|
||||
"timeout", "1740s", str(binary), str(DATA),
|
||||
"--world-assembler-prototype", "--stream-benchmark", "--stream-pipeline",
|
||||
f"--workers={workers}", "--clip-radius=3", "--max-clip-level=8",
|
||||
"--max-level=8", f"--camera={camera}", "--profile-lod-work",
|
||||
"--profile-passage-composer", "--stream-scheduler-policy=3",
|
||||
]
|
||||
with log.open("w", encoding="utf-8") as output:
|
||||
proc = subprocess.run(command, cwd=ROOT, stdout=output,
|
||||
stderr=subprocess.STDOUT, check=False, timeout=1740)
|
||||
text = log.read_text(encoding="utf-8", errors="replace")
|
||||
stamp = STAMP.search(text)
|
||||
if proc.returncode or not stamp or stamp.group(1) != expected_stamp:
|
||||
raise SystemExit(f"pre-change cache census failed: {log}")
|
||||
tiles = []
|
||||
for line in text.splitlines():
|
||||
match = TILE.match(line)
|
||||
if not match or int(match.group(1)) > 2:
|
||||
continue
|
||||
fields = dict(FIELDS.findall(line))
|
||||
tiles.append({key: int(fields.get(key, "0")) for key in CACHE_FIELDS})
|
||||
if not tiles:
|
||||
raise SystemExit(f"no LOD0-2 tile-cache counters in {log}")
|
||||
total = {key: sum(tile[key] for tile in tiles) for key in CACHE_FIELDS}
|
||||
row = {
|
||||
"strate": 1, "workers": workers, "version": version,
|
||||
"source_stamp": stamp.group(1), "tiles": len(tiles),
|
||||
"totals": total,
|
||||
"per_tile": {key: value / len(tiles) for key, value in total.items()},
|
||||
"logs": str(log.relative_to(ROOT)),
|
||||
}
|
||||
rows.append(row)
|
||||
print("[L138PrechangeIslandCache] " + json.dumps(row, sort_keys=True), flush=True)
|
||||
(OUT / "summary.json").write_text(json.dumps(rows, indent=2) + "\n")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,73 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Run the 16-seed composed passage and seam audits on the L138 candidate."""
|
||||
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/l138/seeds"
|
||||
BIN = ROOT / "Saved/Linux/l138/bin/VoxelForgeCoreHeadless-l138-clang"
|
||||
DATA = ROOT / "Standalone/data/owner_world.json"
|
||||
STAMP = "9aade4e6cb33e86c36b89440644d9ef5d440288fb6ff0af03af128291c95f93f"
|
||||
STAMP_RE = re.compile(r"^\[VoxelForgeSourceStamp\] sha256=([0-9a-f]+)$", re.M)
|
||||
REQUIRED = {
|
||||
"passage": re.compile(r"^\[ResolvedPassageAuditSummary\].*status=PASS$", re.M),
|
||||
"seams": re.compile(r"^\[PassageTileSeamAudit\].*status=PASS$", re.M),
|
||||
"shell": re.compile(r"^\[PassageShellAuditSummary\].*status=PASS$", re.M),
|
||||
"naturalness": re.compile(r"^\[PassageNaturalnessSummary\].*status=PASS$", re.M),
|
||||
"mouth_profile": re.compile(r"^\[PassageMouthProfileSummary\].*status=PASS$", re.M),
|
||||
"ripple": re.compile(r"^\[PassageRippleAuditSummary\].*status=PASS$", re.M),
|
||||
"route_negative_control": re.compile(
|
||||
r"^\[TunnelNetworkBlockedRouteControl\].*expected=FAIL status=PASS$", re.M),
|
||||
}
|
||||
|
||||
|
||||
def main() -> int:
|
||||
if not BIN.is_file() or not DATA.is_file():
|
||||
raise SystemExit("missing L138 Clang binary or owner fixture")
|
||||
OUT.mkdir(parents=True, exist_ok=True)
|
||||
results = []
|
||||
for seed in range(16):
|
||||
log = OUT / f"seed{seed}.log"
|
||||
layout = OUT / f"seed{seed}.json"
|
||||
command = ["taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--",
|
||||
"timeout", "1740s", str(BIN), str(DATA),
|
||||
"--world-assembler-prototype", "--stream-benchmark", "--stream-pipeline",
|
||||
"--workers=8", "--clip-radius=3", "--max-clip-level=8", "--max-level=0",
|
||||
"--force-generate", f"--seed={seed}", "--recipe=surface-world",
|
||||
"--audit-resolved-layout-passages", "--audit-passage-tile-seams",
|
||||
f"--resolved-layout-output={layout}"]
|
||||
started = time.monotonic()
|
||||
with log.open("w", encoding="utf-8") as output:
|
||||
proc = subprocess.run(command, cwd=ROOT, stdout=output,
|
||||
stderr=subprocess.STDOUT, check=False, timeout=1740)
|
||||
content = log.read_text(encoding="utf-8", errors="replace")
|
||||
stamp = STAMP_RE.search(content)
|
||||
checks = {name: bool(pattern.search(content)) for name, pattern in REQUIRED.items()}
|
||||
checks["source_stamp"] = stamp is not None and stamp.group(1) == STAMP
|
||||
blocked = re.findall(r"^\[ResolvedPassageBlockedControl\].*detected=true$",
|
||||
content, re.M)
|
||||
checks["three_blocked_controls"] = len(blocked) == 3
|
||||
passed = proc.returncode == 0 and all(checks.values())
|
||||
row = {"seed": seed, "exit": proc.returncode, "passed": passed,
|
||||
"checks": checks, "blocked_controls": len(blocked),
|
||||
"elapsed_s": round(time.monotonic() - started, 3),
|
||||
"log": str(log.relative_to(ROOT)), "layout": str(layout.relative_to(ROOT))}
|
||||
results.append(row)
|
||||
print("[L138SeedSweep] " + json.dumps(row, sort_keys=True), flush=True)
|
||||
(OUT / "runs-partial.json").write_text(json.dumps(results, indent=2) + "\n")
|
||||
if not passed:
|
||||
raise SystemExit(f"seed {seed} failed composed audits; see {log}")
|
||||
summary = {"source_stamp": STAMP, "seeds": list(range(16)),
|
||||
"passed": len(results), "failed": 0, "results": results}
|
||||
(OUT / "summary.json").write_text(json.dumps(summary, indent=2) + "\n")
|
||||
print("[L138SeedSweepSummary] passed=16/16 status=PASS")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in new issue
Block a user