import argparse
import csv
import json
import os
import sys
from datetime import datetime, timezone
from pathlib import Path
from typing import Dict, Any, Optional
def load_json(path: Path) -> Optional[Dict[str, Any]]:
try:
with open(path) as f:
return json.load(f)
except (FileNotFoundError, json.JSONDecodeError) as e:
print(f" Warning: skipping {path}: {e}", file=sys.stderr)
return None
def extract_rust_rows(data: Dict, run_id: str) -> list[Dict]:
rows = []
features = data.get("metadata", {}).get("features", [])
features_str = ",".join(sorted(features)) if features else ""
timestamp = data.get("metadata", {}).get("collection_timestamp", "")
for group_name, benches in data.get("benches", {}).items():
for bench_key, stats in benches.items():
rows.append(
{
"source": "rust",
"group": group_name,
"benchmark": bench_key,
"features": features_str,
"mean_s": stats.get("mean", 0),
"stddev_s": stats.get("stddev", 0),
"min_s": stats.get("min", 0),
"max_s": stats.get("max", 0),
"median_s": stats.get("median", 0),
"ci_lower_s": stats.get("ci_lower"),
"ci_upper_s": stats.get("ci_upper"),
"samples": stats.get("count", 0),
"run_id": run_id,
"timestamp": timestamp,
}
)
return rows
def extract_python_rows(data: Dict, run_id: str) -> list[Dict]:
rows = []
features = data.get("metadata", {}).get("extra_params", {}).get("features", "")
features_str = (
features
if isinstance(features, str)
else ",".join(sorted(features))
if features
else ""
)
timestamp = data.get("metadata", {}).get("timestamp", "")
for bench in data.get("benchmarks", []):
stats = bench.get("statistics", {})
rows.append(
{
"source": "python",
"group": bench.get("group", ""),
"measure": bench.get("measure", ""),
"benchmark": bench.get("name", ""),
"features": features_str,
"mean_s": stats.get("mean", 0),
"stddev_s": stats.get("stddev", 0),
"min_s": stats.get("min", 0),
"max_s": stats.get("max", 0),
"median_s": stats.get("median", 0),
"value": bench.get("value"),
"params": json.dumps(bench.get("params", {})),
"run_id": run_id,
"timestamp": timestamp,
}
)
return rows
def scan_run_directory(runs_dir: Path) -> list[Dict]:
all_rows = []
if not runs_dir.exists():
print(f" Run directory not found: {runs_dir}")
return all_rows
run_dirs = sorted(
[d for d in runs_dir.iterdir() if d.is_dir() and d.name.startswith("run_")]
)
if not run_dirs:
print(f" No run directories found in {runs_dir}")
return all_rows
print(f" Found {len(run_dirs)} run(s)")
for run_dir in run_dirs:
run_id = run_dir.name
rust_file = run_dir / "rust_results.json"
if rust_file.exists():
data = load_json(rust_file)
if data:
rows = extract_rust_rows(data, run_id)
all_rows.extend(rows)
print(f" {run_id}: {len(rows)} Rust entries")
for py_file in sorted(run_dir.glob("python_*.json")):
data = load_json(py_file)
if data:
rows = extract_python_rows(data, run_id)
all_rows.extend(rows)
print(f" {run_id}: {len(rows)} Python entries ({py_file.name})")
return all_rows
def deduplicate_rows(rows: list[Dict]) -> list[Dict]:
seen = {}
for row in rows:
key = (
row.get("source", ""),
row.get("group", ""),
row.get("benchmark", ""),
row.get("features", ""),
)
seen[key] = row return list(seen.values())
def write_csv(rows: list[Dict], path: str):
if not rows:
print(f" No data to write for {path}")
return
os.makedirs(os.path.dirname(path) or ".", exist_ok=True)
fieldnames = sorted(set().union(*(r.keys() for r in rows)))
with open(path, "w", newline="") as f:
writer = csv.DictWriter(f, fieldnames=fieldnames, extrasaction="ignore")
writer.writeheader()
writer.writerows(rows)
print(f"\n Wrote {len(rows)} aggregated rows to {path}")
def main():
parser = argparse.ArgumentParser(
description="Aggregate Rust + Python benchmark results from run directories"
)
parser.add_argument(
"--runs-dir",
default="internal/benchmark_results/runs",
help="Directory containing run_* subdirectories",
)
parser.add_argument(
"--output",
default="internal/benchmark_results/summary.csv",
help="Output CSV file path",
)
args = parser.parse_args()
runs_dir = Path(args.runs_dir)
print("Aggregating benchmark results...")
all_rows = scan_run_directory(runs_dir)
if not all_rows:
print("No data found. Run some benchmarks first:")
print(f" bash scripts/run_full_benchmark_suite.sh --quick")
sys.exit(0)
all_rows.sort(key=lambda r: r.get("timestamp", ""))
deduped = deduplicate_rows(all_rows)
duplicates = len(all_rows) - len(deduped)
if duplicates > 0:
print(f"\n Removed {duplicates} duplicate(s) (keeping latest per config)")
write_csv(deduped, args.output)
from collections import Counter
features_counts = Counter(r.get("features", "") for r in deduped)
print("\n Entries by feature set:")
for feat, count in sorted(features_counts.items()):
label = feat if feat else "(baseline / CPU)"
print(f" [{label}] {count} entries")
if __name__ == "__main__":
main()