rpki/scripts/payload_replay/write_multi_rir_case_report.py
yuyr 557a69cbd2 20260316迭代 增加delta replay以及multi-rir
replay 对比,五个RIR 输出vrp与routinator一致
2026-03-16 22:54:48 +08:00

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())