44#include < cstdint>
55#include " CUDACore/CMSUnrollLoop.h"
66#include " AlpakaCore/alpakaConfig.h"
7+ #include " AlpakaCore/threadfence.h"
78
89#ifdef ALPAKA_ACC_GPU_CUDA_ENABLED
910
@@ -51,7 +52,7 @@ namespace cms {
5152 uint32_t const blockDimension (alpaka::getWorkDiv<alpaka::Block, alpaka::Threads>(acc)[0u ]);
5253 uint32_t const gridBlockIdx (alpaka::getIdx<alpaka::Grid, alpaka::Blocks>(acc)[0u ]);
5354 uint32_t const blockThreadIdx (alpaka::getIdx<alpaka::Block, alpaka::Threads>(acc)[0u ]);
54- assert (ws);
55+ ALPAKA_ASSERT_OFFLOAD (ws);
5556 ALPAKA_ASSERT_OFFLOAD (size <= 1024 );
5657 ALPAKA_ASSERT_OFFLOAD (0 == blockDimension % 32 );
5758 auto first = blockThreadIdx;
@@ -99,7 +100,7 @@ namespace cms {
99100 uint32_t const blockDimension (alpaka::getWorkDiv<alpaka::Block, alpaka::Threads>(acc)[0u ]);
100101 uint32_t const gridBlockIdx (alpaka::getIdx<alpaka::Grid, alpaka::Blocks>(acc)[0u ]);
101102 uint32_t const blockThreadIdx (alpaka::getIdx<alpaka::Block, alpaka::Threads>(acc)[0u ]);
102- assert (ws);
103+ ALPAKA_ASSERT_OFFLOAD (ws);
103104 ALPAKA_ASSERT_OFFLOAD (size <= 1024 );
104105 ALPAKA_ASSERT_OFFLOAD (0 == blockDimension % 32 );
105106 auto first = blockThreadIdx;
@@ -134,43 +135,46 @@ namespace cms {
134135
135136 // limited to 1024*1024 elements....
136137 template <typename T>
137- struct multiBlockPrefixScanFirstStep {
138+ struct multiBlockPrefixScan {
138139 template <typename T_Acc>
139- ALPAKA_FN_ACC void operator ()(const T_Acc& acc, T const * ci, T* co, int32_t size) const {
140+ ALPAKA_FN_ACC void operator ()(const T_Acc& acc, T const * ci, T* co, int32_t size, int32_t * pc ) const {
140141 uint32_t const blockDimension (alpaka::getWorkDiv<alpaka::Block, alpaka::Threads>(acc)[0u ]);
141142 uint32_t const threadDimension (alpaka::getWorkDiv<alpaka::Thread, alpaka::Elems>(acc)[0u ]);
142143 uint32_t const blockIdx (alpaka::getIdx<alpaka::Grid, alpaka::Blocks>(acc)[0u ]);
144+ uint32_t const threadIdx (alpaka::getIdx<alpaka::Block, alpaka::Threads>(acc)[0u ]);
143145
144- auto & ws = alpaka::declareSharedVar<T[32 ], __COUNTER__>(acc);
145146 // first each block does a scan of size 1024; (better be enough blocks....)
146147#ifndef NDEBUG
147148 uint32_t const gridDimension (alpaka::getWorkDiv<alpaka::Grid, alpaka::Blocks>(acc)[0u ]);
148149 ALPAKA_ASSERT_OFFLOAD (gridDimension / threadDimension <= 1024 );
149150#endif
150151 int off = blockDimension * blockIdx * threadDimension;
152+ auto & ws = alpaka::declareSharedVar<T[32 ], __COUNTER__>(acc);
151153 if (size - off > 0 )
152154 blockPrefixScan (acc, ci + off, co + off, std::min (int (blockDimension * threadDimension), size - off), ws);
153- }
154- };
155155
156- // limited to 1024*1024 elements....
157- template <typename T>
158- struct multiBlockPrefixScanSecondStep {
159- template <typename T_Acc>
160- ALPAKA_FN_ACC void operator ()(const T_Acc& acc, T const * ci, T* co, int32_t size, int32_t numBlocks) const {
161- uint32_t const blockDimension (alpaka::getWorkDiv<alpaka::Block, alpaka::Threads>(acc)[0u ]);
162- uint32_t const threadDimension (alpaka::getWorkDiv<alpaka::Thread, alpaka::Elems>(acc)[0u ]);
156+ auto & isLastBlockDone = alpaka::declareSharedVar<bool , __COUNTER__>(acc);
157+ if (0 == threadIdx) {
158+ cms::alpakatools::threadfence (acc);
159+ auto value = alpaka::atomicAdd (acc, pc, 1 , alpaka::hierarchy::Blocks{}); // block counter
160+ isLastBlockDone = (value == (int (gridDimension) - 1 ));
161+ }
163162
164- uint32_t const threadIdx ( alpaka::getIdx<alpaka::Block, alpaka::Threads> (acc)[ 0u ] );
163+ alpaka::syncBlockThreads (acc);
165164
166- auto * const psum (alpaka::getDynSharedMem<T>(acc));
165+ if (!isLastBlockDone)
166+ return ;
167+
168+ ALPAKA_ASSERT_OFFLOAD (int (gridDimension) == *pc);
169+
170+ auto & psum = alpaka::declareSharedVar<T[1024 ], __COUNTER__>(acc);
171+
172+ ALPAKA_ASSERT_OFFLOAD (static_cast <int32_t >(blockDimension * threadDimension) >= gridDimension);
167173
168- // first each block does a scan of size 1024; (better be enough blocks....)
169- ALPAKA_ASSERT_OFFLOAD (static_cast <int32_t >(blockDimension * threadDimension) >= numBlocks);
170174 for (int elemId = 0 ; elemId < static_cast <int >(threadDimension); ++elemId) {
171175 int index = +threadIdx * threadDimension + elemId;
172176
173- if (index < numBlocks ) {
177+ if (index < gridDimension ) {
174178 int lastElementOfPreviousBlockId = index * blockDimension * threadDimension - 1 ;
175179 psum[index] = (lastElementOfPreviousBlockId < size and lastElementOfPreviousBlockId >= 0 )
176180 ? co[lastElementOfPreviousBlockId]
@@ -179,9 +183,7 @@ namespace cms {
179183 }
180184
181185 alpaka::syncBlockThreads (acc);
182-
183- auto & ws = alpaka::declareSharedVar<T[32 ], __COUNTER__>(acc);
184- blockPrefixScan (acc, psum, psum, numBlocks, ws);
186+ blockPrefixScan (acc, psum, psum, gridDimension, ws);
185187
186188 for (int elemId = 0 ; elemId < static_cast <int >(threadDimension); ++elemId) {
187189 int first = threadIdx * threadDimension + elemId;
@@ -192,40 +194,7 @@ namespace cms {
192194 }
193195 }
194196 };
195-
196197 } // namespace alpakatools
197198} // namespace cms
198199
199- namespace alpaka {
200- namespace traits {
201-
202- // #############################################################################
203- // ! The trait for getting the size of the block shared dynamic memory for a kernel.
204- template <typename T, typename TAcc>
205- struct BlockSharedMemDynSizeBytes <cms::alpakatools::multiBlockPrefixScanSecondStep<T>, TAcc> {
206- // -----------------------------------------------------------------------------
207- // ! \return The size of the shared memory allocated for a block.
208- template <typename TVec>
209- ALPAKA_FN_HOST_ACC static auto getBlockSharedMemDynSizeBytes (
210- cms::alpakatools::multiBlockPrefixScanSecondStep<T> const & myKernel,
211- TVec const & blockThreadExtent,
212- TVec const & threadElemExtent,
213- T const * ci,
214- T* co,
215- int32_t size,
216- int32_t numBlocks) -> T {
217- alpaka::ignore_unused (myKernel);
218- alpaka::ignore_unused (blockThreadExtent);
219- alpaka::ignore_unused (threadElemExtent);
220- alpaka::ignore_unused (ci);
221- alpaka::ignore_unused (co);
222- alpaka::ignore_unused (size);
223-
224- return static_cast <size_t >(numBlocks) * sizeof (T);
225- }
226- };
227-
228- } // namespace traits
229- } // namespace alpaka
230-
231200#endif // HeterogeneousCore_AlpakaUtilities_interface_prefixScan_h
0 commit comments