#!/usr/bin/env python3 """p2-84: dev compute profiling report tool. Ingests the per-turn profiling JSONL produced by mc-profiling::drain_turn (called from WorldSim::step and other hot paths when the "profiling" Cargo feature is enabled) plus optional godot-side blocks appended via the Gd bridge. Ranks features by total wall time, max, alloc delta. Use to drive p2-83-style parallelism decisions and p1-22 huge-map budgets. Usage: python tools/profiling-report.py profiling.jsonl (or the combined turn_stats + profiling stream) The JSONL lines are of form: {"turn": N, "spans": [ {"name": "worldsim.ecology", "calls": C, "total_ms": T, "max_ms": M, "alloc_delta": A, "alloc_peak": P}, ... ]} """ import json import sys import collections from pathlib import Path def main(argv): if len(argv) < 2: print(__doc__) print("No input file; using stdin or default 'profiling.jsonl' if present.") p = Path("profiling.jsonl") if p.exists(): lines = p.read_text().splitlines() else: lines = sys.stdin.read().splitlines() else: p = Path(argv[1]) lines = p.read_text().splitlines() by_name = collections.defaultdict(lambda: {"calls": 0, "total_ms": 0.0, "max_ms": 0.0, "alloc_delta": 0, "alloc_peak": 0}) turns = 0 for ln in lines: ln = ln.strip() if not ln: continue try: rec = json.loads(ln) except json.JSONDecodeError: continue turns += 1 for sp in rec.get("spans", []): n = sp.get("name", "unknown") c = by_name[n] c["calls"] += int(sp.get("calls", 1)) c["total_ms"] += float(sp.get("total_ms", 0.0)) c["max_ms"] = max(c["max_ms"], float(sp.get("max_ms", 0.0))) c["alloc_delta"] += int(sp.get("alloc_delta", 0)) c["alloc_peak"] = max(c["alloc_peak"], int(sp.get("alloc_peak", 0))) if not by_name: print("No spans found. (Run with --features profiling and drive some turns.)") return ranked = sorted(by_name.items(), key=lambda kv: -kv[1]["total_ms"]) print(f"Profiling report over {turns} turn(s) with data:") print("name | calls | total_ms | max_ms | alloc_delta | alloc_peak") print("-" * 70) for name, c in ranked[:15]: print(f"{name} | {c['calls']} | {c['total_ms']:.2f} | {c['max_ms']:.2f} | {c['alloc_delta']} | {c['alloc_peak']}") print("\n(Top 15 by total wall time. Use this to target p2-83 parallelism or budgets.)") if __name__ == "__main__": main(sys.argv)