import json
import os
import sys
from pathlib import Path
from dataclasses import dataclass
from typing import Optional
@dataclass
class PerfResult:
scenario: str
impl: str
test_type: str condition: Optional[str] upload_mbps: float
download_mbps: float
cpu_avg: float
cpu_max: float
def parse_quinn_perf_json(path: Path) -> Optional[dict]:
try:
with open(path) as f:
data = json.load(f)
if not data.get('intervals'):
return None
total_send_bps = 0
total_recv_bps = 0
count = 0
for interval in data['intervals']:
if 'sum' in interval:
if interval['sum'].get('sender'):
total_send_bps += interval['sum'].get('bits_per_second', 0)
else:
total_recv_bps += interval['sum'].get('bits_per_second', 0)
for stream in interval.get('streams', []):
if stream.get('sender'):
total_send_bps += stream.get('bits_per_second', 0)
else:
total_recv_bps += stream.get('bits_per_second', 0)
count += 1
if count == 0:
return None
return {
'upload_mbps': (total_send_bps / count) / 1_000_000,
'download_mbps': (total_recv_bps / count) / 1_000_000,
}
except (json.JSONDecodeError, KeyError, FileNotFoundError):
return None
def parse_metadata_json(path: Path) -> Optional[dict]:
try:
with open(path) as f:
return json.load(f)
except (json.JSONDecodeError, FileNotFoundError):
return None
def collect_results(raw_dir: Path, netsim_dir: Path) -> list[PerfResult]:
results = []
if raw_dir.exists():
for impl_dir in raw_dir.iterdir():
if not impl_dir.is_dir():
continue
impl = impl_dir.name
for scenario_dir in impl_dir.iterdir():
if not scenario_dir.is_dir():
continue
scenario = scenario_dir.name
results_json = scenario_dir / 'results.json'
metadata_json = scenario_dir / 'metadata.json'
perf_data = parse_quinn_perf_json(results_json)
metadata = parse_metadata_json(metadata_json)
if perf_data:
results.append(PerfResult(
scenario=scenario,
impl=impl,
test_type='raw',
condition=None,
upload_mbps=perf_data['upload_mbps'],
download_mbps=perf_data['download_mbps'],
cpu_avg=metadata.get('cpu_avg', 0) if metadata else 0,
cpu_max=metadata.get('cpu_max', 0) if metadata else 0,
))
if netsim_dir.exists():
for impl_dir in netsim_dir.iterdir():
if not impl_dir.is_dir():
continue
impl = impl_dir.name
for json_file in impl_dir.glob('*.json'):
if json_file.name == 'metadata.json':
continue
condition = json_file.stem.split('_')[0] if '_' in json_file.stem else json_file.stem
perf_data = parse_quinn_perf_json(json_file)
if perf_data:
results.append(PerfResult(
scenario=f'netsim-{condition}',
impl=impl,
test_type='netsim',
condition=condition,
upload_mbps=perf_data['upload_mbps'],
download_mbps=perf_data['download_mbps'],
cpu_avg=0,
cpu_max=0,
))
return results
def format_delta(iroh_val: float, upstream_val: float) -> str:
if upstream_val == 0:
return "N/A"
delta_pct = ((iroh_val - upstream_val) / upstream_val) * 100
if abs(delta_pct) < 1:
return "~0%"
elif delta_pct > 0:
return f"+{delta_pct:.1f}%"
else:
return f"{delta_pct:.1f}%"
def generate_markdown(results: list[PerfResult]) -> str:
lines = []
iroh_results = {r.scenario: r for r in results if 'iroh' in r.impl.lower()}
upstream_results = {r.scenario: r for r in results if 'upstream' in r.impl.lower()}
raw_scenarios = sorted(set(
r.scenario for r in results
if r.test_type == 'raw'
))
if raw_scenarios:
lines.append("### Raw Benchmarks (localhost)\n")
lines.append("| Scenario | iroh-quinn | upstream | Delta | CPU (avg/max) |")
lines.append("|----------|------------|----------|-------|---------------|")
for scenario in raw_scenarios:
iroh = iroh_results.get(scenario)
upstream = upstream_results.get(scenario)
if iroh:
iroh_dl = f"{iroh.download_mbps:.1f} Mbps"
cpu = f"{iroh.cpu_avg:.1f}% / {iroh.cpu_max:.1f}%"
else:
iroh_dl = "N/A"
cpu = "N/A"
if upstream:
upstream_dl = f"{upstream.download_mbps:.1f} Mbps"
else:
upstream_dl = "N/A"
if iroh and upstream:
delta = format_delta(iroh.download_mbps, upstream.download_mbps)
else:
delta = "N/A"
lines.append(f"| {scenario} | {iroh_dl} | {upstream_dl} | {delta} | {cpu} |")
lines.append("")
netsim_scenarios = sorted(set(
r.scenario for r in results
if r.test_type == 'netsim'
))
if netsim_scenarios:
lines.append("### Netsim Benchmarks (network simulation)\n")
lines.append("| Condition | iroh-quinn | upstream | Delta |")
lines.append("|-----------|------------|----------|-------|")
for scenario in netsim_scenarios:
iroh = iroh_results.get(scenario)
upstream = upstream_results.get(scenario)
condition = scenario.replace('netsim-', '')
if iroh:
iroh_dl = f"{iroh.download_mbps:.1f} Mbps"
else:
iroh_dl = "N/A"
if upstream:
upstream_dl = f"{upstream.download_mbps:.1f} Mbps"
else:
upstream_dl = "N/A"
if iroh and upstream:
delta = format_delta(iroh.download_mbps, upstream.download_mbps)
else:
delta = "N/A"
lines.append(f"| {condition} | {iroh_dl} | {upstream_dl} | {delta} |")
lines.append("")
if iroh_results and upstream_results:
common = set(iroh_results.keys()) & set(upstream_results.keys())
if common:
total_iroh = sum(iroh_results[s].download_mbps for s in common)
total_upstream = sum(upstream_results[s].download_mbps for s in common)
avg_delta = ((total_iroh - total_upstream) / total_upstream) * 100 if total_upstream else 0
lines.append("### Summary\n")
if avg_delta > 5:
lines.append(f"iroh-quinn is **{avg_delta:.1f}% faster** on average")
elif avg_delta < -5:
lines.append(f"iroh-quinn is **{abs(avg_delta):.1f}% slower** on average")
else:
lines.append(f"Performance is roughly equivalent (delta: {avg_delta:+.1f}%)")
if not results:
lines.append("*No results available*")
return "\n".join(lines)
def main():
if len(sys.argv) < 3:
print("Usage: compare_results.py <raw_results_dir> <netsim_results_dir>", file=sys.stderr)
sys.exit(1)
raw_dir = Path(sys.argv[1])
netsim_dir = Path(sys.argv[2])
results = collect_results(raw_dir, netsim_dir)
print(generate_markdown(results))
if __name__ == '__main__':
main()