1#!/usr/bin/env python32"""Compute accounting from the run manifest and forecast status tables: per specification (all instruments) wall/CPU time,3peak RSS, forecast status shares. Writes results/tables/compute_<run>.csv and status_<run>.csv (no return values)."""4from __future__ import annotations56import glob7import json8import sys9from pathlib import Path1011import pandas as pd1213ROOT = Path(__file__).resolve().parents[1]141516def main(run: str = "main") -> None:17 d = ROOT / "results" / "forecasts" / run18 recs = [json.loads(l) for f in sorted(d.glob("_runs*.jsonl")) for l in open(f)]19 R = pd.DataFrame([r for r in recs if "wall_s" in r]).drop_duplicates(["symbol", "spec_id"], keep="last")20 R["model_id"] = R["spec_id"].str.split("__").str[0]; R["dist"] = R["spec_id"].str.split("__").str[1]21 C = R.groupby(["spec_id", "model_id", "dist"]).agg(n_jobs=("wall_s", "size"), wall_mean=("wall_s", "mean"), wall_median=("wall_s", "median"),22 cpu_mean=("cpu_s", "mean"), maxrss_mb_median=("maxrss_mb", "median"), maxrss_mb_max=("maxrss_mb", "max"),23 fit_time_total=("fit_time_total_s", "mean"), fc_time_total=("fc_time_total_s", "mean"), n_origins=("n_origins", "mean")).reset_index()24 C["cpu_per_origin_ms"] = 1000 * C["cpu_mean"] / C["n_origins"]25 (ROOT / "results" / "tables").mkdir(exist_ok=True)26 C.to_csv(ROOT / "results" / "tables" / f"compute_{run}.csv", index=False)27 rows = []28 for f in glob.glob(str(d / "*" / "*.parquet")):29 if f.endswith(".fits.parquet"):30 continue31 F = pd.read_parquet(f, columns=["status", "spec_id", "symbol"])32 vc = F["status"].value_counts(normalize=True)33 rows.append({"symbol": F["symbol"].iloc[0], "spec_id": F["spec_id"].iloc[0], "n": len(F), **{f"share_{k}": float(v) for k, v in vc.items()}})34 S = pd.DataFrame(rows).fillna(0.0)35 S.to_csv(ROOT / "results" / "tables" / f"status_{run}.csv", index=False)36 agg = S.groupby("spec_id")[[c for c in S.columns if c.startswith("share_")]].mean().sort_values("share_ok")37 print(C.sort_values("cpu_per_origin_ms", ascending=False).head(12)[["spec_id", "wall_median", "cpu_per_origin_ms", "maxrss_mb_median"]].round(2).to_string(index=False))38 print(agg.head(15).round(4).to_string())39 print("total CPU hours:", round(R["cpu_s"].sum() / 3600, 1), "jobs:", len(R))404142if __name__ == "__main__":43 main(sys.argv[1] if len(sys.argv) > 1 else "main")44