Repository navigation
quest: delete adapter-waker-alloc, measured no-win - #7556
Conversation
Quest-Claim: c550a108b994eb7e
moq-tokio and moq-uring hand a stream read or write the task's own waker (`waiter.context()`) and never register the waiter on a kio list, so a parking read allocates no shared waker. Pinned instruction and allocation counts across #7042 show no per-read cost; the quest's Plan deletes it on a measured no-win. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Warning Review limit reachedYou'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 5 minutes. View limit details
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. |
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed fc8f352.
No actionable bugs found. Deleting this quest and its index entry is a reasonable simplification: the inspected adapter reads forward the task's context without registering that waiter, and shared-waker allocation is lazy. There is no production API or wire change.
Verification limits: static inspection only. The scratch measurement harness and raw captures are not committed, so I did not independently reproduce the allocation/instruction results, run tests, or validate the reported checks. The separate session-driver and FETCH-close-watch costs remain distinct follow-up work.
(Written by OpenAI)
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
Docs-only deletion of a completed quest; no behavioral surface.
- Quest file removed —
quest/m2/perf/adapter-waker-alloc.md(36 lines) deleted. - Epic link removed — the matching bullet dropped from
quest/m2/perf/README.md.
The PR body's measurement supports the quest's own Plan ("a measured no-win deletes this quest"): moq-tokio and moq-uring both pass the task's own waker (waiter.context()) into a read or write and never register the kio::Waiter on a kio list, so a parking read never hits Waiter::shared's Arc<Waker> allocation. No dangling reference to adapter-waker-alloc (or the quest title) remains anywhere in the tree, and the README bullet list is still well-formed.
deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏

Summary
Deletes
quest/m2/perf/adapter-waker-alloc.mdand its link in the perf epic. The quest's Plan says a measured no-win deletes it, and the measurement is a no-win.Verdict: a parking stream read in moq-tokio or moq-uring allocates no shared waker, before or after moq-dev/moq#7042.
Why: both adapters pass a read or write the task's own waker (
waiter.context()) and never register thekio::Waiteron a kio list:rs/moq-uring/src/transport/adapter.rs(poll_write,poll_write_buf,poll_read_chunk) andrs/moq-uring/src/transport.rs(poll_lease).rs/moq-tokio/src/transport/owned.rs(poll_write,poll_write_buf,poll_read_chunk,poll_lease).Waiter::sharedallocates itsArc<Waker>only on the firstWaiterList::register, so akio::waitfuture around such a read only constructs the waiter: a waker refcount bump, no heap. The uring QUIC driver underneath still keeps a per-streamkio::Park(rs/moq-uring/src/quic/driver/recv.rs,parked), and it is reused because the waker stays the same. The coding-layer async wrappers are not on the moq-lite data path either. Marking them#[deprecated]and runningcargo checkon moq-net, moq-tokio, moq-uring, and moq-relay finds production callers only in the handshakes and in IETF control, fetch/fill, and GOAWAY streams.Measurements
The harness is a scratch
moq-uringexample that was not committed. It sets up a full session pair over loopback QUIC onmoq_uring::Worker(like thesession_litebench) or on moq-tokiolisten/connecton a current-thread runtime, both moq-lite. After a warmup, each iteration writes one group, then receives and reads it. The process is pinned to P-core 2 (Core Ultra 7 270K Plus) withtaskset -c 2.perf stat -e cpu_core/instructions/u --control fifocounts only the measured loop, and a counting global allocator counts allocations across all threads. Each tree was exported withgit archiveand built--release(fat LTO):pre=6eff65506e^(before #7042),post=6eff65506e(#7042),main=0e9e828265. Three alternating rounds agreed to within 0.1% on the small groups and 1% on the 1 MiB groups. Shared-waker counts come from a separately instrumented build that countsWaiter::newand theWaiter::sharedinitializer.Per group:
Arc<Waker>Waiter::sharedinitializer):Waiter::noop()inresume::Reader::learn_end(None)(rs/moq-net/src/model/resume.rs), reached frompoll_lowest,let_go, andpoll_dropon every subscriber read. moq-dev/moq#7504 (draft) makes a no-op waiter register nothing, which removes these.kio::waitperHandle::run/time::run) is rebuilt byPark::hold. The new waiter's first registration lands on the session-closeBridge(moq-uring adapter.rspoll_closed,moq-tokio owned.rspoll_closed). This matches a waiter that is notreusable(), because the driver parks on more thanPARKED = 8lists.SendStream::poll_closedthrough itsBridgeinto the QUIC driver'spark_finishing. That is per stream, not per read.park_readable, the only read-path registration.Decisions needed
None. The Plan settles the outcome ("A measured no-win deletes this quest").
Choices made without asking
session_litewall clock, so the counts are deterministic. moq-tokio has no session bench, and the relay'sbenches/session.rsruns on the in-memory transport, so it cannot reach the adapters.just bench BASEis wall-clock end to end, so I didn't use it.rs/moq-net/src/ietf/publisher.rsbuildspin!(stream.closed())inside the fetch chunk loop. Each chunk gets a freshkio::waitwhose waiter registers on the send stream's closeBridge. That is a cold path and a writer's close watch, not a parking read, so I left it as a follow-up below.Follow-ups (for
/quest-mergeto decide)Park::holdretires a waiter parked on more than 8 lists on every poll (about 4Arc<Waker>per group on the session driver here). A relay session driver parks on many more lists, so it may churn harder there. This is worth measuring on a relay, and possibly raisingPARKEDor changing the retire rule.rs/moq-net/src/ietf/publisher.rs, thestream.closed()pinned inside the chunk loop).learn_endno-op waiter).Checks
quest check --base origin/main: 620 documents ok. No code changes.Review
Round 1:
quest reviewwith Codex, gpt-6.1-sol, medium effort, on headfc8f35248ee4b953a1c088f32e9dfd721fbe38f3againstorigin/main0e9e828265. It reported no findings.🤖 Generated with Claude Code
(Written by Claude Opus 5.5)