26 : identity_(std::move(other.identity_)),
27 index_offsets_(std::move(other.index_offsets_)),
28 index_postings_(std::move(other.index_postings_)),
29 index_keys_(std::move(other.index_keys_)),
30 key_directory_(std::move(other.key_directory_)),
31 bitmap_cells_(std::move(other.bitmap_cells_)),
32 posting_bitmaps_(std::move(other.posting_bitmaps_)),
33 bitmap_count_(std::exchange(other.bitmap_count_, 0U)),
34 index_posting_capacity_(std::exchange(other.index_posting_capacity_, 0)),
35 pair_work_(std::exchange(other.pair_work_, 0ULL)),
36 pair_fraction_(std::exchange(other.pair_fraction_, 0.0)),
37 indexed_(std::exchange(other.indexed_,
false)) {}
42 identity_ = std::move(other.identity_);
43 index_offsets_ = std::move(other.index_offsets_);
44 index_postings_ = std::move(other.index_postings_);
45 index_keys_ = std::move(other.index_keys_);
46 key_directory_ = std::move(other.key_directory_);
47 bitmap_cells_ = std::move(other.bitmap_cells_);
48 posting_bitmaps_ = std::move(other.posting_bitmaps_);
49 bitmap_count_ = std::exchange(other.bitmap_count_, 0U);
50 index_posting_capacity_ = std::exchange(other.index_posting_capacity_, 0);
51 pair_work_ = std::exchange(other.pair_work_, 0ULL);
52 pair_fraction_ = std::exchange(other.pair_fraction_, 0.0);
53 indexed_ = std::exchange(other.indexed_,
false);
67 cuda::stream_ref stream,
72 CUDDL_TRY(index.measure_pair_fraction(database, stream));
74 CUDDL_TRY(index.build_posting_bitmaps(database, stream));
83 return pair_fraction_;
88 return index_offsets_.size() *
sizeof(uint32_t) +
89 index_postings_.size() *
sizeof(uint32_t) + index_keys_.size() *
sizeof(uint16_t);
95 measure_pair_fraction(database_type
const& database, cuda::stream_ref stream) {
96 auto const reference_count = database.reference_count();
97 auto const compatibility = database.metadata().compatibility;
100 if (reference_count == 0U || compatibility.indexed_bucket_count == 0U) {
104 cuda::make_device_buffer<unsigned long long>(stream, stream.device(), 1U, 0ULL)
106 detail::index_pair_work_kernel<<<
108 warp_grid_blocks(
static_cast<size_t>(compatibility.indexed_bucket_count) * 1024U),
112 index_offsets_.empty() ? nullptr : index_offsets_.data(),
113 index_keys_.empty() ? nullptr : index_keys_.data(),
115 compatibility.indexed_bucket_count,
116 static_cast<uint32_t
>(compatibility.key_mask) + 1U,
120 unsigned long long host = 0U;
121 CUDDL_CUDA_TRY(cuda::copy_bytes(stream, work, cuda::std::span{&host,
size_t{1}}));
124 pair_fraction_ =
static_cast<double>(pair_work_) /
126 compatibility.indexed_bucket_count);
130 reference_index(database_type
const& database, cuda::stream_ref stream)
131 : identity_(database.identity_),
132 index_offsets_(stream,
cuda::device_default_memory_pool(stream.device())),
133 index_postings_(stream,
cuda::device_default_memory_pool(stream.device())),
134 index_keys_(stream,
cuda::device_default_memory_pool(stream.device())),
135 key_directory_(stream,
cuda::device_default_memory_pool(stream.device())),
136 bitmap_cells_(stream,
cuda::device_default_memory_pool(stream.device())),
137 posting_bitmaps_(stream,
cuda::device_default_memory_pool(stream.device())) {}
139 template <
typename Row>
140 [[nodiscard]]
static Result<reference_index>
142 auto compatibility = source.metadata().compatibility;
146 cuda::make_device_buffer<Row>(
149 static_cast<size_t>(source.reference_count()) * BucketCount,
153 CUDDL_TRY(source.copy_scores_async({decoded.data(), decoded.size()}, stream));
154 auto rows = device_span<Row const>{decoded.data(), decoded.size()};
161 auto const validated = database_type::validate_rows(rows, compatibility);
163 return Err(validated.error());
166 if (posting_capacity > std::numeric_limits<uint32_t>::max()) {
169 if (posting_capacity > std::numeric_limits<size_t>::max() /
sizeof(uint32_t)) {
173 auto const offset_count = cell_count + 1U;
174 if (offset_count > std::numeric_limits<size_t>::max() /
sizeof(uint32_t)) {
181 index.template build_sparse_index<Row>(rows, compatibility, *validated, stream)
183 index.indexed_ =
true;
187 cuda::make_device_buffer<uint32_t>(
188 stream, stream.device(),
static_cast<size_t>(offset_count), cuda::no_init
192 CUDDL_CUDA_TRY(cuda::fill_bytes(stream, index.index_offsets_, 0));
193 index.indexed_ =
true;
197 cuda::make_device_buffer<uint32_t>(
198 stream, stream.device(),
static_cast<size_t>(posting_capacity), cuda::no_init
201 index.index_posting_capacity_ =
static_cast<size_t>(posting_capacity);
203 auto const indexed_row_count =
static_cast<size_t>(posting_capacity);
210 cuda::make_device_buffer<Row>(stream, stream.device(), indexed_row_count, cuda::no_init)
212 constexpr uint32_t transpose_tile = 32U;
213 dim3
const transpose_grid(
214 (compatibility.indexed_bucket_count + transpose_tile - 1U) / transpose_tile,
215 (reference_count + transpose_tile - 1U) / transpose_tile
217 detail::transpose_indexed_scores_kernel<<<
219 dim3(transpose_tile, transpose_tile),
224 compatibility.indexed_bucket_count,
225 static_cast<uint32_t
>(BucketCount),
234 constexpr uint32_t build_wave_blocks = 64;
235 constexpr uint32_t build_bucket_block_size = 1024;
236 auto const bucket_blocks =
237 std::min<uint32_t>(compatibility.indexed_bucket_count, build_wave_blocks);
241 auto const key_count =
static_cast<uint32_t
>(compatibility.key_mask) + 1U;
242 auto const bucket_smem_bytes =
static_cast<size_t>(
key_count / 4U) *
sizeof(uint32_t);
244 reinterpret_cast<void const*
>(detail::count_index_cells_bucket_kernel<Row>),
245 cudaFuncAttributeMaxDynamicSharedMemorySize,
246 static_cast<int>(bucket_smem_bytes)
249 reinterpret_cast<void const*
>(detail::scatter_index_postings_bucket_kernel<Row>),
250 cudaFuncAttributeMaxDynamicSharedMemorySize,
251 static_cast<int>(bucket_smem_bytes)
257 detail::count_index_cells_bucket_kernel<<<
259 build_bucket_block_size,
263 compatibility.indexed_bucket_count,
265 compatibility.key_mask,
266 index.index_offsets_.data()
271 cub::DeviceScan::ExclusiveSum(
272 index.index_offsets_.data(),
static_cast<int64_t
>(cell_count + 1U), stream
276 detail::scatter_index_postings_bucket_kernel<<<
278 build_bucket_block_size,
282 compatibility.indexed_bucket_count,
284 compatibility.key_mask,
285 index.index_offsets_.data(),
286 index.index_postings_.data()
292 cuda::make_device_buffer<uint32_t>(
293 stream, stream.device(),
static_cast<size_t>(posting_capacity), cuda::no_init
297 cub::DeviceSegmentedSort::SortKeys(
298 index.index_postings_.data(),
300 static_cast<int64_t
>(posting_capacity),
301 static_cast<int64_t
>(cell_count),
302 index.index_offsets_.data(),
303 index.index_offsets_.data() + 1,
307 index.index_postings_ = std::move(sorted);
308 index.indexed_ =
true;
312 template <
typename Row>
313 [[nodiscard]] Result<void> build_sparse_index(
314 device_span<Row const> rows,
315 score_compatibility
const& compatibility,
316 uint32_t reference_count,
317 cuda::stream_ref stream
321 index_posting_capacity_ = size;
325 auto const device = stream.device();
327 CUDDL_CUDA_TRY(cuda::make_device_buffer<uint16_t>(stream, device, size, cuda::no_init));
329 CUDDL_CUDA_TRY(cuda::make_device_buffer<uint32_t>(stream, device, size, cuda::no_init));
331 CUDDL_CUDA_TRY(cuda::make_device_buffer<uint16_t>(stream, device, size, cuda::no_init));
333 CUDDL_CUDA_TRY(cuda::make_device_buffer<uint32_t>(stream, device, size, cuda::no_init));
335 CUDDL_CUDA_TRY(cuda::make_device_buffer<Row>(stream, device, size, cuda::no_init));
336 detail::transpose_indexed_scores_kernel<<<
337 dim3((compatibility.indexed_bucket_count + 31U) / 32U, (reference_count + 31U) / 32U),
343 compatibility.indexed_bucket_count,
344 static_cast<uint32_t
>(BucketCount),
348 auto const mask = compatibility.key_mask;
352 cub::DeviceTransform::Transform(
353 transposed.data(),
keys.data(), size, detail::sparse_index_key{mask}, stream
357 cub::DeviceTransform::Transform(
358 cuda::make_counting_iterator(uint32_t{0}),
361 detail::sparse_reference_id{reference_count},
365 auto const segment_offsets = cuda::make_transform_iterator(
366 cuda::make_counting_iterator(uint32_t{0}),
371 cub::DeviceSegmentedSort::StableSortPairs(
375 index_postings_.data(),
376 static_cast<int64_t
>(size),
377 static_cast<int64_t
>(compatibility.indexed_bucket_count),
383 return build_key_directory(reference_count, compatibility.indexed_bucket_count, stream);
387 [[nodiscard]] Result<void> build_key_directory(
388 uint32_t reference_count,
389 uint32_t indexed_bucket_count,
390 cuda::stream_ref stream
393 indexed_bucket_count;
394 if (index_keys_.empty() || size == 0U) {
398 cuda::make_device_buffer<uint32_t>(stream, stream.device(), size, cuda::no_init)
400 auto const blocks =
static_cast<uint32_t
>(
403 detail::build_sparse_directory_kernel<<<blocks,
detail::block_size, 0, stream.get()>>>(
406 return cuda_try(cudaGetLastError());
409 [[nodiscard]] Result<void>
410 build_posting_bitmaps(database_type
const& database, cuda::stream_ref stream) {
411 auto const references = database.reference_count();
412 auto const buckets = database.metadata().compatibility.indexed_bucket_count;
413 if (references < 8192U || buckets == 0U || buckets > 65535U) {
416 auto const words = detail::candidate_bit_words(references);
418 cuda::make_device_buffer<uint32_t>(
419 stream, stream.device(), index_posting_capacity_ / words, cuda::no_init
423 cuda::make_device_buffer<uint32_t>(stream, stream.device(), 1U, cuda::no_init)
425 auto const*
offsets = index_offsets_.data();
426 auto const*
keys = index_keys_.empty() ? nullptr : index_keys_.data();
427 auto const cells =
keys ==
nullptr ? index_offsets_.size() - 1U : index_keys_.size();
429 cub::DeviceSelect::If(
430 cuda::make_counting_iterator(uint32_t{0}),
431 bitmap_cells_.data(),
433 static_cast<int64_t
>(cells),
434 detail::posting_bitmap_cell{offsets, keys, references, words},
439 cuda::copy_bytes(stream, selected, cuda::std::span{&bitmap_count_,
size_t{1}})
442 if (bitmap_count_ == 0U)
return Ok();
444 cuda::make_device_buffer<uint32_t>(
445 stream, stream.device(),
static_cast<size_t>(bitmap_count_) * words, cuda::no_init
451 bitmap_cells_.data(),
455 static_cast<uint32_t
>(database.metadata().compatibility.key_mask) + 1U,
456 index_postings_.data(),
458 posting_bitmaps_.data()
460 return cuda_try(cudaGetLastError());
463 std::shared_ptr<char const> identity_;
464 cuda::device_buffer<uint32_t> index_offsets_;
465 cuda::device_buffer<uint32_t> index_postings_;
466 cuda::device_buffer<uint16_t> index_keys_;
468 cuda::device_buffer<uint32_t> key_directory_;
469 cuda::device_buffer<uint32_t> bitmap_cells_;
470 cuda::device_buffer<uint32_t> posting_bitmaps_;
471 uint32_t bitmap_count_{};
472 size_t index_posting_capacity_{};
474 unsigned long long pair_work_{};
475 double pair_fraction_{};