1#ifndef AMREX_GPU_REDUCE_H_
2#define AMREX_GPU_REDUCE_H_
3#include <AMReX_Config.H>
13#if defined(AMREX_USE_CUDA)
15#if defined(CCCL_MAJOR_VERSION) && defined(CCCL_MINOR_VERSION) && ((CCCL_MAJOR_VERSION >= 3) || ((CCCL_MAJOR_VERSION >= 2) && (CCCL_MINOR_VERSION >= 8)))
16#define AMREX_CUDA_CCCL_VER_GE_2_8 1
18#elif defined(AMREX_USE_HIP)
19#include <rocprim/rocprim.hpp>
28 void deviceReduceSum (T * dest, T source, Gpu::Handler
const& h)
noexcept;
32 void deviceReduceMin (T * dest, T source, Gpu::Handler
const& h)
noexcept;
36 void deviceReduceMax (T * dest, T source, Gpu::Handler
const& h)
noexcept;
53template <
int warpSize,
typename T,
typename F>
57 T
operator() (T
x, sycl::sub_group
const& sg)
const noexcept
60 T
y = sycl::shift_group_left(sg,
x,
offset);
67template <
int warpSize,
typename T,
typename WARPREDUCE>
69T
blockReduce (T
x, WARPREDUCE && warp_reduce, T x0, Gpu::Handler
const& h)
71 T* shared = (T*)h.local;
72 sycl::sub_group
const& sg = h.item->get_sub_group();
73 int lane = sg.get_local_id()[0];
74 int wid = sg.get_group_id()[0];
75 int numwarps = sg.get_group_range()[0];
76 x = warp_reduce(
x, sg);
81 h.item->barrier(sycl::access::fence_space::local_space);
82 if (lane == 0) { shared[wid] =
x; }
83 h.item->barrier(sycl::access::fence_space::local_space);
88 for (
int i0 = 0; i0 < numwarps; i0 += warpSize-1) {
89 int i = i0 + lane - 1;
90 T
y = (lane == 0) ?
x : ((i < numwarps) ? shared[i] : x0);
91 x = warp_reduce(
y, sg);
97template <
int warpSize,
typename T,
typename WARPREDUCE,
typename ATOMICOP>
100 Gpu::Handler
const& handler)
102 sycl::sub_group
const& sg = handler.item->get_sub_group();
103 int wid = sg.get_group_id()[0];
104 if ((wid+1)*warpSize <= handler.numActiveThreads) {
105 x = warp_reduce(
x, sg);
106 if (sg.get_local_id()[0] == 0) { atomic_op(dest,
x); }
117 return Gpu::blockReduce<Gpu::Device::warp_size>
134 return Gpu::blockReduce<Gpu::Device::warp_size>
151 return Gpu::blockReduce<Gpu::Device::warp_size>
167 return Gpu::blockReduce<Gpu::Device::warp_size>
182 return Gpu::blockReduce<Gpu::Device::warp_size>
195void deviceReduceSum (T * dest, T source, Gpu::Handler
const& h)
noexcept
197 if (h.isFullBlock()) {
200 Gpu::blockReduce_partial<Gpu::Device::warp_size>
202 Gpu::AtomicAdd<T>(), h);
208void deviceReduceMin (T * dest, T source, Gpu::Handler
const& h)
noexcept
210 if (h.isFullBlock()) {
213 Gpu::blockReduce_partial<Gpu::Device::warp_size>
215 Gpu::AtomicMin<T>(), h);
221void deviceReduceMax (T * dest, T source, Gpu::Handler
const& h)
noexcept
223 if (h.isFullBlock()) {
226 Gpu::blockReduce_partial<Gpu::Device::warp_size>
228 Gpu::AtomicMax<T>(), h);
235 if (h.isFullBlock()) {
238 Gpu::blockReduce_partial<Gpu::Device::warp_size>
240 Gpu::AtomicLogicalAnd<int>(), h);
247 if (h.isFullBlock()) {
250 Gpu::blockReduce_partial<Gpu::Device::warp_size>
252 Gpu::AtomicLogicalOr<int>(), h);
256#elif defined(AMREX_USE_CUDA) || defined(AMREX_USE_HIP)
263T shuffle_down (T x,
int offset)
noexcept
266 __shfl_down_sync(0xffffffff, x,
offset));
271requires (
sizeof(T)%
sizeof(
unsigned int) == 0)
273T multi_shuffle_down (T x,
int offset)
noexcept
275 constexpr int nwords = (
sizeof(T) +
sizeof(
unsigned int) - 1) /
sizeof(
unsigned int);
277 auto py =
reinterpret_cast<unsigned int*
>(&
y);
278 auto px =
reinterpret_cast<unsigned int*
>(&
x);
279 for (
int i = 0; i < nwords; ++i) {
280 py[i] = shuffle_down(px[i],
offset);
288template <
int warpSize,
typename T,
typename F>
294 requires (std::is_arithmetic_v<T>)
297 T
y = detail::shuffle_down(
x,
offset);
305 requires (!std::is_arithmetic_v<T>)
308 T
y = detail::multi_shuffle_down(
x,
offset);
315template <
int warpSize,
typename T,
typename WARPREDUCE>
319 __shared__ T shared[warpSize];
320 int lane = threadIdx.x % warpSize;
321 int wid = threadIdx.x / warpSize;
328 if (lane == 0) { shared[wid] =
x; }
330 bool b = (threadIdx.x == 0) || (threadIdx.x < blockDim.x / warpSize);
331 x = b ? shared[lane] : x0;
332 if (wid == 0) {
x = warp_reduce(
x); }
336template <
int warpSize,
typename T,
typename WARPREDUCE,
typename ATOMICOP>
341 int warp = (
int)threadIdx.x / warpSize;
344 if (threadIdx.x % warpSize == 0) { atomic_op(dest,
x); }
355 return Gpu::blockReduce<Gpu::Device::warp_size>
368template <
int BLOCKDIMX,
typename T>
372#if defined(AMREX_USE_CUDA)
373 using BlockReduce = cub::BlockReduce<T,BLOCKDIMX>;
374 __shared__
typename BlockReduce::TempStorage temp_storage;
380 return BlockReduce(temp_storage).Sum(source);
381#elif defined(AMREX_USE_HIP)
382 using BlockReduce = rocprim::block_reduce<T,BLOCKDIMX>;
383 __shared__
typename BlockReduce::storage_type temp_storage;
385 BlockReduce().reduce(source, source, temp_storage, rocprim::plus<T>());
392template <
int BLOCKDIMX,
typename T>
396 T aggregate = blockReduceSum<BLOCKDIMX>(source);
405 return Gpu::blockReduce<Gpu::Device::warp_size>
418template <
int BLOCKDIMX,
typename T>
422#if defined(AMREX_USE_CUDA)
423 using BlockReduce = cub::BlockReduce<T,BLOCKDIMX>;
424 __shared__
typename BlockReduce::TempStorage temp_storage;
431#ifdef AMREX_CUDA_CCCL_VER_GE_2_8
432 return BlockReduce(temp_storage).Reduce(source, cuda::minimum<T>{});
434 return BlockReduce(temp_storage).Reduce(source, cub::Min());
436#elif defined(AMREX_USE_HIP)
437 using BlockReduce = rocprim::block_reduce<T,BLOCKDIMX>;
438 __shared__
typename BlockReduce::storage_type temp_storage;
440 BlockReduce().reduce(source, source, temp_storage, rocprim::minimum<T>());
447template <
int BLOCKDIMX,
typename T>
451 T aggregate = blockReduceMin<BLOCKDIMX>(source);
460 return Gpu::blockReduce<Gpu::Device::warp_size>
473template <
int BLOCKDIMX,
typename T>
477#if defined(AMREX_USE_CUDA)
478 using BlockReduce = cub::BlockReduce<T,BLOCKDIMX>;
479 __shared__
typename BlockReduce::TempStorage temp_storage;
485#ifdef AMREX_CUDA_CCCL_VER_GE_2_8
486 return BlockReduce(temp_storage).Reduce(source, cuda::maximum<T>());
488 return BlockReduce(temp_storage).Reduce(source, cub::Max());
490#elif defined(AMREX_USE_HIP)
491 using BlockReduce = rocprim::block_reduce<T,BLOCKDIMX>;
492 __shared__
typename BlockReduce::storage_type temp_storage;
494 BlockReduce().reduce(source, source, temp_storage, rocprim::maximum<T>());
501template <
int BLOCKDIMX,
typename T>
505 T aggregate = blockReduceMax<BLOCKDIMX>(source);
513 return Gpu::blockReduce<Gpu::Device::warp_size>
525template <
int BLOCKDIMX>
529#if defined(AMREX_USE_CUDA)
530 using BlockReduce = cub::BlockReduce<int,BLOCKDIMX>;
531 __shared__
typename BlockReduce::TempStorage temp_storage;
538#elif defined(AMREX_USE_HIP)
539 using BlockReduce = rocprim::block_reduce<int,BLOCKDIMX>;
540 __shared__
typename BlockReduce::storage_type temp_storage;
549template <
int BLOCKDIMX>
553 int aggregate = blockReduceLogicalAnd<BLOCKDIMX>(source);
561 return Gpu::blockReduce<Gpu::Device::warp_size>
573template <
int BLOCKDIMX>
577#if defined(AMREX_USE_CUDA)
578 using BlockReduce = cub::BlockReduce<int,BLOCKDIMX>;
579 __shared__
typename BlockReduce::TempStorage temp_storage;
586#elif defined(AMREX_USE_HIP)
587 using BlockReduce = rocprim::block_reduce<int,BLOCKDIMX>;
588 __shared__
typename BlockReduce::storage_type temp_storage;
597template <
int BLOCKDIMX>
601 int aggregate = blockReduceLogicalOr<BLOCKDIMX>(source);
609 if (handler.isFullBlock()) {
610 if (blockDim.x == 128) {
611 deviceReduceSum_full<128,T>(dest, source);
612 }
else if (blockDim.x == 256) {
613 deviceReduceSum_full<256,T>(dest, source);
615 deviceReduceSum_full<T>(dest, source);
618 Gpu::blockReduce_partial<Gpu::Device::warp_size>
628 if (handler.isFullBlock()) {
629 if (blockDim.x == 128) {
630 deviceReduceMin_full<128,T>(dest, source);
631 }
else if (blockDim.x == 256) {
632 deviceReduceMin_full<256,T>(dest, source);
634 deviceReduceMin_full<T>(dest, source);
637 Gpu::blockReduce_partial<Gpu::Device::warp_size>
647 if (handler.isFullBlock()) {
648 if (blockDim.x == 128) {
649 deviceReduceMax_full<128,T>(dest, source);
650 }
else if (blockDim.x == 256) {
651 deviceReduceMax_full<256,T>(dest, source);
653 deviceReduceMax_full<T>(dest, source);
656 Gpu::blockReduce_partial<Gpu::Device::warp_size>
665 if (handler.isFullBlock()) {
666 if (blockDim.x == 128) {
667 deviceReduceLogicalAnd_full<128>(dest, source);
668 }
else if (blockDim.x == 256) {
669 deviceReduceLogicalAnd_full<256>(dest, source);
674 Gpu::blockReduce_partial<Gpu::Device::warp_size>
683 if (handler.isFullBlock()) {
684 if (blockDim.x == 128) {
685 deviceReduceLogicalOr_full<128>(dest, source);
686 }
else if (blockDim.x == 256) {
687 deviceReduceLogicalOr_full<256>(dest, source);
692 Gpu::blockReduce_partial<Gpu::Device::warp_size>
722#pragma omp critical (gpureduce_reducemin)
724 *dest = std::min(*dest, source);
739#pragma omp critical (gpureduce_reducemax)
741 *dest = std::max(*dest, source);
755#pragma omp critical (gpureduce_reduceand)
757 *dest = (*dest) && source;
770#pragma omp critical (gpureduce_reduceor)
772 *dest = (*dest) || source;
#define AMREX_FORCE_INLINE
Definition AMReX_Extension.H:124
Function object (functor) types for use with reductions and transforms.
#define AMREX_HIP_OR_CUDA(a, b)
Definition AMReX_GpuControl.H:17
#define AMREX_GPU_DEVICE
Definition AMReX_GpuQualifiers.H:18
Array4< int const > offset
Definition AMReX_HypreMLABecLap.cpp:1131
static constexpr int warp_size
Definition AMReX_GpuDevice.H:236
__host__ __device__ AMREX_FORCE_INLINE int LogicalAnd(int *const m, int const value) noexcept
Definition AMReX_GpuAtomic.H:461
__host__ __device__ AMREX_FORCE_INLINE int LogicalOr(int *const m, int const value) noexcept
Definition AMReX_GpuAtomic.H:436
__host__ __device__ AMREX_FORCE_INLINE void AddNoRet(T *sum, T value) noexcept
Definition AMReX_GpuAtomic.H:283
__host__ __device__ AMREX_FORCE_INLINE T Max(T *const m, T const value) noexcept
Definition AMReX_GpuAtomic.H:419
__host__ __device__ AMREX_FORCE_INLINE T Min(T *const m, T const value) noexcept
Definition AMReX_GpuAtomic.H:356
Definition AMReX_BaseFwd.H:60
__device__ void deviceReduceSum(T *dest, T source, Gpu::Handler const &h) noexcept
Definition AMReX_GpuReduce.H:607
__device__ T blockReduce(T x, WARPREDUCE &&warp_reduce, T x0)
Definition AMReX_GpuReduce.H:317
__device__ void deviceReduceLogicalAnd_full(int *dest, int source) noexcept
Definition AMReX_GpuReduce.H:518
__device__ void blockReduce_partial(T *dest, T x, WARPREDUCE &&warp_reduce, ATOMICOP &&atomic_op, Gpu::Handler const &handler)
Definition AMReX_GpuReduce.H:338
__device__ int blockReduceLogicalOr(int source) noexcept
Definition AMReX_GpuReduce.H:559
__device__ T blockReduceMax(T source) noexcept
Definition AMReX_GpuReduce.H:458
__device__ T blockReduceMin(T source) noexcept
Definition AMReX_GpuReduce.H:403
__device__ int blockReduceLogicalAnd(int source) noexcept
Definition AMReX_GpuReduce.H:511
__device__ void deviceReduceMax(T *dest, T source, Gpu::Handler const &h) noexcept
Definition AMReX_GpuReduce.H:645
__device__ void deviceReduceMax_full(T *dest, T source) noexcept
Definition AMReX_GpuReduce.H:466
__device__ void deviceReduceLogicalAnd(int *dest, int source, Gpu::Handler const &h) noexcept
Definition AMReX_GpuReduce.H:663
__device__ void deviceReduceLogicalOr(int *dest, int source, Gpu::Handler const &h) noexcept
Definition AMReX_GpuReduce.H:681
__device__ void deviceReduceSum_full(T *dest, T source) noexcept
Definition AMReX_GpuReduce.H:361
__device__ void deviceReduceMin_full(T *dest, T source) noexcept
Definition AMReX_GpuReduce.H:411
__device__ void deviceReduceMin(T *dest, T source, Gpu::Handler const &h) noexcept
Definition AMReX_GpuReduce.H:626
__device__ void deviceReduceLogicalOr_full(int *dest, int source) noexcept
Definition AMReX_GpuReduce.H:566
__device__ T blockReduceSum(T source) noexcept
Definition AMReX_GpuReduce.H:353
const int[]
Definition AMReX_BLProfiler.cpp:1665
Definition AMReX_GpuAtomic.H:661
Definition AMReX_GpuAtomic.H:685
Definition AMReX_GpuAtomic.H:693
Definition AMReX_GpuAtomic.H:677
Definition AMReX_GpuAtomic.H:669
Definition AMReX_GpuTypes.H:88
int numActiveThreads
Definition AMReX_GpuTypes.H:98
Definition AMReX_GpuReduce.H:290
__device__ T operator()(T x) const noexcept
Definition AMReX_GpuReduce.H:293
__device__ T operator()(T x) const noexcept
Definition AMReX_GpuReduce.H:304
Function object that returns the logical AND of two values.
Definition AMReX_Functional.H:79
Function object that returns the logical OR of two values.
Definition AMReX_Functional.H:93
Function object that returns the larger of two values.
Definition AMReX_Functional.H:65
Function object that returns the smaller of two values.
Definition AMReX_Functional.H:51
Function object that returns the sum of two values.
Definition AMReX_Functional.H:23