Skip to content

perf: optimize bitmapContainer.fillLeastSignificant16bits using TrailingZeros64#534

Open
perfloop-agent wants to merge 1 commit into
RoaringBitmap:masterfrom
perfloop:perfloop-pr-open-gtf1q33kjy
Open

perf: optimize bitmapContainer.fillLeastSignificant16bits using TrailingZeros64#534
perfloop-agent wants to merge 1 commit into
RoaringBitmap:masterfrom
perfloop:perfloop-pr-open-gtf1q33kjy

Conversation

@perfloop-agent

Copy link
Copy Markdown
Contributor

Description

This PR optimizes the dense bitmap array materialization loop in bitmapContainer.fillLeastSignificant16bits using math/bits.TrailingZeros64 and clear-lowest-bit step bitset &= bitset - 1.

On amd64 architectures, this loop compiles down to efficient TZCNT/BLSR instructions. By using these instructions, we reduce the scalar instructions required per set bit and significantly optimize dense bitmap array materialization.

A comprehensive differential property test TestBitmapContainerFillLeastSignificant16bitsProperties is also added to thoroughly verify 16-bit range correctness, boundary conditions, and return values.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Performance improvement (non-breaking change which improves performance)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)

Changes Made

What was changed?

The scalar loop decoding each set bit in bitmapContainer.fillLeastSignificant16bits was rewritten. Instead of using the legacy isolate-lowest-bit t := bitset & -bitset and popcount(t-1) operations, the code now extracts the trailing zeros with math/bits.TrailingZeros64 and clears the lowest set bit using bitset &= bitset - 1. Additionally, the comment above this loop has been updated to scope any named instruction lowering specifically to the amd64 ISA.

Why was it changed?

The previous implementation performed extra arithmetic work (including popcount and bitwise XOR) for every single set bit during dense bitmap materialization. By leveraging standard compiler intrinsic patterns, the decoding overhead is reduced.

How was it changed?

The implementation in bitmapcontainer.go was updated. A comprehensive property-based test TestBitmapContainerFillLeastSignificant16bitsProperties was added to bitmapcontainer_test.go and a new benchmark BenchmarkBitmapContainerFillLeastSignificant16bits was added to bitmapcontainer_bench_test.go.

Testing

Standard repository-level correctness tests run and pass. The test suite covering fillLeastSignificant16bits correctness (Verify fillLeastSignificant16bits correctness, which executes the TestRle16RandomFillLeastSignificant16bits029 test) runs successfully, as does the newly added differential property test TestBitmapContainerFillLeastSignificant16bitsProperties.

Formatting

The code adheres strictly to repository code style guidelines:

  • Go formatting is perfectly formatted and verified via the standard gofmt code formatting check.
  • Static analysis checks for unnecessary type conversions have been run and passed via go tool unconvert.

Fuzzing

Input validation and boundary coverage are verified through extensive property-based test sweeps. The property-based tests cover random dense and sparse regimes over the full 16-bit container bounds.

Performance Impact

Co-measured benchmark runs on the tested amd64 architecture show a significant improvement in execution time with no changes in memory allocations or object counts. The benchmark was authored by the agent to measure this specific container materialization hot path.

Before:
BenchmarkBitmapContainerFillLeastSignificant16bits-4 1000000 41864.5 ns/op 0 B/op 0 allocs/op

After:
BenchmarkBitmapContainerFillLeastSignificant16bits-4 1000000 29265 ns/op 0 B/op 0 allocs/op

  • ns/op: 41864.5 -> 29265 (effect 30.0959% improvement, p=1.08251e-05, significant, candidate n=10) [PRIMARY WIN outcome=won]
  • B/op: 0 -> 0 (effect 0%, p=1, not significant, candidate n=10) [GUARDRAIL outcome=held]
  • allocs/op: 0 -> 0 (effect 0%, p=1, not significant, candidate n=10) [GUARDRAIL outcome=held]

Reproduction

To reproduce these measurements, run the following benchmark command in the repository root:

go test -bench='^BenchmarkBitmapContainerFillLeastSignificant16bits$' -run='^$' -count=10 -benchmem .

Testing Environment

  • OS: linux
  • Architecture: amd64
  • Runtime: go1.26.4
  • Baseline Commit: dac837d3bbc8b5113e8a313372139bf0cf4f7a23
  • Candidate Commit: 27eb31dc3f7baadf776f5e94b6888a278ec3a21d

Breaking Changes

There are no breaking changes. This change is entirely backwards-compatible and introduces no behavior or API modifications.

Alternatives and Prior Candidates Tried

The following alternative candidates were developed and evaluated during the refinement process for this case:

  • cand_at53nxpm5g (commit 45732f8bc1ccbd1f3658766a311345d9149023a0): Replaced the legacy isolate-lowest-bit plus popcount(t-1) decode loop in bitmapContainer.fillLeastSignificant16bits with math/bits.TrailingZeros64(bitset) and bitset &= bitset - 1 but did not include the comprehensive property-based tests.
  • cand_3y82vyccvm (commit 8936137470283be1f3600a661232add5c3c801fb): Added the property test and benchmark, but retained an obsolete assembly comment.
  • cand_d2z8fp1zze (commit 2e80009f045a1bc4f80ceb4cf2fe8de9101818ae): Optimized the dense bitmap array materialization and updated comments, but the comments made a universal (architecture-independent) claim about the lowering to TZCNT/BLSR. The current candidate cand_6ad8gs5srw addresses feedback by scoping that comment specifically to the amd64 architecture.

Full proof of optimization and verified measurements can be found on the canonical case page: https://app.perfloop.ai/t/oss/case_74j4gzmye2


This is an automated, human-reviewed Perfloop contribution opened by perfloop-agent. The body links to reproducible proof for the change. The change was benchmarked on perfloop/roaring, an automation fork of RoaringBitmap/roaring; the commit on this PR's head branch carries the proof.

Assisted-by: PerfloopAgent:gemini-3.5-flash

…ingZeros64

Signed-off-by: Perfloop Agent <agent@perfloop.ai>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant