134 lines
5.1 KiB
Python
Executable File
134 lines
5.1 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
from pathlib import Path
|
|
|
|
|
|
def parse_args() -> argparse.Namespace:
|
|
p = argparse.ArgumentParser(description="Generate one multi-RIR replay case report")
|
|
p.add_argument("--rir", required=True)
|
|
p.add_argument("--snapshot-meta", required=True)
|
|
p.add_argument("--snapshot-compare", required=True)
|
|
p.add_argument("--delta-meta", required=True)
|
|
p.add_argument("--delta-compare", required=True)
|
|
p.add_argument("--routinator-base-seconds", required=True, type=float)
|
|
p.add_argument("--routinator-delta-seconds", required=True, type=float)
|
|
p.add_argument("--out-md", required=True)
|
|
p.add_argument("--out-json", required=True)
|
|
return p.parse_args()
|
|
|
|
|
|
def read_json(path: str) -> dict:
|
|
return json.loads(Path(path).read_text(encoding="utf-8"))
|
|
|
|
|
|
def parse_compare_md(path: str) -> dict:
|
|
lines = Path(path).read_text(encoding="utf-8").splitlines()
|
|
out = {}
|
|
for line in lines:
|
|
if not line.startswith("| "):
|
|
continue
|
|
parts = [p.strip() for p in line.strip("|").split("|")]
|
|
if len(parts) != 2:
|
|
continue
|
|
key, value = parts
|
|
if key in {"metric", "---"}:
|
|
continue
|
|
try:
|
|
out[key] = int(value)
|
|
except ValueError:
|
|
pass
|
|
return out
|
|
|
|
|
|
def ratio(ours: float, baseline: float) -> float | None:
|
|
if baseline <= 0:
|
|
return None
|
|
return ours / baseline
|
|
|
|
|
|
def build_report(args: argparse.Namespace) -> dict:
|
|
snapshot_meta = read_json(args.snapshot_meta)
|
|
delta_meta = read_json(args.delta_meta)
|
|
snapshot_compare = parse_compare_md(args.snapshot_compare)
|
|
delta_compare = parse_compare_md(args.delta_compare)
|
|
|
|
snapshot_ours = float(snapshot_meta["durations_secs"]["rpki_run"])
|
|
delta_ours = float(delta_meta["durations_secs"]["rpki_run"])
|
|
|
|
report = {
|
|
"rir": args.rir,
|
|
"snapshot": {
|
|
"meta_json": str(Path(args.snapshot_meta).resolve()),
|
|
"compare_md": str(Path(args.snapshot_compare).resolve()),
|
|
"ours_seconds": snapshot_ours,
|
|
"routinator_seconds": args.routinator_base_seconds,
|
|
"ratio": ratio(snapshot_ours, args.routinator_base_seconds),
|
|
"compare": snapshot_compare,
|
|
"match": snapshot_compare.get("only_in_ours", -1) == 0
|
|
and snapshot_compare.get("only_in_record", -1) == 0,
|
|
"counts": snapshot_meta.get("counts", {}),
|
|
},
|
|
"delta": {
|
|
"meta_json": str(Path(args.delta_meta).resolve()),
|
|
"compare_md": str(Path(args.delta_compare).resolve()),
|
|
"ours_seconds": delta_ours,
|
|
"routinator_seconds": args.routinator_delta_seconds,
|
|
"ratio": ratio(delta_ours, args.routinator_delta_seconds),
|
|
"compare": delta_compare,
|
|
"match": delta_compare.get("only_in_ours", -1) == 0
|
|
and delta_compare.get("only_in_record", -1) == 0,
|
|
"counts": delta_meta.get("counts", {}),
|
|
},
|
|
}
|
|
return report
|
|
|
|
|
|
def write_md(path: Path, report: dict) -> None:
|
|
snapshot = report["snapshot"]
|
|
delta = report["delta"]
|
|
lines = []
|
|
lines.append(f"# {report['rir'].upper()} Replay Report\n\n")
|
|
lines.append("## Summary\n\n")
|
|
lines.append("| mode | match | ours_s | routinator_s | ratio | only_in_ours | only_in_record |\n")
|
|
lines.append("|---|---|---:|---:|---:|---:|---:|\n")
|
|
lines.append(
|
|
f"| snapshot | {str(snapshot['match']).lower()} | {snapshot['ours_seconds']:.3f} | {snapshot['routinator_seconds']:.3f} | {snapshot['ratio']:.3f} | {snapshot['compare'].get('only_in_ours', 0)} | {snapshot['compare'].get('only_in_record', 0)} |\n"
|
|
)
|
|
lines.append(
|
|
f"| delta | {str(delta['match']).lower()} | {delta['ours_seconds']:.3f} | {delta['routinator_seconds']:.3f} | {delta['ratio']:.3f} | {delta['compare'].get('only_in_ours', 0)} | {delta['compare'].get('only_in_record', 0)} |\n"
|
|
)
|
|
lines.append("\n## Snapshot Inputs\n\n")
|
|
lines.append(f"- meta_json: `{snapshot['meta_json']}`\n")
|
|
lines.append(f"- compare_md: `{snapshot['compare_md']}`\n")
|
|
lines.append("\n## Delta Inputs\n\n")
|
|
lines.append(f"- meta_json: `{delta['meta_json']}`\n")
|
|
lines.append(f"- compare_md: `{delta['compare_md']}`\n")
|
|
lines.append("\n## Counts\n\n")
|
|
lines.append("### Snapshot\n\n")
|
|
for k, v in sorted(snapshot.get("counts", {}).items()):
|
|
lines.append(f"- {k}: `{v}`\n")
|
|
lines.append("\n### Delta\n\n")
|
|
for k, v in sorted(delta.get("counts", {}).items()):
|
|
lines.append(f"- {k}: `{v}`\n")
|
|
path.write_text("".join(lines), encoding="utf-8")
|
|
|
|
|
|
def main() -> int:
|
|
args = parse_args()
|
|
report = build_report(args)
|
|
out_json = Path(args.out_json)
|
|
out_md = Path(args.out_md)
|
|
out_json.parent.mkdir(parents=True, exist_ok=True)
|
|
out_md.parent.mkdir(parents=True, exist_ok=True)
|
|
out_json.write_text(json.dumps(report, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
|
|
write_md(out_md, report)
|
|
print(out_md)
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|