cuDDL
Loading...
Searching...
No Matches
reference_deltas.cuh
Go to the documentation of this file.
1#pragma once
2
3#include <cub/device/device_radix_sort.cuh>
4#include <cub/device/device_scan.cuh>
5#include <cub/device/device_select.cuh>
6#include <cuda/buffer>
7#include <cuda/iterator>
8#include <cuda/std/cstdint>
9#include <cuda/std/functional>
10#include <cuda/stream>
11
12#include <optional>
13
15#include <cuddl/error.hpp>
16
17namespace cuddl::detail {
18
20constexpr uint32_t delta_change_limit = 160U;
22constexpr uint32_t delta_signatures = 8U;
23constexpr uint32_t delta_signature_buckets = 8U;
25constexpr uint32_t delta_signature_candidates = 4U;
29constexpr uint32_t delta_correction_warps = 24U;
30constexpr uint32_t delta_child_tile = 2048U;
32
35template <size_t BucketCount>
36constexpr uint32_t delta_query_group = static_cast<uint32_t>(32768U / BucketCount);
37
38template <size_t BucketCount>
40 BucketCount * delta_query_group<BucketCount> * sizeof(uint16_t) +
41 size_t{delta_correction_warps} * delta_change_limit * sizeof(uint2);
42
50 uint32_t const* base_bits = nullptr;
53 uint4 const* children = nullptr;
58 uint2 const* records = nullptr;
59 uint32_t child_count = 0U;
60};
61
63 cuda::device_buffer<uint32_t> base_bits;
64 cuda::device_buffer<uint4> children;
65 cuda::device_buffer<uint2> records;
66
67 [[nodiscard]] reference_delta_view view() const noexcept {
68 return {
69 base_bits.data(),
70 children.data(),
71 records.data(),
72 static_cast<uint32_t>(children.size()),
73 };
74 }
75};
76
79template <size_t BucketCount>
80__global__ __launch_bounds__(block_size) void delta_signature_kernel(
81 uint16_t const* rows,
82 uint32_t count,
83 uint32_t signature,
84 uint64_t* keys,
85 uint32_t* ids
86) {
87 constexpr uint32_t spacing =
88 static_cast<uint32_t>(BucketCount / (delta_signatures * delta_signature_buckets));
89 for (auto i = blockIdx.x * blockDim.x + threadIdx.x; i < count; i += gridDim.x * blockDim.x) {
90 auto const row = count - 1U - i;
91 uint64_t key = signature + 1U;
92 _Pragma("unroll")
93 for (uint32_t j = 0; j < delta_signature_buckets; ++j) {
94 auto const bucket = (signature * delta_signature_buckets + j) * spacing;
95 key = (key ^ rows[static_cast<size_t>(row) * BucketCount + bucket]) *
96 0x9e3779b97f4a7c15ULL;
97 key ^= key >> 29U;
98 }
99 keys[i] = key;
100 ids[i] = row;
101 }
102}
103
105__global__ __launch_bounds__(
107) void delta_run_heads_kernel(uint64_t const* keys, uint32_t count, uint32_t* starts) {
108 for (auto p = blockIdx.x * blockDim.x + threadIdx.x; p < count; p += gridDim.x * blockDim.x) {
109 starts[p] = p == 0U || keys[p] != keys[p - 1U] ? p : 0U;
110 }
111}
112
114__global__ __launch_bounds__(block_size) void delta_candidates_kernel(
115 uint32_t const* ids,
116 uint32_t const* starts,
117 uint32_t count,
118 uint32_t signature,
119 uint32_t* candidates
120) {
121 for (auto p = blockIdx.x * blockDim.x + threadIdx.x; p < count; p += gridDim.x * blockDim.x) {
122 auto* const out = candidates + static_cast<size_t>(ids[p]) * delta_candidates +
124 _Pragma("unroll")
125 for (uint32_t j = 0; j < delta_signature_candidates; ++j) {
126 auto const q = starts[p] + j;
127 out[j] = q < p ? ids[q] : ~0U;
128 }
129 }
130}
131
133template <size_t BucketCount, bool Closest>
134__global__ __launch_bounds__(block_size) void delta_targets_kernel(
135 uint16_t const* rows,
136 uint32_t count,
137 uint32_t const* candidates,
138 uint8_t const* is_base,
139 uint32_t* targets,
140 uint32_t* changes
141) {
142 constexpr uint32_t vectors = static_cast<uint32_t>(BucketCount / 8U);
143 auto const lane = threadIdx.x % 32U;
144 for (auto row = (blockIdx.x * blockDim.x + threadIdx.x) / 32U; row < count;
145 row += gridDim.x * blockDim.x / 32U) {
146 if constexpr (Closest) {
147 if (is_base[row] != 0U || changes[row] == 0U) {
148 continue;
149 }
150 }
151 auto target = Closest ? targets[row] : row;
152 uint32_t changed = Closest ? changes[row] : 0U;
153 auto candidate = candidates[static_cast<size_t>(row) * delta_candidates + lane];
154 if constexpr (Closest) {
155 if (candidate != ~0U && (candidate == target || is_base[candidate] == 0U)) {
156 candidate = ~0U;
157 }
158 }
159 auto const* own =
160 reinterpret_cast<uint4 const*>(rows + static_cast<size_t>(row) * BucketCount);
161 for (;;) {
162 auto const best =
163 __reduce_max_sync(0xffffffffU, candidate == ~0U ? 0U : candidate + 1U);
164 if (best == 0U) {
165 break;
166 }
167 auto const* other =
168 reinterpret_cast<uint4 const*>(rows + static_cast<size_t>(best - 1U) * BucketCount);
169 uint32_t differ = 0U;
170 for (auto v = lane; v < vectors; v += 32U) {
171 auto const a = own[v];
172 auto const b = other[v];
173 uint32_t const words[4] = {a.x ^ b.x, a.y ^ b.y, a.z ^ b.z, a.w ^ b.w};
174 _Pragma("unroll")
175 for (auto const x : words) {
176 differ += ((x & 0xffffU) != 0U) + ((x >> 16U) != 0U);
177 }
178 }
179 differ = __reduce_add_sync(0xffffffffU, differ);
180 if (Closest ? differ < changed : differ <= delta_change_limit) {
181 target = best - 1U;
182 changed = differ;
183 if (!Closest || differ == 0U) {
184 break;
185 }
186 }
187 if (candidate == best - 1U) {
188 candidate = ~0U;
189 }
190 }
191 if (lane == 0U) {
192 targets[row] = target;
193 changes[row] = changed;
194 }
195 }
196}
197
198__global__ __launch_bounds__(
200) void delta_mark_bases_kernel(uint32_t const* targets, uint32_t count, uint8_t* is_base) {
201 for (auto row = blockIdx.x * blockDim.x + threadIdx.x; row < count;
202 row += gridDim.x * blockDim.x) {
203 auto const target = targets[row];
204 is_base[target] = 1U;
205 }
206}
207
210__global__ __launch_bounds__(block_size) void delta_classify_kernel(
211 uint8_t const* is_base,
212 uint32_t count,
213 uint32_t* changes,
214 uint8_t* is_child,
215 uint32_t* base_bits
216) {
217 auto const words = candidate_bit_words(count);
218 for (auto row = blockIdx.x * blockDim.x + threadIdx.x; row < words * 32U;
219 row += gridDim.x * blockDim.x) {
220 auto const base = row < count && is_base[row] != 0U;
221 if (row < count) {
222 is_child[row] = !base;
223 if (base) {
224 changes[row] = 0U;
225 }
226 }
227 auto const bits = __ballot_sync(0xffffffffU, base);
228 if (row % 32U == 0U) {
229 base_bits[row / 32U] = bits;
230 }
231 }
232}
233
236template <size_t BucketCount>
237__global__ __launch_bounds__(block_size) void delta_records_kernel(
238 uint16_t const* rows,
239 uint32_t const* child_ids,
240 uint32_t const* child_count,
241 uint32_t const* targets,
242 uint32_t const* offsets,
243 uint4* children,
244 uint2* records
245) {
246 constexpr uint32_t groups = static_cast<uint32_t>(BucketCount / 32U);
247 constexpr uint32_t row_bytes = delta_query_group<BucketCount> * sizeof(uint16_t);
248 auto const lane = threadIdx.x % 32U;
249 auto const below = (1U << lane) - 1U;
250 for (auto index = (blockIdx.x * blockDim.x + threadIdx.x) / 32U; index < *child_count;
251 index += gridDim.x * blockDim.x / 32U) {
252 auto const child = child_ids[index];
253 auto const base = targets[child];
254 auto const* after_row = rows + static_cast<size_t>(child) * BucketCount;
255 auto const* before_row = rows + static_cast<size_t>(base) * BucketCount;
256 uint32_t zeros = 0U;
257 uint32_t increases = 0U;
258 for (uint32_t g = 0; g < groups; ++g) {
259 uint32_t const before = before_row[g * 32U + lane];
260 uint32_t const after = after_row[g * 32U + lane];
261 auto const changed = before != after;
262 auto const zero = changed && (before == 0U || after == 0U);
263 zeros += static_cast<uint32_t>(__popc(__ballot_sync(0xffffffffU, zero)));
264 increases += static_cast<uint32_t>(
265 __popc(__ballot_sync(0xffffffffU, changed && !zero && after > before))
266 );
267 }
268 auto const begin = offsets[child];
269 auto const count = offsets[child + 1U] - begin;
270 uint32_t next[3] = {begin, begin + zeros, begin + zeros + increases};
271 for (uint32_t g = 0; g < groups; ++g) {
272 auto const bucket = g * 32U + lane;
273 uint32_t const before = before_row[bucket];
274 uint32_t const after = after_row[bucket];
275 auto const changed = before != after;
276 auto const low = min(before, after);
277 auto const kind = low == 0U ? 0U : after > before ? 1U : 2U;
278 _Pragma("unroll")
279 for (uint32_t k = 0; k < 3U; ++k) {
280 auto const members = __ballot_sync(0xffffffffU, changed && kind == k);
281 if (changed && kind == k) {
282 auto const width = max(before, after) - low;
283 records[next[k] + static_cast<uint32_t>(__popc(members & below))] = {
284 bucket * row_bytes,
285 (k == 0U ? static_cast<uint32_t>(after < before) : low) | width << 16U,
286 };
287 }
288 next[k] += static_cast<uint32_t>(__popc(members));
289 }
290 }
291 if (lane == 0U) {
292 children[index] = {child, base, begin, count | zeros << 10U | increases << 20U};
293 }
294 }
295}
296
299template <size_t BucketCount>
300[[nodiscard]] Result<std::optional<reference_deltas>>
301build_reference_deltas(uint16_t const* rows, uint32_t count, cuda::stream_ref stream) {
302 if (count < 2U) {
303 return std::optional<reference_deltas>{};
304 }
305 auto const device = stream.device();
306 auto const grid = warp_grid_blocks(count);
307 auto const warp_grid = warp_grid_blocks(static_cast<size_t>(count) * 32U);
308 auto candidates = CUDDL_CUDA_TRY(
309 cuda::make_device_buffer<uint32_t>(
310 stream, device, static_cast<size_t>(count) * delta_candidates, cuda::no_init
311 )
312 );
313 {
314 auto keys = CUDDL_CUDA_TRY(
315 cuda::make_device_buffer<uint64_t>(stream, device, count, cuda::no_init)
316 );
318 cuda::make_device_buffer<uint64_t>(stream, device, count, cuda::no_init)
319 );
320 auto ids = CUDDL_CUDA_TRY(
321 cuda::make_device_buffer<uint32_t>(stream, device, count, cuda::no_init)
322 );
323 auto sorted_ids = CUDDL_CUDA_TRY(
324 cuda::make_device_buffer<uint32_t>(stream, device, count, cuda::no_init)
325 );
326 auto starts = CUDDL_CUDA_TRY(
327 cuda::make_device_buffer<uint32_t>(stream, device, count, cuda::no_init)
328 );
329 for (uint32_t signature = 0; signature < delta_signatures; ++signature) {
330 delta_signature_kernel<BucketCount><<<grid, block_size, 0, stream.get()>>>(
331 rows, count, signature, keys.data(), ids.data()
332 );
333 CUDDL_CUDA_TRY(cudaGetLastError());
335 cub::DeviceRadixSort::SortPairs(
336 keys.data(),
337 sorted_keys.data(),
338 ids.data(),
339 sorted_ids.data(),
340 count,
341 0,
342 64,
343 stream
344 )
345 );
346 delta_run_heads_kernel<<<grid, block_size, 0, stream.get()>>>(
347 sorted_keys.data(), count, starts.data()
348 );
349 CUDDL_CUDA_TRY(cudaGetLastError());
351 cub::DeviceScan::InclusiveScan(
352 starts.data(), cuda::maximum<uint32_t>{}, static_cast<int64_t>(count), stream
353 )
354 );
355 delta_candidates_kernel<<<grid, block_size, 0, stream.get()>>>(
356 sorted_ids.data(), starts.data(), count, signature, candidates.data()
357 );
358 CUDDL_CUDA_TRY(cudaGetLastError());
359 }
360 }
361 auto targets =
362 CUDDL_CUDA_TRY(cuda::make_device_buffer<uint32_t>(stream, device, count, cuda::no_init));
363 // One extra zero entry makes the exclusive scan's last element the record total.
364 auto offsets =
365 CUDDL_CUDA_TRY(cuda::make_device_buffer<uint32_t>(stream, device, count + 1U, 0U));
366 delta_targets_kernel<BucketCount, false><<<warp_grid, block_size, 0, stream.get()>>>(
367 rows, count, candidates.data(), nullptr, targets.data(), offsets.data()
368 );
369 CUDDL_CUDA_TRY(cudaGetLastError());
370 auto is_base = CUDDL_CUDA_TRY(cuda::make_device_buffer<uint8_t>(stream, device, count, 0U));
371 auto is_child =
372 CUDDL_CUDA_TRY(cuda::make_device_buffer<uint8_t>(stream, device, count, cuda::no_init));
373 auto base_bits = CUDDL_CUDA_TRY(
374 cuda::make_device_buffer<uint32_t>(
375 stream, device, candidate_bit_words(count), cuda::no_init
376 )
377 );
378 delta_mark_bases_kernel<<<grid, block_size, 0, stream.get()>>>(
379 targets.data(), count, is_base.data()
380 );
381 CUDDL_CUDA_TRY(cudaGetLastError());
382 delta_targets_kernel<BucketCount, true><<<warp_grid, block_size, 0, stream.get()>>>(
383 rows, count, candidates.data(), is_base.data(), targets.data(), offsets.data()
384 );
385 CUDDL_CUDA_TRY(cudaGetLastError());
386 delta_classify_kernel<<<
387 warp_grid_blocks(candidate_bit_words(count)),
389 0,
390 stream.get()>>>(is_base.data(), count, offsets.data(), is_child.data(), base_bits.data());
391 CUDDL_CUDA_TRY(cudaGetLastError());
393 cub::DeviceScan::ExclusiveSum(offsets.data(), static_cast<int64_t>(count + 1U), stream)
394 );
395 // The candidate buffer is no longer needed; its first words take the child IDs and count.
396 auto* const child_ids = candidates.data();
397 auto* const child_count = candidates.data() + count;
399 cub::DeviceSelect::Flagged(
400 cuda::make_counting_iterator(uint32_t{0}),
401 is_child.data(),
402 child_ids,
403 child_count,
404 static_cast<int64_t>(count),
405 stream
406 )
407 );
408 uint32_t totals[2] = {};
409 CUDDL_CUDA_TRY(cudaMemcpyAsync(
410 &totals[0], child_count, sizeof(uint32_t), cudaMemcpyDeviceToHost, stream.get()
411 ));
412 CUDDL_CUDA_TRY(cudaMemcpyAsync(
413 &totals[1], offsets.data() + count, sizeof(uint32_t), cudaMemcpyDeviceToHost, stream.get()
414 ));
415 if (auto const synced = cuda_try([&] { stream.sync(); }); !synced) {
416 return Err(synced.error());
417 }
418 if (totals[0] == 0U) {
419 return std::optional<reference_deltas>{};
420 }
421 auto children =
422 CUDDL_CUDA_TRY(cuda::make_device_buffer<uint4>(stream, device, totals[0], cuda::no_init));
423 auto records = CUDDL_CUDA_TRY(
424 cuda::make_device_buffer<uint2>(
425 stream, device, cuda::std::max(totals[1], 1U), cuda::no_init
426 )
427 );
428 auto deltas = reference_deltas{std::move(base_bits), std::move(children), std::move(records)};
429 delta_records_kernel<BucketCount>
430 <<<warp_grid_blocks(static_cast<size_t>(totals[0]) * 32U), block_size, 0, stream.get()>>>(
431 rows,
432 child_ids,
433 child_count,
434 targets.data(),
435 offsets.data(),
436 deltas.children.data(),
437 deltas.records.data()
438 );
439 CUDDL_CUDA_TRY(cudaGetLastError());
440 return std::optional<reference_deltas>{std::move(deltas)};
441}
442
449template <size_t BucketCount, typename SearchResult, bool UpperTriangle>
450__global__ __launch_bounds__(delta_correction_warps * 32U, 1) void apply_reference_deltas_kernel(
451 uint32_t const* query_planes,
452 uint32_t query_id_offset,
453 uint32_t query_count,
454 uint32_t reference_count,
455 reference_delta_view deltas,
456 SearchResult* results
457) {
458 constexpr uint32_t group = delta_query_group<BucketCount>;
459 constexpr uint32_t slices = 32U / group;
460 constexpr uint32_t record_registers = delta_change_limit / 32U;
461 constexpr uint32_t bucket_groups = static_cast<uint32_t>(BucketCount / 32U);
462 extern __shared__ uint16_t staged[];
463 auto const lane = threadIdx.x % 32U;
464 auto const warp = threadIdx.x / 32U;
465 auto const member = lane % group;
466 auto const slice = lane / group;
467 auto const query_groups = (query_count + group - 1U) / group;
468 // Few query groups shrink the child tiles until every block gets about two cells.
469 auto const tiles_wanted = (2U * gridDim.x + query_groups) / cuda::std::max(1U, query_groups);
470 auto const child_tile = cuda::std::clamp(
471 (deltas.child_count + tiles_wanted - 1U) / tiles_wanted,
472 uint32_t{delta_min_child_tile},
473 uint32_t{delta_child_tile}
474 );
475 auto const child_tiles = (deltas.child_count + child_tile - 1U) / child_tile;
476 auto const* const row = reinterpret_cast<char const*>(staged) + member * sizeof(uint16_t);
477 auto* const buffer =
478 reinterpret_cast<uint2*>(staged + BucketCount * group) + warp * delta_change_limit;
479 auto const load_records = [&](uint4 child, uint2(&values)[record_registers]) {
480 _Pragma("unroll")
481 for (uint32_t k = 0; k < record_registers; ++k) {
482 auto const index = lane + k * 32U;
483 values[k] = index < (child.w & 1023U) ? deltas.records[child.z + index] : uint2{};
484 }
485 };
486 for (auto cell = blockIdx.x; cell < query_groups * child_tiles; cell += gridDim.x) {
487 // Adjacent child tiles reuse a query group's base-result region.
488 auto const first_member = (cell / child_tiles) * group;
489 auto const members = cuda::std::min(group, query_count - first_member);
490 auto const begin_child = (cell % child_tiles) * child_tile;
491 auto const end_child = cuda::std::min(deltas.child_count, begin_child + child_tile);
492 if constexpr (UpperTriangle) {
493 // Children ascend, so a tile whose last child precedes the group has no pairs.
494 if (deltas.children[end_child - 1U].x <= query_id_offset + first_member) {
495 continue;
496 }
497 }
499 for (auto item = warp; item < group * bucket_groups; item += delta_correction_warps) {
500 auto const m = item % group;
501 auto const bucket_group = item / group;
502 uint32_t score = 0U;
503 if (m < members) {
504 uint32_t words[score_planes];
506 reinterpret_cast<uint4 const*>(
507 query_planes + static_cast<size_t>(first_member + m) * (BucketCount / 2U)
508 ),
509 bucket_group,
510 words
511 );
512 _Pragma("unroll")
513 for (uint32_t p = 0; p < score_planes; ++p) {
514 score |= ((words[p] >> lane) & 1U) << p;
515 }
516 }
517 staged[(bucket_group * 32U + lane) * group + m] = static_cast<uint16_t>(score);
518 }
520 auto const query = first_member + member;
521 auto child_index = begin_child + warp;
522 if (child_index >= end_child) {
523 continue;
524 }
525 auto info = deltas.children[child_index];
526 uint2 pending[record_registers];
527 load_records(info, pending);
528 auto next_info = child_index + delta_correction_warps < end_child
529 ? deltas.children[child_index + delta_correction_warps]
530 : uint4{};
531 for (; child_index < end_child; child_index += delta_correction_warps) {
532 auto const count = info.w & 1023U;
533 __syncwarp();
534 _Pragma("unroll")
535 for (uint32_t k = 0; k < record_registers; ++k) {
536 if (lane + k * 32U < count) buffer[lane + k * 32U] = pending[k];
537 }
538 __syncwarp();
539 auto const next_index = child_index + delta_correction_warps;
540 if (next_index < end_child) load_records(next_info, pending);
541 auto const following_info = next_index + delta_correction_warps < end_child
542 ? deltas.children[next_index + delta_correction_warps]
543 : uint4{};
544 auto const child = info.x;
545 auto included = member < members;
546 if constexpr (UpperTriangle) {
547 included = included && query_id_offset + query < child;
548 }
549 if (__any_sync(0xffffffffU, included)) {
550 SearchResult base{};
551 if (included && slice == 0U) {
552 base = results[batch_result_slot<UpperTriangle>(
554 )];
555 }
556 auto const zeros = (info.w >> 10U) & 1023U;
557 auto const increases = info.w >> 20U;
558 int lower = 0;
559 int higher = 0;
560 int empty_equal = 0;
561 // A low-zero change moves the query's empty buckets between lower and both-empty
562 // rather than equal, which the derived equal count corrects.
563 for (auto i = slice; i < zeros; i += slices) {
564 auto const record = buffer[i];
565 uint32_t const value = *reinterpret_cast<uint16_t const*>(row + record.x);
566 auto const width = record.y >> 16U;
567 int const sign = (record.y & 1U) != 0U ? -1 : 1;
568 lower += value < width ? sign : 0;
569 higher -= value - 1U < width ? sign : 0;
570 empty_equal += value == 0U ? sign : 0;
571 }
572 // Counts query scores in [low, low + width) and in (low, low + width].
573 auto const accumulate = [&](uint32_t begin, uint32_t end, int& inside, int& above) {
574 _Pragma("unroll 4")
575 for (auto i = begin + slice; i < end; i += slices) {
576 auto const record = buffer[i];
577 uint32_t const value = *reinterpret_cast<uint16_t const*>(row + record.x);
578 auto const offset = value - (record.y & 0xffffU);
579 auto const width = record.y >> 16U;
580 inside += offset < width;
581 above += offset - 1U < width;
582 }
583 };
584 int increase_inside = 0;
585 int increase_above = 0;
586 int decrease_inside = 0;
587 int decrease_above = 0;
588 accumulate(zeros, zeros + increases, increase_inside, increase_above);
589 accumulate(zeros + increases, count, decrease_inside, decrease_above);
590 lower += increase_inside - decrease_inside;
591 higher += decrease_above - increase_above;
592 _Pragma("unroll")
593 for (uint32_t offset = group; offset < 32U; offset *= 2U) {
594 lower += __shfl_xor_sync(0xffffffffU, lower, offset);
595 higher += __shfl_xor_sync(0xffffffffU, higher, offset);
596 empty_equal += __shfl_xor_sync(0xffffffffU, empty_equal, offset);
597 }
598 if (included && slice == 0U) {
599 auto const counts = base.unpack(static_cast<uint32_t>(BucketCount));
600 results[batch_result_slot<UpperTriangle>(
602 )] =
603 SearchResult::pack(
604 static_cast<uint32_t>(static_cast<int>(counts.lower) + lower),
605 static_cast<uint32_t>(
606 static_cast<int>(counts.equal) - lower - higher + empty_equal
607 ),
608 static_cast<uint32_t>(static_cast<int>(counts.higher) + higher)
609 );
610 }
611 }
612 info = next_info;
613 next_info = following_info;
614 }
615 }
616}
617
618} // namespace cuddl::detail
#define CUDDL_CUDA_TRY(...)
Propagates a CUDA error wrapped in cuddl::Result<void>.
Definition error.hpp:248
constexpr uint32_t delta_min_child_tile
constexpr uint32_t delta_signatures
Exact bucket signatures that propose base candidates, and buckets per signature.
uint32_t warp_grid_blocks(size_t warps) noexcept
Blocks for a grid-stride launch covering warps warps of block_size threads.
Definition kernels.cuh:1524
__global__ uint16_t const * sorted_keys
Definition kernels.cuh:469
__global__ uint32_t reference_count
Definition kernels.cuh:437
auto const * query
Definition kernels.cuh:1030
constexpr size_t delta_correction_shared_bytes
__global__ uint32_t uint32_t uint64_t * keys
_Pragma("unroll") for(uint32_t bit=0U
__global__ uint32_t uint32_t signature
constexpr uint32_t delta_change_limit
Most buckets in which a child reference may differ from its base reference.
auto const lane
Definition kernels.cuh:966
__device__ __forceinline__ void load_plane_group(uint4 const *row, uint32_t group, uint32_t(&words)[score_planes])
Loads group group of one bit-plane row (score_plane_index layout).
Definition kernels.cuh:1380
constexpr uint32_t delta_child_tile
auto const count
Definition kernels.cuh:1031
constexpr uint32_t delta_correction_warps
Warps per apply_reference_deltas_kernel block, and the most and fewest children one block cell takes.
auto const warp
Definition kernels.cuh:967
constexpr uint32_t delta_query_group
Queries one correction cell stages bucket-major: 64 KiB of scores for every bucket count.
constexpr uint32_t block_size
Threads per CTA for the single-pair and cardinality reduction kernels.
Definition kernels.cuh:28
__global__ uint32_t uint32_t uint64_t uint32_t * ids
auto const groups
Definition kernels.cuh:1886
constexpr uint32_t score_planes
Bits per score, and so bit-planes per 32-bucket group.
Definition kernels.cuh:1326
constexpr uint32_t delta_signature_candidates
Highest-ID rows taken from each matching signature.
__global__ size_t uint32_t query_count
Definition kernels.cuh:600
__global__ uint32_t const uint32_t uint32_t const uint32_t const SearchResult * results
Definition kernels.cuh:1544
constexpr bool staged
Definition kernels.cuh:1860
__global__ size_t uint32_t const uint32_t const uint32_t uint32_t uint16_t uint32_t uint32_t uint16_t const uint2 const uint32_t uint32_t query_id_offset
Definition kernels.cuh:927
auto const words
Definition top_k.cuh:204
constexpr uint32_t delta_signature_buckets
__global__ __launch_bounds__(shared_construction_block_size) void add_shared_kernel(uint64_t const *input
Constructs a sketch through a CTA-local shared-memory register array.
constexpr uint32_t group
Definition kernels.cuh:1858
static __global__ uint32_t const * offsets
Definition kernels.cuh:536
for(auto i=static_cast< size_t >(blockIdx.x) *block_size+threadIdx.x;i< total;i+=static_cast< size_t >(gridDim.x) *block_size)
Definition kernels.cuh:444
constexpr uint32_t delta_candidates
auto *const bits
Definition kernels.cuh:1184
auto const width
Definition kernels.cuh:963
__host__ __device__ uint16_t score(uint64_t hash) noexcept
Computes the 16-bit DDL rarity score for hash.
Definition register.cuh:43
__global__ size_t uint16_t * rows
Definition kernels.cuh:1499
auto const row
Definition top_k.cuh:202
@ counts
One 24-byte batch_search_result per pair: query ID, reference ID and the lower, equal,...
cuda::std::unexpected< Error > Err(Error error)
Failure return; converts to any Result<T> via cuda::std::unexpected.
Definition error.hpp:176
Result< void > cuda_try(cudaError_t error, std::source_location location=std::source_location::current())
Checks a CUDA runtime call and returns an error on failure.
Definition error.hpp:187
Reference rows stored as a base reference plus the buckets that differ from it.
uint2 const * records
Per changed bucket: x is the bucket's byte offset in the bucket-major staged scores; y is low | width...
uint32_t const * base_bits
One bit per reference in the candidate-bitmap layout, set for bases.
uint4 const * children
Per child in ascending ID order: ID, base ID, first record, and count | zero_count << 10 | increase_c...
reference_delta_view view() const noexcept
cuda::device_buffer< uint4 > children
cuda::device_buffer< uint32_t > base_bits
cuda::device_buffer< uint2 > records