Skip to content

SwiftQUIC: Reduce CPU overhead in getting inbound stream data delivered to the stream#53

Open
agnosticdev wants to merge 3 commits into
mainfrom
agnosticdev/InboundStopping
Open

SwiftQUIC: Reduce CPU overhead in getting inbound stream data delivered to the stream#53
agnosticdev wants to merge 3 commits into
mainfrom
agnosticdev/InboundStopping

Conversation

@agnosticdev

Copy link
Copy Markdown
Collaborator

When looking at the CPU usage in inboundStopping for server workloads we enqueue stream data and then call deliverEnqueuedInboundStreamData to send it.
This incurs 2 dictionary lookups for the stream when we can condense it all into one with a new method called deliverInboundStreamData.

Next, in inboundStopping we remove the first value from an array when delivering the stream data. This would be more efficient with a Deque.

Top of tree CPU usage:

187.93 M  1.3%	3.54 M  	     specialized QUICConnection.inboundStopping(path:)
42.02 M   0.3%	-       	       specialized ManyToManyApplicationStreamProtocol<>.deliverEnqueuedInboundStreamData(flow:)
30.90 M   0.2%	-       	       specialized AutomaticUpperStreamProcessing<>.serviceUpperReceiveQueue()
11.12 M   0.1%	-       	       specialized ManyToManyProtocolHandler.flow(for:)
39.97 M   0.3%	-       	        QUICConnection.sendFrames(ignoreCongestionWindow:delayedACK:)
28.14 M   0.2%	-       	        QUICStreamList.removeFirst(connection:)
21.16 M   0.1%	-       	        QUICStreamInstance.dequeueReassembledData(connection:)
12.94 M   0.1%	-       	          specialized ManyToManyProtocolHandler.applyToAllFlows(_:)
7.06 M    0.0%	-       	          specialized ManyToManyApplicationStreamProtocol<>.enqueueInboundStreamData(flow:streamData:)
7.06 M    0.0%	-       	        specialized ManyToManyProtocolHandler.flow(for)

With this change:

131.45 M  97.8%		  specialized QUICConnection.inboundStopping(path:)
35.55 M  26.4%	-	    specialized ManyToManyApplicationStreamProtocol<>.deliverInboundStreamData(flow:streamData:)
23.44 M  17.4%	-	    QUICConnection.sendFrames(ignoreCongestionWindow:delayedACK:)
22.06 M  16.4%	-	    QUICStreamInstance.dequeueReassembledData(connection:)
18.44 M  13.7%	-	    QUICStreamList.removeFirst(connection:)

Overall reduction of about 50 megacycles in aggregate.
Note that this change just adds a new function named deliverInboundStreamData and does not delete the previous methods for enqueueInboundStreamData and deliverEnqueuedInboundStreamData as I can see the utility of them individually.

Comment thread Sources/SwiftNetwork/QUIC/QUICStream.swift Outdated
flow.serviceUpperReceiveQueue()
}
// Enqueue and delivery the stream data all in one shot
public func deliverInboundStreamData(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We should add the same for enqueueInboundDatagrams/deliverEnqueuedInboundDatagrams to keep them parallel

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.

Yep, that makes a lot of sense. Addressed in 62be3ec

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks! Can you also adopt it where we call enqueueInboundDatagrams?

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.

Yeah, good idea. Looks like I missed a place in HeterogeneousManyToManyProtocolHandler so I added it there too and adopted it. b62090c

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.

2 participants