"""Summarize probe.csv between two HH:MM:SS times: idle baseline, download/upload phases.""" import csv, statistics, sys start, end = sys.argv[1], sys.argv[2] rows = [r for r in csv.DictReader(open(sys.argv[3] if len(sys.argv) > 3 else 'probe.csv')) if start <= r['ts'][:8] <= end] for r in rows: for k in [c for c in ('udp_ms', 'icmp_ms', 'tx_mbps', 'rx_mbps', 'v4_pps', 'v6_pps') if c in r]: r[k] = float(r[k]) def phase(r): if r['tx_mbps'] > 100 and r['tx_mbps'] > r['rx_mbps']: return 'upload' if r['rx_mbps'] > 100 and r['rx_mbps'] > r['tx_mbps']: return 'download' if r['tx_mbps'] < 5 and r['rx_mbps'] < 5: return 'idle' return 'other' def pct(v, p): v = sorted(v); return v[min(len(v) - 1, int(round(p / 100 * (len(v) - 1))))] # gaps times = [int(r['ts'][:2]) * 3600 + int(r['ts'][3:5]) * 60 + float(r['ts'][6:]) for r in rows] gap = max((b - a for a, b in zip(times, times[1:])), default=0) print(f"samples {len(rows)} max gap {gap:.2f}s") idle_udp = [r['udp_ms'] for r in rows if phase(r) == 'idle' and r['udp_ms'] > 0] base_udp = statistics.median(idle_udp) if idle_udp else float('nan') idle_icmp = [r['icmp_ms'] for r in rows if phase(r) == 'idle' and r['icmp_ms'] > 0] base_icmp = statistics.median(idle_icmp) if idle_icmp else float('nan') print(f"idle baseline: udp {base_udp:.1f}ms (n={len(idle_udp)}) icmp {base_icmp:.1f}ms") for ph in ('download', 'upload'): sel = [r for r in rows if phase(r) == ph] u = [r['udp_ms'] for r in sel if r['udp_ms'] > 0]; lost_u = sum(1 for r in sel if r['udp_ms'] < 0) i = [r['icmp_ms'] for r in sel if r['icmp_ms'] >= 0]; lost_i = sum(1 for r in sel if r['icmp_ms'] < 0) mb = statistics.median([r['tx_mbps' if ph == 'upload' else 'rx_mbps'] for r in sel]) if sel else 0 if u: print(f"{ph:8s} n={len(sel)} ~{mb:.0f} Mbps | UDP added: median +{statistics.median(u)-base_udp:.0f}ms p95 +{pct(u,95)-base_udp:.0f}ms timeouts {lost_u}" + (f" | ICMP added: median +{statistics.median(i)-base_icmp:.0f}ms p95 +{pct(i,95)-base_icmp:.0f}ms lost {lost_i}" if i else "")) else: print(f"{ph:8s} n={len(sel)} (no valid samples)") if sel and 'v6_pps' in sel[0]: v4=sum(r['v4_pps'] for r in sel); v6=sum(r['v6_pps'] for r in sel) print(f" protocol share: IPv6 {100*v6/max(1,v4+v6):.1f}% of packets")