Repository navigation
Encode large Base64Url inputs with the vectorized encoder on net8 - #721
Merged
Merged
Conversation
SimonCropp
force-pushed
the
perf/base64url-bulk-encode
branch
from
October 12, 2026 22:22
4ca067e to
d3bb497
Compare
This was referenced Oct 12, 2026
This was referenced Oct 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #683, which gave
Base64Urla span-to-span encode loop. On net8 the BCL can do the bulk of that work vectorized, so for inputs of 192 bytes or more the complete 3-byte groups now go throughConvert.TryToBase64Chars/Base64.EncodeToUtf8, straight into the destination. Complete groups encode without padding, so only+and/are left to change, which two vectorizedSpan.Replacepasses do in place. The existing loop then encodes the last one or two bytes.This is net8 only (the type is in the BCL from net9):
Replace, and changing the alphabet with a loop costs as much as encoding with the loop does; measured on the net6.0 build, that was slower than what is there nowEncodeLoop) so that its code is not affected; on other targets nothing changes at allTryEncodeToUtf8InPlaceis left alone: going throughBase64.EncodeToUtf8InPlacemeasured the same as the loopResults are unchanged.
Tests
On top of the existing ones (every overload for every length from 0 to 300 against a
Convertbased reference, and a 100 KB input), a test for inputs that are nothing but+, nothing but/, or the two alternating in standard base-64, for every length from 0 to 400 (both sides of the threshold, every remainder):EncodeToString,EncodeToUtf8,EncodeToCharsandTryEncodeToUtf8InPlace, with+and/placed right after the output to check that only the output is touched.Passes against the previous implementation and against the real
Base64Urlon net9+.Measurements
net8.0, Stopwatch /
GC.GetAllocatedBytesForCurrentThread, Release, minimum of 5 alternating runs of before and after (each the best of 9 rounds after warm-up). Allocations are unchanged.EncodeToString(1KB)EncodeToChars(1KB, dest)EncodeToChars(1KB, dest, out, out)EncodeToUtf8(1KB)EncodeToUtf8(1KB, dest, out, out)TryEncodeToUtf8(1KB, dest)EncodeToString(16B)EncodeToChars(17B, dest)EncodeToChars(32B, dest)EncodeToUtf8(32B)TryEncodeToUtf8InPlace(1KB)(The machine was busy; the rows for small inputs and for in-place run the same code before and after, so their differences are noise.)