FZGPUModules 2.0
GPU-accelerated modular compression pipelines
Loading...
Searching...
No Matches
BatchPrefixSum.h
1
9#ifndef FZ_ANS_DIETGPU_ANS_BATCHPREFIXSUM_H
10#define FZ_ANS_DIETGPU_ANS_BATCHPREFIXSUM_H
11
12#pragma once
13
14#include <cub/cub.cuh>
15#include <vector>
16#include "utils/StaticUtils.h"
17
18namespace fz { namespace ans {
19
20// FIXME: at some point, batchExclusivePrefixSum1 can no longer be run with
21// 1024 threads. Restrict our max threads to 512
22constexpr int kMaxBEPSThreads = 512;
23
24template <typename T>
25struct NoTransform {
26 __host__ __device__ __forceinline__ T operator()(const T& v) const {
27 return v;
28 }
29};
30
31template <typename T, int Threads, typename TransformFn>
32__global__ void batchExclusivePrefixSum1(
33 const T* __restrict__ in,
34 T* __restrict__ out,
35 void* __restrict__ blockTotal,
36 uint32_t maxNumCompressedBlocks,
37 TransformFn fn) {
38 uint32_t batch = blockIdx.y;
39 uint32_t block = blockIdx.x;
40 uint32_t blocksInBatch = gridDim.x;
41 uint32_t tid = threadIdx.x;
42
43 int batchIdx = block * Threads + tid;
44 bool valid = batchIdx < maxNumCompressedBlocks;
45 int totalIdx = batch * maxNumCompressedBlocks + batchIdx;
46 auto v = valid ? fn(in[totalIdx]) : T(0);
47
48 using Scan = cub::BlockScan<T, Threads>;
49 __shared__ typename Scan::TempStorage smem;
50 T prefix = 0;
51 T total = 0;
52 Scan(smem).ExclusiveSum(v, prefix, total);
53
54 if (valid) {
55 out[totalIdx] = prefix;
56 }
57
58 // Only if this is not provided is 1 level of the tree enough
59 if (threadIdx.x == 0 && blockTotal) {
60 ((T*)blockTotal)[batch * blocksInBatch + block] = total;
61 }
62}
63
64// Single block that performs the cross-block prefix sum
65template <typename T, int Threads>
66__global__ void batchExclusivePrefixSum2(
67 void* __restrict__ blockTotal,
68 uint32_t maxNumCompressedBlocks,
69 uint32_t blocksInBatch) {
70 uint32_t batch = blockIdx.x;
71 uint32_t tid = threadIdx.x;
72
73 bool valid = tid < blocksInBatch;
74 auto v = valid ? ((T*)blockTotal)[batch * blocksInBatch + tid] : 0;
75
76 using Scan = cub::BlockScan<T, Threads>;
77 __shared__ typename Scan::TempStorage smem;
78
79 Scan(smem).ExclusiveSum(v, v);
80
81 if (valid) {
82 ((T*)blockTotal)[batch * blocksInBatch + tid] = v;
83 }
84}
85
86template <typename T, int Threads>
87__global__ void batchExclusivePrefixSum3(
88 T* __restrict__ out,
89 const void* __restrict__ blockTotal,
90 uint32_t maxNumCompressedBlocks) {
91 uint32_t batch = blockIdx.y;
92 uint32_t block = blockIdx.x;
93 uint32_t blocksInBatch = gridDim.x;
94 uint32_t tid = threadIdx.x;
95
96 auto vBlock = ((const T*)blockTotal)[batch * blocksInBatch + block];
97
98 int batchIdx = block * Threads + tid;
99 bool valid = batchIdx < maxNumCompressedBlocks;
100
101 int totalIdx = batch * maxNumCompressedBlocks + batchIdx;
102
103 if (valid) {
104 out[totalIdx] += vBlock;
105 }
106}
107
108inline size_t getBatchExclusivePrefixSumTempSize(
109 uint32_t maxNumCompressedBlocks) {
110 if (maxNumCompressedBlocks <= kMaxBEPSThreads) {
111 return 0;
112 } else {
113 // number of blocks required
114 return divUp(maxNumCompressedBlocks, kMaxBEPSThreads);
115 }
116}
117
118// Perform a batched exclusive prefix sum over maxNumCompressedBlocks data
119template <typename T, typename TransformFn>
120void batchExclusivePrefixSum(
121 const T* in_dev,
122 T* out_dev,
123 void* temp_dev,
124 uint32_t maxNumCompressedBlocks,
125 const TransformFn& fn,
126 cudaStream_t stream) {
127 // maximum size we can handle with a two-level reduction
128 assert(maxNumCompressedBlocks <= kMaxBEPSThreads * kMaxBEPSThreads);
129
130#define BPS_LEVEL_1(THREADS, TEMP) \
131 batchExclusivePrefixSum1<T, THREADS, TransformFn> \
132 <<<dim3(blocks, 1), THREADS, 0, stream>>>( \
133 in_dev, out_dev, TEMP, maxNumCompressedBlocks, fn)
134
135#define BPS_LEVEL_2(THREADS) \
136 batchExclusivePrefixSum2<T, THREADS> \
137 <<<1, THREADS, 0, stream>>>(temp_dev, maxNumCompressedBlocks, blocks)
138
139#define BPS_LEVEL_3(THREADS) \
140 batchExclusivePrefixSum3<T, THREADS> \
141 <<<dim3(blocks, 1), THREADS, 0, stream>>>( \
142 out_dev, temp_dev, maxNumCompressedBlocks)
143
144 if (maxNumCompressedBlocks > kMaxBEPSThreads) {
145 // multi-level reduction required
146 uint32_t blocks = divUp(maxNumCompressedBlocks, kMaxBEPSThreads);
147 assert(blocks > 1);
148 assert(temp_dev); // must have this allocated
149
150 BPS_LEVEL_1(kMaxBEPSThreads, temp_dev);
151
152 if (blocks <= 32) {
153 BPS_LEVEL_2(32);
154 } else if (blocks <= 64) {
155 BPS_LEVEL_2(64);
156 } else if (blocks <= 128) {
157 BPS_LEVEL_2(128);
158 } else if (blocks <= 256) {
159 BPS_LEVEL_2(256);
160 } else {
161 assert(blocks <= kMaxBEPSThreads);
162 BPS_LEVEL_2(kMaxBEPSThreads);
163 }
164
165 BPS_LEVEL_3(kMaxBEPSThreads);
166 } else {
167 // single-level reduction
168 uint32_t blocks = 1;
169
170 if (maxNumCompressedBlocks <= 32) {
171 BPS_LEVEL_1(32, (T*)nullptr);
172 } else if (maxNumCompressedBlocks <= 64) {
173 BPS_LEVEL_1(64, (T*)nullptr);
174 } else if (maxNumCompressedBlocks <= 128) {
175 BPS_LEVEL_1(128, (T*)nullptr);
176 } else if (maxNumCompressedBlocks <= 256) {
177 BPS_LEVEL_1(256, (T*)nullptr);
178 } else {
179 assert(maxNumCompressedBlocks <= kMaxBEPSThreads);
180 BPS_LEVEL_1(kMaxBEPSThreads, (T*)nullptr);
181 }
182 }
183
184#undef BPS_LEVEL_3
185#undef BPS_LEVEL_2
186#undef BPS_LEVEL_1
187}
188
189}} // namespace fz::ans
190
191#endif // FZ_ANS_DIETGPU_ANS_BATCHPREFIXSUM_H
Definition dag.h:24