rust/wasmtime: set TCP_NODELAY on the connected socket - #45
Merged
Conversation
Latency-sensitive guests (QUIC over the message stream, per component-iroh) write small messages back-to-back; Nagle holds the second write until the peer's delayed ACK arrives, a ~40 ms stall per occurrence on Linux loopback. Browsers run WebSocket sockets with TCP_NODELAY, so the wasmtime host was the deficient implementation on the portability ladder (enhance, never accumulate divergence). Found driving component-iroh's endpoint to event-driven wakeups (polymorph-components/polymorph-iroh#42): with flushes no longer batched by a 10 ms clock tick, back-to-back small sends surfaced the stall — relay-wire echo roundtrips sat at 27-50 ms and drop to 0-7 ms with this change. Verified: just check; just conformance-ct (4 targets, 220 results, 0 failing).
lann
added a commit
to polymorph-components/polymorph-iroh
that referenced
this pull request
Aug 11, 2026
With host-jco retired (#40), the portable workaround for its scheduler defect - bounded clock polling (5 ms method quantum / 10 ms pump tick) - protected nothing and cost ~5x handshake latency on every host. Wake-ups are now event-driven in both directions, riding wit-bindgen's inter-task-wakeup channel (both hosts deliver it): resource methods kick the pump to flush their mutations (first flight, stream writes, FIN/RESET/STOP_SENDING, datagrams, signals, closes, flow-control credit) and park on wakers in State::waiters; the pump wakes the waiters after every drain that progressed, on signal-inbox pushes, and unconditionally on its 10 ms tick, which stays for noq's timers and now also bounds deadline re-checks and any missed wake edge. The never-cancel-an-import teardown discipline is unchanged; the kick future is guest-local. Going event-driven exposed a latent Nagle stall in the websocket sibling's wasmtime host: back-to-back small sends (STREAM then FIN, no longer batched by the tick) sat out the peer's delayed ACK, putting relay-wire echo roundtrips at 27-50 ms. Fixed upstream (polymorph-components/polymorph-websocket#45, TCP_NODELAY); the websocket pin bumps to that commit here. The two changes are co-dependent: the pump change without the pin bump regresses relay roundtrips 23 -> ~47 ms. Bench on this machine (medians): endpoint handshakes 16/21/14 ms (relay/udp/webrtc) -> 1-4 ms, matching the spike; roundtrips 23/17/23 -> 0 ms; bulk throughput 7.7/49.1/38.1 -> 27.8/85.1/49.1 MB/s (prompt flow-control credit plus nodelay). The budgets tighten accordingly: absolute ceilings 2000 -> 250 ms, and the spike-to-endpoint handshake delta is asserted (<= 10 ms) so the polling tax cannot quietly return. Verified: just check, just probes (5/5), just matrix (12 pairings), just exam-deltic (5/5), just bench (budgets hold, handshake_tax_ms 0). Fixes #42
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Latency-sensitive guests (QUIC over the message stream, per component-iroh) write small messages back-to-back; Nagle holds the second write until the peer's delayed ACK arrives — a ~40 ms stall per occurrence on Linux loopback. Browsers run WebSocket sockets with TCP_NODELAY, so the wasmtime host is the deficient implementation on the portability ladder; this enhances it to match.
Found driving component-iroh's endpoint to event-driven wakeups (polymorph-components/polymorph-iroh#42): with guest flushes no longer batched by a 10 ms clock tick, back-to-back small sends surfaced the stall — relay-wire echo roundtrips sat at 27–50 ms and drop to 0–7 ms with this change (numbers from component-iroh's bench rig; its budget gate re-asserts them once its websocket pin bumps).
The
wss:(Rustls) arm is covered by reaching throughMaybeTlsStream::Rustls; the catch-all arm covers the enum's non-exhaustive future variants by leaving them as-is.Verified:
just check;just conformance-ct— 4 targets, 220 results, 0 failing.