fsp-server: stop clamping GET_FILE replies to 1024, which capped streaming
Streaming measured 509 KB/s, BELOW the menu's 850 KB/s TCP dump, and the
arithmetic says exactly why.
I had this wrong: QUEUE_SIZE 2 is the number of queued GAME reads, not
concurrent network requests. fsp_read_queued() sends ONE fsp_get_file and
arms a 1 s alarm; fsp_pop_queue() issues the next only once the response
arrives. Streaming is therefore STRICTLY ONE REQUEST IN FLIGHT, so
throughput = bytes_per_reply / round_trip
The server clamped replies to FSP_SPACE (1024), giving 1024 B / ~2.01 ms =
509 KB/s -- the measured figure almost exactly. But the in-game client asks
for pmtu - 40 (1460 at a 1500 MTU) and accepts it; only fsplib has the 1024
limit, and fsplib never asks for more than that. So honouring the requested
size is safe for both clients, and at 1440 B (the 1500 MTU budget rounded
down to 32) the same round trip gives ~1.41x, about 700 KB/s.
Replies stay a multiple of 32 unless they are the file tail, because the
client computes data_size = MIN(requested, OSRoundDown32B(reply_len)) and a
non-aligned mid-file reply would be silently truncated.
Also instruments the round trip: with one request in flight the observed
interval IS the RTT, so the report now splits it into total and this server's
median service time and says SERVER-bound or console-bound. Without that,
"it is slow" has no owner. And the raw socket now binds ETH_P_IP rather than
ETH_P_ALL, so our own outgoing frames are no longer copied to userspace and
parsed in Python on the path we are trying to shorten.
T13 checks a 1460-byte request yields 1440 (32-aligned) while an fsplib-sized
1024 request still yields exactly 1024.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -182,6 +182,27 @@ try:
|
||||
else:
|
||||
print("T10 GET_PRO 'swiss/patches' -> CC_ERR (Swiss falls back to root)")
|
||||
|
||||
# T13 reply size must follow the REQUEST, not FSP_SPACE. Clamping to
|
||||
# 1024 is what held streaming to 509 KB/s: one request in flight means
|
||||
# throughput is payload / RTT.
|
||||
r = rt(req(CC_GET_FILE, 60, 0, "/dvd.iso", extra=struct.pack("!H", 1460)))
|
||||
if len(r["data"]) != 1440:
|
||||
fails.append(f"T13 asked 1460 -> got {len(r['data'])} B, want 1440 "
|
||||
f"(1500 MTU budget, rounded down to 32)")
|
||||
elif len(r["data"]) % 32:
|
||||
fails.append(f"T13 reply {len(r['data'])} B not 32-aligned")
|
||||
else:
|
||||
print(f"T13 request 1460 -> 1440 B reply (32-aligned, 1.41x of 1024)")
|
||||
|
||||
# ...and a 1024-byte request (what fsplib asks) still gets exactly 1024,
|
||||
# so the menu client is unaffected by the larger cap.
|
||||
r = rt(req(CC_GET_FILE, 61, 0, "/dvd.iso", extra=struct.pack("!H", 1024)))
|
||||
if len(r["data"]) != 1024:
|
||||
fails.append(f"T13 fsplib-sized request got {len(r['data'])} B, "
|
||||
f"want 1024 - must not exceed what was asked")
|
||||
else:
|
||||
print("T13 request 1024 -> 1024 B (fsplib unaffected)")
|
||||
|
||||
# T11 the write path Swiss needs for patches: MAKE_DIR, then UP_LOAD
|
||||
# (which carries NO filename -- data is raw bytes at pos), then INSTALL
|
||||
# to name the destination. Without this Swiss reports "failed to write
|
||||
|
||||
Reference in New Issue
Block a user