3#include <thrust/device_vector.h>
6#include <cuda/std/atomic>
7#include <cuda/std/cstddef>
8#include <cuda/std/cstdint>
42 size_t maxEvictions_ = 500,
43 size_t blockSize_ = 256,
44 size_t bucketSize_ = 16,
45 template <
typename,
typename,
size_t,
size_t>
class AltBucketPolicy_ = XorAltBucketPolicy,
47 typename WordType_ = uint64_t>
56 using TagType =
typename std::conditional<
59 typename std::conditional<bitsPerTag <= 16, uint16_t, uint32_t>::type>::type;
63 std::is_same_v<WordType, uint32_t> || std::is_same_v<WordType, uint64_t>,
64 "WordType must be uint32_t or uint64_t"
66 static_assert(
sizeof(
TagType) <=
sizeof(
WordType),
"TagType must fit within WordType");
68 using AltBucketPolicy = AltBucketPolicy_<KeyType, TagType, bitsPerTag, bucketSize_>;
71template <
typename Config>
79template <
typename Config>
85 uint32_t* evictionAttempts
91template <
typename Config>
97 uint32_t* evictionAttempts
103template <
typename Config>
114template <
typename Config>
125template <
typename Config>
140template <
typename Config>
155 "The tag must be 8, 16 or 32 bits"
160 using PackedTagType =
typename std::conditional<bitsPerTag <= 8, uint32_t, uint64_t>::type;
177 static_assert(
fpBits <
totalBits,
"fpBits must leave at least some bits for bucketIdx");
231 static_assert(
tagsPerWord >= 1,
"TagType must fit within WordType");
240 __host__ __device__ __forceinline__
TagType
245 __host__ __device__ __forceinline__
WordType
249 return cleared | (
static_cast<WordType>(newTag) << shift);
256 __device__ __forceinline__
static bool
259 for (
size_t j = 0; j < N; ++j) {
272 static_assert(N == 2 || N == 4,
"128-bit loads support 2 or 4 words");
273 if constexpr (
sizeof(
WordType) == 4) {
274 auto vec = __ldg(
reinterpret_cast<const uint4*
>(&
packedTags[startIdx]));
280 auto vec = __ldg(
reinterpret_cast<const ulonglong2*
>(&
packedTags[startIdx]));
300 const uint32_t startSlot = tag & (
bucketSize - 1);
301 const size_t startWordIdx = startSlot /
tagsPerWord;
303#if __CUDA_ARCH__ >= 1000 && !defined(CUCKOO_FILTER_DISABLE_256BIT_LOADS)
305 constexpr size_t wordsPerLoad256 = (
sizeof(
WordType) == 4) ? 8 : 4;
306 if constexpr (
wordCount >= wordsPerLoad256) {
307 constexpr size_t alignMask = wordsPerLoad256 - 1;
308 const size_t startAlignedIdx = startWordIdx & ~alignMask;
311 for (
size_t i = 0; i <
wordCount / wordsPerLoad256; i++) {
312 const size_t idx = (startAlignedIdx + i * wordsPerLoad256) & (
wordCount - 1);
324 constexpr size_t wordsPerLoad128 = (
sizeof(
WordType) == 4) ? 4 : 2;
325 if constexpr (
wordCount >= wordsPerLoad128) {
326 constexpr size_t alignMask = wordsPerLoad128 - 1;
327 const size_t startAlignedIdx = startWordIdx & ~alignMask;
330 for (
size_t i = 0; i <
wordCount / wordsPerLoad128; i++) {
331 const size_t idx = (startAlignedIdx + i * wordsPerLoad128) & (
wordCount - 1);
346 cuda::std::atomic<size_t>*
349#ifdef CUCKOO_FILTER_COUNT_DELETE_CAS
350 cuda::std::atomic<size_t>*
352 cuda::std::atomic<size_t>*
356#ifdef CUCKOO_FILTER_COUNT_EVICTIONS
357 cuda::std::atomic<size_t>* d_numEvictions{};
362 template <
typename H>
363 static __host__ __device__ uint64_t
hash64(
const H& key) {
364 return AltBucketPolicy::hash64(key);
367 static __host__ __device__ cuda::std::tuple<size_t, size_t, TagType, TagType>
369 return AltBucketPolicy::getCandidateBucketsAndFPs(key,
numBuckets);
375 static __host__ __device__
size_t
377 return AltBucketPolicy::getAlternateBucket(bucket, fp,
numBuckets);
384 static __host__ __device__ cuda::std::tuple<size_t, TagType>
386 if constexpr (AltBucketPolicy::usesChoiceBit) {
387 return AltBucketPolicy::getAlternateBucketWithNewFp(bucket, fp,
numBuckets);
389 return {AltBucketPolicy::getAlternateBucket(bucket, fp,
numBuckets), fp};
398 return AltBucketPolicy::calculateNumBuckets(
capacity);
414#ifdef CUCKOO_FILTER_COUNT_DELETE_CAS
418#ifdef CUCKOO_FILTER_COUNT_EVICTIONS
419 CUCKOO_CUDA_CALL(cudaMalloc(&d_numEvictions,
sizeof(cuda::std::atomic<size_t>)));
437#ifdef CUCKOO_FILTER_COUNT_DELETE_CAS
445#ifdef CUCKOO_FILTER_COUNT_EVICTIONS
446 if (d_numEvictions) {
465 bool* d_output =
nullptr,
466 cudaStream_t stream = {}
470 <<<numBlocks,
blockSize, 0, stream>>>(d_keys, d_output, n,
this,
nullptr);
477#ifdef CUCKOO_FILTER_COUNT_EVICTIONS
489 size_t insertManyWithEvictionCounts(
492 uint32_t* d_evictionAttempts,
493 bool* d_output =
nullptr,
494 cudaStream_t stream = {}
498 <<<numBlocks,
blockSize, 0, stream>>>(d_keys, d_output, n,
this, d_evictionAttempts);
520 bool* d_output =
nullptr,
521 cudaStream_t stream = {}
532 void* d_tempStorage =
nullptr;
533 size_t tempStorageBytes = 0;
535 cub::DeviceRadixSort::SortKeys(
546 CUCKOO_CUDA_CALL(cudaMallocAsync(&d_tempStorage, tempStorageBytes, stream));
548 cub::DeviceRadixSort::SortKeys(
562 <<<numBlocks,
blockSize, 0, stream>>>(d_packedTags, d_output, n,
this,
nullptr);
570#ifdef CUCKOO_FILTER_COUNT_EVICTIONS
582 size_t insertManySortedWithEvictionCounts(
585 uint32_t* d_evictionAttempts,
586 bool* d_output =
nullptr,
587 cudaStream_t stream = {}
598 void* d_tempStorage =
nullptr;
599 size_t tempStorageBytes = 0;
601 cub::DeviceRadixSort::SortKeys(
612 CUCKOO_CUDA_CALL(cudaMallocAsync(&d_tempStorage, tempStorageBytes, stream));
614 cub::DeviceRadixSort::SortKeys(
628 d_packedTags, d_output, n,
this, d_evictionAttempts
646 void containsMany(
const T* d_keys,
const size_t n,
bool* d_output, cudaStream_t stream = {}) {
649 <<<numBlocks,
blockSize, 0, stream>>>(d_keys, d_output, n,
this);
668 bool* d_output =
nullptr,
669 cudaStream_t stream = {}
673 <<<numBlocks,
blockSize, 0, stream>>>(d_keys, d_output, n,
this);
688 const thrust::device_vector<T>& d_keys,
689 thrust::device_vector<bool>& d_output,
690 cudaStream_t stream = {}
692 if (d_output.size() != d_keys.size()) {
693 d_output.resize(d_keys.size());
696 thrust::raw_pointer_cast(d_keys.data()),
698 thrust::raw_pointer_cast(d_output.data()),
711 const thrust::device_vector<T>& d_keys,
712 thrust::device_vector<uint8_t>& d_output,
713 cudaStream_t stream = {}
715 if (d_output.size() != d_keys.size()) {
716 d_output.resize(d_keys.size());
719 thrust::raw_pointer_cast(d_keys.data()),
721 reinterpret_cast<bool*
>(thrust::raw_pointer_cast(d_output.data())),
732 size_t insertMany(
const thrust::device_vector<T>& d_keys, cudaStream_t stream = {}) {
733 return insertMany(thrust::raw_pointer_cast(d_keys.data()), d_keys.size(),
nullptr, stream);
736#ifdef CUCKOO_FILTER_COUNT_EVICTIONS
745 size_t insertManyWithEvictionCounts(
746 const thrust::device_vector<T>& d_keys,
747 thrust::device_vector<uint32_t>& d_evictionAttempts,
748 thrust::device_vector<uint8_t>* d_output =
nullptr,
749 cudaStream_t stream = {}
751 if (d_evictionAttempts.size() != d_keys.size()) {
752 d_evictionAttempts.resize(d_keys.size());
755 bool* d_outputPtr =
nullptr;
756 if (d_output !=
nullptr) {
757 if (d_output->size() != d_keys.size()) {
758 d_output->resize(d_keys.size());
760 d_outputPtr =
reinterpret_cast<bool*
>(thrust::raw_pointer_cast(d_output->data()));
763 return insertManyWithEvictionCounts(
764 thrust::raw_pointer_cast(d_keys.data()),
766 thrust::raw_pointer_cast(d_evictionAttempts.data()),
781 const thrust::device_vector<T>& d_keys,
782 thrust::device_vector<bool>& d_output,
783 cudaStream_t stream = {}
785 if (d_output.size() != d_keys.size()) {
786 d_output.resize(d_keys.size());
789 thrust::raw_pointer_cast(d_keys.data()),
791 thrust::raw_pointer_cast(d_output.data()),
804 const thrust::device_vector<T>& d_keys,
805 thrust::device_vector<uint8_t>& d_output,
806 cudaStream_t stream = {}
808 if (d_output.size() != d_keys.size()) {
809 d_output.resize(d_keys.size());
812 thrust::raw_pointer_cast(d_keys.data()),
814 reinterpret_cast<bool*
>(thrust::raw_pointer_cast(d_output.data())),
826 size_t insertManySorted(
const thrust::device_vector<T>& d_keys, cudaStream_t stream = {}) {
828 thrust::raw_pointer_cast(d_keys.data()), d_keys.size(),
nullptr, stream
832#ifdef CUCKOO_FILTER_COUNT_EVICTIONS
842 size_t insertManySortedWithEvictionCounts(
843 const thrust::device_vector<T>& d_keys,
844 thrust::device_vector<uint32_t>& d_evictionAttempts,
845 thrust::device_vector<uint8_t>* d_output =
nullptr,
846 cudaStream_t stream = {}
848 if (d_evictionAttempts.size() != d_keys.size()) {
849 d_evictionAttempts.resize(d_keys.size());
852 bool* d_outputPtr =
nullptr;
853 if (d_output !=
nullptr) {
854 if (d_output->size() != d_keys.size()) {
855 d_output->resize(d_keys.size());
857 d_outputPtr =
reinterpret_cast<bool*
>(thrust::raw_pointer_cast(d_output->data()));
860 return insertManySortedWithEvictionCounts(
861 thrust::raw_pointer_cast(d_keys.data()),
863 thrust::raw_pointer_cast(d_evictionAttempts.data()),
877 const thrust::device_vector<T>& d_keys,
878 thrust::device_vector<bool>& d_output,
879 cudaStream_t stream = {}
881 if (d_output.size() != d_keys.size()) {
882 d_output.resize(d_keys.size());
885 thrust::raw_pointer_cast(d_keys.data()),
887 thrust::raw_pointer_cast(d_output.data()),
899 const thrust::device_vector<T>& d_keys,
900 thrust::device_vector<uint8_t>& d_output,
901 cudaStream_t stream = {}
903 if (d_output.size() != d_keys.size()) {
904 d_output.resize(d_keys.size());
907 thrust::raw_pointer_cast(d_keys.data()),
909 reinterpret_cast<bool*
>(thrust::raw_pointer_cast(d_output.data())),
922 const thrust::device_vector<T>& d_keys,
923 thrust::device_vector<bool>& d_output,
924 cudaStream_t stream = {}
926 if (d_output.size() != d_keys.size()) {
927 d_output.resize(d_keys.size());
930 thrust::raw_pointer_cast(d_keys.data()),
932 thrust::raw_pointer_cast(d_output.data()),
945 const thrust::device_vector<T>& d_keys,
946 thrust::device_vector<uint8_t>& d_output,
947 cudaStream_t stream = {}
949 if (d_output.size() != d_keys.size()) {
950 d_output.resize(d_keys.size());
953 thrust::raw_pointer_cast(d_keys.data()),
955 reinterpret_cast<bool*
>(thrust::raw_pointer_cast(d_output.data())),
966 size_t deleteMany(
const thrust::device_vector<T>& d_keys, cudaStream_t stream = {}) {
967 return deleteMany(thrust::raw_pointer_cast(d_keys.data()), d_keys.size(),
nullptr, stream);
976#ifdef CUCKOO_FILTER_COUNT_DELETE_CAS
980#ifdef CUCKOO_FILTER_COUNT_EVICTIONS
981 CUCKOO_CUDA_CALL(cudaMemset(d_numEvictions, 0,
sizeof(cuda::std::atomic<size_t>)));
1008#ifdef CUCKOO_FILTER_COUNT_EVICTIONS
1016 size_t evictionCount() {
1019 cudaMemcpy(&count, d_numEvictions,
sizeof(
size_t), cudaMemcpyDeviceToHost)
1027 void resetEvictionCount() {
1028 CUCKOO_CUDA_CALL(cudaMemset(d_numEvictions, 0,
sizeof(cuda::std::atomic<size_t>)));
1032#ifdef CUCKOO_FILTER_COUNT_DELETE_CAS
1110 size_t occupiedCount = 0;
1112 for (
size_t bucketIdx = 0; bucketIdx <
numBuckets; ++bucketIdx) {
1113 const Bucket& bucket = h_buckets[bucketIdx];
1116 uint64_t packed =
reinterpret_cast<const uint64_t&
>(bucket.
packedTags[atomicIdx]);
1119 auto tag = bucket.
extractTag(packed, tagIdx);
1128 return occupiedCount;
1152 const uint32_t startSlot = tag & (
bucketSize - 1);
1161 auto expected = bucket.
packedTags[currIdx].load(cuda::memory_order_relaxed);
1167 if (matchMask == 0) {
1174 if constexpr (
sizeof(WordType) == 4) {
1175 bitPos = __ffs(
static_cast<int>(matchMask)) - 1;
1177 bitPos = __ffsll(
static_cast<long long>(matchMask)) - 1;
1183#ifdef CUCKOO_FILTER_COUNT_DELETE_CAS
1186 bool casSuccess = bucket.
packedTags[currIdx].compare_exchange_weak(
1187 expected, desired, cuda::memory_order_relaxed, cuda::memory_order_relaxed
1189#ifdef CUCKOO_FILTER_COUNT_DELETE_CAS
1215 const uint32_t startIdx = tag & (
bucketSize - 1);
1222 auto expected = bucket.
packedTags[currWord].load(cuda::memory_order_relaxed);
1227 if (zeroMask == 0) {
1234 if constexpr (
sizeof(WordType) == 4) {
1235 bitPos = __ffs(
static_cast<int>(zeroMask)) - 1;
1237 bitPos = __ffsll(
static_cast<long long>(zeroMask)) - 1;
1241 auto desired = bucket.
replaceTag(expected, j, tag);
1243 if (bucket.
packedTags[currWord].compare_exchange_strong(
1244 expected, desired, cuda::memory_order_relaxed, cuda::memory_order_relaxed
1268 size_t currentBucket = startBucket;
1270 for (
size_t evictions = 0; evictions <
maxEvictions; ++evictions) {
1271 auto evictSlot = (currentFp + (evictions + 1) * 0x9E3779B1UL) & (
bucketSize - 1);
1277 auto expected = bucket.
packedTags[evictWord].load(cuda::memory_order_relaxed);
1282 evictedFp = bucket.extractTag(expected, evictTagIdx);
1283 desired = bucket.replaceTag(expected, evictTagIdx, currentFp);
1284 }
while (!bucket.packedTags[evictWord].compare_exchange_strong(
1285 expected, desired, cuda::memory_order_relaxed, cuda::memory_order_relaxed
1288#ifdef CUCKOO_FILTER_COUNT_EVICTIONS
1289 d_numEvictions->fetch_add(1, cuda::memory_order_relaxed);
1290 if (evictionAttempts !=
nullptr) {
1291 (*evictionAttempts)++;
1295 currentFp = evictedFp;
1296 auto [altBucket, newFp] =
1298 currentBucket = altBucket;
1324 constexpr size_t numCandidates = std::max(1UL,
bucketSize / 2);
1327 size_t currentBucket = startBucket;
1329 size_t evictions = 0;
1332 size_t restartWord = 0;
1333 size_t restartTagIdx = 0;
1335 for (
size_t i = 0; i < numCandidates; ++i) {
1336 size_t evictSlot = (currentFp + i * 0x9E3779B1UL + (evictions + 1) * 0x85EBCA77) &
1340 restartWord = evictWord;
1341 restartTagIdx = evictTagIdx;
1343 auto packed = bucket.
packedTags[evictWord].load(cuda::memory_order_relaxed);
1346 if (candidateFp ==
EMPTY) {
1353 auto [altBucket, altFp] =
1358 auto expected = bucket.
packedTags[evictWord].load(cuda::memory_order_relaxed);
1361 if (bucket.
extractTag(expected, evictTagIdx) == candidateFp) {
1362 auto desired = bucket.
replaceTag(expected, evictTagIdx, currentFp);
1364 if (bucket.
packedTags[evictWord].compare_exchange_strong(
1367 cuda::memory_order_relaxed,
1368 cuda::memory_order_relaxed
1370#ifdef CUCKOO_FILTER_COUNT_EVICTIONS
1371 d_numEvictions->fetch_add(1, cuda::memory_order_relaxed);
1372 if (evictionAttempts !=
nullptr) {
1373 (*evictionAttempts)++;
1386 auto expected = bucket.
packedTags[restartWord].load(cuda::memory_order_relaxed);
1391 evictedFp = bucket.
extractTag(expected, restartTagIdx);
1392 desired = bucket.
replaceTag(expected, restartTagIdx, currentFp);
1393 }
while (!bucket.
packedTags[restartWord].compare_exchange_strong(
1394 expected, desired, cuda::memory_order_relaxed, cuda::memory_order_relaxed
1397 if (evictedFp ==
EMPTY) {
1401#ifdef CUCKOO_FILTER_COUNT_EVICTIONS
1402 d_numEvictions->fetch_add(1, cuda::memory_order_relaxed);
1403 if (evictionAttempts !=
nullptr) {
1404 (*evictionAttempts)++;
1409 auto [altBucket, altFp] =
1411 currentBucket = altBucket;
1428 __device__
bool insert(
const T& key, uint32_t* evictionAttempts =
nullptr) {
1438 auto startBucket = (fp1 & 1) == 0 ? i1 : i2;
1441 if constexpr (AltBucketPolicy::usesChoiceBit) {
1442 evictFp = (fp1 & 1) == 0 ? fp1 : fp2;
1455 "Unhandled eviction policy"
1491template <
typename Config>
1499 using BlockReduce = cub::BlockReduce<int32_t, Config::blockSize>;
1529template <
typename Config>
1543template <
typename Config>
1546 using BlockReduce = cub::BlockReduce<int32_t, Config::blockSize>;
1567template <
typename Config>
1581 using PackedTagType =
typename FilterType::PackedTagType;
1585 auto [
i1,
i2,
fp1,
fp2] = FilterType::getCandidateBucketsAndFPs(
key, numBuckets);
1588 (
static_cast<PackedTagType
>(
i1) << bitsPerTag) |
static_cast<PackedTagType
>(
fp1);
1591template <
typename Config>
1599 using BlockReduce = cub::BlockReduce<int, Config::blockSize>;
1605 using TagType =
typename FilterType::TagType;
1606 using PackedTagType =
typename FilterType::PackedTagType;
1609 constexpr TagType fpMask = (1ULL << bitsPerTag) - 1;
1616 auto fp =
static_cast<TagType
>(
packedTag & fpMask);
1630 if constexpr (Config::AltBucketPolicy::usesChoiceBit) {
1644 "Unhandled eviction policy"
A CUDA-accelerated Cuckoo Filter implementation.
cuda::std::atomic< size_t > * d_numOccupied
Pointer to the device memory for the occupancy counter.
static constexpr TagType EMPTY
void containsMany(const thrust::device_vector< T > &d_keys, thrust::device_vector< uint8_t > &d_output, cudaStream_t stream={})
Checks for existence of keys in a Thrust device vector (uint8_t output).
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 ...
size_t getNumBuckets() const
Returns the number of buckets in the filter.
static __host__ __device__ uint64_t hash64(const H &key)
Filter(size_t capacity)
Constructs a new Cuckoo Filter.
static constexpr size_t maxEvictions
size_t occupiedSlots()
Returns the total number of occupied slots.
void clear()
Clears the filter, removing all items.
size_t insertMany(const thrust::device_vector< T > &d_keys, thrust::device_vector< uint8_t > &d_output, cudaStream_t stream={})
Inserts keys from a Thrust device vector (uint8_t output).
static constexpr size_t bucketSize
size_t sizeInBytes() const
Returns the size of the filter in bytes.
size_t insertMany(const thrust::device_vector< T > &d_keys, thrust::device_vector< bool > &d_output, cudaStream_t stream={})
Inserts keys from a Thrust device vector.
size_t numBuckets
Number of buckets in the filter.
size_t insertManySorted(const thrust::device_vector< T > &d_keys, cudaStream_t stream={})
Inserts keys from a Thrust device vector, sorting them first, without outputting results.
static constexpr size_t fpMask
__device__ bool tryInsertAtBucket(size_t bucketIdx, TagType tag)
Attempts to insert a tag into a specific bucket.
size_t deleteMany(const T *d_keys, const size_t n, bool *d_output=nullptr, cudaStream_t stream={})
Tries to remove a set of keys from the filter.
size_t insertManySorted(const thrust::device_vector< T > &d_keys, thrust::device_vector< uint8_t > &d_output, cudaStream_t stream={})
Inserts keys from a Thrust device vector, sorting them first (uint8_t output).
float loadFactor()
Calculates the current load factor of the filter.
typename std::conditional< bitsPerTag<=8, uint32_t, uint64_t >::type PackedTagType
static __host__ __device__ size_t getAlternateBucket(size_t bucket, TagType fp, size_t numBuckets)
Computes the alternate bucket for a fingerprint.
size_t deleteCasAttempts()
Returns the total number of delete CAS attempts (compare_exchange calls).
size_t insertMany(const thrust::device_vector< T > &d_keys, cudaStream_t stream={})
Inserts keys from a Thrust device vector without outputting results.
Filter(const Filter &)=delete
__device__ bool insert(const T &key, uint32_t *evictionAttempts=nullptr)
Inserts a single key into the filter.
Bucket * d_buckets
Pointer to the device memory for the buckets.
cuda::std::atomic< size_t > * d_deleteCasFailures
Pointer to device memory for the failed delete CAS counter.
size_t countOccupiedSlots()
Counts occupied slots by iterating over all buckets on the host.
typename Config::AltBucketPolicy AltBucketPolicy
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 choice bit policies.
void containsMany(const thrust::device_vector< T > &d_keys, thrust::device_vector< bool > &d_output, cudaStream_t stream={})
Checks for existence of keys in a Thrust device vector.
typename Config::TagType TagType
static __host__ __device__ cuda::std::tuple< size_t, size_t, TagType, TagType > getCandidateBucketsAndFPs(const T &key, size_t numBuckets)
__device__ bool tryRemoveAtBucket(size_t bucketIdx, TagType tag)
Attempt to remove a single instance of a fingerprint from a bucket.
__device__ bool remove(const T &key)
Removes a key from the filter.
size_t deleteMany(const thrust::device_vector< T > &d_keys, cudaStream_t stream={})
Deletes keys in a Thrust device vector without outputting results.
size_t deleteMany(const thrust::device_vector< T > &d_keys, thrust::device_vector< bool > &d_output, cudaStream_t stream={})
Deletes keys in a Thrust device vector.
static constexpr size_t tagEntryBytes
size_t deleteCasFailures()
Returns the total number of failed delete CAS attempts.
void containsMany(const T *d_keys, const size_t n, bool *d_output, cudaStream_t stream={})
Checks for the existence of a batch of keys.
__device__ bool insertWithEvictionDFS(TagType fp, size_t startBucket, uint32_t *evictionAttempts=nullptr)
Inserts a fingerprint into the filter by evicting existing fingerprints.
static constexpr size_t bitsPerTag
__device__ bool insertWithEvictionBFS(TagType fp, size_t startBucket, uint32_t *evictionAttempts=nullptr)
Inserts a fingerprint using repeated shallow breadth-first attempts.
static constexpr size_t blockSize
size_t deleteMany(const thrust::device_vector< T > &d_keys, thrust::device_vector< uint8_t > &d_output, cudaStream_t stream={})
Deletes keys in a Thrust device vector (uint8_t output).
~Filter()
Destroys the Cuckoo Filter.
size_t insertManySorted(const T *d_keys, const size_t n, bool *d_output=nullptr, cudaStream_t stream={})
This pre-sorts the input keys based on the primary bucket index to allow for coalesced memory access ...
__device__ bool contains(const T &key) const
Checks if a key exists in the filter.
cuda::std::atomic< size_t > * d_deleteCasAttempts
Pointer to device memory for the delete CAS attempt counter.
void resetDeleteCasCounters()
Resets the delete CAS counters to zero.
size_t insertManySorted(const thrust::device_vector< T > &d_keys, thrust::device_vector< bool > &d_output, cudaStream_t stream={})
Inserts keys from a Thrust device vector, sorting them first.
size_t insertMany(const T *d_keys, const size_t n, bool *d_output=nullptr, cudaStream_t stream={})
Inserts a batch of keys into the filter.
Filter & operator=(const Filter &)=delete
size_t h_numOccupied
Number of occupied buckets in the filter.
size_t capacity()
Returns the total capacity of the filter.
typename Config::KeyType T
#define SDIV(x, y)
Integer division with rounding up (ceiling).
#define CUCKOO_CUDA_CALL(err)
Macro for checking CUDA errors.
__global__ void deleteKernel(const typename Config::KeyType *keys, bool *output, size_t n, Filter< Config > *filter)
Kernel for deleting keys.
__host__ __device__ __forceinline__ constexpr bool hasZero(WordType v)
Checks if a packed word contains a zero slot.
__host__ __device__ __forceinline__ uint32_t globalThreadId()
Calculates the global thread ID in a 1D grid.
constexpr bool powerOfTwo(size_t n)
Checks if a number is a power of two.
__global__ void computePackedTagsKernel(const typename Config::KeyType *keys, typename Filter< Config >::PackedTagType *packedTags, size_t n, size_t numBuckets)
Kernel for computing packed tags for sorting.
__global__ void containsKernel(const typename Config::KeyType *keys, bool *output, size_t n, Filter< Config > *filter)
Kernel for checking existence of keys.
__global__ void insertKernelSorted(const typename Filter< Config >::PackedTagType *packedTags, bool *output, size_t n, Filter< Config > *filter, uint32_t *evictionAttempts)
Kernel for inserting pre-sorted keys into the filter.
__global__ void insertKernel(const typename Config::KeyType *keys, bool *output, size_t n, Filter< Config > *filter, uint32_t *evictionAttempts)
Kernel for inserting keys into the filter.
EvictionPolicy
Eviction policy for the Cuckoo Filter.
@ BFS
Breadth-first search (default)
@ DFS
Pure depth-first search.
Configuration structure for the Cuckoo Filter.
static constexpr size_t bucketSize
static constexpr size_t blockSize
static constexpr size_t maxEvictions
static constexpr size_t bitsPerTag
static constexpr EvictionPolicy evictionPolicy
typename std::conditional< bitsPerTag<=8, uint8_t, typename std::conditional< bitsPerTag<=16, uint16_t, uint32_t >::type >::type TagType
AltBucketPolicy_< KeyType, TagType, bitsPerTag, bucketSize_ > AltBucketPolicy
Bucket structure that holds the fingerprint and tags for a given bucket.
__host__ __device__ __forceinline__ TagType extractTag(WordType packed, size_t tagIdx) const
typename Config::WordType WordType
__host__ __device__ __forceinline__ WordType replaceTag(WordType packed, size_t tagIdx, TagType newTag) const
static constexpr size_t tagsPerWord
__device__ __forceinline__ void load128Bit(size_t startIdx, WordType(&out)[N]) const
Loads words using 128-bit vectorized loads into a fixed-size array.
static constexpr size_t wordCount
__device__ static __forceinline__ bool checkWords(const WordType(&loaded)[N], WordType replicatedTag)
Checks an array of loaded words for a matching tag using SWAR.
cuda::std::atomic< WordType > packedTags[wordCount]
__device__ bool contains(TagType tag) const
Checks if a tag is present in the bucket using vectorized loads.
This is used by the sorted insert kernel to store the fingerprint and primary bucket index in a compa...
__host__ __device__ void setFingerprint(TagType fp)
static constexpr PackedTagType fpMask
__host__ __device__ uint64_t getBucketIndex() const
static constexpr size_t fpBits
__host__ __device__ void setBucketIdx(size_t bucketIdx)
static constexpr PackedTagType bucketIdxMask
__host__ __device__ PackedTag()
static constexpr size_t bucketIdxBits
static constexpr size_t totalBits
__host__ __device__ TagType getFingerprint() const
__host__ __device__ PackedTag(TagType fp, uint64_t bucketIdx)