mirror of
https://github.com/horizon-rust/horizon.git
synced 2026-11-07 11:06:11 -10:00
lab.VERSION, lab.GAME (.local/minecraft/<version>) and lab.RESOURCES (.local/horizon-client/<version>) come from the lock, and lab.version_info() reads the pinned client jar's version.json. Every harness, generator and tool that named 26.3 (resource folders, jar and source paths, result records, the vanilla client's --version and asset index, the bare login client's protocol, the benchmark's options.txt data version, the packet id table's header) uses them, so a candidate worktree pinned to another version runs them unchanged. Co-Authored-By: Claude Opus 5.5 <[email protected]>
100 lines
5.3 KiB
Python
100 lines
5.3 KiB
Python
#!/usr/bin/env python3
|
|
"""Measure shallow quad-reuse retention in private Fabric clients, not whole-game RAM."""
|
|
|
|
import argparse
|
|
import hashlib
|
|
import json
|
|
import os
|
|
import platform
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
import zipfile
|
|
|
|
try:
|
|
from . import lab
|
|
except ImportError:
|
|
import lab
|
|
|
|
try:
|
|
from . import build_mod, build_pack
|
|
from .test_culling_rays import run_fixture
|
|
except ImportError:
|
|
import build_mod
|
|
import build_pack
|
|
from test_culling_rays import run_fixture
|
|
|
|
|
|
def build_agent():
|
|
output = build_mod.BUILD / "size-agent"
|
|
classes = output / "classes"
|
|
classes.mkdir(parents=True, exist_ok=True)
|
|
source = build_mod.SOURCE / "test/java/dev/horizonlab/metrics/ObjectSizeAgent.java"
|
|
subprocess.run(["javac", "--release", "25", "-d", str(classes), str(source)], check=True)
|
|
agent = output / "size-agent.jar"
|
|
with zipfile.ZipFile(agent, "w", compression=zipfile.ZIP_DEFLATED) as archive:
|
|
archive.writestr("META-INF/MANIFEST.MF", "Manifest-Version: 1.0\n"
|
|
"Premain-Class: dev.horizonlab.metrics.ObjectSizeAgent\n\n")
|
|
for path in sorted(classes.rglob("*.class")):
|
|
archive.write(path, path.relative_to(classes).as_posix())
|
|
return agent
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument("--native-display", action="store_true")
|
|
args = parser.parse_args()
|
|
root = build_pack.ROOT
|
|
agent = build_agent()
|
|
fixture = build_mod.build_integration_fixture("quad-size", "dev.horizonlab.dispatch.QuadSizeIntegration")
|
|
mod = root / "dist" / f"horizon-{build_pack.read_lock()['pack_version']}.jar"
|
|
mod_hash = hashlib.sha256(mod.read_bytes()).hexdigest()
|
|
results = []
|
|
for headers in [False, True]:
|
|
for enabled in [False, True]:
|
|
instance = root / ".local/runtime" / f"quad-size-{headers}-{enabled}"
|
|
build_pack.prepare_instance("m2-balanced", instance, mod)
|
|
assert hashlib.sha256((instance / "mods" / mod.name).read_bytes()).hexdigest() == mod_hash
|
|
shutil.copy2(fixture, instance / "mods/quad-size-fixture.jar")
|
|
(instance / "config/horizon-quad-reuse.properties").write_text(f"enabled={str(enabled).lower()}\n")
|
|
environment = os.environ.copy()
|
|
header_option = "-XX:" + ("+" if headers else "-") + "UseCompactObjectHeaders"
|
|
if '"' in str(agent) or "\n" in str(agent):
|
|
raise ValueError("Instrumentation agent path contains an unsupported quote or newline")
|
|
environment["_JAVA_OPTIONS"] = f'-javaagent:"{agent}" {header_option} -Dhorizon.fixture.exit=true'
|
|
command = [sys.executable, str(root / "tools/runtime.py"), "demo", "--instance", str(instance), "--heap", "3G"]
|
|
if platform.system() == "Linux" and not args.native_display:
|
|
command = ["xvfb-run", "-a", *command]
|
|
run = run_fixture(command, instance, environment)
|
|
marker = "HORIZON_SIZE_RESULT "
|
|
reports = [json.loads(line.split(marker, 1)[1]) for line in run.stdout.splitlines() if marker in line]
|
|
if run.returncode or len(reports) != 1:
|
|
raise RuntimeError("Private quad-size fixture failed; diagnostics remain in its fixture.log")
|
|
report = reports[0]
|
|
if report["enabled"] != enabled or report["compact_headers"] != headers or report["geometry_quads"] != 1:
|
|
raise AssertionError("Size probe did not measure the requested hook/header combination")
|
|
if bool(report["pending_scratch_shallow_bytes"]) != enabled:
|
|
raise AssertionError("Size probe retained an unexpected scratch object")
|
|
results.append(report)
|
|
print(json.dumps(report), flush=True)
|
|
differences = []
|
|
for control, candidate in zip(results[::2], results[1::2]):
|
|
differences.append({"compact_headers": candidate["compact_headers"],
|
|
"additional_builder_shallow_bytes": candidate["builder_shallow_bytes"] - control["builder_shallow_bytes"],
|
|
"additional_builder_and_scratch_bytes": candidate["builder_shallow_bytes"] - control["builder_shallow_bytes"] + candidate["pending_scratch_shallow_bytes"]})
|
|
output = root / "dist/quad-size-integration.json"
|
|
output.write_text(json.dumps({"schema": 1, "platform": platform.platform(), "architecture": platform.machine(),
|
|
"minecraft": lab.VERSION, "distant_horizons": "3.3.4", "original_mod_sha256": mod_hash,
|
|
"results": results, "differences": differences,
|
|
"notes": ["Instrumentation.getObjectSize measures shallow object sizes inside real applied Fabric clients.",
|
|
"Four adjacent north-facing quads premerge to one retained geometry quad in each combination.",
|
|
"Builder plus pending scratch difference excludes referenced lists, existing pools and every other game object.",
|
|
"Object alignment/header/compressed-reference settings can differ on other JVMs or architectures.",
|
|
"Not deep heap, GC residency, whole-game RSS/unified RAM, FPS or Apple Silicon performance.",
|
|
"The agent and fixture are private test binaries excluded from playable packs."]}, indent=2) + "\n")
|
|
print(f"Quad object-size observations: {output}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|