From 6ee12595d339eeafc7fdc7dbb9ba4c4c757f3565 Mon Sep 17 00:00:00 2001 From: Luke Hoersten Date: Wed, 15 Jul 2026 18:04:31 -0500 Subject: stream: instrument TCP-window decomposition (wire kbps, hdr_gap, pend_age) Before touching CONFIG_LWIP_TCP_WND_DEFAULT, make the window question decidable from the logs. New per-window metrics in the stream log, /state, and stats struct: - wire min/avg/max kbps: instantaneous throughput while each body drained (jpeg_len/recv_us). Ceiling ~= TCP_WND/RTT, so it scales with the window iff the window is the limiter. - hdr_gap min/avg/max us: time blocked waiting for the next header after finishing a body. Large = sender-paced; ~0 = receive path is the bottleneck. - pend_age min/avg/max us: publish->claim latency of painted frames. Growing across windows = queue backlog building, the failure mode that killed the previous WND=65535 attempt. Together with recv/dec/paint the frame interval is now fully decomposable: interval ~= hdr_gap + recv + pend_age + dec + paint. Also stamp TCP_WND/TCP_MSS/RECVMBOX into the client-connect log line so every capture is self-labeled with the config it ran under. --- main/stream_server.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'main/stream_server.h') diff --git a/main/stream_server.h b/main/stream_server.h index e2eba06..2562738 100644 --- a/main/stream_server.h +++ b/main/stream_server.h @@ -73,6 +73,22 @@ typedef struct { uint32_t last_paint_event_us_low; // last v1 frame's event_us_low, // 0 if none seen yet on this // boot or last frame was v0 + // TCP-window decomposition. Together with recv/dec/paint these account + // for the whole frame interval: + // interval ≈ hdr_gap (sender idle) + recv (wire) + pend_age (handoff + // queue wait) + dec + paint. + // wire = instantaneous throughput while the body drained (jpeg_len / + // recv_us). Ceiling ≈ TCP_WND / RTT — the definitive window-throttle + // metric: scales with CONFIG_LWIP_TCP_WND iff the window is the limiter. + uint32_t wire_min_kbps, wire_avg_kbps, wire_max_kbps; + // Blocked-with-nothing-to-read time between previous body completion + // and next header completion. Large → sender-paced (we are NOT the + // bottleneck); ~0 → back-to-back arrivals, receive path is the limiter. + uint32_t hdr_gap_min_us, hdr_gap_avg_us, hdr_gap_max_us; + // publish → decode-claim latency of painted frames. Healthy: bounded + // well under a frame interval. Growing window-over-window = latency + // backlog building (the failure mode that killed the last WND raise). + uint32_t pend_age_min_us, pend_age_avg_us, pend_age_max_us; } stream_server_stats_t; void stream_server_snapshot_stats(stream_server_stats_t *out); -- cgit v1.2.3