Skip to content

Commit 20130b8

Browse files
antoniopetrefwyzard
authored andcommitted
[alpaka] Refactor prefixScan implementation
1 parent 0733b90 commit 20130b8

3 files changed

Lines changed: 41 additions & 82 deletions

File tree

src/alpaka/AlpakaCore/HistoContainer.h

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ namespace cms {
4141
T const *__restrict__ v,
4242
uint32_t const *__restrict__ offsets) const {
4343
const uint32_t nt = offsets[nh];
44+
4445
cms::alpakatools::for_each_element_in_grid_strided(acc, nt, [&](uint32_t i) {
4546
auto off = alpaka_std::upper_bound(offsets, offsets + nh + 1, i);
4647
ALPAKA_ASSERT_OFFLOAD((*off) > 0);
@@ -74,17 +75,15 @@ namespace cms {
7475
const unsigned int nblocks = (num_items + nthreads - 1) / nthreads;
7576
const Vec1 blocksPerGrid(nblocks);
7677

78+
auto d_pc = cms::alpakatools::allocDeviceBuf<int32_t>(1u);
79+
int32_t *pc = alpaka::getPtrNative(d_pc);
80+
alpaka::memset(queue, d_pc, 0, 1u);
81+
7782
const WorkDiv1 &workDiv = cms::alpakatools::make_workdiv(blocksPerGrid, threadsPerBlockOrElementsPerThread);
7883
alpaka::enqueue(queue,
7984
alpaka::createTaskKernel<ALPAKA_ACCELERATOR_NAMESPACE::Acc1>(
80-
workDiv, multiBlockPrefixScanFirstStep<uint32_t>(), poff, poff, num_items));
81-
82-
const WorkDiv1 &workDivWith1Block =
83-
cms::alpakatools::make_workdiv(Vec1::all(1), threadsPerBlockOrElementsPerThread);
84-
alpaka::enqueue(
85-
queue,
86-
alpaka::createTaskKernel<ALPAKA_ACCELERATOR_NAMESPACE::Acc1>(
87-
workDivWith1Block, multiBlockPrefixScanSecondStep<uint32_t>(), poff, poff, num_items, nblocks));
85+
workDiv, multiBlockPrefixScan<uint32_t>(), poff, poff, num_items, pc));
86+
alpaka::wait(queue);
8887
}
8988

9089
template <typename Histo, typename T>
@@ -318,4 +317,4 @@ namespace cms {
318317
} // namespace alpakatools
319318
} // namespace cms
320319

321-
#endif // HeterogeneousCore_CUDAUtilities_interface_HistoContainer_h
320+
#endif // HeterogeneousCore_CUDAUtilities_interface_HistoContainer_h

src/alpaka/AlpakaCore/prefixScan.h

Lines changed: 24 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
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

src/alpaka/test/alpaka/prefixScan_t.cc

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -176,28 +176,19 @@ int main() {
176176
cms::alpakatools::make_workdiv(blocksPerGrid4, threadsPerBlockOrElementsPerThread4);
177177

178178
std::cout << "launch multiBlockPrefixScan " << num_items << ' ' << nBlocks << std::endl;
179-
alpaka::enqueue(queue,
180-
alpaka::createTaskKernel<Acc1>(workDivMultiBlock,
181-
cms::alpakatools::multiBlockPrefixScanFirstStep<uint32_t>(),
182-
input_d,
183-
output1_d,
184-
num_items));
185-
186-
const Vec1 blocksPerGridSecondStep(Vec1::all(1));
187-
const WorkDiv1& workDivMultiBlockSecondStep =
188-
cms::alpakatools::make_workdiv(blocksPerGridSecondStep, threadsPerBlockOrElementsPerThread4);
189-
alpaka::enqueue(queue,
190-
alpaka::createTaskKernel<Acc1>(workDivMultiBlockSecondStep,
191-
cms::alpakatools::multiBlockPrefixScanSecondStep<uint32_t>(),
192-
input_d,
193-
output1_d,
194-
num_items,
195-
nBlocks));
179+
auto d_pc(alpaka::allocBuf<int32_t, Idx>(device, size));
180+
int32_t* pc = alpaka::getPtrNative(d_pc);
181+
182+
alpaka::memset(queue, d_pc, 0, size);
183+
alpaka::enqueue(
184+
queue,
185+
alpaka::createTaskKernel<Acc1>(
186+
workDivMultiBlock, cms::alpakatools::multiBlockPrefixScan<uint32_t>(), input_d, output1_d, num_items, pc));
196187

197188
alpaka::enqueue(queue, alpaka::createTaskKernel<Acc1>(workDivMultiBlock, verify(), output1_d, num_items));
198189

199190
alpaka::wait(queue); // input_dBuf and output1_dBuf end of scope
200191
} // ksize
201192

202193
return 0;
203-
}
194+
}

0 commit comments

Comments
 (0)