Skip to content

Commit 90b6fc5

Browse files
committed
64-bit roaring bitmap
1 parent 26e23da commit 90b6fc5

File tree

9 files changed

+749
-196
lines changed

9 files changed

+749
-196
lines changed
46.9 KB
Binary file not shown.
Lines changed: 97 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,129 @@
1-
#include <cuco/detail/error.hpp>
1+
/*
2+
* Copyright (c) 2025 NVIDIA CORPORATION.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
216
#include <cuco/roaring_bitmap.cuh>
17+
#include <cuco/utility/traits.hpp>
318

4-
#include <cuda/std/span>
19+
#include <cuda/std/type_traits>
20+
#include <thrust/device_vector.h>
521
#include <thrust/logical.h>
622
#include <thrust/universal_vector.h>
723

8-
#include <cuda_runtime.h>
9-
1024
#include <fstream>
1125
#include <iostream>
26+
#include <string>
1227
#include <vector>
1328

14-
int main(int argc, char* argv[])
29+
/**
30+
* @file host_bulk_example.cu
31+
* @brief Demonstrates usage of the roaring_bitmap "bulk" lookup host APIs.
32+
*
33+
* In this example we load two 32-bit bitmaps and one 64-bit bitmap (portable format) from the
34+
* [RoaringBitmapFormatSpec](https://github.com/RoaringBitmap/RoaringFormatSpec) repository and
35+
* check if the bulk lookup API returns the correct results. Namely, we test the following files:
36+
* -
37+
* [examples/roaring_bitmap/bitmapwithoutruns.bin](https://github.com/RoaringBitmap/RoaringFormatSpec/blob/master/testdata/bitmapwithoutruns.bin)
38+
* -
39+
* [examples/roaring_bitmap/bitmapwithruns.bin](https://github.com/RoaringBitmap/RoaringFormatSpec/blob/master/testdata/bitmapwithruns.bin)
40+
* -
41+
* [examples/roaring_bitmap/portable_bitmap64.bin](https://github.com/RoaringBitmap/RoaringFormatSpec/blob/master/testdata64/portable_bitmap64.bin)
42+
*
43+
*/
44+
45+
template <typename KeyType>
46+
bool check(std::string const& bitmap_file_path)
1547
{
16-
if (argc != 2) {
17-
std::cerr << "Usage: " << argv[0] << " <bitmap_file_path>" << std::endl;
18-
return -1;
19-
}
48+
auto generate_keys = []() -> thrust::device_vector<KeyType> {
49+
if constexpr (cuda::std::is_same_v<KeyType, cuda::std::uint32_t>) {
50+
// reference:
51+
// https://github.com/RoaringBitmap/RoaringFormatSpec/blob/master/testdata/README.md#test-data
52+
std::vector<cuda::std::uint32_t> keys;
53+
for (cuda::std::uint32_t k = 0; k < 100000; k += 1000) {
54+
keys.push_back(k);
55+
}
56+
for (int k = 100000; k < 200000; ++k) {
57+
keys.push_back(3 * k);
58+
}
59+
for (int k = 700000; k < 800000; ++k) {
60+
keys.push_back(k);
61+
}
62+
return thrust::device_vector<cuda::std::uint32_t>(keys.begin(), keys.end());
63+
} else if constexpr (cuda::std::is_same_v<KeyType, cuda::std::uint64_t>) {
64+
// reference:
65+
// https://github.com/RoaringBitmap/RoaringFormatSpec/blob/master/testdata64/README.md#portable_bitmap64bin
66+
std::vector<cuda::std::uint64_t> keys;
67+
for (cuda::std::uint64_t k = 0x00000ull; k < 0x09000ull; ++k) {
68+
keys.push_back(k);
69+
}
70+
for (cuda::std::uint64_t k = 0x0A000ull; k < 0x10000ull; ++k) {
71+
keys.push_back(k);
72+
}
73+
keys.push_back(0x20000ull);
74+
keys.push_back(0x20005ull);
75+
for (cuda::std::uint64_t i = 0; i < 0x10000ull; i += 2ull) {
76+
keys.push_back(0x80000ull + i);
77+
}
78+
return thrust::device_vector<cuda::std::uint64_t>(keys.begin(), keys.end());
79+
} else {
80+
static_assert(cuco::dependent_false<KeyType>, "KeyType must be uint32_t or uint64_t");
81+
return {};
82+
}
83+
};
2084

2185
// Open file
22-
std::ifstream file(argv[1], std::ios::binary);
86+
std::ifstream file(bitmap_file_path, std::ios::binary);
2387
if (!file.is_open()) {
24-
std::cerr << "Failed to open " << argv[1] << std::endl;
25-
return -1;
88+
std::cerr << "Failed to open " << bitmap_file_path << std::endl;
89+
return false;
2690
}
2791

2892
// Get file size
2993
file.seekg(0, std::ios::end);
3094
std::streamsize file_size = file.tellg();
3195
file.seekg(0, std::ios::beg);
3296

33-
// Allocate pinned host memory using cudaMallocHost
34-
char* buffer;
35-
CUCO_CUDA_TRY(cudaMallocHost(&buffer, file_size));
97+
thrust::universal_host_pinned_vector<cuda::std::byte> buffer(file_size);
3698

3799
// Read file into memory
38-
file.read(buffer, file_size);
100+
file.read(reinterpret_cast<char*>(thrust::raw_pointer_cast(buffer.data())), file_size);
39101
file.close();
40102

41-
cuco::roaring_bitmap<cuda::std::uint32_t> roaring_bitmap(
42-
reinterpret_cast<cuda::std::byte const*>(buffer));
103+
cuco::roaring_bitmap<KeyType> roaring_bitmap(thrust::raw_pointer_cast(buffer.data()));
43104

44-
std::vector<cuda::std::uint32_t> keys;
45-
for (cuda::std::uint32_t k = 0; k < 100000; k += 1000) {
46-
keys.push_back(k);
47-
}
48-
for (int k = 100000; k < 200000; ++k) {
49-
keys.push_back(3 * k);
50-
}
51-
for (int k = 700000; k < 800000; ++k) {
52-
keys.push_back(k);
53-
}
105+
auto keys = generate_keys();
106+
thrust::device_vector<bool> contained(keys.size(), false);
54107

55-
thrust::universal_vector<cuda::std::uint32_t> keys_d(keys.begin(), keys.end());
56-
thrust::universal_vector<bool> contained(keys.size(), false);
108+
roaring_bitmap.contains(keys.begin(), keys.end(), contained.begin());
57109

58-
roaring_bitmap.contains(keys_d.begin(), keys_d.end(), contained.begin());
110+
bool all_contained = thrust::all_of(contained.begin(), contained.end(), ::cuda::std::identity{});
111+
return all_contained;
112+
}
59113

60-
size_t num_errors = 0;
61-
for (size_t i = 0; i < keys.size(); i++) {
62-
if (not contained[i]) {
63-
if (num_errors <= 10) {
64-
std::cout << "Error: " << keys_d[i] << " is not contained" << std::endl;
65-
}
66-
num_errors++;
67-
}
68-
}
69-
if (num_errors > 0) { std::cout << "num_errors: " << num_errors << std::endl; }
114+
int main()
115+
{
116+
auto data_dir_prefix = []() -> std::string {
117+
std::string source_path = __FILE__;
118+
auto pos = source_path.find_last_of("/\\");
119+
return (pos == std::string::npos) ? std::string(".") : source_path.substr(0, pos);
120+
};
70121

71-
// check if all elements are contained and written to output
72-
bool all_contained = thrust::all_of(contained.begin(), contained.end(), ::cuda::std::identity{});
73-
std::cout << "all_contained: " << all_contained << std::endl;
122+
bool success = check<cuda::std::uint32_t>(data_dir_prefix() + "/bitmapwithoutruns.bin");
123+
success &= check<cuda::std::uint32_t>(data_dir_prefix() + "/bitmapwithruns.bin");
124+
success &= check<cuda::std::uint64_t>(data_dir_prefix() + "/portable_bitmap64.bin");
74125

75-
// Free the allocated memory
76-
CUCO_CUDA_TRY(cudaFreeHost(buffer));
126+
std::cout << "success: " << (success ? "true" : "false") << std::endl;
77127

78-
return 0;
128+
return success ? 0 : 1;
79129
}
16.1 KB
Binary file not shown.

include/cuco/detail/roaring_bitmap/roaring_bitmap.inl

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ template <class T, class Allocator>
2525
roaring_bitmap<T, Allocator>::roaring_bitmap(cuda::std::byte const* bitmap,
2626
Allocator const& alloc,
2727
cuda::stream_ref stream)
28-
: storage_{bitmap, alloc, stream}, ref_{storage_.ref()}
28+
: storage_{bitmap, alloc, stream}
2929
{
3030
}
3131

@@ -36,7 +36,7 @@ void roaring_bitmap<T, Allocator>::contains(InputIt first,
3636
OutputIt output,
3737
cuda::stream_ref stream) const
3838
{
39-
ref_.contains(first, last, output, stream);
39+
ref_type{storage_.ref()}.contains(first, last, output, stream);
4040
}
4141

4242
template <class T, class Allocator>
@@ -46,31 +46,31 @@ void roaring_bitmap<T, Allocator>::contains_async(InputIt first,
4646
OutputIt output,
4747
cuda::stream_ref stream) const noexcept
4848
{
49-
ref_.contains_async(first, last, output, stream);
49+
ref_type{storage_.ref()}.contains_async(first, last, output, stream);
5050
}
5151

5252
template <class T, class Allocator>
5353
cuda::std::size_t roaring_bitmap<T, Allocator>::size() const noexcept
5454
{
55-
return ref_.size();
55+
return ref_type{storage_.ref()}.size();
5656
}
5757

5858
template <class T, class Allocator>
5959
bool roaring_bitmap<T, Allocator>::empty() const noexcept
6060
{
61-
return ref_.empty();
61+
return ref_type{storage_.ref()}.empty();
6262
}
6363

6464
template <class T, class Allocator>
6565
cuda::std::byte const* roaring_bitmap<T, Allocator>::data() const noexcept
6666
{
67-
return ref_.data();
67+
return ref_type{storage_.ref()}.data();
6868
}
6969

7070
template <class T, class Allocator>
7171
cuda::std::size_t roaring_bitmap<T, Allocator>::size_bytes() const noexcept
7272
{
73-
return ref_.size_bytes();
73+
return ref_type{storage_.ref()}.size_bytes();
7474
}
7575

7676
template <class T, class Allocator>
@@ -83,6 +83,6 @@ typename roaring_bitmap<T, Allocator>::allocator_type roaring_bitmap<T, Allocato
8383
template <class T, class Allocator>
8484
typename roaring_bitmap<T, Allocator>::ref_type roaring_bitmap<T, Allocator>::ref() const noexcept
8585
{
86-
return ref_;
86+
return ref_type{storage_.ref()};
8787
}
8888
} // namespace cuco

0 commit comments

Comments
 (0)