analyse-pcap: count UDP, because ROM streaming is UDP/FSP not TCP
The 850 KB/s dump measurement does not bound ROM streaming, and the tool could not have measured streaming at all: it only counted TCP payload, so a streaming capture would have reported ~zero throughput. Swiss's ROM streaming runs in the game via the patch driver's own stack (cube/patches/bba/tcpip.c), which contains no TCP whatsoever -- UDP + FSP, plus ICMP and ARP. Reads are sized to the path MTU rather than 1024: _fsp.data_length = MIN(length, env->pmtu - (fsp->data - eth->data)); so ~1446 B of payload per datagram at a 1500 MTU, with QUEUE_SIZE 2 outstanding and udp->checksum = 0x0000 (no payload checksum). None of the menu path's TCP window, lwIP overhead or 1024-byte writes apply. The analyser now counts UDP payload and picks the bulk direction by which way the payload actually flows -- streaming is PC -> GC, the opposite of a disc dump -- with --bulk to_gc to steer the gap analysis. Self-test H replays the streaming shape (1446 B datagrams, 2 per request) and checks the bulk direction is identified and the payload counted. Recorded in the TODO that "can it stream?" is still OPEN, but open on the GC's side: the dump established the adapter has headroom (zero retransmissions, ~17% W5100 bus utilisation, 26% of the EXI ceiling). The hard ceiling is 3375 KB/s and the GC's disc delivers ~2000-3100 KB/s, so full disc rate has no margin -- but games read in bursts, not continuously at peak. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -158,6 +158,39 @@ else:
|
||||
print("G 1024B segments + 2920B window -> window x RTT bound,")
|
||||
print(" full-MSS suggested, coalescing warned against")
|
||||
|
||||
def udp_frame(src, dst, smac, dmac, payload):
|
||||
udp = struct.pack("!HHHH", 7717, 7717, 8 + len(payload), 0) + payload
|
||||
ip = struct.pack("!BBHHHBBH4s4s", 0x45, 0, 20 + len(udp), 0, 0, 64,
|
||||
socket.IPPROTO_UDP, 0, src, dst)
|
||||
return dmac + smac + b"\x08\x00" + ip + udp
|
||||
|
||||
|
||||
# Scenario H: ROM streaming shape -- UDP/FSP, bulk flowing PC -> GC, with
|
||||
# small requests going the other way. Before UDP was counted this reported
|
||||
# zero throughput, because Swiss's in-game stack has no TCP at all.
|
||||
pkts, t = [], 7000.0
|
||||
for i in range(300):
|
||||
pkts.append((t, udp_frame(GC, PC, MAC_GC, MAC_PC, b"\0" * 20))) # request
|
||||
t += 0.0001
|
||||
for _ in range(2): # 2 queued
|
||||
pkts.append((t, udp_frame(PC, GC, MAC_PC, MAC_GC, b"\0" * 1446)))
|
||||
t += 0.0002
|
||||
t += 0.0008
|
||||
pH = os.path.join(tmp, "h.pcap")
|
||||
write_pcap(pH, pkts)
|
||||
out = run(pH, "--bulk", "to_gc")
|
||||
if "bulk direction: PC -> GC" not in out:
|
||||
fails.append(f"H: bulk direction not detected as PC->GC\n{out}")
|
||||
elif "UDP" not in out:
|
||||
fails.append(f"H: UDP frames not counted\n{out}")
|
||||
else:
|
||||
# 600 x 1446 B over ~0.39 s should be well above 1 MB/s
|
||||
kbs = float(out.split("throughput")[2].split("KB/s")[0].strip())
|
||||
if kbs < 500:
|
||||
fails.append(f"H: UDP payload undercounted, {kbs} KB/s")
|
||||
else:
|
||||
print(f"H UDP/FSP streaming shape -> bulk PC->GC, {kbs:.0f} KB/s")
|
||||
|
||||
print("\nFAILURES:\n " + "\n ".join(fails) if fails else
|
||||
"\nAll analyse-pcap self-tests passed.")
|
||||
sys.exit(1 if fails else 0)
|
||||
|
||||
Reference in New Issue
Block a user