Repository navigation
Faster range cardinality and flip of 32-bit bitmaps - #961
Merged
Merged
Conversation
roaring_bitmap_range_cardinality() counted the values of a range in a bitset container as the difference of two ranks, each a popcount from the start of the container: up to 2048 words for a range of a few words. The new container_range_cardinality() counts only the words of the range, or the words outside it when that is shorter. roaring_bitmap_flip() looked up each key of the range with two binary searches, one in the input and one in the result, and inserted into the result. It now visits the keys of the range and the containers of the input together in one pass, and appends to the result. A full container flips to nothing, so it is skipped without building an empty container.
lemire
added a commit
to lemire/valkey
that referenced
this pull request
Nov 4, 2026
roaring.c and roaring.h are the amalgamation of CRoaring at commit b4cc0c48cd608addf91cf1595b2f268d9b2d2e66, unchanged: the merge of RoaringBitmap/CRoaring#961, after release 5.5.5. They are built with CRoaring's amalgamation.sh in the C locale, which gives the release files when run at a release tag. ROARING_VERSION still reads 5.5.5. CRoaring#961 makes roaring_bitmap_range_cardinality() count only the words of the range in bitset containers, and roaring_bitmap_flip() a single pass that skips full containers. On an Intel Xeon Gold 6548N, server-side: - BITCOUNT over 1 KB of a dense bitmap: 2.45 us to 0.88 us; - BITOP NOT on a 50M-bit prefix: 54 us to 9.4 us; - BITOP NOT on 100k random 32-bit ids: 7.9 ms to 3.4 ms. deps/README.md documents the pinned commit and how to build the files from a commit. Signed-off-by: Daniel Lemire <daniel@lemire.me>
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.
Two 32-bit operations were slow when Valkey's Roaring encoding of strings used them for
BITCOUNT key start endandBITOP NOT. Profiles showedcontainer_rankat 46% of a 1 KBBITCOUNT, and most of aBITOP NOTinroaring_bitmap_flip_closeditself.Changes
roaring_bitmap_range_cardinality(): in the first and last containers of the range, it subtracted two ranks. In a bitset container each rank is a popcount from the start of the container, so counting a range of 128 words could read up to 2048. The newcontainer_range_cardinality()counts the values in[min, max]:roaring_bitmap_flip(): each key of the range cost two binary searches (input and result) and an insertion into the result. It now visits the keys of the range and the containers of the input together, in one pass, and appends to the result. A full container flips to nothing and is skipped, instead of building and freeing an empty container.insert_flipped_container()andinsert_fully_flipped_container()are removed: nothing else used them.roaring_bitmap_flip_inplace()is unchanged.Results
Intel Xeon Gold 6548N, GCC 14
-O3 -march=native, best of 10 (range cardinality, 20,000 random ranges) or 20 (flip) runs:In Valkey (server-side time per call),
BITCOUNTover 1 KB of a dense bitmap goes from 2.45 µs to 0.88 µs, andBITOP NOTon a 50M-bit prefix from 54 µs to 9.4 µs.Benchmark program
Testing
test_range_cardinality_and_flip_by_containerintoplevel_unit: checks range cardinality and flip against a plain bit array, for ranges ending inside and on the boundaries of chunks holding each kind of container (missing, array, bitset, full, one run, many runs).ctest: all 27 suites pass, also withROARING_SANITIZE=ON.