44#include < cstdint>
55
66#include " AlpakaCore/alpakaConfig.h"
7+ #include " AlpakaCore/threadfence.h"
78#include " Framework/CMSUnrollLoop.h"
89
910#ifdef ALPAKA_ACC_GPU_CUDA_ENABLED
@@ -49,23 +50,23 @@ namespace cms {
4950#endif
5051 ) {
5152#if defined ALPAKA_ACC_GPU_CUDA_ENABLED and __CUDA_ARCH__
52- uint32_t const blockDimension (alpaka::getWorkDiv<alpaka::Block, alpaka::Threads>(acc)[0u ]);
53- uint32_t const gridBlockIdx (alpaka::getIdx<alpaka::Grid, alpaka::Blocks>(acc)[0u ]);
54- uint32_t const blockThreadIdx (alpaka::getIdx<alpaka::Block, alpaka::Threads>(acc)[0u ]);
55- assert (ws);
53+ const int32_t blockDim (alpaka::getWorkDiv<alpaka::Block, alpaka::Threads>(acc)[0u ]);
54+ const int32_t gridBlockIdx (alpaka::getIdx<alpaka::Grid, alpaka::Blocks>(acc)[0u ]);
55+ const int32_t blockThreadIdx (alpaka::getIdx<alpaka::Block, alpaka::Threads>(acc)[0u ]);
56+ ALPAKA_ASSERT_OFFLOAD (ws);
5657 ALPAKA_ASSERT_OFFLOAD (size <= 1024 );
57- ALPAKA_ASSERT_OFFLOAD (0 == blockDimension % 32 );
58+ ALPAKA_ASSERT_OFFLOAD (0 == blockDim % 32 );
5859 auto first = blockThreadIdx;
5960 auto mask = __ballot_sync (0xffffffff , first < size);
6061 auto laneId = blockThreadIdx & 0x1f ;
6162
62- for (auto i = first; i < size; i += blockDimension ) {
63+ for (auto i = first; i < size; i += blockDim ) {
6364 warpPrefixScan (laneId, ci, co, i, mask);
6465 auto warpId = i / 32 ;
6566 ALPAKA_ASSERT_OFFLOAD (warpId < 32 );
6667 if (31 == laneId)
6768 ws[warpId] = co[i];
68- mask = __ballot_sync (mask, i + blockDimension < size);
69+ mask = __ballot_sync (mask, i + blockDim < size);
6970 }
7071 alpaka::syncBlockThreads (acc);
7172 if (size <= 32 )
@@ -74,7 +75,7 @@ namespace cms {
7475 warpPrefixScan (laneId, ws, blockThreadIdx, 0xffffffff );
7576 }
7677 alpaka::syncBlockThreads (acc);
77- for (auto i = first + 32 ; i < size; i += blockDimension ) {
78+ for (auto i = first + 32 ; i < size; i += blockDim ) {
7879 uint32_t warpId = i / 32 ;
7980 co[i] += ws[warpId - 1 ];
8081 }
@@ -97,23 +98,23 @@ namespace cms {
9798#endif
9899 ) {
99100#if defined ALPAKA_ACC_GPU_CUDA_ENABLED and __CUDA_ARCH__
100- uint32_t const blockDimension (alpaka::getWorkDiv<alpaka::Block, alpaka::Threads>(acc)[0u ]);
101- uint32_t const gridBlockIdx (alpaka::getIdx<alpaka::Grid, alpaka::Blocks>(acc)[0u ]);
102- uint32_t const blockThreadIdx (alpaka::getIdx<alpaka::Block, alpaka::Threads>(acc)[0u ]);
103- assert (ws);
101+ const int32_t blockDim (alpaka::getWorkDiv<alpaka::Block, alpaka::Threads>(acc)[0u ]);
102+ const int32_t gridBlockIdx (alpaka::getIdx<alpaka::Grid, alpaka::Blocks>(acc)[0u ]);
103+ const int32_t blockThreadIdx (alpaka::getIdx<alpaka::Block, alpaka::Threads>(acc)[0u ]);
104+ ALPAKA_ASSERT_OFFLOAD (ws);
104105 ALPAKA_ASSERT_OFFLOAD (size <= 1024 );
105- ALPAKA_ASSERT_OFFLOAD (0 == blockDimension % 32 );
106+ ALPAKA_ASSERT_OFFLOAD (0 == blockDim % 32 );
106107 auto first = blockThreadIdx;
107108 auto mask = __ballot_sync (0xffffffff , first < size);
108109 auto laneId = blockThreadIdx & 0x1f ;
109110
110- for (auto i = first; i < size; i += blockDimension ) {
111+ for (auto i = first; i < size; i += blockDim ) {
111112 warpPrefixScan (laneId, c, i, mask);
112113 auto warpId = i / 32 ;
113114 ALPAKA_ASSERT_OFFLOAD (warpId < 32 );
114115 if (31 == laneId)
115116 ws[warpId] = c[i];
116- mask = __ballot_sync (mask, i + blockDimension < size);
117+ mask = __ballot_sync (mask, i + blockDim < size);
117118 }
118119 alpaka::syncBlockThreads (acc);
119120 if (size <= 32 )
@@ -122,7 +123,7 @@ namespace cms {
122123 warpPrefixScan (laneId, ws, blockThreadIdx, 0xffffffff );
123124 }
124125 alpaka::syncBlockThreads (acc);
125- for (auto i = first + 32 ; i < size; i += blockDimension ) {
126+ for (auto i = first + 32 ; i < size; i += blockDim ) {
126127 auto warpId = i / 32 ;
127128 c[i] += ws[warpId - 1 ];
128129 }
@@ -135,98 +136,64 @@ namespace cms {
135136
136137 // limited to 1024*1024 elements....
137138 template <typename T>
138- struct multiBlockPrefixScanFirstStep {
139+ struct multiBlockPrefixScan {
139140 template <typename T_Acc>
140- ALPAKA_FN_ACC void operator ()(const T_Acc& acc, T const * ci, T* co, int32_t size) const {
141- uint32_t const blockDimension (alpaka::getWorkDiv<alpaka::Block, alpaka::Threads>(acc)[0u ]);
142- uint32_t const threadDimension (alpaka::getWorkDiv<alpaka::Thread, alpaka::Elems>(acc)[0u ]);
143- uint32_t const blockIdx (alpaka::getIdx<alpaka::Grid, alpaka::Blocks>(acc)[0u ]);
141+ ALPAKA_FN_ACC void operator ()(const T_Acc& acc, T const * ci, T* co, int32_t size, int32_t * pc) const {
142+ const int32_t blockDim (alpaka::getWorkDiv<alpaka::Block, alpaka::Threads>(acc)[0u ]);
143+ const int32_t threadDim (alpaka::getWorkDiv<alpaka::Thread, alpaka::Elems>(acc)[0u ]);
144+ const int32_t blockIdx (alpaka::getIdx<alpaka::Grid, alpaka::Blocks>(acc)[0u ]);
145+ const int32_t threadIdx (alpaka::getIdx<alpaka::Block, alpaka::Threads>(acc)[0u ]);
144146
145- auto & ws = alpaka::declareSharedVar<T[32 ], __COUNTER__>(acc);
146147 // first each block does a scan of size 1024; (better be enough blocks....)
147- #ifndef NDEBUG
148- uint32_t const gridDimension (alpaka::getWorkDiv<alpaka::Grid, alpaka::Blocks>(acc)[0u ]);
149- ALPAKA_ASSERT_OFFLOAD (gridDimension / threadDimension <= 1024 );
150- #endif
151- int off = blockDimension * blockIdx * threadDimension;
148+ int32_t const gridDim (alpaka::getWorkDiv<alpaka::Grid, alpaka::Blocks>(acc)[0u ]);
149+ ALPAKA_ASSERT_OFFLOAD (gridDim / threadDim <= 1024 );
150+ int off = blockDim * blockIdx * threadDim;
151+ auto & ws = alpaka::declareSharedVar<T[32 ], __COUNTER__>(acc);
152152 if (size - off > 0 )
153- blockPrefixScan (acc, ci + off, co + off, std::min (int (blockDimension * threadDimension), size - off), ws);
154- }
155- };
153+ blockPrefixScan (acc, ci + off, co + off, std::min (int (blockDim * threadDim), size - off), ws);
156154
157- // limited to 1024*1024 elements....
158- template <typename T>
159- struct multiBlockPrefixScanSecondStep {
160- template <typename T_Acc>
161- ALPAKA_FN_ACC void operator ()(const T_Acc& acc, T const * ci, T* co, int32_t size, int32_t numBlocks) const {
162- uint32_t const blockDimension (alpaka::getWorkDiv<alpaka::Block, alpaka::Threads>(acc)[0u ]);
163- uint32_t const threadDimension (alpaka::getWorkDiv<alpaka::Thread, alpaka::Elems>(acc)[0u ]);
155+ auto & isLastBlockDone = alpaka::declareSharedVar<bool , __COUNTER__>(acc);
156+ if (0 == threadIdx) {
157+ cms::alpakatools::threadfence (acc);
158+ auto value = alpaka::atomicAdd (acc, pc, 1 , alpaka::hierarchy::Blocks{}); // block counter
159+ isLastBlockDone = (value == (gridDim - 1 ));
160+ }
164161
165- uint32_t const threadIdx ( alpaka::getIdx<alpaka::Block, alpaka::Threads> (acc)[ 0u ] );
162+ alpaka::syncBlockThreads (acc);
166163
167- auto * const psum (alpaka::getDynSharedMem<T>(acc));
164+ if (!isLastBlockDone)
165+ return ;
168166
169- // first each block does a scan of size 1024; (better be enough blocks....)
170- ALPAKA_ASSERT_OFFLOAD (static_cast <int32_t >(blockDimension * threadDimension) >= numBlocks);
171- for (int elemId = 0 ; elemId < static_cast <int >(threadDimension); ++elemId) {
172- int index = +threadIdx * threadDimension + elemId;
167+ ALPAKA_ASSERT_OFFLOAD (gridDim == *pc);
173168
174- if (index < numBlocks) {
175- int lastElementOfPreviousBlockId = index * blockDimension * threadDimension - 1 ;
169+ auto & psum = alpaka::declareSharedVar<T[1024 ], __COUNTER__>(acc);
170+
171+ ALPAKA_ASSERT_OFFLOAD (static_cast <int32_t >(blockDim * threadDim) >= gridDim);
172+
173+ for (int elemId = 0 ; elemId < static_cast <int >(threadDim); ++elemId) {
174+ int index = +threadIdx * threadDim + elemId;
175+
176+ if (index < gridDim) {
177+ int lastElementOfPreviousBlockId = index * blockDim * threadDim - 1 ;
176178 psum[index] = (lastElementOfPreviousBlockId < size and lastElementOfPreviousBlockId >= 0 )
177179 ? co[lastElementOfPreviousBlockId]
178180 : T (0 );
179181 }
180182 }
181183
182184 alpaka::syncBlockThreads (acc);
185+ blockPrefixScan (acc, psum, psum, gridDim, ws);
183186
184- auto & ws = alpaka::declareSharedVar<T[32 ], __COUNTER__>(acc);
185- blockPrefixScan (acc, psum, psum, numBlocks, ws);
186-
187- for (int elemId = 0 ; elemId < static_cast <int >(threadDimension); ++elemId) {
188- int first = threadIdx * threadDimension + elemId;
189- for (int i = first + blockDimension * threadDimension; i < size; i += blockDimension * threadDimension) {
190- auto k = i / (blockDimension * threadDimension);
187+ for (int elemId = 0 ; elemId < static_cast <int >(threadDim); ++elemId) {
188+ int first = threadIdx * threadDim + elemId;
189+ for (int i = first + blockDim * threadDim; i < size; i += blockDim * threadDim) {
190+ auto k = i / (blockDim * threadDim);
191191 co[i] += psum[k];
192192 }
193193 }
194194 }
195195 };
196-
197196 } // namespace alpakatools
198197} // namespace cms
199198
200- namespace alpaka {
201- namespace traits {
202-
203- // #############################################################################
204- // ! The trait for getting the size of the block shared dynamic memory for a kernel.
205- template <typename T, typename TAcc>
206- struct BlockSharedMemDynSizeBytes <cms::alpakatools::multiBlockPrefixScanSecondStep<T>, TAcc> {
207- // -----------------------------------------------------------------------------
208- // ! \return The size of the shared memory allocated for a block.
209- template <typename TVec>
210- ALPAKA_FN_HOST_ACC static auto getBlockSharedMemDynSizeBytes (
211- cms::alpakatools::multiBlockPrefixScanSecondStep<T> const & myKernel,
212- TVec const & blockThreadExtent,
213- TVec const & threadElemExtent,
214- T const * ci,
215- T* co,
216- int32_t size,
217- int32_t numBlocks) -> T {
218- alpaka::ignore_unused (myKernel);
219- alpaka::ignore_unused (blockThreadExtent);
220- alpaka::ignore_unused (threadElemExtent);
221- alpaka::ignore_unused (ci);
222- alpaka::ignore_unused (co);
223- alpaka::ignore_unused (size);
224-
225- return static_cast <size_t >(numBlocks) * sizeof (T);
226- }
227- };
228-
229- } // namespace traits
230- } // namespace alpaka
231-
232199#endif // HeterogeneousCore_AlpakaUtilities_interface_prefixScan_h
0 commit comments