From 1ac8e832f49827805d15444439986a7cce6b7bb5 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Mon, 21 Sep 2026 19:24:33 -0700 Subject: [PATCH] quest: plan GPU pool reservations and the io_uring handshake flush Two follow-ups from today's media and uring landings: the bounded GPU frame pool reports exhaustion as Error::Unsupported prose (#3869), and an io_uring dial can resolve before its last handshake flight is sent (#3865). Co-Authored-By: Claude Opus 5 --- quest/next/README.md | 2 ++ quest/next/gpu-pool-reservation.md | 34 ++++++++++++++++++++++++++++ quest/next/uring-handshake-flush.md | 35 +++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+) create mode 100644 quest/next/gpu-pool-reservation.md create mode 100644 quest/next/uring-handshake-flush.md diff --git a/quest/next/README.md b/quest/next/README.md index 85311c08af..fd2ba826d5 100644 --- a/quest/next/README.md +++ b/quest/next/README.md @@ -39,6 +39,7 @@ transport, benchmark tooling); worktrees isolate commits, not semantics. - [Broadcast route](/quest/next/js-broadcast-route.md) - JS Announce.Broadcast goes live on any claim matching its path, like Rust routed() - [io_uring check](/quest/next/check-uring-feature.md) - a moq-relay diff compiles the io-uring feature in `just check`, not only nightly - [io_uring handshake cancellation](/quest/next/uring-handshake-cancel.md) - dropping a pending handshake releases its connection while the worker keeps running +- [io_uring handshake flush](/quest/next/uring-handshake-flush.md) - a dial resolves only once its last handshake flight is on the wire, never stranding the peer - [Flaky timing tests](/quest/next/flaky-timing-tests.md) - three real-clock tests become deterministic instead of failing under load - [Binding stats docs](/quest/next/binding-stats-docs.md) - every binding's doc page lists its connection stats fields with units @@ -71,6 +72,7 @@ transport, benchmark tooling); worktrees isolate commits, not semantics. - [Opus descriptions](/quest/next/audio-opus-input.md) - validate headers and honor codec clock, pre-skip, and gain - [Capture formats](/quest/next/audio-capture-format.md) - unsupported overrides refuse before device open and channel counts cannot wrap - [NVENC recovery](/quest/next/nvenc-recovery.md) - partial initialization and rejected rate changes preserve valid state +- [GPU pool reservation](/quest/next/gpu-pool-reservation.md) - a full GPU frame pool is a `None` reservation the caller drops on, not an error to match - [Transcode source](/quest/next/transcode-source.md) - select a rendition the chosen backend can actually decode - [Keyframe trigger](/quest/next/keyframe-trigger.md) - an application can ask the built-in capture encoder for a keyframe - [QoS](/quest/next/qos/README.md) - broadcast health: relay starvation and timeliness histograms, and client stats broadcasts from publishers and viewers diff --git a/quest/next/gpu-pool-reservation.md b/quest/next/gpu-pool-reservation.md new file mode 100644 index 0000000000..95a2fc9b9a --- /dev/null +++ b/quest/next/gpu-pool-reservation.md @@ -0,0 +1,34 @@ +# [S] GPU frame pool back-pressure is a reservation, not an error + +## Goal + +A caller feeding imported Vulkan frames through `moq_video::frame::cuda::Converter` +can drop a frame when the bounded GPU pool is full without matching an error. +Exhaustion is expected back-pressure; only real failures are errors. + +## Plan + +`Converter::convert` and `cuda::Frame::resize` take a pooled buffer and report +a full pool as `Error::Unsupported` with a prose message (#3869), so the CARLA +bridge in moq.pro can only drop-and-continue by matching the text. + +Split the reservation from the work, the way the bandwidth allocator hands out +a `Reservation`: `Converter::reserve() -> Option` returns `None` when +every buffer is live, and `Slot::convert(&vulkan::Frame) -> Result` +does the GPU work on the held buffer, failing only for a genuine error. The +slot returns its buffer to the pool on drop, converted or not. Apply the same +shape to the resize pool. Keep the pool itself crate-private and its capacity +bound unchanged. + +Tests on the injected allocator: `reserve` yields exactly `capacity` slots and +then `None`, dropping an unconverted slot frees it, and a failed conversion +does not leak the buffer. Update the `just rs vulkan-cuda` hardware test and +`doc/lib/rs/moq-video.md` inline. + +Public API: `moq-video` 0.0.x, breaking for `Converter::convert` callers. Wire: +none. + +## Related + +- [GPU conversion and NVENC](/quest/main/video-gpu-encode.md) - the converter and pool this reshapes +- [Bandwidth allocator](/quest/next/2848-follow-the-bandwidth-grant-in-moq-audio-instead-of.md) - the reservation-handle precedent diff --git a/quest/next/uring-handshake-flush.md b/quest/next/uring-handshake-flush.md new file mode 100644 index 0000000000..670c45f75c --- /dev/null +++ b/quest/next/uring-handshake-flush.md @@ -0,0 +1,35 @@ +# [M] An io_uring dial resolves once its last handshake flight is sent + +## Goal + +`moq_uring::quic::client::connect` hands back a connection only after the +handshake's final flight has been written to the socket, so a worker that +stops right after the dial resolves cannot strand a peer that is still waiting +for it. A worker that stops before that point fails the dial loudly. No new +public API or wire format. + +## Plan + +Today the dial resolves when the handshake completes locally, while the +client's last flight is still queued behind pacing on the worker (#3865). If +the worker stops in that window nothing is sent, the server times the +connection out, and the client holds a connection that looks established. The +behaviour is documented but easy to hit from a short-lived task. + +Reproduce it first on Linux CI: dial, stop the worker immediately, and show +the server never accepts. Then keep the dial future pending until the driver +reports the handshake flight flushed, and return `quic::Error` when the worker +stops before then. The flush belongs in moq-uring's connect and establish +path; moq-tokio is unaffected. Do not add a timeout or a retry, and do not +drain sends from worker shutdown. + +Linux CI covers the stopped-worker dial (now refused or fully sent, never +stranded), a normal dial still resolving promptly, and a paced flight on a +slow link. Update the moq-uring docs where the window was described. + +Public API: none. Wire: none. + +## Related + +- [io_uring handshake cancellation](/quest/next/uring-handshake-cancel.md) - the same establish path, for a dropped dial +- [uring identity](https://github.com/moq-dev/moq/pull/3865) - where the window was found