Skip to content

perf(h3-quinn): hand DATA payloads to quinn without copying - #368

Open
jothomas-xai wants to merge 1 commit into
hyperium:masterfrom
jothomas-xai:h3-quinn-write-chunks
Open

jothomas-xai wants to merge 1 commit into
hyperium:masterfrom
jothomas-xai:h3-quinn-write-chunks

Conversation

@jothomas-xai

Copy link
Copy Markdown

What happens

h3-quinn's SendStream::poll_ready writes each chunk of a WriteBuf with quinn::SendStream::poll_write(cx, data.chunk()). quinn turns that &[u8] into an owned buffer in ByteSlice::pop_chunk (self.data[..limit].to_owned()), so every byte of every DATA frame is copied once into quinn's send buffer before it is copied again into a packet. #279 removed the copy on the h3-quinn side; this one is the copy inside quinn.

quinn already has a path that keeps the caller's buffers: SendStream::write_chunks(&mut [Bytes]).

Change

  • h3-quinn: poll_ready takes each chunk out of the WriteBuf with copy_to_bytes and passes it to write_chunks. write_chunks is documented as cancellation safe ("If this does not resolve, no bytes were written"), so creating and polling a fresh future on each poll_ready is the same pattern quinn's own poll_write uses. A partially written chunk stays in writing (now Option<(WriteBuf<B>, Bytes)>) until quinn accepts the rest. No quinn changes.
  • h3: WriteBuf overrides Buf::copy_to_bytes to delegate to the frame payload once the header is consumed. For a Bytes payload that is a split_to, so the payload reaches quinn without a copy. The frame header (a few bytes) is still copied, and a non-Bytes payload is copied once by its own copy_to_bytes, here instead of inside quinn.

poll_send (SendStreamUnframed) is unchanged.

Testing

  • New unit test write_buf_copy_to_bytes_shares_payload_after_header: copy_to_bytes across the header/payload boundary copies, and after the header it returns a slice that shares the payload's allocation.
  • finish_after_cancelled_send_data_keeps_connection_open sends a 4 MiB body that exceeds the stream window, so it exercises partial writes and Pending through the new path.
  • cargo test --features 'tracing,i-implement-a-third-party-backend-and-opt-into-breaking-changes', cargo fmt --all -- --check, cargo clippy, ci/example_test.sh, and cargo +1.74.1 check --locked -p h3-quinn / -p h3 (lockfile from CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS=fallback) all pass locally.

`SendStream::poll_ready` wrote each chunk with `quinn::SendStream::poll_write(&[u8])`,
which copies the slice into an owned buffer inside quinn-proto (`ByteSlice::pop_chunk`).
Every byte of every DATA frame was copied once before packetization.

Take each chunk out of the `WriteBuf` with `copy_to_bytes` and pass it to
`quinn::SendStream::write_chunks`, which keeps the `Bytes` as is. `write_chunks` is
cancellation safe, so polling a fresh future each time matches what quinn's own
`poll_write` does. A partially written chunk stays in `writing` until quinn accepts the rest.

`WriteBuf::copy_to_bytes` now delegates to the frame payload once the header is consumed,
so a `Bytes` payload is split without copying. The header is still copied (a few bytes),
and a non-`Bytes` payload is copied once, here instead of inside quinn.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant