GPU-Accelerated Cuckoo Filter
Loading...
Searching...
No Matches
bucket_policies.cuh
Go to the documentation of this file.
1#pragma once
2
3#include <cmath>
4#include <cstdint>
5#include <cuda/std/tuple>
6#include "hashutil.cuh"
7#include "helpers.cuh"
8
9namespace cuckoogpu {
10
16template <typename KeyType, typename TagType, size_t bitsPerTag, size_t bucketSize>
18 static constexpr size_t fpMask = (1ULL << bitsPerTag) - 1;
19
20 static constexpr bool usesChoiceBit = false;
21
22 static constexpr char name[] = "XorAltBucketPolicy";
23
30 template <typename H>
31 static __host__ __device__ uint64_t hash64(const H& key) {
32 return xxhash::xxhash64(key);
33 }
34
47 static __host__ __device__ cuda::std::tuple<size_t, size_t, TagType, TagType>
48 getCandidateBucketsAndFPs(const KeyType& key, size_t numBuckets) {
49 const uint64_t h = hash64(key);
50
51 // Upper 32 bits for the fingerprint
52 const uint32_t h_fp = h >> 32;
53 const uint32_t masked = h_fp & fpMask;
54
55 const auto fp = TagType(masked == 0 ? 1 : masked);
56
57 // Lower 32 bits for the bucket indices
58 const uint32_t h_bucket = h & 0xFFFFFFFF;
59 const size_t i1 = h_bucket & (numBuckets - 1);
60 const size_t i2 = getAlternateBucket(i1, fp, numBuckets);
61
62 return {i1, i2, fp, fp};
63 }
64
73 static __host__ __device__ size_t
74 getAlternateBucket(size_t bucket, TagType fp, size_t numBuckets) {
75 return bucket ^ (hash64(fp) & (numBuckets - 1));
76 }
77
82 static size_t calculateNumBuckets(size_t capacity) {
83 auto requiredBuckets = std::ceil(static_cast<double>(capacity) / bucketSize);
84 return detail::nextPowerOfTwo(requiredBuckets);
85 }
86};
87
98template <typename KeyType, typename TagType, size_t bitsPerTag, size_t bucketSize>
100 static constexpr size_t fpMask = (1ULL << bitsPerTag) - 1;
101
102 static constexpr bool usesChoiceBit = false;
103
104 static constexpr char name[] = "AddSubAltBucketPolicy";
105
112 template <typename H>
113 static __host__ __device__ uint64_t hash64(const H& key) {
114 return xxhash::xxhash64(key);
115 }
116
128 static __host__ __device__ cuda::std::tuple<size_t, size_t, TagType, TagType>
129 getCandidateBucketsAndFPs(const KeyType& key, size_t numBuckets) {
130 const uint64_t h = hash64(key);
131
132 // Upper 32 bits for the fingerprint
133 const uint32_t h_fp = h >> 32;
134 const uint32_t masked = h_fp & fpMask;
135 const auto fp = TagType(masked == 0 ? 1 : masked);
136
137 // Lower 32 bits for bucket index in block 0
138 const uint32_t h_bucket = h & 0xFFFFFFFF;
139 const size_t bucketsPerBlock = numBuckets / 2;
140
141 const size_t i1 = h_bucket % bucketsPerBlock;
142 const size_t i2 = getAlternateBucket(i1, fp, numBuckets);
143
144 return {i1, i2, fp, fp};
145 }
146
158 static __host__ __device__ size_t
159 getAlternateBucket(size_t bucket, TagType fp, size_t numBuckets) {
160 const size_t bucketsPerBlock = numBuckets / 2;
161 const uint64_t fpHash = hash64(fp) % bucketsPerBlock;
162
163 if (bucket < bucketsPerBlock) {
164 return ((bucket + fpHash) % bucketsPerBlock) + bucketsPerBlock;
165 } else {
166 return (bucket - fpHash) % bucketsPerBlock;
167 }
168 }
169
174 static size_t calculateNumBuckets(size_t capacity) {
175 auto requiredBuckets = std::ceil(static_cast<double>(capacity) / bucketSize);
176
177 // Round up to next even number to ensure equal block sizes
178 if (static_cast<size_t>(requiredBuckets) % 2 != 0) {
179 requiredBuckets += 1;
180 }
181
182 return static_cast<size_t>(requiredBuckets);
183 }
184};
185
200template <typename KeyType, typename TagType, size_t bitsPerTag, size_t bucketSize>
202 static_assert(bitsPerTag >= 2, "bitsPerTag must be at least 2 for choice bit");
203
204 // Choice bit is MSB, fingerprint uses remaining bits
205 static constexpr size_t choiceBitPos = bitsPerTag - 1;
206 static constexpr TagType choiceBitMask = TagType(1) << choiceBitPos;
207 static constexpr TagType pureFpMask = (TagType(1) << choiceBitPos) - 1;
208 static constexpr size_t fpMask = (1ULL << bitsPerTag) - 1;
209
210 static constexpr bool usesChoiceBit = true;
211
212 static constexpr char name[] = "OffsetAltBucketPolicy";
213
217 template <typename H>
218 static __host__ __device__ uint64_t hash64(const H& key) {
219 return xxhash::xxhash64(key);
220 }
221
225 static __host__ __device__ TagType getPureFingerprint(TagType fp) {
226 return fp & pureFpMask;
227 }
228
232 static __host__ __device__ TagType getChoiceBit(TagType fp) {
233 return (fp >> choiceBitPos) & 1;
234 }
235
239 static __host__ __device__ TagType setChoiceBit(TagType fp, TagType choice) {
240 return (fp & pureFpMask) | (choice << choiceBitPos);
241 }
242
250 static __host__ __device__ size_t computeOffset(TagType pureFp, size_t numBuckets) {
251 const uint64_t fpHash = hash64(pureFp);
252 const uint64_t offset = fpHash % numBuckets;
253 return offset == 0 ? 1 : offset;
254 }
255
267 static __host__ __device__ cuda::std::tuple<size_t, size_t, TagType, TagType>
268 getCandidateBucketsAndFPs(const KeyType& key, size_t numBuckets) {
269 const uint64_t h = hash64(key);
270
271 // Upper 32 bits for the fingerprint (use bitsPerTag-1 bits)
272 const uint32_t h_fp = h >> 32;
273 const uint32_t masked = h_fp & pureFpMask;
274 // Ensure non-zero (0 is reserved for empty)
275 const TagType pureFp = TagType(masked == 0 ? 1 : masked);
276
277 // Create both fingerprint variants (choice=0 and choice=1)
278 const TagType fp1 = setChoiceBit(pureFp, 0);
279 const TagType fp2 = setChoiceBit(pureFp, 1);
280
281 // Lower 32 bits for the bucket index
282 const uint32_t h_bucket = h & 0xFFFFFFFF;
283 const size_t i1 = h_bucket % numBuckets;
284
285 // Compute i2 using the fingerprint offset
286 const size_t offset = computeOffset(pureFp, numBuckets);
287 const size_t i2 = (i1 + offset) % numBuckets;
288
289 return {i1, i2, fp1, fp2};
290 }
291
304 static __host__ __device__ size_t
305 getAlternateBucket(size_t bucket, TagType fp, size_t numBuckets) {
306 const TagType pureFp = getPureFingerprint(fp);
307 const TagType choice = getChoiceBit(fp);
308 const size_t offset = computeOffset(pureFp, numBuckets);
309
310 if (choice == 0) {
311 return (bucket + offset) % numBuckets;
312 } else {
313 return (bucket + numBuckets - offset) % numBuckets;
314 }
315 }
316
328 static __host__ __device__ cuda::std::tuple<size_t, TagType>
329 getAlternateBucketWithNewFp(size_t bucket, TagType fp, size_t numBuckets) {
330 const TagType pureFp = getPureFingerprint(fp);
331 const TagType choice = getChoiceBit(fp);
332 const size_t offset = computeOffset(pureFp, numBuckets);
333
334 size_t alt;
335 if (choice == 0) {
336 alt = (bucket + offset) % numBuckets;
337 } else {
338 alt = (bucket + numBuckets - offset) % numBuckets;
339 }
340
341 TagType newFp = setChoiceBit(pureFp, 1 - choice);
342 return {alt, newFp};
343 }
344
348 static size_t calculateNumBuckets(size_t capacity) {
349 auto requiredBuckets = std::ceil(static_cast<double>(capacity) / bucketSize);
350 return static_cast<size_t>(requiredBuckets);
351 }
352};
353
354} // namespace cuckoogpu
constexpr size_t nextPowerOfTwo(size_t n)
Calculates the next power of two greater than or equal to n.
Definition helpers.cuh:33
__host__ __device__ uint64_t xxhash64(const T &key, uint64_t seed=0)
Definition hashutil.cuh:71
Addition/Subtraction-based hashing strategy for cuckoo filters (ASCF).
static __host__ __device__ cuda::std::tuple< size_t, size_t, TagType, TagType > getCandidateBucketsAndFPs(const KeyType &key, size_t numBuckets)
Computes fingerprint and candidate buckets using ADD/SUB operations.
static size_t calculateNumBuckets(size_t capacity)
Calculates number of buckets without requiring power of two.
static __host__ __device__ size_t getAlternateBucket(size_t bucket, TagType fp, size_t numBuckets)
Computes alternate bucket using ADD/SUB operations.
static __host__ __device__ uint64_t hash64(const H &key)
Computes a 64-bit hash of the key.
Offset-based alternate bucket policy from "Smaller and More Flexible Cuckoo Filters" by Schmitz,...
static __host__ __device__ TagType getChoiceBit(TagType fp)
Extracts the choice bit (0 or 1).
static __host__ __device__ uint64_t hash64(const H &key)
Computes a 64-bit hash of the key.
static __host__ __device__ size_t getAlternateBucket(size_t bucket, TagType fp, size_t numBuckets)
Computes the alternate bucket index using asymmetric offset.
static constexpr TagType choiceBitMask
static __host__ __device__ TagType setChoiceBit(TagType fp, TagType choice)
Sets the choice bit in a fingerprint.
static __host__ __device__ cuda::std::tuple< size_t, size_t, TagType, TagType > getCandidateBucketsAndFPs(const KeyType &key, size_t numBuckets)
Computes the primary and alternate bucket indices for a given key.
static size_t calculateNumBuckets(size_t capacity)
Calculates number of buckets without requiring power of two.
static __host__ __device__ TagType getPureFingerprint(TagType fp)
Extracts the pure fingerprint (without choice bit).
static constexpr size_t choiceBitPos
static __host__ __device__ cuda::std::tuple< size_t, TagType > getAlternateBucketWithNewFp(size_t bucket, TagType fp, size_t numBuckets)
Computes alternate bucket AND updated fingerprint for eviction.
static __host__ __device__ size_t computeOffset(TagType pureFp, size_t numBuckets)
Computes a non-zero offset from a fingerprint (uses pure fp).
static constexpr TagType pureFpMask
Default XOR-based hashing strategy for cuckoo filters.
static constexpr bool usesChoiceBit
static constexpr size_t fpMask
static __host__ __device__ uint64_t hash64(const H &key)
Computes a 64-bit hash of the key.
static size_t calculateNumBuckets(size_t capacity)
The number of buckets is enforced to be a power of two in order to allow for efficient modulo on the ...
static __host__ __device__ cuda::std::tuple< size_t, size_t, TagType, TagType > getCandidateBucketsAndFPs(const KeyType &key, size_t numBuckets)
Performs partial-key cuckoo hashing to find the fingerprint and both bucket indices for a given key.
static __host__ __device__ size_t getAlternateBucket(size_t bucket, TagType fp, size_t numBuckets)
Computes the alternate bucket index using XOR.
static constexpr char name[]