Skip to content

SwiftQUIC: PERF: Create a reusable buffer to run xor operations - #242

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

agnosticdev wants to merge 3 commits into
mainfrom
agnosticdev/Ackxor

Conversation

@agnosticdev

Copy link
Copy Markdown
Collaborator

Today when xor operation are run in Recovery to find acked packets AckBitstringSequence will create a fresh array each time to compute words.
When there are many packets in-flight this gets really expensive. This change creates a re-usable buffer called AckBitstringXORBuffer that avoids creating that array each time.
So I am using a class here because AckBitstringSequence needs to conform to Sequence and in those cases having a struct or a non-copyable struct does not work.
I did not see a CPU impact due to the addition of the class in Recovery.

The memory impact here is we save 101k for QUICTransfer running 1000 iterations.
The more packets the more the savings will be!

So this:

0	_ContiguousArrayStorage<UInt64>	112 Bytes	2	1098	102.59 KiB	1100	Ratio: %0.00, %0.00

Now becomes:

0	_ContiguousArrayStorage<UInt64>	   368 Bytes	2	5	784 Bytes	7	Ratio: %0.00, %0.00
0	SwiftNetwork.AckBitstringXORBuffer	96 Bytes	3	9	384 Bytes	12	Ratio: %0.00, %0.00

Here is the CPU usage:

QUICTransfer Top Tree 1000 iterations:
4.36 G 100.0%	-	 QUICTransfer (63466)	
4.40 G 100.0%	-	 QUICTransfer (63457)	
4.38 G 100.0%	-	 QUICTransfer (63444)	

QUICTransfer With Change 1000 iterations:
4.34 G 100.0%	-	 QUICTransfer (62574)	
4.33 G 100.0%	-	 QUICTransfer (62559)
4.26 G 100.0%	-	 QUICTransfer (62545)	


QUICStreamLoad Top Tree 1,000,000 streams:
61.73 G 100.0%	-	 QUICStreamLoad (63236)	
61.62 G 100.0%	-	 QUICStreamLoad (63189)	
61.52 G 100.0%	-	 QUICStreamLoad (63158)	

QUICStreamLoad With Change 1,000,000 streams:
61.65 G 100.0%	-	 QUICStreamLoad (62850)	
61.49 G 100.0%	-	 QUICStreamLoad (62806)	
61.11 G 100.0%	-	 QUICStreamLoad (62759)	

@agnosticdev
agnosticdev requested a review from rnro October 9, 2026 19:37
@agnosticdev agnosticdev added the 🔨 semver/patch No public API change. label Oct 9, 2026
@rpaulo

rpaulo commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

The original objective of this code was to compose a bit string only for the packets that are in flight, so the total number of packets doesn't matter, what matters is the packets in flight. The second objective was to be able to swap bit strings in a non costly (i.e., non copying) way. In a language like C, the array wouldn't be recreated at all and it would be a simple pointer swap. Is there an existing data structure in Swift that would do this?

@agnosticdev

Copy link
Copy Markdown
Collaborator Author

The original objective of this code was to compose a bit string only for the packets that are in flight, so the total number of packets doesn't matter, what matters is the packets in flight. The second objective was to be able to swap bit strings in a non costly (i.e., non copying) way. In a language like C, the array wouldn't be recreated at all and it would be a simple pointer swap. Is there an existing data structure in Swift that would do this?

What I am doing here is very similar to a pointer swap because Recovery creates the reference type and then its passed in and used by reference in AckBitstringIterator and AckBitstringSequence. So multiple instances are not being created. Its using the original one the key state for Recovery is holding.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🔨 semver/patch No public API change.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants