Link test: download series (bulk sampled, warm bursts, paced) and burst-vs-idle; car results
Orin -> tablet over NCM: paced streams up to 4 MB/s are clean; unpaced bursts and bulk hit multi-second holds that inflate the RTO to 10-16 s. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DDwfd6Ki8UfG4hK6W5YpJz
This commit is contained in:
+34
-7
@@ -4,7 +4,12 @@
|
||||
The tablet's own sockets are the only ones bound to the USB link (`adb shell`
|
||||
traffic goes over WiFi), so the app drives the test and this end only serves:
|
||||
|
||||
7791/tcp down: client sends "<id> <secs>\\n", gets zeros for <secs>
|
||||
7791/tcp down: client sends one line, then reads until the server closes:
|
||||
"<id> <secs>" zeros for <secs>
|
||||
"<id> burst" then per line "<bytes>": exactly <bytes> zeros,
|
||||
on the same connection until the client closes
|
||||
"<id> paced <B/s> <secs>" 30 frames/s, each [u32 length][f64 send time][zeros],
|
||||
length counting the whole frame
|
||||
7792/tcp up: client sends "<id>\\n" then data until EOF; gets "<bytes>\\n" back
|
||||
7793/udp echo
|
||||
7794/tcp results: one JSON line per connection, appended to the results file
|
||||
@@ -51,15 +56,37 @@ def readline(conn):
|
||||
|
||||
|
||||
def down(conn, peer):
|
||||
test_id, secs = readline(conn).split()
|
||||
end = time.monotonic() + float(secs)
|
||||
test_id, *args = readline(conn).split()
|
||||
mode = args[0] if args[0] in ("burst", "paced") else "bulk"
|
||||
sent = 0
|
||||
try:
|
||||
while time.monotonic() < end:
|
||||
sent += conn.send(CHUNK)
|
||||
if mode == "burst":
|
||||
# One warm connection, as an utterance would arrive on the open WebSocket.
|
||||
while line := readline(conn):
|
||||
left = int(line)
|
||||
while left > 0:
|
||||
n = conn.send(CHUNK[:min(left, len(CHUNK))])
|
||||
left -= n
|
||||
sent += n
|
||||
elif mode == "paced":
|
||||
rate, secs = float(args[1]), float(args[2])
|
||||
size = max(12, int(rate / 30))
|
||||
t0 = time.monotonic()
|
||||
for i in range(int(secs * 30)):
|
||||
# Pace on the schedule, not on the last send: a stall must not lower the offered rate.
|
||||
delay = t0 + i / 30 - time.monotonic()
|
||||
if delay > 0:
|
||||
time.sleep(delay)
|
||||
conn.sendall(struct.pack("!Id", size, time.time()) + bytes(size - 12))
|
||||
sent += size
|
||||
else:
|
||||
end = time.monotonic() + float(args[0])
|
||||
while time.monotonic() < end:
|
||||
sent += conn.send(CHUNK)
|
||||
except OSError as e:
|
||||
log({"id": test_id, "kind": "tcp_down_orin", "error": str(e)})
|
||||
log({"id": test_id, "kind": "tcp_down_orin", "peer": peer, "bytes": sent, **tcp_info(conn)})
|
||||
log({"id": test_id, "kind": "tcp_down_orin", "mode": mode, "error": str(e)})
|
||||
log({"id": test_id, "kind": "tcp_down_orin", "mode": mode, "args": args, "peer": peer, "bytes": sent,
|
||||
**tcp_info(conn)})
|
||||
|
||||
|
||||
def up(conn, peer):
|
||||
|
||||
@@ -25,7 +25,21 @@ for run_id, recs in runs.items():
|
||||
elif k in ("tcp_down", "tcp_up"):
|
||||
print(f" {k:8} {r['mb_s']:>6} MB/s over {r['secs']} s")
|
||||
elif k in ("tcp_down_orin", "tcp_up_orin"):
|
||||
print(f" {k:13} retrans {r.get('retrans')} rtt {r.get('rtt_ms')} ms rto {r.get('rto_ms')} ms {r.get('error', '')}")
|
||||
mode = r.get("mode", "")
|
||||
print(f" {k:13} {mode:6} retrans {r.get('retrans')} rtt {r.get('rtt_ms')} ms rto {r.get('rto_ms')} ms {r.get('error', '')}")
|
||||
elif k == "dl_bulk":
|
||||
print(f" bulk #{r['n']} {r['mb_s']:>5} MB/s over {r['secs']} s 250 ms windows: min {r['win_min_mb_s']} "
|
||||
f"p10 {r['win_p10_mb_s']} p50 {r['win_p50_mb_s']} max {r['win_max_mb_s']} zero {r['zero_windows']} "
|
||||
f"longest stall {r['max_gap_ms']} ms")
|
||||
elif k == "dl_bursts":
|
||||
print(f" bursts after {r.get('idle_ms', 1000)} ms idle, keepalive {r.get('keepalive_pps', 0)}/s:")
|
||||
for e in r["sizes"]:
|
||||
print(f" burst {e['bytes'] // 1024:>5} KB p50 {e['p50_ms']:>7} ms max {e['max_ms']:>7} ms "
|
||||
f"({e['mb_s_p50']} MB/s at p50) all {e['ms']}")
|
||||
elif k == "dl_paced":
|
||||
print(f" paced {r['rate'] / 1e6:>3} MB/s got {r['mb_s']:>5} MB/s frames {r['frames']}/{r['expected']} "
|
||||
f"queueing p50 {r['q_p50_ms']} p99 {r['q_p99_ms']} max {r['q_max_ms']} ms "
|
||||
f">100 ms {r['late_100']} >500 ms {r['late_500']}")
|
||||
elif k == "error":
|
||||
print(f" ERROR {r['error']}")
|
||||
elif k == "end":
|
||||
|
||||
Reference in New Issue
Block a user