Skip to content

Commit d966cb7

Browse files
committed
Fix the fragile dynamic map reserve logic
1 parent 209a566 commit d966cb7

File tree

1 file changed

+43
-33
lines changed

1 file changed

+43
-33
lines changed

include/cuco/detail/dynamic_map.inl

Lines changed: 43 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -79,42 +79,52 @@ dynamic_map<Key, Value, Scope, Allocator>::dynamic_map(std::size_t initial_capac
7979
template <typename Key, typename Value, cuda::thread_scope Scope, typename Allocator>
8080
void dynamic_map<Key, Value, Scope, Allocator>::reserve(std::size_t n, cudaStream_t stream)
8181
{
82-
std::size_t num_elements_remaining = n;
83-
std::size_t submap_idx = 0;
84-
while (num_elements_remaining > 0) {
85-
std::size_t submap_capacity;
86-
87-
// if the submap already exists
88-
if (submap_idx < submaps_.size()) {
89-
submap_capacity = submaps_[submap_idx]->get_capacity();
82+
// Calculate current total available capacity across all submaps
83+
std::size_t total_available_capacity = 0;
84+
for (std::size_t i = 0; i < submaps_.size(); ++i) {
85+
std::size_t submap_usable_capacity =
86+
static_cast<std::size_t>(max_load_factor_ * submaps_[i]->get_capacity());
87+
// Only count capacity above the minimum insert threshold
88+
if (submap_usable_capacity >= min_insert_size_) {
89+
total_available_capacity += submap_usable_capacity - min_insert_size_;
9090
}
91-
// if the submap does not exist yet, create it
92-
else {
93-
submap_capacity = capacity_;
94-
if (erased_key_sentinel_ != empty_key_sentinel_) {
95-
submaps_.push_back(std::make_unique<cuco::legacy::static_map<Key, Value, Scope, Allocator>>(
96-
submap_capacity,
97-
empty_key<Key>{empty_key_sentinel_},
98-
empty_value<Value>{empty_value_sentinel_},
99-
erased_key<Key>{erased_key_sentinel_},
100-
alloc_,
101-
stream));
102-
} else {
103-
submaps_.push_back(std::make_unique<cuco::legacy::static_map<Key, Value, Scope, Allocator>>(
104-
submap_capacity,
105-
empty_key<Key>{empty_key_sentinel_},
106-
empty_value<Value>{empty_value_sentinel_},
107-
alloc_,
108-
stream));
109-
}
110-
submap_num_successes_.push_back(submaps_[submap_idx]->num_successes_);
111-
submap_views_.push_back(submaps_[submap_idx]->get_device_view());
112-
submap_mutable_views_.push_back(submaps_[submap_idx]->get_device_mutable_view());
113-
capacity_ *= 2;
91+
}
92+
93+
// Create new submaps until we have enough capacity
94+
while (total_available_capacity < n) {
95+
std::size_t new_submap_capacity = capacity_;
96+
97+
if (erased_key_sentinel_ != empty_key_sentinel_) {
98+
submaps_.push_back(std::make_unique<cuco::legacy::static_map<Key, Value, Scope, Allocator>>(
99+
new_submap_capacity,
100+
empty_key<Key>{empty_key_sentinel_},
101+
empty_value<Value>{empty_value_sentinel_},
102+
erased_key<Key>{erased_key_sentinel_},
103+
alloc_,
104+
stream));
105+
} else {
106+
submaps_.push_back(std::make_unique<cuco::legacy::static_map<Key, Value, Scope, Allocator>>(
107+
new_submap_capacity,
108+
empty_key<Key>{empty_key_sentinel_},
109+
empty_value<Value>{empty_value_sentinel_},
110+
alloc_,
111+
stream));
114112
}
115113

116-
num_elements_remaining -= max_load_factor_ * submap_capacity - min_insert_size_;
117-
submap_idx++;
114+
std::size_t submap_idx = submaps_.size() - 1;
115+
submap_num_successes_.push_back(submaps_[submap_idx]->num_successes_);
116+
submap_views_.push_back(submaps_[submap_idx]->get_device_view());
117+
submap_mutable_views_.push_back(submaps_[submap_idx]->get_device_mutable_view());
118+
119+
// Add the new submap's usable capacity
120+
std::size_t new_usable_capacity =
121+
static_cast<std::size_t>(max_load_factor_ * new_submap_capacity);
122+
if (new_usable_capacity >= min_insert_size_) {
123+
total_available_capacity += new_usable_capacity - min_insert_size_;
124+
}
125+
126+
// Update capacity for next submap (double the size)
127+
capacity_ *= 2;
118128
}
119129
}
120130

0 commit comments

Comments
 (0)