4f52027ccb
Diagnosis (qlog): 1361 GETs in 58s = 23/sec, but only 2618 packets sent in that window — 0.5 GETs per packet. We were sending nearly empty packets one at a time, not coalescing requests. Root cause: stream.send.enqueue + stream.send.finish() don't wake the send loop. The send loop suspends on sendWakeup until either an inbound packet arrives or the PTO timer fires (~1s). For our chunked parallel multiplexing path: 1. enqueue 64 GETs into 64 streams 2. send loop is asleep (last drain happened on previous chunk) 3. wait ~1s for PTO before any of them go on the wire 4. server processes, replies, our read loop wakes the send loop 5. send loop drains ACKs (no new requests yet) Each chunk wasted ~1s of PTO wait. With ~21 chunks at 1s each plus RTTs and server processing, throughput floored at ~23 streams/sec. Fix: pass QuicConnectionDriver to Http3GetClient + HqInteropGetClient constructors. After stream.send.finish(), call driver.wakeup() to nudge the send loop. The first request of each chunk now leaves within microseconds instead of waiting for PTO. Predicted throughput: 600+ streams/sec (RTT-bound at 30ms per chunk of 64 = 2100/sec ceiling; CPU and lock contention drop it to ~600). 1999 streams in 3-5s instead of timing out at 60s. The architectural fix would be having stream.send.enqueue auto-wake via a callback set during stream creation. That's the cleaner shape; this commit takes the minimal path: explicit driver-passed wakeup from interop client code where the throughput matters. https://claude.ai/code/session_01HcvfQq1ttPV9PkRoJb4nyT