These variants will perform an update to the atomic according to op with value of the sum of input values of all threads in the group. Previous value of the atomic will be combined with the result of scan by each thread and returned.
What would be some examples where the value in the atomic argument is required?
The programming guide gives the following example. Total value is required by other warps to compute the correct offset into temporary storage:
#include <cooperative_groups.h>
#include <cooperative_groups/scan.h>
namespace cg = cooperative_groups;
// Buffer partitioning is static to make the example easier to follow,
// but any arbitrary dynamic allocation scheme can be implemented by replacing this function.
__device__ int calculate_buffer_space_needed(cg::thread_block_tile<32>& tile) {
return tile.thread_rank() % 2 + 1;
}
__device__ int my_thread_data(int i) {
return i;
}
__global__ void kernel() {
__shared__ extern int buffer[];
__shared__ cuda::atomic<int, cuda::thread_scope_block> buffer_used;
auto block = cg::this_thread_block();
auto tile = cg::tiled_partition<32>(block);
buffer_used = 0;
block.sync();
// each thread calculates buffer size it needs
int buf_needed = calculate_buffer_space_needed(tile);
// scan over the needs of each thread, result for each thread is an offset
// of that thread’s part of the buffer. buffer_used is atomically updated with
// the sum of all thread's inputs, to correctly offset other tile’s allocations
int buf_offset =
cg::exclusive_scan_update(tile, buffer_used, buf_needed);
// each thread fills its own part of the buffer with thread specific data
for (int i = 0 ; i < buf_needed ; ++i) {
buffer[buf_offset + i] = my_thread_data(i);
}
block.sync();
// buffer_used now holds total amount of memory allocated
// buffer is {0, 0, 1, 0, 0, 1 ...};
}