Open-source release: pipeline code, raw logs, derived data, licences, tests
Adds src/ (scripts, raw measurement logs, derived data, report source), tests/, LICENSE (MIT, code) and LICENSE-DATA.md (CC BY 4.0 for the survey's data; third-party terms). The report is updated to the current site; the v1 and v2 data hand-off files are unchanged. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
"""Reduce WonderNetwork's public one-day ping dump (2020-07-19/20) to one
|
||||
robust RTT floor per city pair and test it against every model.
|
||||
|
||||
RTT used = median of the per-run minimums (each run = 30 pings). Using the
|
||||
median instead of the single fastest ping discards glitch runs and errs in the
|
||||
flat models' favour (a higher RTT is easier for a long flat route to explain).
|
||||
"""
|
||||
import csv, gzip, json, statistics, sys
|
||||
from collections import defaultdict
|
||||
from models import MODELS, distance, floor_ms, C_FIBER, C_VACUUM
|
||||
|
||||
RAW = "raw/wn"
|
||||
SLACK_KM = 200 # each endpoint may sit up to 100 km from its listed coordinates
|
||||
SLACK_MS = 1.0 # timer / queueing jitter allowance
|
||||
|
||||
servers = {}
|
||||
with open(f"{RAW}/servers-2020-07-19.csv") as f:
|
||||
for r in csv.DictReader(f):
|
||||
servers[r["id"]] = dict(name=r["title"], country=r["country"],
|
||||
lat=float(r["latitude"]), lon=float(r["longitude"]))
|
||||
|
||||
runs = defaultdict(list)
|
||||
avgs = defaultdict(list)
|
||||
with gzip.open(f"{RAW}/pings-2020-07-19-2020-07-20.csv.gz", "rt") as f:
|
||||
for r in csv.DictReader(f):
|
||||
s, d = r["source"], r["destination"]
|
||||
if s == d or s not in servers or d not in servers:
|
||||
continue
|
||||
try:
|
||||
mn, av = float(r["min"]), float(r["avg"])
|
||||
except ValueError:
|
||||
continue
|
||||
if mn > 0:
|
||||
key = tuple(sorted((s, d), key=int))
|
||||
runs[key].append(mn)
|
||||
avgs[key].append(av)
|
||||
|
||||
|
||||
def impossible(rtt, km, speed=C_FIBER):
|
||||
return rtt + SLACK_MS < floor_ms(max(0.0, km - SLACK_KM), speed)
|
||||
|
||||
|
||||
pairs = []
|
||||
for (a, b), mins in runs.items():
|
||||
if len(mins) < 5:
|
||||
continue
|
||||
A, B = servers[a], servers[b]
|
||||
pa, pb = (A["lat"], A["lon"]), (B["lat"], B["lon"])
|
||||
row = dict(a=a, b=b, n=len(mins), rtt=round(statistics.median(mins), 2),
|
||||
best=round(min(mins), 2), avg=round(statistics.median(avgs[(a, b)]), 2))
|
||||
for m in MODELS:
|
||||
row[m] = round(distance(m, pa, pb), 1)
|
||||
pairs.append(row)
|
||||
|
||||
# A pair that is impossible on the globe is impossible on every flat map too
|
||||
# (all three flat maps stretch every distance relative to the globe), so one
|
||||
# of the two servers' advertised location must be wrong. Greedily drop the
|
||||
# server implicated most often; when only 1:1 conflicts remain we can't tell
|
||||
# which side is lying, so both go.
|
||||
mislocated = set()
|
||||
while True:
|
||||
bad = [r for r in pairs if r["a"] not in mislocated and r["b"] not in mislocated
|
||||
and impossible(r["rtt"], r["globe"])]
|
||||
if not bad:
|
||||
break
|
||||
count = defaultdict(int)
|
||||
for r in bad:
|
||||
count[r["a"]] += 1
|
||||
count[r["b"]] += 1
|
||||
worst = max(count.values())
|
||||
mislocated |= {s for s, n in count.items() if n == worst} if worst == 1 else {max(count, key=count.get)}
|
||||
clean = [r for r in pairs if r["a"] not in mislocated and r["b"] not in mislocated]
|
||||
|
||||
|
||||
def report(rows, label):
|
||||
print(f"\n{label}: {len(rows)} pairs")
|
||||
for m in MODELS:
|
||||
fib = sum(impossible(r["rtt"], r[m]) for r in rows)
|
||||
vac = sum(impossible(r["rtt"], r[m], C_VACUUM) for r in rows)
|
||||
print(f" {m:9s} beats light-in-fibre: {fib:5d} ({fib/len(rows):6.2%}) beats light-in-vacuum: {vac:5d} ({vac/len(rows):6.2%})")
|
||||
|
||||
|
||||
print("mislocated servers dropped:", ", ".join(f"{servers[s]['name']} ({servers[s]['country']})" for s in sorted(mislocated, key=int)))
|
||||
report(pairs, "ALL pairs")
|
||||
report(clean, "CLEAN pairs")
|
||||
south = [r for r in clean if servers[r["a"]]["lat"] < 0 and servers[r["b"]]["lat"] < 0]
|
||||
report(south, "CLEAN, both ends in southern hemisphere")
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
used = {s for r in clean for s in (r["a"], r["b"])}
|
||||
json.dump(dict(servers={k: v for k, v in servers.items() if k in used},
|
||||
mislocated=[servers[s] for s in sorted(mislocated, key=int)],
|
||||
pairs=clean), open(sys.argv[1], "w"))
|
||||
Reference in New Issue
Block a user