mirror of
https://github.com/horizon-rust/horizon.git
synced 2026-11-07 11:06:11 -10:00
90 lines
4.0 KiB
Python
90 lines
4.0 KiB
Python
#!/usr/bin/env python3
|
|
"""Compare four JSON loading sequences in the client startup table phase.
|
|
|
|
Build first with `cargo build --release -p horizon-client --example shared_json_startup_profile`.
|
|
Modes: baseline uses independent public loaders, pr607 reproduces a01d47f2,
|
|
shared uses the paired wrapper, and deferred retains the projection until the
|
|
normal behaviour stage. All modes use one optimized executable. This covers
|
|
Assets::load plus BlockFacts and Behaviours loading; it excludes full startup,
|
|
rendering, resource-pack resolution and first frame. Peak RSS includes Assets.
|
|
"""
|
|
import argparse
|
|
import json
|
|
import os
|
|
import statistics
|
|
import subprocess
|
|
import tempfile
|
|
from pathlib import Path
|
|
|
|
|
|
def run(binary, resources, mode):
|
|
with tempfile.TemporaryFile(mode="w+t") as output:
|
|
proc = subprocess.Popen([str(binary), str(resources), mode], stdout=output, stderr=subprocess.PIPE)
|
|
_, status, usage = os.wait4(proc.pid, 0)
|
|
proc.returncode = os.waitstatus_to_exitcode(status)
|
|
_, stderr = proc.communicate()
|
|
if os.waitstatus_to_exitcode(status):
|
|
raise RuntimeError(f"{mode}: {stderr.decode(errors='replace')}")
|
|
output.seek(0)
|
|
fields = dict(line.rstrip().split("=", 1) for line in output if "=" in line)
|
|
return {
|
|
"phase_ms": float(fields["phase_ms"]),
|
|
"total_ms": float(fields["total_ms"]),
|
|
"cpu_ms": (usage.ru_utime + usage.ru_stime) * 1000.0,
|
|
"peak_rss_kib": usage.ru_maxrss,
|
|
}
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument("--binary", type=Path, default=Path("target/release/examples/shared_json_startup_profile"))
|
|
parser.add_argument("--resources", type=Path, default=Path(".local/horizon-client/26.3"))
|
|
parser.add_argument("--repeats", type=int, default=5)
|
|
parser.add_argument("--reference-binary", type=Path,
|
|
help="Release binary built from cf837118; compare its deferred mode against current")
|
|
parser.add_argument("--output", type=Path)
|
|
args = parser.parse_args()
|
|
if args.repeats < 1:
|
|
parser.error("--repeats must be positive")
|
|
binary, resources = args.binary.resolve(), args.resources.resolve()
|
|
if not binary.is_file() or not resources.is_dir():
|
|
parser.error("binary or resources missing; build the example and prepare resources first")
|
|
if args.reference_binary:
|
|
reference = args.reference_binary.resolve()
|
|
if not reference.is_file():
|
|
parser.error("reference binary missing")
|
|
modes = ["baseline", "pr607", "cf837118", "current"]
|
|
commands = {
|
|
"baseline": (binary, "baseline"),
|
|
"pr607": (binary, "pr607"),
|
|
"cf837118": (reference, "deferred"),
|
|
"current": (binary, "deferred"),
|
|
}
|
|
else:
|
|
modes = ["baseline", "pr607", "shared", "deferred"]
|
|
commands = {mode: (binary, mode) for mode in modes}
|
|
samples = {mode: [] for mode in modes}
|
|
for i in range(args.repeats):
|
|
for mode in (modes if i % 2 == 0 else list(reversed(modes))):
|
|
executable, binary_mode = commands[mode]
|
|
samples[mode].append(run(executable, resources, binary_mode))
|
|
result = {
|
|
"scope": "Assets + block facts + behaviours loader only; excludes full startup",
|
|
"resources": str(resources),
|
|
"repeats": args.repeats,
|
|
"comparison": "historical cf837118 release binary" if args.reference_binary else "same binary loading modes",
|
|
"reference_binary": str(args.reference_binary) if args.reference_binary else None,
|
|
"metrics": {mode: {key: {"median": round(statistics.median(row[key] for row in rows), 3),
|
|
"samples": [round(row[key], 3) for row in rows]}
|
|
for key in rows[0]} for mode, rows in samples.items()},
|
|
}
|
|
data = json.dumps(result, indent=2)
|
|
print(data)
|
|
if args.output:
|
|
args.output.parent.mkdir(parents=True, exist_ok=True)
|
|
args.output.write_text(data + "\n")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|