Skip to content

Vectorize BMP string#131170

Open
vcsjones wants to merge 2 commits into
dotnet:mainfrom
vcsjones:vector-bmp-string
Open

Vectorize BMP string#131170
vcsjones wants to merge 2 commits into
dotnet:mainfrom
vcsjones:vector-bmp-string

Conversation

@vcsjones

@vcsjones vcsjones commented Jul 21, 2026

Copy link
Copy Markdown
Member

As a follow up to #131109, this introduces vectorization for the BMPEncoding.

BMPEncoding is big-endian UCS-2 encoding. It is a subset of UTF-16-BE, with the exception that it is truly fixed width and only supports plane 0 without the surrogate pairs.

Performance is largely improved across the board. Small inputs, like country codes, regress ~0.5ns simply because the method body itself has slightly more register pressure. Other inputs like common names, etc. see notable performance improvements.

This also incorporates some feedback about making the SIMD more JIT-friendly into the existing IA5 and VisibleString encoding.

Performance Benchmarks

Source: https://gist.github.com/vcsjones/4b91a33bcae337333cb26d46fd087bf9


BenchmarkDotNet v0.15.8, macOS Tahoe 26.5.2 (25F84) [Darwin 25.5.0]
Apple M1 Ultra, 1 CPU, 20 logical and 20 physical cores
  [Host] : .NET 11.0.0 (11.0.0-dev, 42.42.42.42424), Arm64 RyuJIT armv8.0-a
  Main   : .NET 11.0.0 (11.0.0-dev, 42.42.42.42424), Arm64 RyuJIT armv8.0-a
  Vector : .NET 11.0.0 (11.0.0-dev, 42.42.42.42424), Arm64 RyuJIT armv8.0-a

Runtime=.NET 10.0  IterationCount=15  WarmupCount=5  

Method Job Toolchain Alignment Input Mean Error StdDev Ratio RatioSD Gen0 Gen1 Allocated Alloc Ratio
Decode Main Main Aligned CountryCode 14.27 ns 0.037 ns 0.031 ns 1.00 0.00 0.0051 - 32 B 1.00
Decode Vector Vector Aligned CountryCode 14.97 ns 0.031 ns 0.029 ns 1.05 0.00 0.0051 - 32 B 1.00
TryDecode Main Main Aligned CountryCode 11.34 ns 0.012 ns 0.011 ns 1.00 0.00 - - - NA
TryDecode Vector Vector Aligned CountryCode 11.74 ns 0.007 ns 0.006 ns 1.04 0.00 - - - NA
Write Main Main Aligned CountryCode 16.13 ns 0.043 ns 0.040 ns 1.00 0.00 0.0127 - 80 B 1.00
Write Vector Vector Aligned CountryCode 16.79 ns 0.044 ns 0.039 ns 1.04 0.00 0.0127 - 80 B 1.00
Decode Main Main Aligned CommonName 56.85 ns 0.073 ns 0.068 ns 1.00 0.00 0.0127 - 80 B 1.00
Decode Vector Vector Aligned CommonName 26.71 ns 0.040 ns 0.035 ns 0.47 0.00 0.0127 - 80 B 1.00
TryDecode Main Main Aligned CommonName 52.77 ns 0.033 ns 0.029 ns 1.00 0.00 - - - NA
TryDecode Vector Vector Aligned CommonName 21.71 ns 0.038 ns 0.034 ns 0.41 0.00 - - - NA
Write Main Main Aligned CommonName 43.31 ns 0.067 ns 0.060 ns 1.00 0.00 0.0216 - 136 B 1.00
Write Vector Vector Aligned CommonName 26.72 ns 0.394 ns 0.349 ns 0.62 0.01 0.0217 - 136 B 1.00
Decode Main Main Aligned UnicodeName 28.28 ns 0.078 ns 0.069 ns 1.00 0.00 0.0076 - 48 B 1.00
Decode Vector Vector Aligned UnicodeName 19.37 ns 0.037 ns 0.034 ns 0.68 0.00 0.0076 - 48 B 1.00
TryDecode Main Main Aligned UnicodeName 24.90 ns 0.039 ns 0.032 ns 1.00 0.00 - - - NA
TryDecode Vector Vector Aligned UnicodeName 15.75 ns 0.024 ns 0.020 ns 0.63 0.00 - - - NA
Write Main Main Aligned UnicodeName 25.70 ns 0.397 ns 0.371 ns 1.00 0.02 0.0166 - 104 B 1.00
Write Vector Vector Aligned UnicodeName 20.71 ns 0.040 ns 0.037 ns 0.81 0.01 0.0166 - 104 B 1.00
Decode Main Main Aligned Length8 23.64 ns 0.012 ns 0.011 ns 1.00 0.00 0.0063 - 40 B 1.00
Decode Vector Vector Aligned Length8 14.63 ns 0.044 ns 0.041 ns 0.62 0.00 0.0063 - 40 B 1.00
TryDecode Main Main Aligned Length8 20.37 ns 0.020 ns 0.019 ns 1.00 0.00 - - - NA
TryDecode Vector Vector Aligned Length8 11.74 ns 0.020 ns 0.016 ns 0.58 0.00 - - - NA
Write Main Main Aligned Length8 22.18 ns 0.062 ns 0.058 ns 1.00 0.00 0.0153 - 96 B 1.00
Write Vector Vector Aligned Length8 17.24 ns 0.064 ns 0.057 ns 0.78 0.00 0.0153 - 96 B 1.00
Decode Main Main Aligned Length16 36.07 ns 0.010 ns 0.008 ns 1.00 0.00 0.0089 - 56 B 1.00
Decode Vector Vector Aligned Length16 16.58 ns 0.027 ns 0.025 ns 0.46 0.00 0.0089 - 56 B 1.00
TryDecode Main Main Aligned Length16 32.38 ns 0.046 ns 0.043 ns 1.00 0.00 - - - NA
TryDecode Vector Vector Aligned Length16 13.21 ns 0.030 ns 0.025 ns 0.41 0.00 - - - NA
Write Main Main Aligned Length16 30.14 ns 0.054 ns 0.051 ns 1.00 0.00 0.0178 - 112 B 1.00
Write Vector Vector Aligned Length16 19.41 ns 0.356 ns 0.315 ns 0.64 0.01 0.0179 - 112 B 1.00
Decode Main Main Aligned Length32 61.89 ns 0.310 ns 0.290 ns 1.00 0.01 0.0139 - 88 B 1.00
Decode Vector Vector Aligned Length32 21.06 ns 0.647 ns 0.605 ns 0.34 0.01 0.0140 - 88 B 1.00
TryDecode Main Main Aligned Length32 58.35 ns 0.375 ns 0.332 ns 1.00 0.01 - - - NA
TryDecode Vector Vector Aligned Length32 16.27 ns 0.343 ns 0.268 ns 0.28 0.00 - - - NA
Write Main Main Aligned Length32 47.59 ns 0.814 ns 0.680 ns 1.00 0.02 0.0229 - 144 B 1.00
Write Vector Vector Aligned Length32 23.47 ns 0.717 ns 0.671 ns 0.49 0.02 0.0229 - 144 B 1.00
Decode Main Main Aligned Length64 123.09 ns 1.822 ns 1.704 ns 1.00 0.02 0.0241 - 152 B 1.00
Decode Vector Vector Aligned Length64 30.67 ns 0.297 ns 0.278 ns 0.25 0.00 0.0242 - 152 B 1.00
TryDecode Main Main Aligned Length64 117.53 ns 0.437 ns 0.409 ns 1.00 0.00 - - - NA
TryDecode Vector Vector Aligned Length64 23.48 ns 0.103 ns 0.091 ns 0.20 0.00 - - - NA
Write Main Main Aligned Length64 83.22 ns 0.652 ns 0.578 ns 1.00 0.01 0.0331 - 208 B 1.00
Write Vector Vector Aligned Length64 31.31 ns 0.323 ns 0.286 ns 0.38 0.00 0.0331 - 208 B 1.00
Decode Main Main Aligned Length256 460.07 ns 0.758 ns 0.709 ns 1.00 0.00 0.0854 - 536 B 1.00
Decode Vector Vector Aligned Length256 73.86 ns 0.125 ns 0.104 ns 0.16 0.00 0.0854 - 536 B 1.00
TryDecode Main Main Aligned Length256 447.23 ns 0.333 ns 0.311 ns 1.00 0.00 - - - NA
TryDecode Vector Vector Aligned Length256 54.62 ns 0.059 ns 0.055 ns 0.12 0.00 - - - NA
Write Main Main Aligned Length256 297.00 ns 0.250 ns 0.234 ns 1.00 0.00 0.0939 - 592 B 1.00
Write Vector Vector Aligned Length256 71.91 ns 0.080 ns 0.071 ns 0.24 0.00 0.0943 0.0001 592 B 1.00
Decode Main Main Aligned Length1024 1,769.30 ns 1.602 ns 1.420 ns 1.00 0.00 0.3300 - 2072 B 1.00
Decode Vector Vector Aligned Length1024 270.31 ns 0.690 ns 0.611 ns 0.15 0.00 0.3300 - 2072 B 1.00
TryDecode Main Main Aligned Length1024 1,693.69 ns 1.338 ns 1.252 ns 1.00 0.00 - - - NA
TryDecode Vector Vector Aligned Length1024 195.24 ns 0.092 ns 0.086 ns 0.12 0.00 - - - NA
Write Main Main Aligned Length1024 1,119.74 ns 1.917 ns 1.700 ns 1.00 0.00 0.3376 0.0019 2128 B 1.00
Write Vector Vector Aligned Length1024 250.16 ns 1.218 ns 1.080 ns 0.22 0.00 0.3390 0.0024 2128 B 1.00
Decode Main Main Unaligned CountryCode 14.42 ns 0.127 ns 0.119 ns 1.00 0.01 0.0051 - 32 B 1.00
Decode Vector Vector Unaligned CountryCode 15.08 ns 0.040 ns 0.033 ns 1.05 0.01 0.0051 - 32 B 1.00
TryDecode Main Main Unaligned CountryCode 11.31 ns 0.021 ns 0.018 ns 1.00 0.00 - - - NA
TryDecode Vector Vector Unaligned CountryCode 11.63 ns 0.021 ns 0.020 ns 1.03 0.00 - - - NA
Write Main Main Unaligned CountryCode 16.89 ns 0.182 ns 0.170 ns 1.00 0.01 0.0127 - 80 B 1.00
Write Vector Vector Unaligned CountryCode 17.38 ns 0.043 ns 0.038 ns 1.03 0.01 0.0127 - 80 B 1.00
Decode Main Main Unaligned CommonName 56.72 ns 0.067 ns 0.056 ns 1.00 0.00 0.0127 - 80 B 1.00
Decode Vector Vector Unaligned CommonName 26.71 ns 0.057 ns 0.053 ns 0.47 0.00 0.0127 - 80 B 1.00
TryDecode Main Main Unaligned CommonName 52.68 ns 0.068 ns 0.064 ns 1.00 0.00 - - - NA
TryDecode Vector Vector Unaligned CommonName 21.68 ns 0.018 ns 0.017 ns 0.41 0.00 - - - NA
Write Main Main Unaligned CommonName 43.62 ns 0.035 ns 0.033 ns 1.00 0.00 0.0216 - 136 B 1.00
Write Vector Vector Unaligned CommonName 26.82 ns 0.068 ns 0.064 ns 0.61 0.00 0.0217 - 136 B 1.00
Decode Main Main Unaligned UnicodeName 28.22 ns 0.061 ns 0.057 ns 1.00 0.00 0.0076 - 48 B 1.00
Decode Vector Vector Unaligned UnicodeName 19.32 ns 0.033 ns 0.031 ns 0.68 0.00 0.0076 - 48 B 1.00
TryDecode Main Main Unaligned UnicodeName 24.74 ns 0.022 ns 0.021 ns 1.00 0.00 - - - NA
TryDecode Vector Vector Unaligned UnicodeName 15.72 ns 0.023 ns 0.022 ns 0.64 0.00 - - - NA
Write Main Main Unaligned UnicodeName 25.81 ns 0.032 ns 0.030 ns 1.00 0.00 0.0166 - 104 B 1.00
Write Vector Vector Unaligned UnicodeName 21.11 ns 0.033 ns 0.031 ns 0.82 0.00 0.0166 - 104 B 1.00
Decode Main Main Unaligned Length8 23.47 ns 0.032 ns 0.030 ns 1.00 0.00 0.0063 - 40 B 1.00
Decode Vector Vector Unaligned Length8 14.49 ns 0.036 ns 0.034 ns 0.62 0.00 0.0063 - 40 B 1.00
TryDecode Main Main Unaligned Length8 20.27 ns 0.025 ns 0.022 ns 1.00 0.00 - - - NA
TryDecode Vector Vector Unaligned Length8 11.39 ns 0.004 ns 0.003 ns 0.56 0.00 - - - NA
Write Main Main Unaligned Length8 22.72 ns 0.080 ns 0.062 ns 1.00 0.00 0.0153 - 96 B 1.00
Write Vector Vector Unaligned Length8 18.17 ns 0.627 ns 0.586 ns 0.80 0.03 0.0153 - 96 B 1.00
Decode Main Main Unaligned Length16 36.14 ns 0.537 ns 0.476 ns 1.00 0.02 0.0089 - 56 B 1.00
Decode Vector Vector Unaligned Length16 16.50 ns 0.147 ns 0.114 ns 0.46 0.01 0.0089 - 56 B 1.00
TryDecode Main Main Unaligned Length16 32.57 ns 0.478 ns 0.447 ns 1.00 0.02 - - - NA
TryDecode Vector Vector Unaligned Length16 12.89 ns 0.022 ns 0.020 ns 0.40 0.01 - - - NA
Write Main Main Unaligned Length16 31.11 ns 0.646 ns 0.604 ns 1.00 0.03 0.0178 - 112 B 1.00
Write Vector Vector Unaligned Length16 19.64 ns 0.068 ns 0.064 ns 0.63 0.01 0.0179 - 112 B 1.00
Decode Main Main Unaligned Length32 61.77 ns 0.095 ns 0.084 ns 1.00 0.00 0.0139 - 88 B 1.00
Decode Vector Vector Unaligned Length32 20.65 ns 0.032 ns 0.028 ns 0.33 0.00 0.0140 - 88 B 1.00
TryDecode Main Main Unaligned Length32 57.64 ns 0.049 ns 0.046 ns 1.00 0.00 - - - NA
TryDecode Vector Vector Unaligned Length32 15.87 ns 0.013 ns 0.012 ns 0.28 0.00 - - - NA
Write Main Main Unaligned Length32 47.41 ns 0.314 ns 0.294 ns 1.00 0.01 0.0229 - 144 B 1.00
Write Vector Vector Unaligned Length32 23.44 ns 0.072 ns 0.068 ns 0.49 0.00 0.0229 - 144 B 1.00
Decode Main Main Unaligned Length64 123.07 ns 0.224 ns 0.199 ns 1.00 0.00 0.0241 - 152 B 1.00
Decode Vector Vector Unaligned Length64 29.79 ns 0.068 ns 0.063 ns 0.24 0.00 0.0242 - 152 B 1.00
TryDecode Main Main Unaligned Length64 117.86 ns 1.290 ns 1.077 ns 1.00 0.01 - - - NA
TryDecode Vector Vector Unaligned Length64 23.68 ns 0.010 ns 0.008 ns 0.20 0.00 - - - NA
Write Main Main Unaligned Length64 85.83 ns 0.225 ns 0.211 ns 1.00 0.00 0.0331 - 208 B 1.00
Write Vector Vector Unaligned Length64 31.51 ns 0.062 ns 0.058 ns 0.37 0.00 0.0331 - 208 B 1.00
Decode Main Main Unaligned Length256 462.01 ns 0.529 ns 0.495 ns 1.00 0.00 0.0854 - 536 B 1.00
Decode Vector Vector Unaligned Length256 73.40 ns 0.129 ns 0.114 ns 0.16 0.00 0.0854 - 536 B 1.00
TryDecode Main Main Unaligned Length256 436.59 ns 0.388 ns 0.344 ns 1.00 0.00 - - - NA
TryDecode Vector Vector Unaligned Length256 53.95 ns 0.054 ns 0.051 ns 0.12 0.00 - - - NA
Write Main Main Unaligned Length256 299.77 ns 0.426 ns 0.398 ns 1.00 0.00 0.0939 - 592 B 1.00
Write Vector Vector Unaligned Length256 73.73 ns 0.133 ns 0.124 ns 0.25 0.00 0.0943 0.0001 592 B 1.00
Decode Main Main Unaligned Length1024 1,770.61 ns 1.237 ns 1.033 ns 1.00 0.00 0.3300 - 2072 B 1.00
Decode Vector Vector Unaligned Length1024 269.57 ns 0.657 ns 0.583 ns 0.15 0.00 0.3300 - 2072 B 1.00
TryDecode Main Main Unaligned Length1024 1,692.96 ns 1.859 ns 1.739 ns 1.00 0.00 - - - NA
TryDecode Vector Vector Unaligned Length1024 194.38 ns 0.181 ns 0.169 ns 0.11 0.00 - - - NA
Write Main Main Unaligned Length1024 1,127.43 ns 1.654 ns 1.548 ns 1.00 0.00 0.3376 0.0019 2128 B 1.00
Write Vector Vector Unaligned Length1024 251.62 ns 0.766 ns 0.717 ns 0.22 0.00 0.3390 0.0024 2128 B 1.00

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).
13 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @dotnet/area-system-formats-asn1, @bartonjs, @vcsjones
See info in area-owners.md if you want to be subscribed.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces a vectorized implementation of ASN.1 BMPString (big-endian UCS-2 without surrogates) encode/decode logic in BMPEncoding, aiming to improve throughput on larger inputs while preserving scalar behavior for validation and exact error indexing.

Changes:

  • Add Vector<ushort>-based fast paths for BMPString encode (GetBytes) and decode (GetChars), including big-endian handling and surrogate detection.
  • Split BMPEncoding into partial implementations for net vs downlevel builds, keeping max-count logic in the shared file.
  • Add reader/writer tests covering vector boundary lengths, bounds safety (BoundedMemory), and surrogate detection index correctness.
Show a summary per file
File Description
src/libraries/System.Formats.Asn1/src/System/Formats/Asn1/AsnCharacterStringEncodings.net.cs Adds vectorized BMPEncoding encode/decode with endian swap + surrogate scanning.
src/libraries/System.Formats.Asn1/src/System/Formats/Asn1/AsnCharacterStringEncodings.downlevel.cs Restores scalar BMPEncoding implementation for downlevel targets.
src/libraries/System.Formats.Asn1/src/System/Formats/Asn1/AsnCharacterStringEncodings.cs Makes BMPEncoding partial and retains max byte/char count logic.
src/libraries/System.Formats.Asn1/tests/Writer/WriteBMPString.cs Adds vector-boundary + surrogate-index writer regression tests and bounds checks.
src/libraries/System.Formats.Asn1/tests/Reader/ReadBMPString.cs Adds vector-boundary + surrogate-index reader regression tests and bounds checks.

Copilot's findings

  • Files reviewed: 5/5 changed files
  • Comments generated: 1

@EgorBo

EgorBo commented Jul 21, 2026

Copy link
Copy Markdown
Member

@vcsjones not sure if it matters, but currently for loop shapes that load more than one element (either SIMD or BinaryOperations.*) it's more jit friendly to use code like

while (span.Length >= <const>)
{
    var vec = Vector.Create(span); // or any other operation that loads from/saves to span slice.
    span = span.Slice(const);
}

the ones you used will lead to redundant checks (hopefully will be optimized in .NET 12.0).

Regardless, thanks for using safe code for that 🙂

Copilot AI review requested due to automatic review settings July 21, 2026 22:42
@vcsjones

Copy link
Copy Markdown
Member Author

not sure if it matters, but currently for loop shapes that load more than one element (either SIMD or BinaryOperations.*) it's more jit friendly to use code like

Hm yeah that gave a nice 20~25% performance bump.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot's findings

  • Files reviewed: 5/5 changed files
  • Comments generated: 2

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants