Skip to content

Commit 4efa462

Browse files
authored
Clean up hash-based groupby aggregation, reducing overhead and memory usage (#20658)
This does some minor cleanup to the hash-based groupby aggregation code, removing some code path that seems never (or very rarely) executed and reducing a little of memory usage. Authors: - Nghia Truong (https://github.com/ttnghia) Approvers: - Yunsong Wang (https://github.com/PointKernel) - Bradley Dice (https://github.com/bdice) URL: #20658
1 parent c706b0b commit 4efa462

10 files changed

Lines changed: 99 additions & 302 deletions

cpp/src/groupby/hash/compute_mapping_indices.cu

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,6 @@ template void compute_mapping_indices<hash_set_ref_t<cuco::insert_and_find_tag>>
1717
size_type* local_mapping_index,
1818
size_type* global_mapping_index,
1919
size_type* block_cardinality,
20+
cuda::std::atomic_flag* needs_global_memory_fallback,
2021
rmm::cuda_stream_view stream);
2122
} // namespace cudf::groupby::detail::hash

cpp/src/groupby/hash/compute_mapping_indices.cuh

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,13 @@ __device__ void find_local_mapping(cooperative_groups::thread_block const& block
4242
auto const ref_cardinality =
4343
cuda::atomic_ref<size_type, cuda::thread_scope_block>{*cardinality};
4444
auto const shared_set_index = ref_cardinality.fetch_add(1, cuda::std::memory_order_relaxed);
45+
46+
// The value of `shared_set_index` is before increment, thus if we have
47+
// `shared_set_index == GROUPBY_CARDINALITY_THRESHOLD` the value of cardinality
48+
// will be at least `GROUPBY_CARDINALITY_THRESHOLD + 1`.
49+
// This will trigger fallback to global memory.
50+
if (shared_set_index >= GROUPBY_CARDINALITY_THRESHOLD) { return cuda::std::pair{0, true}; }
51+
4552
shared_set_indices[shared_set_index] = idx;
4653
local_mapping_indices[idx] = shared_set_index;
4754
}
@@ -71,7 +78,7 @@ __device__ void find_global_mapping(cooperative_groups::thread_block const& bloc
7178
auto const input_idx = shared_set_indices[idx];
7279
auto const key_idx = *global_set.insert_and_find(input_idx).first;
7380

74-
global_mapping_indices[block.group_index().x * GROUPBY_SHM_MAX_ELEMENTS + idx] = key_idx;
81+
global_mapping_indices[block.group_index().x * GROUPBY_CARDINALITY_THRESHOLD + idx] = key_idx;
7582
}
7683
}
7784

@@ -88,9 +95,10 @@ CUDF_KERNEL void mapping_indices_kernel(size_type num_input_rows,
8895
bitmask_type const* row_bitmask,
8996
size_type* local_mapping_indices,
9097
size_type* global_mapping_indices,
91-
size_type* block_cardinality)
98+
size_type* block_cardinality,
99+
cuda::std::atomic_flag* needs_global_memory_fallback)
92100
{
93-
__shared__ size_type shared_set_indices[GROUPBY_SHM_MAX_ELEMENTS];
101+
__shared__ size_type shared_set_indices[GROUPBY_CARDINALITY_THRESHOLD];
94102

95103
// Shared set initialization
96104
__shared__ size_type slots[valid_extent.value()];
@@ -126,12 +134,17 @@ CUDF_KERNEL void mapping_indices_kernel(size_type num_input_rows,
126134
shared_set_indices);
127135

128136
block.sync();
129-
if (cardinality >= GROUPBY_CARDINALITY_THRESHOLD) { break; }
137+
if (cardinality > GROUPBY_CARDINALITY_THRESHOLD) {
138+
if (block.thread_rank() == 0) {
139+
needs_global_memory_fallback->test_and_set(cuda::std::memory_order_relaxed);
140+
}
141+
break;
142+
}
130143
}
131144

132145
// Insert unique keys from shared to global hash set if block-cardinality
133146
// doesn't exceed the threshold upper-limit
134-
if (cardinality < GROUPBY_CARDINALITY_THRESHOLD) {
147+
if (cardinality <= GROUPBY_CARDINALITY_THRESHOLD) {
135148
find_global_mapping(block, cardinality, global_set, shared_set_indices, global_mapping_indices);
136149
}
137150

@@ -155,13 +168,16 @@ void compute_mapping_indices(size_type grid_size,
155168
size_type* local_mapping_indices,
156169
size_type* global_mapping_indices,
157170
size_type* block_cardinality,
171+
cuda::std::atomic_flag* needs_global_memory_fallback,
158172
rmm::cuda_stream_view stream)
159173
{
160-
mapping_indices_kernel<<<grid_size, GROUPBY_BLOCK_SIZE, 0, stream>>>(num_rows,
161-
global_set,
162-
row_bitmask,
163-
local_mapping_indices,
164-
global_mapping_indices,
165-
block_cardinality);
174+
mapping_indices_kernel<<<grid_size, GROUPBY_BLOCK_SIZE, 0, stream>>>(
175+
num_rows,
176+
global_set,
177+
row_bitmask,
178+
local_mapping_indices,
179+
global_mapping_indices,
180+
block_cardinality,
181+
needs_global_memory_fallback);
166182
}
167183
} // namespace cudf::groupby::detail::hash

cpp/src/groupby/hash/compute_mapping_indices.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,6 @@ void compute_mapping_indices(size_type grid_size,
2727
size_type* local_mapping_index,
2828
size_type* global_mapping_index,
2929
size_type* block_cardinality,
30+
cuda::std::atomic_flag* needs_global_memory_fallback,
3031
rmm::cuda_stream_view stream);
3132
} // namespace cudf::groupby::detail::hash

cpp/src/groupby/hash/compute_mapping_indices_null.cu

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,6 @@ template void compute_mapping_indices<nullable_hash_set_ref_t<cuco::insert_and_f
1818
size_type* local_mapping_index,
1919
size_type* global_mapping_index,
2020
size_type* block_cardinality,
21+
cuda::std::atomic_flag* needs_global_memory_fallback,
2122
rmm::cuda_stream_view stream);
2223
} // namespace cudf::groupby::detail::hash

cpp/src/groupby/hash/compute_shared_memory_aggs.cu

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ __device__ void compute_final_aggregations(cooperative_groups::thread_block cons
145145
// Aggregates shared memory sources to global memory targets
146146
for (auto idx = block.thread_rank(); idx < num_agg_locations; idx += block.num_threads()) {
147147
auto const target_idx =
148-
global_mapping_index[(block.group_index().x * GROUPBY_SHM_MAX_ELEMENTS) +
148+
global_mapping_index[(block.group_index().x * GROUPBY_CARDINALITY_THRESHOLD) +
149149
(idx % cardinality)];
150150
for (auto col_idx = col_start; col_idx < col_end; col_idx++) {
151151
auto target_col = target.column(col_idx);
@@ -182,7 +182,7 @@ CUDF_KERNEL void single_pass_shmem_aggs_kernel(cudf::size_type num_rows,
182182
{
183183
auto const block = cooperative_groups::this_thread_block();
184184
auto const cardinality = block_cardinality[block.group_index().x];
185-
if (cardinality >= GROUPBY_CARDINALITY_THRESHOLD or cardinality == 0) { return; }
185+
if (cardinality > GROUPBY_CARDINALITY_THRESHOLD or cardinality == 0) { return; }
186186

187187
auto constexpr min_shmem_agg_locations = 32;
188188
auto const multiplication_factor = min_shmem_agg_locations / cardinality;

cpp/src/groupby/hash/compute_single_pass_aggs.cu

Lines changed: 1 addition & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,10 @@
55

66
#include "compute_single_pass_aggs.cuh"
77
#include "compute_single_pass_aggs.hpp"
8+
#include "single_pass_functors.cuh"
89

9-
#include <rmm/device_scalar.hpp>
1010
#include <rmm/device_uvector.hpp>
1111

12-
#include <cub/device/device_select.cuh>
13-
1412
namespace cudf::groupby::detail::hash {
1513

1614
std::pair<bool, size_type> is_shared_memory_compatible(host_span<aggregation::Kind const> agg_kinds,
@@ -39,39 +37,6 @@ std::pair<bool, size_type> is_shared_memory_compatible(host_span<aggregation::Ki
3937
return {can_run_by_shared_mem_kernel, available_shmem_size};
4038
}
4139

42-
std::pair<size_type, rmm::device_uvector<size_type>> find_fallback_blocks(
43-
size_type grid_size, size_type const* block_cardinality, rmm::cuda_stream_view stream)
44-
{
45-
rmm::device_uvector<size_type> fallback_block_ids(grid_size, stream);
46-
rmm::device_scalar<size_type> d_num_fallback_blocks(stream);
47-
48-
std::size_t storage_bytes = 0;
49-
auto const select_pred = [block_cardinality] __device__(auto const idx) {
50-
return block_cardinality[idx] >= GROUPBY_CARDINALITY_THRESHOLD;
51-
};
52-
auto const exec_copy_if = [&](auto const storage_ptr) {
53-
cub::DeviceSelect::If(storage_ptr,
54-
storage_bytes,
55-
thrust::make_counting_iterator(0),
56-
fallback_block_ids.begin(),
57-
d_num_fallback_blocks.data(),
58-
grid_size,
59-
select_pred,
60-
stream.value());
61-
};
62-
63-
exec_copy_if(nullptr);
64-
rmm::device_buffer tmp_storage(storage_bytes, stream);
65-
exec_copy_if(tmp_storage.data());
66-
67-
auto const num_fallback_blocks = d_num_fallback_blocks.value(stream);
68-
if (num_fallback_blocks > 0) { fallback_block_ids.resize(num_fallback_blocks, stream); }
69-
70-
return {num_fallback_blocks,
71-
num_fallback_blocks > 0 ? std::move(fallback_block_ids)
72-
: rmm::device_uvector<size_type>{0, stream}};
73-
}
74-
7540
template std::pair<rmm::device_uvector<size_type>, bool> compute_single_pass_aggs<global_set_t>(
7641
global_set_t& global_set,
7742
bitmask_type const* row_bitmask,

0 commit comments

Comments
 (0)