Skip to content

Restore BitArray constructor performance - #131833

Draft
joshuajyue wants to merge 3 commits into
dotnet:mainfrom
joshuajyue:fix-bitarray-constructor-performance
Draft

Restore BitArray constructor performance#131833
joshuajyue wants to merge 3 commits into
dotnet:mainfrom
joshuajyue:fix-bitarray-constructor-performance

Conversation

@joshuajyue

@joshuajyue joshuajyue commented Aug 4, 2026

Copy link
Copy Markdown
Member

Summary

  • Restore the original byte[], bool[], and int[] constructor implementations to eliminate helper-call and inlining regressions.
  • Keep separate implementations for the new ReadOnlySpan<byte>, ReadOnlySpan<bool>, and ReadOnlySpan<int> constructors.
  • Use an int induction variable in the Boolean span constructor so span indexing and bounds analysis stay in the JIT's canonical signed form.

Fixes #131815

Performance

Performance tracking identified regressions in three affected benchmark groups:

  • BitArrayBoolArrayCtor: automated bisection tied the confirmed Size: 512 regression to Add ReadOnlySpan constructors to BitArray #131500 (16.73 ns to 22.65 ns, approximately +35%).
  • BitArrayIntArrayCtor: additional regressions were reported at multiple input sizes.
  • BitArraySetLengthGrow(Size: 4): this benchmark includes construction from byte[]; automated bisection also flagged possible code-alignment noise, so it is included in the validation set.

This change prioritizes preserving the existing array-constructor performance over sharing implementation with the span overloads. Focused Windows x64 EgorBot runs cover all three benchmark groups on the original regression architecture.

Validation

  • Checked System.Private.CoreLib build
  • Verified the restored array constructor bodies match their pre-Add ReadOnlySpan constructors to BitArray #131500 implementations
  • Two independent read-only reviews found no correctness, bounds-safety, endianness, or exception-behavior issues
  • Full PR CI and focused EgorBot benchmarks will validate the updated commit

Note

This pull request description was generated with GitHub Copilot and reviewed before publication.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 4236475d-0243-488d-93d8-cd78e94d532b
Copilot AI review requested due to automatic review settings August 4, 2026 22:00
@joshuajyue

Copy link
Copy Markdown
Member Author

@EgorBot -windows_x64 -attempts 3 --filter "Perf_BitArray.BitArrayBoolArrayCtor"

Note

This benchmark request was generated with GitHub Copilot.

@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.

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 tweaks BitArray constructors to reduce JIT impediments in hot paths, with the goal of restoring constructor microbenchmark performance after recent refactoring.

Changes:

  • Avoids using an out-parameter as the source value for allocation sizing in the byte/int span helpers by computing the bit length in a local first.
  • Removes the out bitLength parameter from the Boolean packing helper and assigns _bitLength directly from the source length in the constructors.
  • Switches the Boolean packing loop induction variable to int to keep span indexing and bounds analysis in canonical signed form for the JIT.
Suppressed comments (1)

src/libraries/System.Private.CoreLib/src/System/Collections/BitArray.cs:342

  • length here is a bit count (values.Length * BitsPerInt32), but the name reads like an element/byte count. Consider renaming it to bitLengthLocal (and updating the two uses) to make the unit explicit.
            int length = values.Length * BitsPerInt32;
            byte[] array = AllocateByteArray(length);

            if (BitConverter.IsLittleEndian)
            {

Comment on lines +175 to +179
int length = bytes.Length * BitsPerByte;
byte[] array = AllocateByteArray(length);

bytes.CopyTo(array);
bitLength = length;
@joshuajyue

This comment was marked as outdated.

@EgorBo

EgorBo commented Aug 4, 2026

Copy link
Copy Markdown
Member

I've filed an alternative fix to make it fully memory safe #131838 (part of the on-going effort). Let's see if it improves.

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

Copilot reviewed 1 out of 1 changed files in this pull request and generated 1 comment.

Comment on lines +261 to +264
if (values[i])
{
(uint byteIndex, uint bitOffset) = Math.DivRem(i, BitsPerByte);
_array[byteIndex] |= (byte)(1 << (int)bitOffset);
@joshuajyue

Copy link
Copy Markdown
Member Author

@EgorBot -windows_x64 -linux_x64 -arm --filter "Perf_BitArray.BitArrayBoolArrayCtor"

@joshuajyue

Copy link
Copy Markdown
Member Author

@EgorBot -windows_x64 -attempts 3 --filter "Perf_BitArray.BitArrayBoolArrayCtor"

@joshuajyue

Copy link
Copy Markdown
Member Author

@EgorBot -windows_x64 -linux_x64 -arm --filter "Perf_BitArray.BitArrayIntArrayCtor"

@joshuajyue

Copy link
Copy Markdown
Member Author

@EgorBot -windows_x64 -commits PR_131833,31004ff8dc2,fffed311025,44687f2d763 --envvars DOTNET_ReadyToRun:0 DOTNET_TieredCompilation:0 DOTNET_JitDisasm:BitArray DOTNET_JitDisasmDiffable:1 DOTNET_JitPrintInlinedMethods:BitArray --filter "Perf_BitArray.BitArraySetLengthGrow"

Note

This benchmark request was generated with GitHub Copilot and reviewed before publication.

@joshuajyue

Copy link
Copy Markdown
Member Author

@EgorBot -windows_x64 -commits PR_131833,31004ff8dc2,fffed311025,44687f2d763 --envvars DOTNET_ReadyToRun:0 DOTNET_TieredCompilation:0 DOTNET_JitDisasm:BitArray DOTNET_JitDisasmDiffable:1 DOTNET_JitPrintInlinedMethods:BitArray --filter "Perf_BitArray.BitArrayIntArrayCtor"

Note

This benchmark request was generated with GitHub Copilot and reviewed before publication.

@joshuajyue

Copy link
Copy Markdown
Member Author

@EgorBot -windows_x64 -commits ca4ed7d,31004ff8dc2 -attempts 5 --envvars DOTNET_ReadyToRun:0 DOTNET_TieredCompilation:0 DOTNET_JitDisasm:System.Collections.BitArray:.ctor* DOTNET_JitDisasmWithAddress:1 DOTNET_JitDisasmWithAlignmentBoundaries:1 DOTNET_JitDisasmWithCodeBytes:1 --filter "Perf_BitArray.BitArrayBoolArrayCtor"

Note

This benchmark request was generated with GitHub Copilot and reviewed before publication.

@joshuajyue

Copy link
Copy Markdown
Member Author

@EgorBot -windows_x64 -commits 31004ff,31004ff8dc241f47d07361678d82e1e55b66f729 -attempts 5 --filter "Perf_BitArray.BitArrayBoolArrayCtor"

Note

This benchmark request was generated with GitHub Copilot and reviewed before publication.

@joshuajyue

Copy link
Copy Markdown
Member Author

@EgorBot -linux_x64 -commits ca4ed7d,31004ff8dc2 -attempts 3 -perf_events cycles,instructions,branches,branch-misses --filter "Perf_BitArray.BitArrayBoolArrayCtor"

Note

This benchmark request was generated with GitHub Copilot and reviewed before publication.

@joshuajyue

Copy link
Copy Markdown
Member Author

@EgorBot -windows_x64 -commits PR_131833,31004ff8dc2,31004ff8dc241f47d07361678d82e1e55b66f729 -attempts 5 --filter "Perf_BitArray.BitArrayBoolArrayCtor"

Note

This benchmark request was generated with GitHub Copilot and reviewed before publication.

@joshuajyue

Copy link
Copy Markdown
Member Author

@EgorBot -windows_x64 -commits PR_131833,ca4ed7d4a26,31004ff8dc2 -attempts 5 --envvars DOTNET_ReadyToRun:0 DOTNET_TieredCompilation:0 DOTNET_JitDisasm:System.Collections.BitArray:.ctor* DOTNET_JitDisasmWithAddress:1 DOTNET_JitDisasmWithAlignmentBoundaries:1 DOTNET_JitDisasmWithCodeBytes:1 --filter "Perf_BitArray.BitArrayBoolArrayCtor"

Note

This benchmark request was generated with GitHub Copilot and reviewed before publication.

@joshuajyue

Copy link
Copy Markdown
Member Author

@EgorBot -linux_x64 -commits PR_131833,ca4ed7d4a26,31004ff8dc2 -attempts 3 -perf_events cycles,instructions,branches,branch-misses --filter "Perf_BitArray.BitArrayBoolArrayCtor"

Note

This benchmark request was generated with GitHub Copilot and reviewed before publication.

@joshuajyue

Copy link
Copy Markdown
Member Author

@EgorBot -windows_x64 -commits PR_131833,ca4ed7d4a26,9072500a881 -attempts 3 --filter "Perf_BitArray.BitArrayIntArrayCtor"

Note

This benchmark request was generated with GitHub Copilot and reviewed before publication.

@joshuajyue

Copy link
Copy Markdown
Member Author

@EgorBot -windows_x64 -commits PR_131833,ca4ed7d4a26,9072500a881 -attempts 3 --filter "Perf_BitArray.BitArrayBoolArrayCtor"

Note

This benchmark request was generated with GitHub Copilot and reviewed before publication.

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 encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Note

This error may be related to your runner configuration. You can now configure runners for Copilot code review separately from Copilot cloud agent by creating a copilot-code-review.yml file with your setup steps. Read the docs for details.

@EgorBo

EgorBo commented Aug 6, 2026

Copy link
Copy Markdown
Member

@joshuajyue I would recommend running locally. You can just use the benchmark skill & your favorite AI tool to set it up and validate till it's ready.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 4236475d-0243-488d-93d8-cd78e94d532b
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 4236475d-0243-488d-93d8-cd78e94d532b
@joshuajyue
joshuajyue force-pushed the fix-bitarray-constructor-performance branch from fbdc44b to 5b91478 Compare August 6, 2026 22:44
@joshuajyue

Copy link
Copy Markdown
Member Author

@EgorBot -windows_x64 -commits PR_131833,ca4ed7d4a26,9072500a881,a491f2f5ede -attempts 3 --filter "Perf_BitArray.BitArrayBoolArrayCtor"

Note

This benchmark request was generated with GitHub Copilot and reviewed before publication.

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.

[Perf] Windows/x64: 2 Regressions on 7/31/2026 4:48:31 PM +00:00

3 participants