Skip to content

Commit 93d6172

Browse files
Refactor window storage (#627)
Closes #621 Based on the offline discussions, this PR replaces the `window` logic with `bucket` and adds new overloads of `make_bucket_extent` so OA no longer relies on the `Container` type to determine the bucket extent. --------- Co-authored-by: Daniel Jünger <[email protected]>
1 parent 5b4a80e commit 93d6172

37 files changed

+807
-630
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ Similar to how [Thrust](https://github.com/thrust/thrust) and [CUB](https://gith
1515

1616
### Major Updates
1717

18+
__11/01/2024__ Refined the term `window` as `bucket`
19+
1820
__01/08/2024__ Deprecated the `experimental` namespace
1921

2022
__01/02/2024__ Moved the legacy `static_map` to `cuco::legacy` namespace
@@ -254,4 +256,4 @@ We plan to add many GPU-accelerated, concurrent data structures to `cuCollection
254256
`cuco::bloom_filter` implements a Blocked Bloom Filter for approximate set membership queries.
255257

256258
#### Examples:
257-
- [Host-bulk APIs (Default fingerprinting policy)](https://github.com/NVIDIA/cuCollections/blob/dev/examples/bloom_filter/host_bulk_example.cu) (see [live example in godbolt](https://godbolt.org/clientstate/eJydVmtvGjkU_StXsx8WmuEVbVUJQiSapLtoK5IF2qpaVsjj8TBWBnvqBwRF-e977ZmBgZBqtVRqwL6Pc889vvZzoJnWXAod9P9-Dngc9HthkBGxsmTFgn5AbUyCMNDSKup-d94tBLyDG5nvFF-lBhq0CZfdy99CmHwd345HcHM_fbifjubj-0nb2Xr7z5wyoVkMVsRMgUkZjHJC8U-5E8JXphwQuGx3oeEMFkG5twiaAx9lJy2syQ6ENGA1wzBcQ8IzBuyJstwAF0DlOs84EZTBlpvUpyrjeDjwvQwiI0PQnqBHjr-SuiUQs4fuPqkxeb_T2W63beJht6VadbLCWHc-j2_uJrO7FkLfu30RGTILiv2wXGHh0Q5IjsgoiRBvRrYgFZCVYrhnpEO-VdxwsQpBy8RsiWI-Tsy1UTyy5oi8CifWXzdA-ohA4kYzGM8WAXwczcaz0Mf5Np7_cf9lDt9G0-loMh_fzeB-is2a3I5dq_DXJxhNvsOf48ltCAypw1TsKVeuCoTKHa0sLjicMXYEI5EFLJ0zyhNOoVIQrOSGKYFlQc7UmhdaQ5Cxj5PxNTfE-LVXxflUnYVYiF-4oJmNGVxRS2UnyqRcL7Hvhqk2ten1sY1JldWmQ6UVpu02X23FbIMplhtGjVTnTdgTo9YBW-YSm7Y7b6Wxuwyl1j7FwCU2hZG1X-bCoOK4aGwkj5sL8YyFgVukWLdxHIOw6-Uj22kntiH0ur92u90B7D-dTucKfmeCKWJYuQ3O_nwkkxduw0Pcd9Btvx-UkcbIrjKe64QrbSAlWeLjuWCy3PD0vpFAvErQKjMPXntoG5Xd0uhx6SvzOPCr22xVmygR8M0tszvynKmDBmaXF0I7tgCcBE5eaLL0JkOXfbB3neVk60553auYDDFLiM0MFA12mjwF5Kt3kuv365q7qnJdl_GeaxW-lKm1ift91KCBqys8kR9t9ojAPO-e47fxJFgOU7lyJK6Knru5WMDsY6yFgNoHw_tcTMRZmbtQZ79_pPMaatewRtU5P1v3LpWiG26rHbEVyrYZeo82ZnDfe80yDbFOK_nSWyHvdZdB3QAdvVj2thd1sRRWYh-mcDjaqgIcYBwafF7M5Tz3Ds6wlDOJ40aFIiwzNX_KWiRldu0scRBidxoF8BASkml2zN1ZR1F3PDoptRhlKX9Zpna107efqziFN1xane1KDeGs35eGjnN3EepU2iyGIh34q80oy1q51HixbBj44YHEzB-mw16dFTyq7i7Ur6gJD4VXjf0vcH2ZJiUG8Bbzt7W7RpjwqE6Gizui3N3W9QOhvWOuZEQyvN7wQomJIahzZamxGCushSmjsKeUR9yga8HrSd2fHqbXXTxjOZbl5oUskGArIkSOrHhfXtVWq8oNhmPTlOiUafcEif3MwnrP0yn2dIqSTvEGnUkmkS7HtgM7LI64X2xU8vIXWuNYbGcaVF8qT6yTQbMJnTJgIb9Cu0Xe5H_kPa2kvvSTvKJ5fkA6UeKLBb9XJPhl17dyPTmsnw48xVAVArr48wVfq-4NiK9CdXjUBmJDae_yve3htsxN8eINWhhoSC8ueh-gRRRNh3q9_NCFVgvvLYP_GczB4lZG1pF_Bmc8qsWklGa4uCkerriA9YrH4CWs9vHmONpH7oKXf_y_fwHeCexw))
259+
- [Host-bulk APIs (Default fingerprinting policy)](https://github.com/NVIDIA/cuCollections/blob/dev/examples/bloom_filter/host_bulk_example.cu) (see [live example in godbolt](https://godbolt.org/clientstate/eJydVmtvGjkU_StXsx8WmuEVbVUJQiSapLtoK5IF2qpaVsjj8TBWBnvqBwRF-e977ZmBgZBqtVRqwL6Pc889vvZzoJnWXAod9P9-Dngc9HthkBGxsmTFgn5AbUyCMNDSKup-d94tBLyDG5nvFF-lBhq0CZfdy99CmHwd345HcHM_fbifjubj-0nb2Xr7z5wyoVkMVsRMgUkZjHJC8U-5E8JXphwQuGx3oeEMFkG5twiaAx9lJy2syQ6ENGA1wzBcQ8IzBuyJstwAF0DlOs84EZTBlpvUpyrjeDjwvQwiI0PQnqBHjr-SuiUQs4fuPqkxeb_T2W63beJht6VadbLCWHc-j2_uJrO7FkLfu30RGTILiv2wXGHh0Q5IjsgoiRBvRrYgFZCVYrhnpEO-VdxwsQpBy8RsiWI-Tsy1UTyy5oi8CifWXzdA-ohA4kYzGM8WAXwczcaz0Mf5Np7_cf9lDt9G0-loMh_fzeB-is2a3I5dq_DXJxhNvsOf48ltCAypw1TsKVeuCoTKHa0sLjicMXYEI5EFLJ0zyhNOoVIQrOSGKYFlQc7UmhdaQ5Cxj5PxNTfE-LVXxflUnYVYiF-4oJmNGVxRS2UnyqRcL7Hvhqk2ten1sY1JldWmQ6UVpu02X23FbIMplhtGjVTnTdgTo9YBW-YSm7Y7b6Wxuwyl1j7FwCU2hZG1X-bCoOK4aGwkj5sL8YyFgVukWLdxHIOw6-Uj22kntiH0ur92u90B7D-dTucKfmeCKWJYuQ3O_nwkkxduw0Pcd9Btvx-UkcbIrjKe64QrbSAlWeLjuWCy3PD0vpFAvErQKjMPXntoG5Xd0uhx6SvzOPCr22xVmygR8M0tszvynKmDBmaXF0I7tgCcBE5eaLL0JkOXfbB3neVk60553auYDDFLiM0MFA12mjwF5Kt3kuv365q7qnJdl_GeaxW-lKm1ift91KCBqys8kR9t9ojAPO-e47fxJFgOU7lyJK6Knru5WMDsY6yFgNoHw_tcTMRZmbtQZ79_pPMaatewRtU5P1v3LpWiG26rHbEVyrYZeo82ZnDfe80yDbFOK_nSWyHvdZdB3QAdvVj2thd1sRRWYh-mcDjaqgIcYBwafF7M5Tz3Ds6wlDOJ40aFIiwzNX_KWiRldu0scRBidxoF8BASkml2zN1ZR1F3PDoptRhlKX9Zpna107efqziFN1xane1KDeGs35eGjnN3EepU2iyGIh34q80oy1q51HixbBj44YHEzB-mw16dFTyq7i7Ur6gJD4VXjf0vcH2ZJiUG8Bbzt7W7RpjwqE6Gizui3N3W9QOhvWOuZEQyvN7wQomJIahzZamxGCushSmjsKeUR9yga8HrSd2fHqbXXTxjOZbl5oUskGArIkSOrHhfXtVWq8oNhmPTlOiUafcEif3MwnrP0yn2dIqSTvEGnUkmkS7HtgM7LI64X2xU8vIXWuNYbGcaVF8qT6yTQbMJnTJgIb9Cu0Xe5H_kPa2kvvSTvKJ5fkA6UeKLBb9XJPhl17dyPTmsnw48xVAVArr48wVfq-4NiK9CdXjUBmJDae_yve3htsxN8eINWhhoSC8ueh-gRRRNh3q9_NCFVgvvLYP_GczB4lZG1pF_Bmc8qsWklGa4uCkerriA9YrH4CWs9vHmONpH7oKXf_y_fwHeCexw))
Lines changed: 121 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
#pragma once
1818

19-
#include <cuco/detail/storage/aow_storage_base.cuh>
19+
#include <cuco/detail/storage/bucket_storage_base.cuh>
2020
#include <cuco/extent.cuh>
2121
#include <cuco/utility/allocator.hpp>
2222

@@ -29,200 +29,213 @@
2929
#include <memory>
3030

3131
namespace cuco {
32+
/// Bucket type alias
33+
template <typename T, int32_t BucketSize>
34+
using bucket = detail::bucket<T, BucketSize>;
3235

33-
/// Window type alias
34-
template <typename T, int32_t WindowSize>
35-
using window = detail::window<T, WindowSize>;
36-
37-
/// forward declaration
38-
template <typename T, int32_t WindowSize, typename Extent>
39-
class aow_storage_ref;
36+
/// Alias for bucket
37+
template <typename T, int32_t BucketSize>
38+
using window = bucket<T, BucketSize>;
4039

4140
/**
42-
* @brief Array of Window open addressing storage class.
41+
* @brief Non-owning array of buckets storage reference type.
4342
*
44-
* @tparam T Slot type
45-
* @tparam WindowSize Number of slots in each window
46-
* @tparam Extent Type of extent denoting number of windows
47-
* @tparam Allocator Type of allocator used for device storage (de)allocation
43+
* @tparam T Storage element type
44+
* @tparam BucketSize Number of slots in each bucket
45+
* @tparam Extent Type of extent denoting storage capacity
4846
*/
49-
template <typename T,
50-
int32_t WindowSize,
51-
typename Extent = cuco::extent<std::size_t>,
52-
typename Allocator = cuco::cuda_allocator<cuco::window<T, WindowSize>>>
53-
class aow_storage : public detail::aow_storage_base<T, WindowSize, Extent> {
47+
template <typename T, int32_t BucketSize, typename Extent = cuco::extent<std::size_t>>
48+
class bucket_storage_ref : public detail::bucket_storage_base<T, BucketSize, Extent> {
5449
public:
55-
using base_type = detail::aow_storage_base<T, WindowSize, Extent>; ///< AoW base class type
50+
/// Array of buckets base class type
51+
using base_type = detail::bucket_storage_base<T, BucketSize, Extent>;
5652

57-
using base_type::window_size; ///< Number of elements processed per window
53+
using base_type::bucket_size; ///< Number of elements processed per bucket
5854

5955
using extent_type = typename base_type::extent_type; ///< Storage extent type
6056
using size_type = typename base_type::size_type; ///< Storage size type
6157
using value_type = typename base_type::value_type; ///< Slot type
62-
using window_type = typename base_type::window_type; ///< Slot window type
58+
using bucket_type = typename base_type::bucket_type; ///< Slot bucket type
6359

6460
using base_type::capacity;
65-
using base_type::num_windows;
66-
67-
/// Type of the allocator to (de)allocate windows
68-
using allocator_type =
69-
typename std::allocator_traits<Allocator>::template rebind_alloc<window_type>;
70-
using window_deleter_type =
71-
detail::custom_deleter<size_type, allocator_type>; ///< Type of window deleter
72-
using ref_type = aow_storage_ref<value_type, window_size, extent_type>; ///< Storage ref type
61+
using base_type::num_buckets;
7362

7463
/**
75-
* @brief Constructor of AoW storage.
76-
*
77-
* @note The input `size` should be exclusively determined by the return value of
78-
* `make_window_extent` since it depends on the requested low-bound value, the probing scheme, and
79-
* the storage.
64+
* @brief Constructor of AoS storage ref.
8065
*
81-
* @param size Number of windows to (de)allocate
82-
* @param allocator Allocator used for (de)allocating device storage
66+
* @param size Number of buckets
67+
* @param buckets Pointer to the buckets array
8368
*/
84-
explicit constexpr aow_storage(Extent size, Allocator const& allocator = {});
69+
__host__ __device__ explicit constexpr bucket_storage_ref(Extent size,
70+
bucket_type* buckets) noexcept;
8571

86-
aow_storage(aow_storage&&) = default; ///< Move constructor
8772
/**
88-
* @brief Replaces the contents of the storage with another storage.
73+
* @brief Custom un-incrementable input iterator for the convenience of `find` operations.
8974
*
90-
* @return Reference of the current storage object
75+
* @note This iterator is for read only and NOT incrementable.
9176
*/
92-
aow_storage& operator=(aow_storage&&) = default;
93-
~aow_storage() = default; ///< Destructor
94-
95-
aow_storage(aow_storage const&) = delete;
96-
aow_storage& operator=(aow_storage const&) = delete;
77+
struct iterator;
78+
using const_iterator = iterator const; ///< Const forward iterator type
9779

9880
/**
99-
* @brief Gets windows array.
81+
* @brief Returns an iterator to one past the last slot.
82+
*
83+
* This is provided for convenience for those familiar with checking
84+
* an iterator returned from `find()` against the `end()` iterator.
10085
*
101-
* @return Pointer to the first window
86+
* @return An iterator to one past the last slot
10287
*/
103-
[[nodiscard]] constexpr window_type* data() const noexcept;
88+
[[nodiscard]] __device__ constexpr iterator end() noexcept;
10489

10590
/**
106-
* @brief Gets the storage allocator.
91+
* @brief Returns a const_iterator to one past the last slot.
10792
*
108-
* @return The storage allocator
93+
* This is provided for convenience for those familiar with checking
94+
* an iterator returned from `find()` against the `end()` iterator.
95+
*
96+
* @return A const_iterator to one past the last slot
10997
*/
110-
[[nodiscard]] constexpr allocator_type allocator() const noexcept;
98+
[[nodiscard]] __device__ constexpr const_iterator end() const noexcept;
11199

112100
/**
113-
* @brief Gets window storage reference.
101+
* @brief Gets buckets array.
114102
*
115-
* @return Reference of window storage
103+
* @return Pointer to the first bucket
116104
*/
117-
[[nodiscard]] constexpr ref_type ref() const noexcept;
105+
[[nodiscard]] __device__ constexpr bucket_type* data() noexcept;
118106

119107
/**
120-
* @brief Initializes each slot in the AoW storage to contain `key`.
108+
* @brief Gets bucket array.
121109
*
122-
* @param key Key to which all keys in `slots` are initialized
123-
* @param stream Stream used for executing the kernel
110+
* @return Pointer to the first bucket
124111
*/
125-
void initialize(value_type key, cuda::stream_ref stream = {});
112+
[[nodiscard]] __device__ constexpr bucket_type* data() const noexcept;
126113

127114
/**
128-
* @brief Asynchronously initializes each slot in the AoW storage to contain `key`.
115+
* @brief Returns an array of slots (or a bucket) for a given index.
129116
*
130-
* @param key Key to which all keys in `slots` are initialized
131-
* @param stream Stream used for executing the kernel
117+
* @param index Index of the bucket
118+
* @return An array of slots
132119
*/
133-
void initialize_async(value_type key, cuda::stream_ref stream = {}) noexcept;
120+
[[nodiscard]] __device__ constexpr bucket_type operator[](size_type index) const noexcept;
134121

135122
private:
136-
allocator_type allocator_; ///< Allocator used to (de)allocate windows
137-
window_deleter_type window_deleter_; ///< Custom windows deleter
138-
std::unique_ptr<window_type, window_deleter_type> windows_; ///< Pointer to AoW storage
123+
bucket_type* buckets_; ///< Pointer to the buckets array
139124
};
140125

141126
/**
142-
* @brief Non-owning AoW storage reference type.
127+
* @brief Array of buckets open addressing storage class.
143128
*
144-
* @tparam T Storage element type
145-
* @tparam WindowSize Number of slots in each window
146-
* @tparam Extent Type of extent denoting storage capacity
129+
* @tparam T Slot type
130+
* @tparam BucketSize Number of slots in each bucket
131+
* @tparam Extent Type of extent denoting number of buckets
132+
* @tparam Allocator Type of allocator used for device storage (de)allocation
147133
*/
148-
template <typename T, int32_t WindowSize, typename Extent = cuco::extent<std::size_t>>
149-
class aow_storage_ref : public detail::aow_storage_base<T, WindowSize, Extent> {
134+
template <typename T,
135+
int32_t BucketSize,
136+
typename Extent = cuco::extent<std::size_t>,
137+
typename Allocator = cuco::cuda_allocator<cuco::bucket<T, BucketSize>>>
138+
class bucket_storage : public detail::bucket_storage_base<T, BucketSize, Extent> {
150139
public:
151-
using base_type = detail::aow_storage_base<T, WindowSize, Extent>; ///< AoW base class type
140+
/// Array of buckets base class type
141+
using base_type = detail::bucket_storage_base<T, BucketSize, Extent>;
152142

153-
using base_type::window_size; ///< Number of elements processed per window
143+
using base_type::bucket_size; ///< Number of elements processed per bucket
154144

155145
using extent_type = typename base_type::extent_type; ///< Storage extent type
156146
using size_type = typename base_type::size_type; ///< Storage size type
157147
using value_type = typename base_type::value_type; ///< Slot type
158-
using window_type = typename base_type::window_type; ///< Slot window type
148+
using bucket_type = typename base_type::bucket_type; ///< Slot bucket type
159149

160150
using base_type::capacity;
161-
using base_type::num_windows;
151+
using base_type::num_buckets;
152+
153+
/// Type of the allocator to (de)allocate buckets
154+
using allocator_type =
155+
typename std::allocator_traits<Allocator>::template rebind_alloc<bucket_type>;
156+
using bucket_deleter_type =
157+
detail::custom_deleter<size_type, allocator_type>; ///< Type of bucket deleter
158+
using ref_type = bucket_storage_ref<value_type, bucket_size, extent_type>; ///< Storage ref type
162159

163160
/**
164-
* @brief Constructor of AoS storage ref.
161+
* @brief Constructor of bucket storage.
162+
*
163+
* @note The input `size` should be exclusively determined by the return value of
164+
* `make_bucket_extent` since it depends on the requested low-bound value, the probing scheme, and
165+
* the storage.
165166
*
166-
* @param size Number of windows
167-
* @param windows Pointer to the windows array
167+
* @param size Number of buckets to (de)allocate
168+
* @param allocator Allocator used for (de)allocating device storage
168169
*/
169-
__host__ __device__ explicit constexpr aow_storage_ref(Extent size,
170-
window_type* windows) noexcept;
170+
explicit constexpr bucket_storage(Extent size, Allocator const& allocator = {});
171171

172+
bucket_storage(bucket_storage&&) = default; ///< Move constructor
172173
/**
173-
* @brief Custom un-incrementable input iterator for the convenience of `find` operations.
174+
* @brief Replaces the contents of the storage with another storage.
174175
*
175-
* @note This iterator is for read only and NOT incrementable.
176+
* @return Reference of the current storage object
176177
*/
177-
struct iterator;
178-
using const_iterator = iterator const; ///< Const forward iterator type
178+
bucket_storage& operator=(bucket_storage&&) = default;
179+
~bucket_storage() = default; ///< Destructor
180+
181+
bucket_storage(bucket_storage const&) = delete;
182+
bucket_storage& operator=(bucket_storage const&) = delete;
179183

180184
/**
181-
* @brief Returns an iterator to one past the last slot.
185+
* @brief Gets buckets array.
182186
*
183-
* This is provided for convenience for those familiar with checking
184-
* an iterator returned from `find()` against the `end()` iterator.
185-
*
186-
* @return An iterator to one past the last slot
187+
* @return Pointer to the first bucket
187188
*/
188-
[[nodiscard]] __device__ constexpr iterator end() noexcept;
189+
[[nodiscard]] constexpr bucket_type* data() const noexcept;
189190

190191
/**
191-
* @brief Returns a const_iterator to one past the last slot.
192-
*
193-
* This is provided for convenience for those familiar with checking
194-
* an iterator returned from `find()` against the `end()` iterator.
192+
* @brief Gets the storage allocator.
195193
*
196-
* @return A const_iterator to one past the last slot
194+
* @return The storage allocator
197195
*/
198-
[[nodiscard]] __device__ constexpr const_iterator end() const noexcept;
196+
[[nodiscard]] constexpr allocator_type allocator() const noexcept;
199197

200198
/**
201-
* @brief Gets windows array.
199+
* @brief Gets bucket storage reference.
202200
*
203-
* @return Pointer to the first window
201+
* @return Reference of bucket storage
204202
*/
205-
[[nodiscard]] __device__ constexpr window_type* data() noexcept;
203+
[[nodiscard]] constexpr ref_type ref() const noexcept;
206204

207205
/**
208-
* @brief Gets windows array.
206+
* @brief Initializes each slot in the bucket storage to contain `key`.
209207
*
210-
* @return Pointer to the first window
208+
* @param key Key to which all keys in `slots` are initialized
209+
* @param stream Stream used for executing the kernel
211210
*/
212-
[[nodiscard]] __device__ constexpr window_type* data() const noexcept;
211+
void initialize(value_type key, cuda::stream_ref stream = {});
213212

214213
/**
215-
* @brief Returns an array of slots (or a window) for a given index.
214+
* @brief Asynchronously initializes each slot in the bucket storage to contain `key`.
216215
*
217-
* @param index Index of the window
218-
* @return An array of slots
216+
* @param key Key to which all keys in `slots` are initialized
217+
* @param stream Stream used for executing the kernel
219218
*/
220-
[[nodiscard]] __device__ constexpr window_type operator[](size_type index) const noexcept;
219+
void initialize_async(value_type key, cuda::stream_ref stream = {}) noexcept;
221220

222221
private:
223-
window_type* windows_; ///< Pointer to the windows array
222+
allocator_type allocator_; ///< Allocator used to (de)allocate buckets
223+
bucket_deleter_type bucket_deleter_; ///< Custom buckets deleter
224+
/// Pointer to the bucket storage
225+
std::unique_ptr<bucket_type, bucket_deleter_type> buckets_;
224226
};
225227

228+
/// Alias for bucket_storage_ref
229+
template <typename T, int32_t BucketSize, typename Extent = cuco::extent<std::size_t>>
230+
using aow_storage_ref = bucket_storage_ref<T, BucketSize, Extent>;
231+
232+
/// Alias for bucket_storage
233+
template <typename T,
234+
int32_t BucketSize,
235+
typename Extent = cuco::extent<std::size_t>,
236+
typename Allocator = cuco::cuda_allocator<cuco::bucket<T, BucketSize>>>
237+
using aow_storage = bucket_storage<T, BucketSize, Extent, Allocator>;
238+
226239
} // namespace cuco
227240

228-
#include <cuco/detail/storage/aow_storage.inl>
241+
#include <cuco/detail/storage/bucket_storage.inl>

include/cuco/detail/equal_wrapper.cuh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ struct equal_wrapper {
8181
*
8282
* @note This function always compares the right-hand side element against sentinel values first
8383
* then performs a equality check with the given `equal_` callable, i.e., `equal_(lhs, rhs)`.
84-
* @note Container (like set or map) buckets MUST be always on the right-hand side.
84+
* @note Container (like set or map) slots MUST be always on the right-hand side.
8585
*
8686
* @tparam IsInsert Flag indicating whether it's an insert equality check or not. Insert probing
8787
* stops when it's an empty or erased slot while query probing stops only when it's empty.

0 commit comments

Comments
 (0)