GPU-Accelerated Cuckoo Filter
Loading...
Searching...
No Matches
Functions
cuckoogpu::detail Namespace Reference

Functions

template<typename Config >
__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.
 
template<typename Config >
__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.
 
template<typename Config >
__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.
 
template<typename Config >
__global__ void containsKernel (const typename Config::KeyType *keys, bool *output, size_t n, Filter< Config > *filter)
 Kernel for checking existence of keys.
 
template<typename Config >
__global__ void deleteKernel (const typename Config::KeyType *keys, bool *output, size_t n, Filter< Config > *filter)
 Kernel for deleting keys.
 
constexpr bool powerOfTwo (size_t n)
 Checks if a number is a power of two.
 
__host__ __device__ __forceinline__ uint32_t globalThreadId ()
 Calculates the global thread ID in a 1D grid.
 
constexpr size_t nextPowerOfTwo (size_t n)
 Calculates the next power of two greater than or equal to n.
 
template<typename TagType , typename WordType >
__host__ __device__ __forceinline__ constexpr WordType getZeroMask (WordType v)
 Returns a bitmask indicating which slots in a packed word are zero.
 
template<typename TagType , typename WordType >
__host__ __device__ __forceinline__ constexpr bool hasZero (WordType v)
 Checks if a packed word contains a zero slot.
 
template<typename TagType , typename WordType >
__host__ __device__ __forceinline__ constexpr WordType replicateTag (TagType tag)
 Replicates a tag value across all slots in a word.
 
template<typename Kernel >
constexpr size_t maxOccupancyGridSize (int32_t blockSize, Kernel kernel, size_t dynamicSMemSize)
 Calculates the maximum occupancy grid size for a kernel.
 

Function Documentation

◆ computePackedTagsKernel()

template<typename Config >
__global__ void cuckoogpu::detail::computePackedTagsKernel ( const typename Config::KeyType *  keys,
typename Filter< Config >::PackedTagType *  packedTags,
size_t  n,
size_t  numBuckets 
)

Kernel for computing packed tags for sorting.

Definition at line 1568 of file CuckooFilter.cuh.

1573 {
1574 size_t idx = globalThreadId();
1575
1576 if (idx >= n) {
1577 return;
1578 }
1579
1580 using FilterType = Filter<Config>;
1581 using PackedTagType = typename FilterType::PackedTagType;
1582 constexpr size_t bitsPerTag = Config::bitsPerTag;
1583
1584 typename Config::KeyType key = keys[idx];
1585 auto [i1, i2, fp1, fp2] = FilterType::getCandidateBucketsAndFPs(key, numBuckets);
1586
1587 packedTags[idx] =
1588 (static_cast<PackedTagType>(i1) << bitsPerTag) | static_cast<PackedTagType>(fp1);
1589}
A CUDA-accelerated Cuckoo Filter implementation.
__host__ __device__ __forceinline__ uint32_t globalThreadId()
Calculates the global thread ID in a 1D grid.
Definition helpers.cuh:22
Here is the call graph for this function:

◆ containsKernel()

template<typename Config >
__global__ void cuckoogpu::detail::containsKernel ( const typename Config::KeyType *  keys,
bool *  output,
size_t  n,
Filter< Config > *  filter 
)

Kernel for checking existence of keys.

Definition at line 1530 of file CuckooFilter.cuh.

1535 {
1536 auto idx = globalThreadId();
1537
1538 if (idx < n) {
1539 output[idx] = filter->contains(keys[idx]);
1540 }
1541}
__device__ bool contains(const T &key) const
Checks if a key exists in the filter.
Here is the call graph for this function:

◆ deleteKernel()

template<typename Config >
__global__ void cuckoogpu::detail::deleteKernel ( const typename Config::KeyType *  keys,
bool *  output,
size_t  n,
Filter< Config > *  filter 
)

Kernel for deleting keys.

Definition at line 1545 of file CuckooFilter.cuh.

1545 {
1546 using BlockReduce = cub::BlockReduce<int32_t, Config::blockSize>;
1547 __shared__ typename BlockReduce::TempStorage tempStorage;
1548
1549 auto idx = globalThreadId();
1550
1551 int32_t success = 0;
1552 if (idx < n) {
1553 success = filter->remove(keys[idx]);
1554
1555 if (output != nullptr) {
1556 output[idx] = success;
1557 }
1558 }
1559
1560 int32_t blockSum = BlockReduce(tempStorage).Sum(success);
1561
1562 if (threadIdx.x == 0 && blockSum > 0) {
1563 filter->d_numOccupied->fetch_sub(blockSum, cuda::memory_order_relaxed);
1564 }
1565}
cuda::std::atomic< size_t > * d_numOccupied
Pointer to the device memory for the occupancy counter.
__device__ bool remove(const T &key)
Removes a key from the filter.
Here is the call graph for this function:

◆ getZeroMask()

template<typename TagType , typename WordType >
__host__ __device__ __forceinline__ constexpr WordType cuckoogpu::detail::getZeroMask ( WordType  v)
constexpr

Returns a bitmask indicating which slots in a packed word are zero.

Uses SWAR (SIMD Within A Register) to check multiple items in parallel. See https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord

The high bit of each slot that is zero will be set in the result.

Template Parameters
TagTypeThe type of the individual items (uint8_t, uint16_t, or uint32_t)
WordTypeThe packed word type (uint32_t or uint64_t)
Parameters
vThe packed integer
Returns
A bitmask with the high bit of each zero slot set

Definition at line 61 of file helpers.cuh.

61 {
62 static_assert(sizeof(WordType) == 4 || sizeof(WordType) == 8, "WordType must be 32 or 64 bits");
63
64 if constexpr (sizeof(WordType) == 8) {
65 if constexpr (sizeof(TagType) == 1) {
66 return (v - 0x0101010101010101ULL) & ~v & 0x8080808080808080ULL;
67 } else if constexpr (sizeof(TagType) == 2) {
68 return (v - 0x0001000100010001ULL) & ~v & 0x8000800080008000ULL;
69 } else if constexpr (sizeof(TagType) == 4) {
70 return (v - 0x0000000100000001ULL) & ~v & 0x8000000080000000ULL;
71 } else {
72 return 0;
73 }
74 } else {
75 if constexpr (sizeof(TagType) == 1) {
76 return (v - 0x01010101U) & ~v & 0x80808080U;
77 } else if constexpr (sizeof(TagType) == 2) {
78 return (v - 0x00010001U) & ~v & 0x80008000U;
79 } else if constexpr (sizeof(TagType) == 4) {
80 return (v - 0x00000001U) & ~v & 0x80000000U;
81 } else {
82 return 0;
83 }
84 }
85}
Here is the call graph for this function:

◆ globalThreadId()

__host__ __device__ __forceinline__ uint32_t cuckoogpu::detail::globalThreadId ( )

Calculates the global thread ID in a 1D grid.

Returns
uint32_t Global thread ID.

Definition at line 22 of file helpers.cuh.

22 {
23 return blockIdx.x * blockDim.x + threadIdx.x;
24}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ hasZero()

template<typename TagType , typename WordType >
__host__ __device__ __forceinline__ constexpr bool cuckoogpu::detail::hasZero ( WordType  v)
constexpr

Checks if a packed word contains a zero slot.

Template Parameters
TagTypeThe type of the individual items (uint8_t, uint16_t, or uint32_t)
WordTypeThe packed word type (uint32_t or uint64_t)
Parameters
vThe packed integer
Returns
true if any of the items in v are zero

Definition at line 96 of file helpers.cuh.

96 {
97 return getZeroMask<TagType, WordType>(v) != 0;
98}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ insertKernel()

template<typename Config >
__global__ void cuckoogpu::detail::insertKernel ( const typename Config::KeyType *  keys,
bool *  output,
size_t  n,
Filter< Config > *  filter,
uint32_t *  evictionAttempts 
)

Kernel for inserting keys into the filter.

Definition at line 1492 of file CuckooFilter.cuh.

1498 {
1499 using BlockReduce = cub::BlockReduce<int32_t, Config::blockSize>;
1500 __shared__ typename BlockReduce::TempStorage tempStorage;
1501
1502 auto idx = globalThreadId();
1503
1504 int32_t success = 0;
1505
1506 if (idx < n) {
1507 uint32_t threadEvictions = 0;
1508 success = filter->insert(keys[idx], &threadEvictions);
1509
1510 if (output != nullptr) {
1511 output[idx] = success;
1512 }
1513
1514 if (evictionAttempts != nullptr) {
1515 evictionAttempts[idx] = threadEvictions;
1516 }
1517 }
1518
1519 int32_t blockSuccessSum = BlockReduce(tempStorage).Sum(success);
1520 __syncthreads();
1521
1522 if (threadIdx.x == 0) {
1523 if (blockSuccessSum > 0) {
1524 filter->d_numOccupied->fetch_add(blockSuccessSum, cuda::memory_order_relaxed);
1525 }
1526 }
1527}
__device__ bool insert(const T &key, uint32_t *evictionAttempts=nullptr)
Inserts a single key into the filter.
Here is the call graph for this function:

◆ insertKernelSorted()

template<typename Config >
__global__ void cuckoogpu::detail::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.

Definition at line 1592 of file CuckooFilter.cuh.

1598 {
1599 using BlockReduce = cub::BlockReduce<int, Config::blockSize>;
1600 __shared__ typename BlockReduce::TempStorage tempStorage;
1601
1602 size_t idx = globalThreadId();
1603
1604 using FilterType = Filter<Config>;
1605 using TagType = typename FilterType::TagType;
1606 using PackedTagType = typename FilterType::PackedTagType;
1607
1608 constexpr size_t bitsPerTag = Config::bitsPerTag;
1609 constexpr TagType fpMask = (1ULL << bitsPerTag) - 1;
1610
1611 int32_t success = 0;
1612 uint32_t threadEvictions = 0;
1613 if (idx < n) {
1614 PackedTagType packedTag = packedTags[idx];
1615 size_t primaryBucket = packedTag >> bitsPerTag;
1616 auto fp = static_cast<TagType>(packedTag & fpMask);
1617
1618 if (filter->tryInsertAtBucket(primaryBucket, fp)) {
1619 success = 1;
1620 } else {
1621 auto [i2, fp2] =
1622 FilterType::getAlternateBucketWithNewFp(primaryBucket, fp, filter->numBuckets);
1623
1624 if (filter->tryInsertAtBucket(i2, fp2)) {
1625 success = 1;
1626 } else {
1627 TagType evictFp;
1628 auto startBucket = (fp & 1) == 0 ? primaryBucket : i2;
1629
1630 if constexpr (Config::AltBucketPolicy::usesChoiceBit) {
1631 evictFp = (fp & 1) == 0 ? fp : fp2;
1632 } else {
1633 evictFp = fp;
1634 }
1635
1636 if constexpr (Config::evictionPolicy == EvictionPolicy::BFS) {
1637 success = filter->insertWithEvictionBFS(evictFp, startBucket, &threadEvictions);
1638 } else if constexpr (Config::evictionPolicy == EvictionPolicy::DFS) {
1639 success = filter->insertWithEvictionDFS(evictFp, startBucket, &threadEvictions);
1640 } else {
1641 static_assert(
1642 Config::evictionPolicy == EvictionPolicy::DFS ||
1643 Config::evictionPolicy == EvictionPolicy::BFS,
1644 "Unhandled eviction policy"
1645 );
1646 }
1647 }
1648 }
1649
1650 if (output != nullptr) {
1651 output[idx] = success;
1652 }
1653
1654 if (evictionAttempts != nullptr) {
1655 evictionAttempts[idx] = threadEvictions;
1656 }
1657 }
1658
1659 int32_t blockSum = BlockReduce(tempStorage).Sum(success);
1660
1661 if (threadIdx.x == 0 && blockSum > 0) {
1662 filter->d_numOccupied->fetch_add(blockSum, cuda::memory_order_relaxed);
1663 }
1664}
size_t numBuckets
Number of buckets in the filter.
__device__ bool tryInsertAtBucket(size_t bucketIdx, TagType tag)
Attempts to insert a tag into a specific bucket.
__device__ bool insertWithEvictionDFS(TagType fp, size_t startBucket, uint32_t *evictionAttempts=nullptr)
Inserts a fingerprint into the filter by evicting existing fingerprints.
__device__ bool insertWithEvictionBFS(TagType fp, size_t startBucket, uint32_t *evictionAttempts=nullptr)
Inserts a fingerprint using repeated shallow breadth-first attempts.
Here is the call graph for this function:

◆ maxOccupancyGridSize()

template<typename Kernel >
constexpr size_t cuckoogpu::detail::maxOccupancyGridSize ( int32_t  blockSize,
Kernel  kernel,
size_t  dynamicSMemSize 
)
constexpr

Calculates the maximum occupancy grid size for a kernel.

Template Parameters
KernelType of the kernel function.
Parameters
blockSizeBlock size (threads per block).
kernelThe kernel function.
dynamicSMemSizeDynamic shared memory size per block.
Returns
size_t The calculated grid size (number of blocks).

Definition at line 204 of file helpers.cuh.

204 {
205 int device = 0;
206 cudaGetDevice(&device);
207
208 int numSM = -1;
209 cudaDeviceGetAttribute(&numSM, cudaDevAttrMultiProcessorCount, device);
210
211 int maxActiveBlocksPerSM{};
212 cudaOccupancyMaxActiveBlocksPerMultiprocessor(
213 &maxActiveBlocksPerSM, kernel, blockSize, dynamicSMemSize
214 );
215
216 return maxActiveBlocksPerSM * numSM;
217}
Here is the call graph for this function:

◆ nextPowerOfTwo()

constexpr size_t cuckoogpu::detail::nextPowerOfTwo ( size_t  n)
constexpr

Calculates the next power of two greater than or equal to n.

Parameters
nInput number.
Returns
size_t Next power of two.

Definition at line 31 of file helpers.cuh.

31 {
32 if (powerOfTwo(n))
33 return n;
34
35 n--;
36 n |= n >> 1;
37 n |= n >> 2;
38 n |= n >> 4;
39 n |= n >> 8;
40 n |= n >> 16;
41 n |= n >> 32;
42 n++;
43
44 return n;
45}
constexpr bool powerOfTwo(size_t n)
Checks if a number is a power of two.
Definition helpers.cuh:14
Here is the call graph for this function:
Here is the caller graph for this function:

◆ powerOfTwo()

constexpr bool cuckoogpu::detail::powerOfTwo ( size_t  n)
constexpr

Checks if a number is a power of two.

Parameters
nNumber to check.
Returns
true if n is a power of two, false otherwise.

Definition at line 14 of file helpers.cuh.

14 {
15 return n != 0 && (n & (n - 1)) == 0;
16}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ replicateTag()

template<typename TagType , typename WordType >
__host__ __device__ __forceinline__ constexpr WordType cuckoogpu::detail::replicateTag ( TagType  tag)
constexpr

Replicates a tag value across all slots in a word.

Template Parameters
TagTypeThe type of the tag (uint8_t, uint16_t, or uint32_t)
WordTypeThe target word type (uint32_t or uint64_t)
Parameters
tagThe tag value to replicate
Returns
A word with the tag replicated in every slot

Definition at line 109 of file helpers.cuh.

109 {
110 static_assert(sizeof(WordType) == 4 || sizeof(WordType) == 8, "WordType must be 32 or 64 bits");
111
112 if constexpr (sizeof(WordType) == 8) {
113 if constexpr (sizeof(TagType) == 1) {
114 return static_cast<uint64_t>(tag) * 0x0101010101010101ULL;
115 } else if constexpr (sizeof(TagType) == 2) {
116 return static_cast<uint64_t>(tag) * 0x0001000100010001ULL;
117 } else if constexpr (sizeof(TagType) == 4) {
118 return static_cast<uint64_t>(tag) * 0x0000000100000001ULL;
119 } else {
120 return tag;
121 }
122 } else {
123 if constexpr (sizeof(TagType) == 1) {
124 return static_cast<uint32_t>(tag) * 0x01010101U;
125 } else if constexpr (sizeof(TagType) == 2) {
126 return static_cast<uint32_t>(tag) * 0x00010001U;
127 } else if constexpr (sizeof(TagType) == 4) {
128 return static_cast<uint32_t>(tag);
129 } else {
130 return tag;
131 }
132 }
133}
Here is the call graph for this function: