From a73f1a7aececed436076c21e208f6100908dc8dc Mon Sep 17 00:00:00 2001 From: agnosticdev Date: Wed, 15 Jul 2026 11:22:54 -0700 Subject: [PATCH 1/3] SwiftQUIC: Reduce CPU overhead in getting inbound stream data delivered to the stream --- Sources/SwiftNetwork/Protocols/ManyToManyProtocol.swift | 9 +++++++++ Sources/SwiftNetwork/QUIC/QUICConnection.swift | 6 ++---- Sources/SwiftNetwork/QUIC/QUICStream.swift | 2 +- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/Sources/SwiftNetwork/Protocols/ManyToManyProtocol.swift b/Sources/SwiftNetwork/Protocols/ManyToManyProtocol.swift index 1c213b6..e75f044 100644 --- a/Sources/SwiftNetwork/Protocols/ManyToManyProtocol.swift +++ b/Sources/SwiftNetwork/Protocols/ManyToManyProtocol.swift @@ -1388,6 +1388,15 @@ extension ManyToManyApplicationStreamProtocol where Flow: AutomaticUpperStreamPr guard let flow = self.flow(for: flowID) else { throw NetworkError.posix(EINVAL) } flow.serviceUpperReceiveQueue() } + // Enqueue and delivery the stream data all in one shot + public func deliverInboundStreamData( + flow flowID: MultiplexedFlowIdentifier, + streamData: consuming FrameArray + ) throws(NetworkError) { + guard var flow = self.flow(for: flowID) else { throw NetworkError.posix(EINVAL) } + try flow.addToUpperReceiveQueue(streamData) + flow.serviceUpperReceiveQueue() + } } @_spi(ProtocolProvider) diff --git a/Sources/SwiftNetwork/QUIC/QUICConnection.swift b/Sources/SwiftNetwork/QUIC/QUICConnection.swift index e12d024..44df63e 100644 --- a/Sources/SwiftNetwork/QUIC/QUICConnection.swift +++ b/Sources/SwiftNetwork/QUIC/QUICConnection.swift @@ -2374,8 +2374,7 @@ public final class QUICConnection: ManyToManyApplicationStreamProtocol, continue } - try? enqueueInboundStreamData(flow: flowID, streamData: frameArray) - try? deliverEnqueuedInboundStreamData(flow: flowID) + try? deliverInboundStreamData(flow: flowID, streamData: frameArray) // When the stream is already in `resetReceived` state, // it should be closed when we receive STOP_SENDING, so we @@ -4317,8 +4316,7 @@ public final class QUICConnection: ManyToManyApplicationStreamProtocol, } if let frameArray = stream.dequeueReassembledData(connection: self) { do { - try enqueueInboundStreamData(flow: flowID, streamData: frameArray) - try deliverEnqueuedInboundStreamData(flow: flowID) + try deliverInboundStreamData(flow: flowID, streamData: frameArray) sendFrames() } catch { log.error("Error sending frames on stream close: \(error)") diff --git a/Sources/SwiftNetwork/QUIC/QUICStream.swift b/Sources/SwiftNetwork/QUIC/QUICStream.swift index 4b6774b..7179a29 100644 --- a/Sources/SwiftNetwork/QUIC/QUICStream.swift +++ b/Sources/SwiftNetwork/QUIC/QUICStream.swift @@ -328,7 +328,7 @@ struct StreamListMembership: OptionSet { // Also note that a flow identifier can exist in multiple lists at one time. @available(Network 0.1.0, *) struct QUICStreamList: ~Copyable { - private var list: [MultiplexedFlowIdentifier] = [] + private var list: Deque = [] private let name: StaticString private let listType: StreamListMembership From 62be3ec4f7255dc651d866017edfef424913e2ae Mon Sep 17 00:00:00 2001 From: agnosticdev Date: Mon, 20 Jul 2026 06:25:08 -0700 Subject: [PATCH 2/3] Review feedback --- .../SwiftNetwork/Protocols/ManyToManyProtocol.swift | 10 ++++++++++ Sources/SwiftNetwork/QUIC/QUICStream.swift | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Sources/SwiftNetwork/Protocols/ManyToManyProtocol.swift b/Sources/SwiftNetwork/Protocols/ManyToManyProtocol.swift index e75f044..a1483dc 100644 --- a/Sources/SwiftNetwork/Protocols/ManyToManyProtocol.swift +++ b/Sources/SwiftNetwork/Protocols/ManyToManyProtocol.swift @@ -1590,6 +1590,16 @@ extension ManyToManyApplicationDatagramProtocol where Flow: AutomaticUpperDatagr guard let flow = self.flow(for: flowID) else { throw NetworkError.posix(EINVAL) } flow.serviceUpperReceiveQueue() } + + // Enqueue and delivery the datagrams all in one shot + public func deliverInboundDatagrams( + flow flowID: MultiplexedFlowIdentifier, + datagrams: consuming FrameArray + ) throws(NetworkError) { + guard var flow = self.flow(for: flowID) else { throw NetworkError.posix(EINVAL) } + try flow.addToUpperReceiveQueue(datagrams) + flow.serviceUpperReceiveQueue() + } } @available(Network 0.1.0, *) diff --git a/Sources/SwiftNetwork/QUIC/QUICStream.swift b/Sources/SwiftNetwork/QUIC/QUICStream.swift index 7179a29..865ac29 100644 --- a/Sources/SwiftNetwork/QUIC/QUICStream.swift +++ b/Sources/SwiftNetwork/QUIC/QUICStream.swift @@ -328,7 +328,7 @@ struct StreamListMembership: OptionSet { // Also note that a flow identifier can exist in multiple lists at one time. @available(Network 0.1.0, *) struct QUICStreamList: ~Copyable { - private var list: Deque = [] + private var list = Deque() private let name: StaticString private let listType: StreamListMembership From b62090cfb698d6d91fdb0868ad5258e9b2297253 Mon Sep 17 00:00:00 2001 From: agnosticdev Date: Mon, 20 Jul 2026 09:32:07 -0700 Subject: [PATCH 3/3] Adopted new condensed API --- .../SwiftNetwork/Protocols/ManyToManyProtocol.swift | 10 ++++++++++ Sources/SwiftNetwork/QUIC/QUICConnection.swift | 3 +-- Tests/SwiftNetworkTests/TestMultiplexingProtocol.swift | 3 +-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/Sources/SwiftNetwork/Protocols/ManyToManyProtocol.swift b/Sources/SwiftNetwork/Protocols/ManyToManyProtocol.swift index a1483dc..d351dae 100644 --- a/Sources/SwiftNetwork/Protocols/ManyToManyProtocol.swift +++ b/Sources/SwiftNetwork/Protocols/ManyToManyProtocol.swift @@ -1632,6 +1632,16 @@ extension HeterogeneousManyToManyProtocolHandler where SecondaryFlow: AutomaticU guard let flow = self.secondaryFlow(for: flowID) else { throw NetworkError.posix(EINVAL) } flow.serviceUpperReceiveQueue() } + + // Enqueue and delivery the datagrams all in one shot + public func deliverInboundDatagrams( + flow flowID: MultiplexedFlowIdentifier, + datagrams: consuming FrameArray + ) throws(NetworkError) { + guard var flow = self.secondaryFlow(for: flowID) else { throw NetworkError.posix(EINVAL) } + try flow.addToUpperReceiveQueue(datagrams) + flow.serviceUpperReceiveQueue() + } } @_spi(ProtocolProvider) diff --git a/Sources/SwiftNetwork/QUIC/QUICConnection.swift b/Sources/SwiftNetwork/QUIC/QUICConnection.swift index 44df63e..58a2922 100644 --- a/Sources/SwiftNetwork/QUIC/QUICConnection.swift +++ b/Sources/SwiftNetwork/QUIC/QUICConnection.swift @@ -5562,8 +5562,7 @@ extension QUICConnection { var frame = frame.frame frame.metadataComplete = true - try? enqueueInboundDatagrams(flow: matchingFlowIdentifier, datagrams: .init(frame: frame)) - try? deliverEnqueuedInboundDatagrams(flow: matchingFlowIdentifier) + try? deliverInboundDatagrams(flow: matchingFlowIdentifier, datagrams: .init(frame: frame)) return true } } diff --git a/Tests/SwiftNetworkTests/TestMultiplexingProtocol.swift b/Tests/SwiftNetworkTests/TestMultiplexingProtocol.swift index ed1f776..338387f 100644 --- a/Tests/SwiftNetworkTests/TestMultiplexingProtocol.swift +++ b/Tests/SwiftNetworkTests/TestMultiplexingProtocol.swift @@ -91,8 +91,7 @@ final class TestMultiplexingProtocol: ManyToManyApplicationDatagramProtocol, Man return } accessReceivedDatagrams(path: path) { frames in - try? enqueueInboundDatagrams(flow: flow, datagrams: frames.drainArray()) - try? deliverEnqueuedInboundDatagrams(flow: flow) + try? deliverInboundDatagrams(flow: flow, datagrams: frames.drainArray()) } }