35 template<alpaka::concepts::DeviceKind TDeviceKind,
typename T_Idx,
typename T_Data>
39 return static_cast<T_Idx
>(8);
41 return static_cast<T_Idx
>(8);
43 return static_cast<T_Idx
>(8);
45 return static_cast<T_Idx
>(32768) /
sizeof(T_Data);
52 template<
typename T_Acc,
typename T_Idx>
56 return n + n / warpSize;
61 template<
typename T_Idx,
typename T_Data>
65 for(T_Idx d = extent.x() / T_Idx{2}, offset = T_Idx{1}; d > 0; d >>= 1, offset <<= 1)
67 for(
auto frameElem = T_Idx{0}; frameElem < T_Idx{2} * d; frameElem += T_Idx{2})
69 T_Idx left = offset * (frameElem + T_Idx{1}) - T_Idx{1};
70 T_Idx right = offset * (frameElem + T_Idx{2}) - T_Idx{1};
71 block[right] += block[left];
76 T_Data blockSum = block[extent.x() - T_Idx{1}];
79 block[extent.x() - T_Idx{1}] = T_Data{0};
82 for(T_Idx d = 1, offset = extent.x() / T_Idx{2}; d < extent.x(); d <<= 1, offset >>= 1)
84 for(
auto frameElem = T_Idx{0}; frameElem < T_Idx{2} * d; frameElem += T_Idx{2})
86 T_Idx left = offset * (frameElem + T_Idx{1}) - T_Idx{1};
87 T_Idx right = offset * (frameElem + T_Idx{2}) - T_Idx{1};
89 block[left] = block[right];
98 template<
typename T_Idx,
typename T_Data>
101 T_Data
const& blockSum,
104 for(
auto i = T_Idx{0}; i < extent.x(); ++i)
106 block[i] += blockSum;
114 template<ScanType SCAN_TYPE,
typename T_Idx,
typename T_Data>
124 auto... blockSums)
const
130 constexpr std::integral
auto elsPerThread = largeChunkExtents.x() / numThreadsPerBlock.x();
134 constexpr std::integral
auto miniBlockSize
136 constexpr std::integral
auto miniBlocksPerThread = elsPerThread / miniBlockSize;
137 constexpr std::integral
auto miniBlocksPerChunk = chunkExtent.x() / miniBlockSize;
139 constexpr auto LocalArrayLength = miniBlocksPerThread * miniBlockSize;
140 using LocalArray = T_Data[LocalArrayLength];
142 auto const validElementsInLastFrame = (numElements - T_Idx{1}) % chunkExtent + T_Idx{1};
152 bool const lastFrameFull = validElementsInLastFrame == chunkExtent;
153 bool const isLastFrame = chunkIdx == numChunks - T_Idx{1};
160 auto const frameOffset = chunkExtent * chunkIdx;
168 if((!lastFrameFull && isLastFrame) || elsPerThread % T_Idx{4} != T_Idx{0})
171 for(
auto i = T_Idx{0}; i < elsPerThread; ++i)
173 if(frameOffset + frameElem + i < numElements)
174 regMem[i] = inputVec[frameOffset + frameElem + i];
183 for(
auto i = T_Idx{0}; i < elsPerThread; i += T_Idx{4})
187 Vec{frameOffset + frameElem + i},
192 regView = inputVecView.
load();
197 for(
auto miniBlockOffset = T_Idx{0}; miniBlockOffset < elsPerThread;
198 miniBlockOffset += miniBlockSize)
210 for(T_Idx d = miniBlocksPerChunk / T_Idx{2}, offset = T_Idx{1}; d > 0; d >>= 1, offset <<= 1)
218 T_Idx left = offset * (frameElem + T_Idx{1}).x() - T_Idx{1};
219 T_Idx right = offset * (frameElem + T_Idx{2}).x() - T_Idx{1};
222 tmp[right] += tmp[left];
227 for([[maybe_unused]]
auto frameElem :
231 if constexpr(
sizeof...(blockSums))
233 auto _blockSums = std::get<0>(std::make_tuple(blockSums...));
242 for(T_Idx d = 1, offset = miniBlocksPerChunk / T_Idx{2}; d < miniBlocksPerChunk; d <<= 1, offset >>= 1)
250 T_Idx left = offset * (frameElem.x() + T_Idx{1}) - T_Idx{1};
251 T_Idx right = offset * (frameElem.x() + T_Idx{2}) - T_Idx{1};
255 tmp[left] = tmp[right];
268 for(
auto miniBlockOffset = T_Idx{0}; miniBlockOffset < elsPerThread;
269 miniBlockOffset += miniBlockSize)
273 if(frameOffset + frameElem + miniBlockOffset < numElements)
283 if((!lastFrameFull && isLastFrame) || elsPerThread % T_Idx{4} != T_Idx{0})
286 for(
auto i = T_Idx{0}; i < elsPerThread; ++i)
288 if(frameOffset + frameElem + i < numElements)
291 outputVec[frameOffset + frameElem + i] = regMem[i];
293 outputVec[frameOffset + frameElem + i]
294 = inputVec[frameOffset + frameElem + i] + regMem[i];
302 for(
auto i = T_Idx{0}; i < elsPerThread; i += T_Idx{4})
306 Vec{frameOffset + frameElem + i},
311 outputVecView = regView.
load();
316 Vec{frameOffset + frameElem + i},
319 outputVecView = inputVecView.
load() + regView.load();
331 template<
typename T_Idx>
343 constexpr auto elsPerThread = largeChunkExtents.x() / numThreadsPerBlock.x();
350 [&](
auto const&,
auto&& simdOut)
constexpr
351 { simdOut = simdOut.load() + blockSums[simdOut.getIdx() / chunkExtent]; },
356 template<
typename T_Data>
362 auto bufSize = T_Idx{0};
363 while(elements > T_Idx{1})
369 return bufSize * T_Idx{
sizeof(T_Data)};
372 template<
typename T_Data>
375 static_assert(
ALPAKA_TYPEOF(extents)::dim() == 1,
"scan is only usable for one dimensional buffers");
379 template<ScanType SCAN_TYPE>
392 std::is_same_v<T_Data,
typename ALPAKA_TYPEOF(outputVec)::value_type>,
393 "output vector must have the same data type as input vector");
407 std::stringstream ss;
410 ss <<
", scanType= INCLUSIVE_SCAN";
412 ss <<
", scanType= EXCLUSIVE_SCAN";
413 ss <<
", numFrames= " << numChunks;
414 ss <<
", chunkExtent= " << chunkExtent;
420 if(frameSpec.getNumFrames() > T_Idx{1})
425 auto bufSizeBytes = frameSpec.getNumFrames() * T_Idx{
sizeof(T_Data)};
426 assert(buffer.getExtents() * T_Idx{sizeof(typename ALPAKA_TYPEOF(buffer)::value_type)} >= bufSizeBytes);
429 auto subBuf = buffer.getSubView(bufSizeBytes);
431 reinterpret_cast<T_Data*
>(subBuf.data()),
432 frameSpec.getNumFrames(),
436 auto bufferNext = buffer.getSubView(bufSizeBytes, buffer.getExtents() - bufSizeBytes);
441 KernelBundle{scanBlocks, numChunks, chunkExtent, inputVec, outputVec, increments});
450 queue.enqueue(frameSpec,
KernelBundle{scanBlocks, numChunks, chunkExtent, inputVec, outputVec});
454 template<ScanType SCAN_TYPE>
471 buf.keepAlive(queue);
The class used to bind kernel function object and arguments together. Once an instance of this class ...
ALPAKA_FN_ACC void operator()(auto const &acc, alpaka::concepts::CVector auto const largeChunkExtents, alpaka::concepts::IMdSpan auto const &blockSums, alpaka::concepts::IMdSpan auto outputVec) const
ALPAKA_FN_ACC void operator()(auto const &acc, alpaka::concepts::Vector auto const numChunks, alpaka::concepts::CVector auto const largeChunkExtents, alpaka::concepts::IDataSource auto const &inputVec, alpaka::concepts::IMdSpan auto outputVec, auto... blockSums) const
#define ALPAKA_FN_ACC
All functions that can be used on an accelerator have to be attributed with ALPAKA_FN_ACC or ALPAKA_F...
#define ALPAKA_TYPEOF(...)
Get the type of instance.
Concept to check if a type is a CVector.
Concept to check for an executor.
Interface concept for objects describing multidimensional memory access.
Concept to check if a type is a vector.
Concept to check if something is a device.
#define ALPAKA_LOG_INFO(logLvl, callable)
Write a meta data message to the output.
constexpr uint32_t getSize()
Return the warp size.
constexpr auto blocksInGrid
constexpr auto threadsInGrid
constexpr auto threadsInBlock
constexpr decltype(auto) declareSharedMdArray(concepts::Acc auto const &acc, alpaka::concepts::CVector auto const &extent)
creates an M-dimensional array
ALPAKA_FN_HOST_ACC constexpr auto makeIdxMap(auto const &acc, auto const workGroup, auto const range, T_Traverse traverse=T_Traverse{}, T_IdxLayout idxLayout=T_IdxLayout{})
Creates an index container.
constexpr void syncBlockThreads(concepts::Acc auto const &acc)
Synchronize all threads within a thread block.
ALPAKA_FN_ACC T_Data scanMiniBlock(T_Data *block, alpaka::concepts::CVector< T_Idx > auto const &extent)
void scan(auto &queue, alpaka::onHost::concepts::Device auto &devAcc, alpaka::concepts::Executor auto &exec, alpaka::concepts::IMdSpan auto &buffer, alpaka::concepts::IMdSpan auto &outputVec, alpaka::concepts::IDataSource auto &inputVec)
ALPAKA_FN_ACC void addIncrements(T_Data *block, T_Data const &blockSum, alpaka::concepts::CVector< T_Idx > auto const &extent)
auto scanBufferSize(std::integral auto const &extent)
constexpr std::size_t chunkSize
consteval T_Idx maximumMiniBlockSize()
constexpr T_Idx conflictFreeAccess(T_Idx const &n)
constexpr auto demangledName()
auto alloc(concepts::Device auto const &device, alpaka::concepts::VectorOrScalar auto const &extents)
Allocate memory on the given device.
ALPAKA_FN_HOST_ACC constexpr auto divCeil(Integral a, Integral b) -> Integral
Returns the ceiling of a / b, as integer.
Vec< T, sizeof...(T_values), detail::CVec< T, T_values... > > CVec
A vector with compile-time known values.
Strongly typed and constexpr representation of a byte-alignment of memory.
Lightweight view to data in an n-dimensional array.
pointer to a SIMD pack with the width T_SimdWidth
constexpr decltype(auto) load() const
Creates a functor operate on contiguous data concurrently.
ALPAKA_FN_INLINE ALPAKA_FN_ACC constexpr void concurrent(auto const &acc, auto &&func, alpaka::concepts::IDataSource auto &&data0, alpaka::concepts::IDataSource auto &&... dataN) const
execute the functor concurrently over the given data.
Device/Api-agnostic description of the logical parallelism exposed to a kernel.