perf(cyper-axum): avoid buffered TCP compatibility I/O - #70
Open
Xerxes-2 wants to merge 1 commit into
Open
Conversation
Xerxes-2
force-pushed
the
perf/websocket-io
branch
11 times, most recently
from
August 4, 2026 13:44
c464e9c to
65c61dd
Compare
Berrysoft
reviewed
Aug 4, 2026
Xerxes-2
force-pushed
the
perf/websocket-io
branch
from
August 4, 2026 14:21
65c61dd to
d5fecd6
Compare
Member
|
Oh, please... don't write response with LLM. |
Contributor
Author
|
My bad, Claude Opus is so eager to do this, deleted |
Berrysoft
requested changes
Aug 4, 2026
Berrysoft
left a comment
Member
There was a problem hiding this comment.
Please make all targets use the PollFd, not only Linux and Android.
Xerxes-2
force-pushed
the
perf/websocket-io
branch
from
August 4, 2026 14:30
d5fecd6 to
e612114
Compare
Contributor
Author
|
Done, feature gate is removed for using |
Reuse the accepted socket's descriptor through `PollFd` so hyper writes to it directly instead of going through Compio's futures adapter and its intermediate buffer, keeping vectored writes and TCP half-close. Unix only: on Windows `PollFd` funnels every readiness kind through a single `WSAEventSelect` registration, which does not survive hyper reading and writing one socket concurrently.
Xerxes-2
force-pushed
the
perf/websocket-io
branch
from
August 4, 2026 15:06
e612114 to
caa3348
Compare
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.
Uses readiness-based TCP I/O on every platform, where hyper writes to the socket directly instead of going through Compio's futures adapter and its intermediate buffer. Accepted sockets reuse their shared descriptor via
to_poll_fd(); if that fails the buffered path is kept.Relies on the vectored-write and half-close impls for
PollFdfrom compio#993, released incompio-runtime0.12.4. Cargo resolves that by default, but thecompiofacade still declarescompio-runtime = "0.12.3", so the requirement cannot be expressed transitively — see the note below.Closes #53.
Latency
Measured on Linux. Single connection, tokio-tungstenite client, 40 000 round trips per series (6 000 at 1 MiB).
masteraxummasteraxummasteraxumEvery percentile improves on
master, including max. At 1 MiB the whole distribution moves left and stays ahead of Axum out to the tail. At 64 B the median is now level with Axum; at 16 KiB a gap remains, and in both cases it is concentrated in the tail rather than the median — the same upward bend shows up at every payload size, which looks more like an occasional extra wakeup than per-byte cost. Worth a follow-up.Concurrency
A separate measurement, so small differences from the table above are run-to-run variance.
masterp50masterMiB/sMedians of 4 alternating runs per build. The buffered path degrades sharply past 256 connections at 16 KiB while this branch stays flat — at 16 KiB × 1024
mastermeasures 20.2–21.5 ms against 374–398 µs here, consistent across every run on both sides. Note this compares two implementations, not two I/O models:masterchunks every message through an 8 KiB buffer, and raising that buffer alone recovers much of the difference.Only the 64-connection rows are safe to read as an axum comparison. Axum reproduces to within 1.00–1.02× there, but swings several-fold at 256, so its 1.09 ms is not meaningful. Two separate reasons:
ws_latencysplits a fixed round-trip budget across connections, leaving too few samples per connection to support a tail percentile at these depths (8 at 16 KiB × 1024, addressed in #71); and axum keeps swinging at 256 even with 500 samples each, which looks like real behaviour rather than a measurement artefact. Themaster-versus-branch gap is unaffected either way, since both sides see identical sampling. Thecompioclient saturates around 1024 connections — 17–27 ms for both servers — so those rows say nothing about the server and are omitted.HTTP
Vectored writes let hyper keep its
Queuestrategy instead of flattening the body into its own buffer, so plain HTTP benefits too: a 1 MiB keep-alive response body goes from 73.8 µs to 58.4 µs (median of 3 runs).Benchmark environment
performancegovernortaskset -c 0-7). A mask spanning both CCDs makes round trips bimodal — at 16 KiB, ~9.6 µs when co-resident against ~20.7 µs across the fabric — which flips run-level p50. This affectsmasterand this branch alike.ws_latencybenchmark in bench(cyper-axum): add websocket latency benchmark #69, withCELLSextended to 256 and 1024 connections; the single-connection distributions come from a standalone dumper so every round trip is recorded individually.