Block-Structured AMR Software Framework
Loading...
Searching...
No Matches
AMReX_GpuReduce.H
Go to the documentation of this file.
1#ifndef AMREX_GPU_REDUCE_H_
2#define AMREX_GPU_REDUCE_H_
3#include <AMReX_Config.H>
4
6#include <AMReX_GpuControl.H>
7#include <AMReX_GpuTypes.H>
8#include <AMReX_GpuAtomic.H>
9#include <AMReX_GpuUtility.H>
10#include <AMReX_Functional.H>
11#include <AMReX_TypeTraits.H>
12
13#if defined(AMREX_USE_CUDA)
14#include <cub/cub.cuh>
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
17#endif
18#elif defined(AMREX_USE_HIP)
19#include <rocprim/rocprim.hpp>
20#endif
21
22//
23// Public interface
24//
25namespace amrex::Gpu {
26 template <typename T>
28 void deviceReduceSum (T * dest, T source, Gpu::Handler const& h) noexcept;
29
30 template <typename T>
32 void deviceReduceMin (T * dest, T source, Gpu::Handler const& h) noexcept;
33
34 template <typename T>
36 void deviceReduceMax (T * dest, T source, Gpu::Handler const& h) noexcept;
37
39 void deviceReduceLogicalAnd (int * dest, int source, Gpu::Handler const& h) noexcept;
40
42 void deviceReduceLogicalOr (int * dest, int source, Gpu::Handler const& h) noexcept;
43}
44
45//
46// Reduce functions based on _shfl_down_sync
47//
48
49namespace amrex::Gpu {
50
51#ifdef AMREX_USE_SYCL
52
53template <int warpSize, typename T, typename F>
54struct warpReduce
55{
57 T operator() (T x, sycl::sub_group const& sg) const noexcept
58 {
59 for (int offset = warpSize/2; offset > 0; offset /= 2) {
60 T y = sycl::shift_group_left(sg, x, offset);
61 x = F()(x,y);
62 }
63 return x;
64 }
65};
66
67template <int warpSize, typename T, typename WARPREDUCE>
69T blockReduce (T x, WARPREDUCE && warp_reduce, T x0, Gpu::Handler const& h)
70{
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);
77 // __syncthreads() prior to writing to shared memory is necessary
78 // if this reduction call is occurring multiple times in a kernel,
79 // and since we don't know how many times the user is calling it,
80 // we do it always to be safe.
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);
84 x = x0;
85 if (wid == 0) {
86 // numwarps can be greater than warpSize. So warp 0 folds the
87 // partials in rounds of warpSize-1, carrying the result in lane 0.
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);
92 }
93 }
94 return x;
95}
96
97template <int warpSize, typename T, typename WARPREDUCE, typename ATOMICOP>
99void blockReduce_partial (T* dest, T x, WARPREDUCE && warp_reduce, ATOMICOP && atomic_op,
100 Gpu::Handler const& handler)
101{
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); // full warp
106 if (sg.get_local_id()[0] == 0) { atomic_op(dest, x); }
107 } else {
108 atomic_op(dest, x);
109 }
110}
111
112// block-wide reduction for thread0
113template <typename T>
115T blockReduceSum (T source, Gpu::Handler const& h) noexcept
116{
117 return Gpu::blockReduce<Gpu::Device::warp_size>
118 (source, Gpu::warpReduce<Gpu::Device::warp_size,T,amrex::Plus<T> >(), (T)0, h);
119}
120
121template <typename T>
123void deviceReduceSum_full (T * dest, T source, Gpu::Handler const& h) noexcept
124{
125 T aggregate = blockReduceSum(source, h);
126 if (h.item->get_local_id(0) == 0) { Gpu::Atomic::AddNoRet(dest, aggregate); }
127}
128
129// block-wide reduction for thread0
130template <typename T>
132T blockReduceMin (T source, Gpu::Handler const& h) noexcept
133{
134 return Gpu::blockReduce<Gpu::Device::warp_size>
135 (source, Gpu::warpReduce<Gpu::Device::warp_size,T,amrex::Minimum<T> >(), source, h);
136}
137
138template <typename T>
140void deviceReduceMin_full (T * dest, T source, Gpu::Handler const& h) noexcept
141{
142 T aggregate = blockReduceMin(source, h);
143 if (h.item->get_local_id(0) == 0) { Gpu::Atomic::Min(dest, aggregate); }
144}
145
146// block-wide reduction for thread0
147template <typename T>
149T blockReduceMax (T source, Gpu::Handler const& h) noexcept
150{
151 return Gpu::blockReduce<Gpu::Device::warp_size>
152 (source, Gpu::warpReduce<Gpu::Device::warp_size,T,amrex::Maximum<T> >(), source, h);
153}
154
155template <typename T>
157void deviceReduceMax_full (T * dest, T source, Gpu::Handler const& h) noexcept
158{
159 T aggregate = blockReduceMax(source, h);
160 if (h.item->get_local_id(0) == 0) { Gpu::Atomic::Max(dest, aggregate); }
161}
162
163// block-wide reduction for thread0
165int blockReduceLogicalAnd (int source, Gpu::Handler const& h) noexcept
166{
167 return Gpu::blockReduce<Gpu::Device::warp_size>
168 (source, Gpu::warpReduce<Gpu::Device::warp_size,int,amrex::LogicalAnd<int> >(), 1, h);
169}
170
172void deviceReduceLogicalAnd_full (int * dest, int source, Gpu::Handler const& h) noexcept
173{
174 int aggregate = blockReduceLogicalAnd(source, h);
175 if (h.item->get_local_id(0) == 0) { Gpu::Atomic::LogicalAnd(dest, aggregate); }
176}
177
178// block-wide reduction for thread0
180int blockReduceLogicalOr (int source, Gpu::Handler const& h) noexcept
181{
182 return Gpu::blockReduce<Gpu::Device::warp_size>
183 (source, Gpu::warpReduce<Gpu::Device::warp_size,int,amrex::LogicalOr<int> >(), 0, h);
184}
185
187void deviceReduceLogicalOr_full (int * dest, int source, Gpu::Handler const& h) noexcept
188{
189 int aggregate = blockReduceLogicalOr(source, h);
190 if (h.item->get_local_id(0) == 0) { Gpu::Atomic::LogicalOr(dest, aggregate); }
191}
192
193template <typename T>
195void deviceReduceSum (T * dest, T source, Gpu::Handler const& h) noexcept
196{
197 if (h.isFullBlock()) {
198 deviceReduceSum_full(dest, source, h);
199 } else {
200 Gpu::blockReduce_partial<Gpu::Device::warp_size>
201 (dest, source, Gpu::warpReduce<Gpu::Device::warp_size,T,amrex::Plus<T> >(),
202 Gpu::AtomicAdd<T>(), h);
203 }
204}
205
206template <typename T>
208void deviceReduceMin (T * dest, T source, Gpu::Handler const& h) noexcept
209{
210 if (h.isFullBlock()) {
211 deviceReduceMin_full(dest, source, h);
212 } else {
213 Gpu::blockReduce_partial<Gpu::Device::warp_size>
214 (dest, source, Gpu::warpReduce<Gpu::Device::warp_size,T,amrex::Minimum<T> >(),
215 Gpu::AtomicMin<T>(), h);
216 }
217}
218
219template <typename T>
221void deviceReduceMax (T * dest, T source, Gpu::Handler const& h) noexcept
222{
223 if (h.isFullBlock()) {
224 deviceReduceMax_full(dest, source, h);
225 } else {
226 Gpu::blockReduce_partial<Gpu::Device::warp_size>
227 (dest, source, Gpu::warpReduce<Gpu::Device::warp_size,T,amrex::Maximum<T> >(),
228 Gpu::AtomicMax<T>(), h);
229 }
230}
231
233void deviceReduceLogicalAnd (int * dest, int source, Gpu::Handler const& h) noexcept
234{
235 if (h.isFullBlock()) {
236 deviceReduceLogicalAnd_full(dest, source, h);
237 } else {
238 Gpu::blockReduce_partial<Gpu::Device::warp_size>
239 (dest, source, Gpu::warpReduce<Gpu::Device::warp_size,int,amrex::LogicalAnd<int> >(),
240 Gpu::AtomicLogicalAnd<int>(), h);
241 }
242}
243
245void deviceReduceLogicalOr (int * dest, int source, Gpu::Handler const& h) noexcept
246{
247 if (h.isFullBlock()) {
248 deviceReduceLogicalOr_full(dest, source, h);
249 } else {
250 Gpu::blockReduce_partial<Gpu::Device::warp_size>
251 (dest, source, Gpu::warpReduce<Gpu::Device::warp_size,int,amrex::LogicalOr<int> >(),
252 Gpu::AtomicLogicalOr<int>(), h);
253 }
254}
255
256#elif defined(AMREX_USE_CUDA) || defined(AMREX_USE_HIP)
257
259namespace detail {
260
261template <typename T>
263T shuffle_down (T x, int offset) noexcept
264{
265 return AMREX_HIP_OR_CUDA(__shfl_down(x, offset),
266 __shfl_down_sync(0xffffffff, x, offset));
267}
268
269// If other sizeof is needed, we can implement it later.
270template <class T>
271requires (sizeof(T)%sizeof(unsigned int) == 0)
273T multi_shuffle_down (T x, int offset) noexcept
274{
275 constexpr int nwords = (sizeof(T) + sizeof(unsigned int) - 1) / sizeof(unsigned int);
276 T y;
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);
281 }
282 return y;
283}
284
285}
287
288template <int warpSize, typename T, typename F>
290{
291 // Not all arithmetic types can be taken by shuffle_down, but it's good enough.
293 T operator()(T x) const noexcept
294 requires (std::is_arithmetic_v<T>)
295 {
296 for (int offset = warpSize/2; offset > 0; offset /= 2) {
297 T y = detail::shuffle_down(x, offset);
298 x = F()(x,y);
299 }
300 return x;
301 }
302
304 T operator()(T x) const noexcept
305 requires (!std::is_arithmetic_v<T>)
306 {
307 for (int offset = warpSize/2; offset > 0; offset /= 2) {
308 T y = detail::multi_shuffle_down(x, offset);
309 x = F()(x,y);
310 }
311 return x;
312 }
313};
314
315template <int warpSize, typename T, typename WARPREDUCE>
317T blockReduce (T x, WARPREDUCE && warp_reduce, T x0)
318{
319 __shared__ T shared[warpSize];
320 int lane = threadIdx.x % warpSize;
321 int wid = threadIdx.x / warpSize;
322 x = warp_reduce(x);
323 // __syncthreads() prior to writing to shared memory is necessary
324 // if this reduction call is occurring multiple times in a kernel,
325 // and since we don't know how many times the user is calling it,
326 // we do it always to be safe.
327 __syncthreads();
328 if (lane == 0) { shared[wid] = x; }
329 __syncthreads();
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); }
333 return x;
334}
335
336template <int warpSize, typename T, typename WARPREDUCE, typename ATOMICOP>
338void blockReduce_partial (T* dest, T x, WARPREDUCE && warp_reduce, ATOMICOP && atomic_op,
339 Gpu::Handler const& handler)
340{
341 int warp = (int)threadIdx.x / warpSize;
342 if ((warp+1)*warpSize <= handler.numActiveThreads) {
343 x = warp_reduce(x); // full warp
344 if (threadIdx.x % warpSize == 0) { atomic_op(dest, x); }
345 } else {
346 atomic_op(dest,x);
347 }
348}
349
350// Compute the block-wide reduction for thread0
351template <typename T>
353T blockReduceSum (T source) noexcept
354{
355 return Gpu::blockReduce<Gpu::Device::warp_size>
357}
358
359template <typename T>
361void deviceReduceSum_full (T * dest, T source) noexcept
362{
363 T aggregate = blockReduceSum(source);
364 if (threadIdx.x == 0) { Gpu::Atomic::AddNoRet(dest, aggregate); }
365}
366
367// Compute the block-wide reduction for thread0
368template <int BLOCKDIMX, typename T>
370T blockReduceSum (T source) noexcept
371{
372#if defined(AMREX_USE_CUDA)
373 using BlockReduce = cub::BlockReduce<T,BLOCKDIMX>;
374 __shared__ typename BlockReduce::TempStorage temp_storage;
375 // __syncthreads() prior to writing to shared memory is necessary
376 // if this reduction call is occurring multiple times in a kernel,
377 // and since we don't know how many times the user is calling it,
378 // we do it always to be safe.
379 __syncthreads();
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;
384 __syncthreads();
385 BlockReduce().reduce(source, source, temp_storage, rocprim::plus<T>());
386 return source;
387#else
388 return blockReduceSum(source);
389#endif
390}
391
392template <int BLOCKDIMX, typename T>
394void deviceReduceSum_full (T * dest, T source) noexcept
395{
396 T aggregate = blockReduceSum<BLOCKDIMX>(source);
397 if (threadIdx.x == 0) { Gpu::Atomic::AddNoRet(dest, aggregate); }
398}
399
400// Compute the block-wide reduction for thread0
401template <typename T>
403T blockReduceMin (T source) noexcept
404{
405 return Gpu::blockReduce<Gpu::Device::warp_size>
407}
408
409template <typename T>
411void deviceReduceMin_full (T * dest, T source) noexcept
412{
413 T aggregate = blockReduceMin(source);
414 if (threadIdx.x == 0) { Gpu::Atomic::Min(dest, aggregate); }
415}
416
417// Compute the block-wide reduction for thread0
418template <int BLOCKDIMX, typename T>
420T blockReduceMin (T source) noexcept
421{
422#if defined(AMREX_USE_CUDA)
423 using BlockReduce = cub::BlockReduce<T,BLOCKDIMX>;
424 __shared__ typename BlockReduce::TempStorage temp_storage;
425 // __syncthreads() prior to writing to shared memory is necessary
426 // if this reduction call is occurring multiple times in a kernel,
427 // and since we don't know how many times the user is calling it,
428 // we do it always to be safe.
429 __syncthreads();
430
431#ifdef AMREX_CUDA_CCCL_VER_GE_2_8
432 return BlockReduce(temp_storage).Reduce(source, cuda::minimum<T>{});
433#else
434 return BlockReduce(temp_storage).Reduce(source, cub::Min());
435#endif
436#elif defined(AMREX_USE_HIP)
437 using BlockReduce = rocprim::block_reduce<T,BLOCKDIMX>;
438 __shared__ typename BlockReduce::storage_type temp_storage;
439 __syncthreads();
440 BlockReduce().reduce(source, source, temp_storage, rocprim::minimum<T>());
441 return source;
442#else
443 return blockReduceMin(source);
444#endif
445}
446
447template <int BLOCKDIMX, typename T>
449void deviceReduceMin_full (T * dest, T source) noexcept
450{
451 T aggregate = blockReduceMin<BLOCKDIMX>(source);
452 if (threadIdx.x == 0) { Gpu::Atomic::Min(dest, aggregate); }
453}
454
455// Compute the block-wide reduction for thread0
456template <typename T>
458T blockReduceMax (T source) noexcept
459{
460 return Gpu::blockReduce<Gpu::Device::warp_size>
462}
463
464template <typename T>
466void deviceReduceMax_full (T * dest, T source) noexcept
467{
468 T aggregate = blockReduceMax(source);
469 if (threadIdx.x == 0) { Gpu::Atomic::Max(dest, aggregate); }
470}
471
472// Compute the block-wide reduction for thread0
473template <int BLOCKDIMX, typename T>
475T blockReduceMax (T source) noexcept
476{
477#if defined(AMREX_USE_CUDA)
478 using BlockReduce = cub::BlockReduce<T,BLOCKDIMX>;
479 __shared__ typename BlockReduce::TempStorage temp_storage;
480 // __syncthreads() prior to writing to shared memory is necessary
481 // if this reduction call is occurring multiple times in a kernel,
482 // and since we don't know how many times the user is calling it,
483 // we do it always to be safe.
484 __syncthreads();
485#ifdef AMREX_CUDA_CCCL_VER_GE_2_8
486 return BlockReduce(temp_storage).Reduce(source, cuda::maximum<T>());
487#else
488 return BlockReduce(temp_storage).Reduce(source, cub::Max());
489#endif
490#elif defined(AMREX_USE_HIP)
491 using BlockReduce = rocprim::block_reduce<T,BLOCKDIMX>;
492 __shared__ typename BlockReduce::storage_type temp_storage;
493 __syncthreads();
494 BlockReduce().reduce(source, source, temp_storage, rocprim::maximum<T>());
495 return source;
496#else
497 return blockReduceMax(source);
498#endif
499}
500
501template <int BLOCKDIMX, typename T>
503void deviceReduceMax_full (T * dest, T source) noexcept
504{
505 T aggregate = blockReduceMax<BLOCKDIMX>(source);
506 if (threadIdx.x == 0) { Gpu::Atomic::Max(dest, aggregate); }
507}
508
509// Compute the block-wide reduction for thread0
511int blockReduceLogicalAnd (int source) noexcept
512{
513 return Gpu::blockReduce<Gpu::Device::warp_size>
515}
516
518void deviceReduceLogicalAnd_full (int * dest, int source) noexcept
519{
520 int aggregate = blockReduceLogicalAnd(source);
521 if (threadIdx.x == 0) { Gpu::Atomic::LogicalAnd(dest, aggregate); }
522}
523
524// Compute the block-wide reduction for thread0
525template <int BLOCKDIMX>
527int blockReduceLogicalAnd (int source) noexcept
528{
529#if defined(AMREX_USE_CUDA)
530 using BlockReduce = cub::BlockReduce<int,BLOCKDIMX>;
531 __shared__ typename BlockReduce::TempStorage temp_storage;
532 // __syncthreads() prior to writing to shared memory is necessary
533 // if this reduction call is occurring multiple times in a kernel,
534 // and since we don't know how many times the user is calling it,
535 // we do it always to be safe.
536 __syncthreads();
537 return BlockReduce(temp_storage).Reduce(source, amrex::LogicalAnd<int>());
538#elif defined(AMREX_USE_HIP)
539 using BlockReduce = rocprim::block_reduce<int,BLOCKDIMX>;
540 __shared__ typename BlockReduce::storage_type temp_storage;
541 __syncthreads();
542 BlockReduce().reduce(source, source, temp_storage, amrex::LogicalAnd<int>());
543 return source;
544#else
545 return blockReduceLogicalAnd(source);
546#endif
547}
548
549template <int BLOCKDIMX>
551void deviceReduceLogicalAnd_full (int * dest, int source) noexcept
552{
553 int aggregate = blockReduceLogicalAnd<BLOCKDIMX>(source);
554 if (threadIdx.x == 0) { Gpu::Atomic::LogicalAnd(dest, aggregate); }
555}
556
557// Compute the block-wide reduction for thread0
559int blockReduceLogicalOr (int source) noexcept
560{
561 return Gpu::blockReduce<Gpu::Device::warp_size>
563}
564
566void deviceReduceLogicalOr_full (int * dest, int source) noexcept
567{
568 int aggregate = blockReduceLogicalOr(source);
569 if (threadIdx.x == 0) { Gpu::Atomic::LogicalOr(dest, aggregate); }
570}
571
572// Compute the block-wide reduction for thread0
573template <int BLOCKDIMX>
575int blockReduceLogicalOr (int source) noexcept
576{
577#if defined(AMREX_USE_CUDA)
578 using BlockReduce = cub::BlockReduce<int,BLOCKDIMX>;
579 __shared__ typename BlockReduce::TempStorage temp_storage;
580 // __syncthreads() prior to writing to shared memory is necessary
581 // if this reduction call is occurring multiple times in a kernel,
582 // and since we don't know how many times the user is calling it,
583 // we do it always to be safe.
584 __syncthreads();
585 return BlockReduce(temp_storage).Reduce(source, amrex::LogicalOr<int>());
586#elif defined(AMREX_USE_HIP)
587 using BlockReduce = rocprim::block_reduce<int,BLOCKDIMX>;
588 __shared__ typename BlockReduce::storage_type temp_storage;
589 __syncthreads();
590 BlockReduce().reduce(source, source, temp_storage, amrex::LogicalOr<int>());
591 return source;
592#else
593 return blockReduceLogicalOr(source);
594#endif
595}
596
597template <int BLOCKDIMX>
599void deviceReduceLogicalOr_full (int * dest, int source) noexcept
600{
601 int aggregate = blockReduceLogicalOr<BLOCKDIMX>(source);
602 if (threadIdx.x == 0) { Gpu::Atomic::LogicalOr(dest, aggregate); }
603}
604
605template <typename T>
607void deviceReduceSum (T * dest, T source, Gpu::Handler const& handler) noexcept
608{
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);
614 } else {
615 deviceReduceSum_full<T>(dest, source);
616 }
617 } else {
618 Gpu::blockReduce_partial<Gpu::Device::warp_size>
620 Gpu::AtomicAdd<T>(), handler);
621 }
622}
623
624template <typename T>
626void deviceReduceMin (T * dest, T source, Gpu::Handler const& handler) noexcept
627{
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);
633 } else {
634 deviceReduceMin_full<T>(dest, source);
635 }
636 } else {
637 Gpu::blockReduce_partial<Gpu::Device::warp_size>
639 Gpu::AtomicMin<T>(), handler);
640 }
641}
642
643template <typename T>
645void deviceReduceMax (T * dest, T source, Gpu::Handler const& handler) noexcept
646{
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);
652 } else {
653 deviceReduceMax_full<T>(dest, source);
654 }
655 } else {
656 Gpu::blockReduce_partial<Gpu::Device::warp_size>
658 Gpu::AtomicMax<T>(), handler);
659 }
660}
661
663void deviceReduceLogicalAnd (int * dest, int source, Gpu::Handler const& handler) noexcept
664{
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);
670 } else {
671 deviceReduceLogicalAnd_full(dest, source);
672 }
673 } else {
674 Gpu::blockReduce_partial<Gpu::Device::warp_size>
676 Gpu::AtomicLogicalAnd<int>(), handler);
677 }
678}
679
681void deviceReduceLogicalOr (int * dest, int source, Gpu::Handler const& handler) noexcept
682{
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);
688 } else {
689 deviceReduceLogicalOr_full(dest, source);
690 }
691 } else {
692 Gpu::blockReduce_partial<Gpu::Device::warp_size>
694 Gpu::AtomicLogicalOr<int>(), handler);
695 }
696}
697
698#else
699
700template <typename T>
702void deviceReduceSum_full (T * dest, T source) noexcept
703{
704#ifdef AMREX_USE_OMP
705#pragma omp atomic
706#endif
707 *dest += source;
708}
709
710template <typename T>
712void deviceReduceSum (T * dest, T source, Gpu::Handler const&) noexcept
713{
714 deviceReduceSum_full(dest, source);
715}
716
717template <typename T>
719void deviceReduceMin_full (T * dest, T source) noexcept
720{
721#ifdef AMREX_USE_OMP
722#pragma omp critical (gpureduce_reducemin)
723#endif
724 *dest = std::min(*dest, source);
725}
726
727template <typename T>
729void deviceReduceMin (T * dest, T source, Gpu::Handler const&) noexcept
730{
731 deviceReduceMin_full(dest, source);
732}
733
734template <typename T>
736void deviceReduceMax_full (T * dest, T source) noexcept
737{
738#ifdef AMREX_USE_OMP
739#pragma omp critical (gpureduce_reducemax)
740#endif
741 *dest = std::max(*dest, source);
742}
743
744template <typename T>
746void deviceReduceMax (T * dest, T source, Gpu::Handler const&) noexcept
747{
748 deviceReduceMax_full(dest, source);
749}
750
752void deviceReduceLogicalAnd_full (int * dest, int source) noexcept
753{
754#ifdef AMREX_USE_OMP
755#pragma omp critical (gpureduce_reduceand)
756#endif
757 *dest = (*dest) && source;
758}
759
761void deviceReduceLogicalAnd (int * dest, int source, Gpu::Handler const&) noexcept
762{
763 deviceReduceLogicalAnd_full(dest, source);
764}
765
767void deviceReduceLogicalOr_full (int * dest, int source) noexcept
768{
769#ifdef AMREX_USE_OMP
770#pragma omp critical (gpureduce_reduceor)
771#endif
772 *dest = (*dest) || source;
773}
774
776void deviceReduceLogicalOr (int * dest, int source, Gpu::Handler const&) noexcept
777{
778 deviceReduceLogicalOr_full(dest, source);
779}
780
781#endif
782}
783
784#endif
#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