Skip to content

perf(moq-quic): decode a PADDING run as one frame - #7075

Merged
kixelated merged 3 commits into
mainfrom
quest/m0/ci/quic-padding
Oct 29, 2026
Merged

kixelated merged 3 commits into
mainfrom
quest/m0/ci/quic-padding

Conversation

@kixelated

@kixelated kixelated commented Oct 28, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

quest/m0/ci/quic-padding.md, found by moq-dev/moq#6987's profile: moq-quic's frame::Iter yielded one Frame::Padding per PADDING byte. A 1200-byte padded Initial became about a thousand iterator steps, each moving a Frame through Option<Result<..>> and the receive loop. In debug builds those moves dominate packet receive.

Change

  • frame::Iter consumes a whole run of PADDING (consecutive 0x00 bytes) in one step and yields a single Frame::Padding. next_with_size reports the run's full length. The remaining per-byte work is one zero check per byte.
  • QMux draft-00 still allows only one frame per message: the mux counts a decoded PADDING run as one frame per byte, so a message of two PADDING bytes is still a FRAME_ENCODING_ERROR. Without this, the collapse would have silently started accepting it.
  • wire_decode bench: a padded case (below).
  • Tests: an iterator test for runs before, between, and after other frames, and a QMux draft-00 test that one PADDING byte is accepted and two are refused.

Padding stats

No stat counts PADDING. FrameStats::record ignores Frame::Padding (and every receive loop skips it before recording), so there is no field whose meaning could change. UDP byte counts are taken from datagrams, not frames. Nothing to keep or migrate.

Measurement

Debug build of the moq-quic lib tests, tests::characterize (handshake-heavy), single-threaded, frame pointers, perf record:

Total cycles Connection::handle_packet (inclusive) frame::Iter (inclusive) memmove (self)
main 2.47 G 0.95 G (38.4%) ~11.6% 8.0%
this PR 2.29 G 0.64 G (27.8%) ~1.4% 3.5%

Packet receive CPU falls by a third. User CPU of that test group: 0.60 to 0.63 s on main, 0.53 to 0.55 s here (3 runs each). The whole moq-quic lib suite: 10.8 to 11.2 s on main, 10.6 to 10.7 s here, since most of it is not handshakes.

It matters in release too. The wire_decode bench gains a padded case: one small DATAGRAM frame with PADDING filling the rest of a 1360-byte payload, as a padded Initial or MTU probe arrives.

wire_decode/padded main this PR
packets_64 712 µs 24.1 µs
packets_1024 12.70 ms 393 µs

That is about 11 µs of decode per padded packet on main, against about 0.4 µs now. For comparison, frames_1 (one DATAGRAM frame filling the packet) measures 12.7 µs and 212 µs.

Impact

  • Public API: none. Frame and frame::Iter are pub(crate).
  • Wire: none. Every input decodes to the same frames apart from PADDING grouping, and QMux draft-00 keeps refusing multi-frame messages.
  • Stats: unchanged (see above).

Choices made without asking

  • Kept QMux draft-00's one-frame-per-message rule exact for PADDING runs (fail loud on malformed input) instead of letting a multi-byte PADDING message through. It costs one match in the mux receive loop.
  • Extended the existing wire_decode bench with a padded shape rather than adding a new bench target.
  • The run is found with a plain position scan. It still touches every byte (about 0.13 ns a byte in release); a chunked zero check would be faster but is not worth the extra code at these numbers.

Follow-ups

None found.

(Written by Claude Opus 5.5)

🤖 Generated with Claude Code

kixelated and others added 2 commits October 28, 2026 03:04
frame::Iter yielded one Frame::Padding per padding byte, so every padded
packet cost about a thousand iterator steps. Consume the run in one step.
QMux draft-00 still counts each PADDING byte as a frame, so its
one-frame-per-message rule is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated kixelated changed the title moq-quic collapses padding runs perf(moq-quic): decode a PADDING run as one frame Oct 28, 2026
@kixelated
kixelated marked this pull request as ready for review October 28, 2026 16:41
@coderabbitai

coderabbitai Bot commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 23 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 4 included reviews currently available.

Learn how review limits work.

Review configuration:

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: b3cba703-7010-4422-886f-1fb8fcec7d23
Commits

Reviewing files that changed from the base of the PR and between 66bdbb9 and 5fd50de.

Files selected for processing: 6
  • quest/m0/ci/README.md
  • quest/m0/ci/quic-padding.md
  • rs/moq-quic/benches/wire.rs
  • rs/moq-quic/src/connection/mux/mod.rs
  • rs/moq-quic/src/connection/mux/tests.rs
  • rs/moq-quic/src/frame.rs
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review 🔄 Running since 2026-10-29T15:26:46.463637Z 5fd50de New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@kixelated kixelated left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review by review (OpenAI)

Reviewed commit: aeff48a

No actionable bugs found in the changed code and relevant receive paths. Collapsing zero-byte runs is a focused optimization: the iterator preserves consumed-byte accounting, QUIC receive paths already skip padding, and QMux draft-00 still rejects multiple padding frames. The plain scan is simpler than chunked/vectorized parsing and avoids unnecessary complexity. The new iterator and draft-00 regression tests address the main semantic risks; the padded benchmark covers the intended workload.

Verification limits: static GitHub review only; I did not run tests or benchmarks or independently verify the reported performance numbers.

@kixelated

Copy link
Copy Markdown
Collaborator Author

Merge summary for head aeff48a547a6f408c491be1e5b637b07cc0644c0:

  • Reviews: the automated OpenAI review on this head found nothing actionable, and Codex finished with a thumbs up (no findings). CodeRabbit was rate-limited, so its review doesn't count.
  • CI: all 12 checks pass. The merge state is clean, with no conflicts against main.
  • quest check --base origin/main passes. This PR deletes quest/m0/ci/quic-padding.md and its link in quest/m0/ci/README.md.
  • No changes were made during merge and no decisions were left open. Landing through the merge queue (squash).

(Written by Claude Opus 5.5)

@kixelated
kixelated added this pull request to the merge queue Oct 29, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Oct 29, 2026
@kixelated

Copy link
Copy Markdown
Collaborator Author

Re-land summary for head 5fd50dec7fc5d2c3f88e8eb0a8e7037a85f19309:

  • The PR left the merge queue on merge_conflict. I merged main into the branch locally; the only conflict was the quest/m0/ci/README.md link list, which quest's merge driver resolved (no hand edits). The PR still deletes quest/m0/ci/quic-padding.md and its link.
  • cargo test -p moq-quic --all-targets passes locally on the merged tree; all CI checks pass on the new head.
  • The new head is a conflict-free base merge, so the existing review of aeff48a carries over. quest check --base origin/main is clean.

(Written by Claude Opus 5.5)

@kixelated
kixelated added this pull request to the merge queue Oct 29, 2026
Merged via the queue into main with commit 14537ef Oct 29, 2026
11 checks passed
@kixelated
kixelated deleted the quest/m0/ci/quic-padding branch October 29, 2026 17:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant