MFEM v4.10.0
Finite element discretization library
Loading...
Searching...
No Matches
forall.hpp
Go to the documentation of this file.
1// Copyright (c) 2010-2026, Lawrence Livermore National Security, LLC. Produced
2// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3// LICENSE and NOTICE for details. LLNL-CODE-806117.
4//
5// This file is part of the MFEM library. For more information and source code
6// availability visit https://mfem.org.
7//
8// MFEM is free software; you can redistribute it and/or modify it under the
9// terms of the BSD-3 license. We welcome feedback and contributions, see file
10// CONTRIBUTING.md for details.
11
12#ifndef MFEM_FORALL_HPP
13#define MFEM_FORALL_HPP
14
15#include "../config/config.hpp"
16#include "annotation.hpp"
17#include "error.hpp"
18#include "backends.hpp"
19#include "device.hpp"
20#include "mem_manager.hpp"
21#include "../linalg/dtensor.hpp"
22#ifdef MFEM_USE_MPI
23#include <_hypre_utilities.h>
24#endif
25
26namespace mfem
27{
28
29// The following DofQuadLimit_ structs define the maximum values of D1D and Q1D
30// often used in the "fallback kernels" for partial assembly. Different limits
31// take effect for different architectures. The limits should be queried using
32// the public interface in DeviceDofQuadLimits or DofQuadLimits, and generally
33// not be directly accessing the structs defined below.
34//
35// In host code, the limits associated with the currently configured Device can
36// be accessed using DeviceDofQuadLimits::Get().
37//
38// In mfem::forall kernels or MFEM_HOST_DEVICE functions, the limits
39// corresponding to the architecture the function is being compiled for can be
40// accessed as static constexpr variables using the type alias DofQuadLimits.
41
42namespace internal
43{
44
45struct DofQuadLimits_CUDA
46{
47 static constexpr int MAX_D1D = 14;
48 static constexpr int MAX_Q1D = 14;
49 static constexpr int MAX_D1D_SIMPLEX = 14;
50 static constexpr int MAX_Q1D_SIMPLEX = 14;
51 static constexpr int MAX_T1D = 32;
52 static constexpr int HCURL_MAX_D1D = 5;
53 static constexpr int HCURL_MAX_Q1D = 6;
54 static constexpr int HDIV_MAX_D1D = 5;
55 static constexpr int HDIV_MAX_Q1D = 6;
56 static constexpr int MAX_INTERP_1D = 8;
57 static constexpr int MAX_DET_1D = 6;
58};
59
60struct DofQuadLimits_HIP
61{
62 static constexpr int MAX_D1D = 10;
63 static constexpr int MAX_Q1D = 10;
64 static constexpr int MAX_D1D_SIMPLEX = 9;
65 static constexpr int MAX_Q1D_SIMPLEX = 9;
66 static constexpr int MAX_T1D = 32;
67 static constexpr int HCURL_MAX_D1D = 5;
68 static constexpr int HCURL_MAX_Q1D = 5;
69 static constexpr int HDIV_MAX_D1D = 5;
70 static constexpr int HDIV_MAX_Q1D = 6;
71 static constexpr int MAX_INTERP_1D = 8;
72 static constexpr int MAX_DET_1D = 6;
73};
74
75struct DofQuadLimits_CPU
76{
77#ifndef _WIN32
78 static constexpr int MAX_D1D = 24;
79 static constexpr int MAX_Q1D = 24;
80 static constexpr int MAX_D1D_SIMPLEX = 24;
81 static constexpr int MAX_Q1D_SIMPLEX = 24;
82#else
83 static constexpr int MAX_D1D = 14;
84 static constexpr int MAX_Q1D = 14;
85 static constexpr int MAX_D1D_SIMPLEX = 14;
86 static constexpr int MAX_Q1D_SIMPLEX = 14;
87#endif
88 static constexpr int MAX_T1D = 32;
89 static constexpr int HCURL_MAX_D1D = 10;
90 static constexpr int HCURL_MAX_Q1D = 10;
91 static constexpr int HDIV_MAX_D1D = 10;
92 static constexpr int HDIV_MAX_Q1D = 10;
93 static constexpr int MAX_INTERP_1D = MAX_D1D;
94 static constexpr int MAX_DET_1D = MAX_D1D;
95};
96
97} // namespace internal
98
99/// @brief Maximum number of 1D DOFs or quadrature points for the architecture
100/// currently being compiled for (used in fallback kernels).
101///
102/// DofQuadLimits provides access to the limits as static constexpr member
103/// variables for use in mfem::forall kernels or MFEM_HOST_DEVICE functions.
104///
105/// @sa For accessing the limits according to the runtime configuration of the
106/// Device, see DeviceDofQuadLimits.
107#if defined(__CUDA_ARCH__)
108using DofQuadLimits = internal::DofQuadLimits_CUDA;
109#elif defined(__HIP_DEVICE_COMPILE__)
110using DofQuadLimits = internal::DofQuadLimits_HIP;
111#else
112using DofQuadLimits = internal::DofQuadLimits_CPU;
113#endif
114
115/// @brief Maximum number of 1D DOFs or quadrature points for the current
116/// runtime configuration of the Device (used in fallback kernels).
117///
118/// DeviceDofQuadLimits can be used in host code to query the limits for the
119/// configured device (e.g. when the user has selected GPU execution at
120/// runtime).
121///
122/// @sa For accessing the limits according to the current compiler pass, see
123/// DofQuadLimits.
125{
126 int MAX_D1D; ///< Maximum number of 1D nodal points.
127 int MAX_Q1D; ///< Maximum number of 1D quadrature points.
128 int MAX_D1D_SIMPLEX; ///< Maximum number of 1D nodal points for simplices.
129 int MAX_Q1D_SIMPLEX; ///< Maximum number of 1D quadrature points for simplices.
130 int HCURL_MAX_D1D; ///< Maximum number of 1D nodal points for H(curl).
131 int HCURL_MAX_Q1D; ///< Maximum number of 1D quadrature points for H(curl).
132 int HDIV_MAX_D1D; ///< Maximum number of 1D nodal points for H(div).
133 int HDIV_MAX_Q1D; ///< Maximum number of 1D quadrature points for H(div).
134 int MAX_INTERP_1D; ///< Maximum number of points for use in QuadratureInterpolator.
135 int MAX_DET_1D; ///< Maximum number of points for determinant computation in QuadratureInterpolator.
136
137 /// Return a const reference to the DeviceDofQuadLimits singleton.
138 static const DeviceDofQuadLimits &Get()
139 {
140 static const DeviceDofQuadLimits dof_quad_limits;
141 return dof_quad_limits;
142 }
143
144private:
145 /// Initialize the limits depending on the configuration of the Device.
147 {
148 if (Device::Allows(Backend::CUDA_MASK)) { Populate<internal::DofQuadLimits_CUDA>(); }
149 else if (Device::Allows(Backend::HIP_MASK)) { Populate<internal::DofQuadLimits_HIP>(); }
150 else { Populate<internal::DofQuadLimits_CPU>(); }
151 }
152
153 /// @brief Set the limits using the static members of the type @a T.
154 ///
155 /// @a T should be one of DofQuadLimits_CUDA, DofQuadLimits_HIP, or
156 /// DofQuadLimits_CPU.
157 template <typename T> void Populate()
158 {
159 MAX_D1D = T::MAX_D1D;
160 MAX_Q1D = T::MAX_Q1D;
161 MAX_D1D_SIMPLEX = T::MAX_D1D_SIMPLEX;
162 MAX_Q1D_SIMPLEX = T::MAX_Q1D_SIMPLEX;
163 HCURL_MAX_D1D = T::HCURL_MAX_D1D;
164 HCURL_MAX_Q1D = T::HCURL_MAX_Q1D;
165 HDIV_MAX_D1D = T::HDIV_MAX_D1D;
166 HDIV_MAX_Q1D = T::HDIV_MAX_Q1D;
167 MAX_INTERP_1D = T::MAX_INTERP_1D;
168 MAX_DET_1D = T::MAX_DET_1D;
169 }
170};
171
172// MFEM pragma macros that can be used inside MFEM_FORALL macros.
173#define MFEM_PRAGMA(X) _Pragma(#X)
174
175// MFEM_UNROLL pragma macro that can be used inside MFEM_FORALL macros.
176#if defined(MFEM_USE_CUDA) && defined(__CUDA_ARCH__) // Clang cuda or nvcc
177#ifdef __NVCC__ // nvcc specifically
178#define MFEM_UNROLL(N) MFEM_PRAGMA(unroll(N))
179#else // Assuming Clang CUDA
180#define MFEM_UNROLL(N) MFEM_PRAGMA(unroll N)
181#endif
182#else
183#define MFEM_UNROLL(N)
184#endif
185
186// MFEM_GPU_FORALL: "parallel for" executed with CUDA or HIP based on the MFEM
187// build-time configuration (MFEM_USE_CUDA or MFEM_USE_HIP), and if compiling
188// with CUDA/HIP language. Otherwise, this macro is a no-op.
189#if defined(MFEM_USE_CUDA) && defined(__CUDACC__)
190#define MFEM_GPU_FORALL(i, N,...) CuWrap1D(N, [=] MFEM_DEVICE \
191 (int i) {__VA_ARGS__})
192#elif defined(MFEM_USE_HIP) && defined(__HIP__)
193#define MFEM_GPU_FORALL(i, N,...) HipWrap1D(N, [=] MFEM_DEVICE \
194 (int i) {__VA_ARGS__})
195#else
196#define MFEM_GPU_FORALL(i, N,...) do { } while (false)
197#endif
198
199// Implementation of MFEM's "parallel for" (forall) device/host kernel
200// interfaces supporting RAJA, CUDA, OpenMP, and sequential backends.
201
202// The MFEM_FORALL wrapper
203#define MFEM_FORALL(i,N,...) \
204 ForallWrap<1>(true,N,[=] MFEM_HOST_DEVICE (int i) {__VA_ARGS__})
205
206// MFEM_FORALL with a 2D CUDA block
207#define MFEM_FORALL_2D(i,N,X,Y,BZ,...) \
208 ForallWrap<2>(true,N,[=] MFEM_HOST_DEVICE (int i) {__VA_ARGS__},X,Y,BZ)
209
210// MFEM_FORALL with a 3D CUDA block
211#define MFEM_FORALL_3D(i,N,X,Y,Z,...) \
212 ForallWrap<3>(true,N,[=] MFEM_HOST_DEVICE (int i) {__VA_ARGS__},X,Y,Z)
213
214// MFEM_FORALL with a 3D CUDA block and grid
215// With G=0, this is the same as MFEM_FORALL_3D(i,N,X,Y,Z,...)
216#define MFEM_FORALL_3D_GRID(i,N,X,Y,Z,G,...) \
217 ForallWrap<3>(true,N,[=] MFEM_HOST_DEVICE (int i) {__VA_ARGS__},X,Y,Z,G)
218
219// MFEM_FORALL that uses the basic CPU backend when use_dev is false. See for
220// example the functions in vector.cpp, where we don't want to use the mfem
221// device for operations on small vectors.
222#define MFEM_FORALL_SWITCH(use_dev,i,N,...) \
223 ForallWrap<1>(use_dev,N,[=] MFEM_HOST_DEVICE (int i) {__VA_ARGS__})
224
225
226/// OpenMP backend
227template <typename HBODY>
228void OmpWrap(const int N, HBODY &&h_body)
229{
230#ifdef MFEM_USE_OPENMP
231 #pragma omp parallel for
232 for (int k = 0; k < N; k++)
233 {
234 h_body(k);
235 }
236#else
237 MFEM_CONTRACT_VAR(N);
238 MFEM_CONTRACT_VAR(h_body);
239 MFEM_ABORT("OpenMP requested for MFEM but OpenMP is not enabled!");
240#endif
241}
242
243template <typename HBODY>
244void OmpWrap2D(const int Nx, const int Ny, HBODY &&h_body)
245{
246#ifdef MFEM_USE_OPENMP
247 // requires OpenMP 3.1
248 #pragma omp parallel for collapse(2)
249 for (int j = 0; j < Ny; j++)
250 {
251 for (int i = 0; i < Nx; i++)
252 {
253 h_body(i, j);
254 }
255 }
256#else
257 MFEM_CONTRACT_VAR(Nx);
258 MFEM_CONTRACT_VAR(Ny);
259 MFEM_CONTRACT_VAR(h_body);
260 MFEM_ABORT("OpenMP requested for MFEM but OpenMP is not enabled!");
261#endif
262}
263
264template <typename HBODY>
265void OmpWrap3D(const int Nx, const int Ny, const int Nz, HBODY &&h_body)
266{
267#ifdef MFEM_USE_OPENMP
268 // requires OpenMP 3.1
269 #pragma omp parallel for collapse(3)
270 for (int k = 0; k < Nz; k++)
271 {
272 for (int j = 0; j < Ny; j++)
273 {
274 for (int i = 0; i < Nx; i++)
275 {
276 h_body(i, j, k);
277 }
278 }
279 }
280#else
281 MFEM_CONTRACT_VAR(Nx);
282 MFEM_CONTRACT_VAR(Ny);
283 MFEM_CONTRACT_VAR(Nz);
284 MFEM_CONTRACT_VAR(h_body);
285 MFEM_ABORT("OpenMP requested for MFEM but OpenMP is not enabled!");
286#endif
287}
288
289
290/// RAJA Cuda and Hip backends
291#if defined(MFEM_USE_RAJA) && defined(RAJA_ENABLE_CUDA) && defined(__CUDACC__)
292template <int LB>
294 RAJA::LaunchPolicy<RAJA::cuda_launch_t<true, LB>>;
296 RAJA::LaunchPolicy<RAJA::cuda_launch_t<true>>;
298 RAJA::LoopPolicy<RAJA::cuda_block_x_direct>;
300 RAJA::LoopPolicy<RAJA::cuda_thread_z_direct>;
301#endif
302
303#if defined(MFEM_USE_RAJA) && defined(RAJA_ENABLE_HIP) && defined(__HIP__)
305 RAJA::LaunchPolicy<RAJA::hip_launch_t<true>>;
306template <int LB>
308 RAJA::LaunchPolicy<RAJA::hip_launch_t<true, LB>>;
310 RAJA::LoopPolicy<RAJA::hip_block_x_direct>;
312 RAJA::LoopPolicy<RAJA::hip_thread_z_direct>;
313#endif
314
315#if defined(MFEM_USE_RAJA) && defined(RAJA_ENABLE_CUDA) && defined(__CUDACC__)
316template <typename DBODY>
317void RajaCuWrap1D(const int N, DBODY &&d_body)
318{
319 //true denotes asynchronous kernel
320 RAJA::forall<RAJA::cuda_exec<MFEM_CUDA_BLOCKS, true> >(
321 Device::GetRajaResource(), RAJA::RangeSegment(0, N), d_body);
322}
323
324template <typename DBODY>
325void RajaCuWrap2D(const int N, DBODY &&d_body,
326 const int X, const int Y, const int BZ)
327{
328 MFEM_VERIFY(BZ>0, "");
329 const int G = (N+BZ-1)/BZ;
330
331 using namespace RAJA;
332 using RAJA::RangeSegment;
333
334 launch<cuda_launch_policy>(Device::GetRajaResource(),
335 LaunchParams(Teams(G), Threads(X, Y, BZ)),
336 [=] RAJA_DEVICE(LaunchContext ctx)
337 {
338
339 loop<cuda_teams_x>(ctx, RangeSegment(0, G), [&] (const int n)
340 {
341
342 loop<cuda_threads_z>(ctx, RangeSegment(0, BZ), [&] (const int tz)
343 {
344
345 const int k = n*BZ + tz;
346 if (k >= N) { return; }
347 d_body(k);
348
349 });
350
351 });
352 });
353
354 MFEM_GPU_CHECK(cudaGetLastError());
355}
356
357template <int LB, typename DBODY>
358void RajaCuWrap2DLaunchBounds(const int N, DBODY &&d_body, const int X,
359 const int Y, const int BZ)
360{
361 MFEM_VERIFY(BZ>0, "");
362 const int G = (N+BZ-1)/BZ;
363
364 using namespace RAJA;
365 using RAJA::RangeSegment;
366
367 launch<cuda_launch_bounds_policy<LB> >(
368 Device::GetRajaResource(), LaunchParams(Teams(G), Threads(X, Y, BZ)),
369 [=] RAJA_DEVICE(LaunchContext ctx)
370 {
371 loop<cuda_teams_x>(ctx, RangeSegment(0, G), [&] (const int n)
372 {
373 loop<cuda_threads_z>(ctx, RangeSegment(0, BZ), [&] (const int tz)
374 {
375 const int k = n*BZ + tz;
376 if (k >= N) { return; }
377 d_body(k);
378 });
379 });
380 });
381 MFEM_GPU_CHECK(cudaGetLastError());
382}
383
384template <typename DBODY>
385void RajaCuWrap3D(const int N, DBODY &&d_body,
386 const int X, const int Y, const int Z, const int G)
387{
388 const int GRID = G == 0 ? N : G;
389 using namespace RAJA;
390 using RAJA::RangeSegment;
391
392 launch<cuda_launch_policy>(Device::GetRajaResource(),
393 LaunchParams(Teams(GRID), Threads(X, Y, Z)),
394 [=] RAJA_DEVICE(LaunchContext ctx)
395 {
396
397 loop<cuda_teams_x>(ctx, RangeSegment(0, N), d_body);
398 });
399
400 MFEM_GPU_CHECK(cudaGetLastError());
401}
402
403template <int LB, typename DBODY>
404void RajaCuWrap3DLaunchBounds(const int N, DBODY &&d_body,
405 const int X, const int Y, const int Z, const int G)
406{
407 const int GRID = G == 0 ? N : G;
408 using namespace RAJA;
409 using RAJA::RangeSegment;
410
411 launch<cuda_launch_bounds_policy<LB> >(
412 Device::GetRajaResource(), LaunchParams(Teams(GRID), Threads(X, Y, Z)),
413 [=] RAJA_DEVICE(LaunchContext ctx)
414 { loop<cuda_teams_x>(ctx, RangeSegment(0, N), d_body); });
415 MFEM_GPU_CHECK(cudaGetLastError());
416}
417
418template <int Dim, int MAX_THREADS_PER_BLOCK>
420
421template <int MAX_THREADS_PER_BLOCK>
422struct RajaCuWrap<1, MAX_THREADS_PER_BLOCK>
423{
424 template <typename DBODY>
425 static void run(const int N, DBODY &&d_body,
426 const int X, const int Y, const int Z, const int G)
427 {
428 RajaCuWrap1D(N, d_body);
429 }
430};
431
432template <>
433struct RajaCuWrap<2, 0>
434{
435 template <typename DBODY>
436 static void run(const int N, DBODY &&d_body,
437 const int X, const int Y, const int Z, const int G)
438 {
439 RajaCuWrap2D(N, d_body, X, Y, Z);
440 }
441};
442
443template <int MAX_THREADS_PER_BLOCK>
444struct RajaCuWrap<2, MAX_THREADS_PER_BLOCK>
445{
446 template <typename DBODY>
447 static void run(const int N, DBODY &&d_body,
448 const int X, const int Y, const int Z, const int G)
449 {
451 }
452};
453
454template <>
455struct RajaCuWrap<3, 0>
456{
457 template <typename DBODY>
458 static void run(const int N, DBODY &&d_body,
459 const int X, const int Y, const int Z, const int G)
460 {
461 RajaCuWrap3D(N, d_body, X, Y, Z, G);
462 }
463};
464
465template <int MAX_THREADS_PER_BLOCK>
466struct RajaCuWrap<3, MAX_THREADS_PER_BLOCK>
467{
468 template <typename DBODY>
469 static void run(const int N, DBODY &&d_body,
470 const int X, const int Y, const int Z, const int G)
471 {
473 }
474};
475
476#endif
477
478#if defined(MFEM_USE_RAJA) && defined(RAJA_ENABLE_HIP) && defined(__HIP__)
479template <typename DBODY>
480void RajaHipWrap1D(const int N, DBODY &&d_body)
481{
482 //true denotes asynchronous kernel
483 RAJA::forall<RAJA::hip_exec<MFEM_HIP_BLOCKS, true> >(
484 Device::GetRajaResource(), RAJA::RangeSegment(0, N), d_body);
485}
486
487template <typename DBODY>
488void RajaHipWrap2D(const int N, DBODY &&d_body,
489 const int X, const int Y, const int BZ)
490{
491 MFEM_VERIFY(BZ>0, "");
492 const int G = (N+BZ-1)/BZ;
493
494 using namespace RAJA;
495 using RAJA::RangeSegment;
496
497 launch<hip_launch_policy>(Device::GetRajaResource(),
498 LaunchParams(Teams(G), Threads(X, Y, BZ)),
499 [=] RAJA_DEVICE(LaunchContext ctx)
500 {
501
502 loop<hip_teams_x>(ctx, RangeSegment(0, G), [&] (const int n)
503 {
504
505 loop<hip_threads_z>(ctx, RangeSegment(0, BZ), [&] (const int tz)
506 {
507
508 const int k = n*BZ + tz;
509 if (k >= N) { return; }
510 d_body(k);
511
512 });
513
514 });
515 });
516
517 MFEM_GPU_CHECK(hipGetLastError());
518}
519
520template <int LB, typename DBODY>
521void RajaHipWrap2DLaunchBounds(const int N, DBODY &&d_body, const int X,
522 const int Y, const int BZ)
523{
524 MFEM_VERIFY(BZ>0, "");
525 const int G = (N+BZ-1)/BZ;
526
527 using namespace RAJA;
528 using RAJA::RangeSegment;
529
530 launch<hip_launch_bounds_policy<LB> >(
531 Device::GetRajaResource(), LaunchParams(Teams(G), Threads(X, Y, BZ)),
532 [=] RAJA_DEVICE(LaunchContext ctx)
533 {
534 loop<hip_teams_x>(ctx, RangeSegment(0, G), [&] (const int n)
535 {
536 loop<hip_threads_z>(ctx, RangeSegment(0, BZ), [&] (const int tz)
537 {
538 const int k = n*BZ + tz;
539 if (k >= N) { return; }
540 d_body(k);
541 });
542 });
543 });
544 MFEM_GPU_CHECK(hipGetLastError());
545}
546
547template <typename DBODY>
548void RajaHipWrap3D(const int N, DBODY &&d_body,
549 const int X, const int Y, const int Z, const int G)
550{
551 const int GRID = G == 0 ? N : G;
552 using namespace RAJA;
553 using RAJA::RangeSegment;
554
555 launch<hip_launch_policy>(Device::GetRajaResource(),
556 LaunchParams(Teams(GRID), Threads(X, Y, Z)),
557 [=] RAJA_DEVICE(LaunchContext ctx)
558 {
559
560 loop<hip_teams_x>(ctx, RangeSegment(0, N), d_body);
561 });
562
563 MFEM_GPU_CHECK(hipGetLastError());
564}
565
566template <int LB, typename DBODY>
567void RajaHipWrap3DLaunchBounds(const int N, DBODY &&d_body, const int X,
568 const int Y, const int Z, const int G)
569{
570 const int GRID = G == 0 ? N : G;
571 using namespace RAJA;
572 using RAJA::RangeSegment;
573
574 launch<hip_launch_bounds_policy<LB> >(
575 Device::GetRajaResource(), LaunchParams(Teams(GRID), Threads(X, Y, Z)),
576 [=] RAJA_DEVICE(LaunchContext ctx)
577 { loop<hip_teams_x>(ctx, RangeSegment(0, N), d_body); });
578 MFEM_GPU_CHECK(hipGetLastError());
579}
580
581template <int Dim, int MAX_THREADS_PER_BLOCK>
583
584template <int MAX_THREADS_PER_BLOCK>
585struct RajaHipWrap<1, MAX_THREADS_PER_BLOCK>
586{
587 template <typename DBODY>
588 static void run(const int N, DBODY &&d_body,
589 const int X, const int Y, const int Z, const int G)
590 {
591 RajaHipWrap1D(N, d_body);
592 }
593};
594
595template <>
596struct RajaHipWrap<2, 0>
597{
598 template <typename DBODY>
599 static void run(const int N, DBODY &&d_body,
600 const int X, const int Y, const int Z, const int G)
601 {
602 RajaHipWrap2D(N, d_body, X, Y, Z);
603 }
604};
605
606template <int MAX_THREADS_PER_BLOCK>
607struct RajaHipWrap<2, MAX_THREADS_PER_BLOCK>
608{
609 template <typename DBODY>
610 static void run(const int N, DBODY &&d_body,
611 const int X, const int Y, const int Z, const int G)
612 {
614 }
615};
616
617template <>
618struct RajaHipWrap<3, 0>
619{
620 template <typename DBODY>
621 static void run(const int N, DBODY &&d_body,
622 const int X, const int Y, const int Z, const int G)
623 {
624 RajaHipWrap3D(N, d_body, X, Y, Z, G);
625 }
626};
627
628template <int MAX_THREADS_PER_BLOCK>
629struct RajaHipWrap<3, MAX_THREADS_PER_BLOCK>
630{
631 template <typename DBODY>
632 static void run(const int N, DBODY &&d_body,
633 const int X, const int Y, const int Z, const int G)
634 {
636 }
637};
638
639#endif
640
641/// RAJA OpenMP backend
642#if defined(MFEM_USE_RAJA) && defined(RAJA_ENABLE_OPENMP)
643
644template <typename HBODY>
645void RajaOmpWrap(const int N, HBODY &&h_body)
646{
647 RAJA::forall<RAJA::omp_parallel_for_exec>(RAJA::RangeSegment(0,N), h_body);
648}
649
650template <typename HBODY>
651void RajaOmpWrap2D(const int Nx, const int Ny, HBODY &&h_body)
652{
653 using omp_launch_policy = RAJA::LaunchPolicy<RAJA::omp_launch_t>;
654 using global_thread_xy = RAJA::LoopPolicy<RAJA::omp_for_exec>;
655 RAJA::RangeSegment xrange(0, Nx);
656 RAJA::RangeSegment yrange(0, Ny);
657 RAJA::launch<omp_launch_policy>(RAJA::ExecPlace::HOST, RAJA::LaunchParams(),
658 [=](RAJA::LaunchContext ctx)
659 {
660 // contiguous in x
661 RAJA::expt::loop<global_thread_xy>(ctx, xrange, yrange, [&](int i, int j)
662 {
663 h_body(i, j);
664 });
665 });
666}
667
668template <typename HBODY>
669void RajaOmpWrap3D(const int Nx, const int Ny, const int Nz, HBODY &&h_body)
670{
671 using omp_launch_policy = RAJA::LaunchPolicy<RAJA::omp_launch_t>;
672 using global_thread_xyz = RAJA::LoopPolicy<RAJA::omp_for_exec>;
673 RAJA::RangeSegment xrange(0, Nx);
674 RAJA::RangeSegment yrange(0, Ny);
675 RAJA::RangeSegment zrange(0, Nz);
676 RAJA::launch<omp_launch_policy>(RAJA::ExecPlace::HOST, RAJA::LaunchParams(),
677 [=](RAJA::LaunchContext ctx)
678 {
679 // contiguous in x
680 RAJA::expt::loop<global_thread_xyz>(ctx, xrange, yrange, zrange,
681 [&](int i, int j, int k)
682 { h_body(i, j, k); });
683 });
684}
685
686#endif
687
688
689/// RAJA sequential loop backend
690template <typename HBODY>
691void RajaSeqWrap(const int N, HBODY &&h_body)
692{
693#ifdef MFEM_USE_RAJA
694
695#if (RAJA_VERSION_MAJOR >= 2023)
696 //loop_exec was marked deprecated in RAJA version 2023.06.0
697 //and will be removed. We now use seq_exec.
698 using raja_forall_pol = RAJA::seq_exec;
699#else
700 using raja_forall_pol = RAJA::loop_exec;
701#endif
702
703 RAJA::forall<raja_forall_pol>(RAJA::RangeSegment(0,N), h_body);
704#else
705 MFEM_CONTRACT_VAR(N);
706 MFEM_CONTRACT_VAR(h_body);
707 MFEM_ABORT("RAJA requested but RAJA is not enabled!");
708#endif
709}
710
711
712/// CUDA backend
713#if defined(MFEM_USE_CUDA) && defined(__CUDACC__)
714
715template <typename BODY> __global__ static
716void CuKernel1D(const int N, BODY body)
717{
718 const int k = blockDim.x*blockIdx.x + threadIdx.x;
719 if (k >= N) { return; }
720 body(k);
721}
722
723template <typename BODY> __global__ static
724void CuKernel2D(const int N, BODY body)
725{
726 const int k = blockIdx.x*blockDim.z + threadIdx.z;
727 if (k >= N) { return; }
728 body(k);
729}
730
731// __launch_bounds__ second argument is omitted to get the default behavior
732template <int MAX_THREADS_PER_BLOCK, typename BODY>
733__global__
734MFEM_LAUNCH_BOUNDS(MAX_THREADS_PER_BLOCK)
735static void CuKernel2DLaunchBounds(const int N, BODY body)
736{
737 const int k = blockIdx.x*blockDim.z + threadIdx.z;
738 if (k >= N) { return; }
740}
741
742template <typename BODY> __global__ static
743void CuKernel3D(const int N, BODY body)
744{
745 for (int k = blockIdx.x; k < N; k += gridDim.x) { body(k); }
746}
747
748template <int MAX_THREADS_PER_BLOCK, typename BODY>
749__global__
750MFEM_LAUNCH_BOUNDS(MAX_THREADS_PER_BLOCK)
751static void CuKernel3DLaunchBounds(const int N, BODY body)
752{
753 for (int k = blockIdx.x; k < N; k += gridDim.x) { body(k); }
754}
755
756template <const int BLCK = MFEM_CUDA_BLOCKS, typename DBODY>
757void CuWrap1D(const int N, DBODY &&d_body)
758{
759 if (N==0) { return; }
760 const int GRID = (N+BLCK-1)/BLCK;
761 CuKernel1D<<<GRID,BLCK>>>(N, d_body);
762 MFEM_GPU_CHECK(cudaGetLastError());
763}
764
765template <typename DBODY>
766void CuWrap2D(const int N, DBODY &&d_body,
767 const int X, const int Y, const int BZ)
768{
769 if (N==0) { return; }
770 // required for optimized GCC/NVCC builds to prevent runtime
771 // ODR/linkage violations of inlined templated kernel helpers
772 MFEM_VERIFY(BZ>0, "");
773 const int GRID = (N+BZ-1)/BZ;
774 const dim3 BLCK(X,Y,BZ);
775 CuKernel2D<<<GRID,BLCK>>>(N,d_body);
776 MFEM_GPU_CHECK(cudaGetLastError());
777}
778
779template <int MAX_THREADS_PER_BLOCK, typename DBODY>
780void CuWrap2DLaunchBounds(const int N, DBODY &&d_body,
781 const int X, const int Y, const int BZ)
782{
783 if (N==0) { return; }
784 MFEM_VERIFY(BZ>0, "");
785 const int GRID = (N+BZ-1)/BZ;
786 const dim3 BLCK(X,Y,BZ);
787 static_assert(MAX_THREADS_PER_BLOCK > 0);
788 CuKernel2DLaunchBounds<MAX_THREADS_PER_BLOCK><<<GRID,BLCK>>>(N, d_body);
789 MFEM_GPU_CHECK(cudaGetLastError());
790}
791
792template <typename DBODY>
793void CuWrap3D(const int N, DBODY &&d_body,
794 const int X, const int Y, const int Z, const int G)
795{
796 if (N==0) { return; }
797 const int GRID = G == 0 ? N : G;
798 const dim3 BLCK(X,Y,Z);
799 CuKernel3D<<<GRID,BLCK>>>(N,d_body);
800 MFEM_GPU_CHECK(cudaGetLastError());
801}
802
803template <int MAX_THREADS_PER_BLOCK, typename DBODY>
804void CuWrap3DLaunchBounds(const int N, DBODY &&d_body,
805 const int X, const int Y, const int Z, const int G)
806{
807 if (N==0) { return; }
808 const int GRID = G == 0 ? N : G;
809 const dim3 BLCK(X,Y,Z);
810 static_assert(MAX_THREADS_PER_BLOCK > 0);
811 CuKernel3DLaunchBounds<MAX_THREADS_PER_BLOCK><<<GRID, BLCK>>>(N, d_body);
812 MFEM_GPU_CHECK(cudaGetLastError());
813}
814
815template <int Dim, int MAX_THREADS_PER_BLOCK> struct CuWrap;
816
817template <int MAX_THREADS_PER_BLOCK>
818struct CuWrap<1, MAX_THREADS_PER_BLOCK>
819{
820 template <typename DBODY>
821 static void run(const int N, DBODY &&d_body,
822 const int X, const int Y, const int Z, const int G)
823 {
824 CuWrap1D<MFEM_CUDA_BLOCKS>(N, d_body);
825 }
826};
827
828template <>
829struct CuWrap<2, 0>
830{
831 template <typename DBODY>
832 static void run(const int N, DBODY &&d_body,
833 const int X, const int Y, const int Z, const int G)
834 {
835 CuWrap2D(N, d_body, X, Y, Z);
836 }
837};
838
839template <int MAX_THREADS_PER_BLOCK>
840struct CuWrap<2, MAX_THREADS_PER_BLOCK>
841{
842 template <typename DBODY>
843 static void run(const int N, DBODY &&d_body,
844 const int X, const int Y, const int Z, const int G)
845 {
846 static_assert(MAX_THREADS_PER_BLOCK > 0);
847 CuWrap2DLaunchBounds<MAX_THREADS_PER_BLOCK>(N, d_body, X, Y, Z);
848 }
849};
850
851template <>
852struct CuWrap<3, 0>
853{
854 template <typename DBODY>
855 static void run(const int N, DBODY &&d_body,
856 const int X, const int Y, const int Z, const int G)
857 {
858 CuWrap3D(N, d_body, X, Y, Z, G);
859 }
860};
861
862template <int MAX_THREADS_PER_BLOCK>
863struct CuWrap<3, MAX_THREADS_PER_BLOCK>
864{
865 template <typename DBODY>
866 static void run(const int N, DBODY &&d_body,
867 const int X, const int Y, const int Z, const int G)
868 {
869 CuWrap3DLaunchBounds<MAX_THREADS_PER_BLOCK>(N, d_body, X, Y, Z, G);
870 }
871};
872
873#endif // defined(MFEM_USE_CUDA) && defined(__CUDACC__)
874
875
876/// HIP backend
877#if defined(MFEM_USE_HIP) && defined(__HIP__)
878
879template <typename BODY> __global__ static
880void HipKernel1D(const int N, BODY body)
881{
882 const int k = hipBlockDim_x*hipBlockIdx_x + hipThreadIdx_x;
883 if (k >= N) { return; }
884 body(k);
885}
886
887template <typename BODY> __global__ static
888void HipKernel2D(const int N, BODY body)
889{
890 const int k = hipBlockIdx_x*hipBlockDim_z + hipThreadIdx_z;
891 if (k >= N) { return; }
892 body(k);
893}
894
895template <int MAX_THREADS_PER_BLOCK, typename BODY>
896__global__
897MFEM_LAUNCH_BOUNDS(MAX_THREADS_PER_BLOCK)
898static void HipKernel2DLaunchBounds(const int N, BODY body)
899{
900 const int k = hipBlockIdx_x*hipBlockDim_z + hipThreadIdx_z;
901 if (k >= N) { return; }
902 body(k);
903}
904
905template <typename BODY> __global__ static
906void HipKernel3D(const int N, BODY body)
907{
908 for (int k = hipBlockIdx_x; k < N; k += hipGridDim_x) { body(k); }
909}
910
911template <int MAX_THREADS_PER_BLOCK, typename BODY>
912__global__
913MFEM_LAUNCH_BOUNDS(MAX_THREADS_PER_BLOCK)
914static void HipKernel3DLaunchBounds(const int N, BODY body)
915{
916 for (int k = hipBlockIdx_x; k < N; k += hipGridDim_x) { body(k); }
917}
918
919template <int BLCK = MFEM_HIP_BLOCKS, typename DBODY>
920void HipWrap1D(const int N, DBODY &&d_body)
921{
922 if (N==0) { return; }
923 const int GRID = (N+BLCK-1)/BLCK;
924 hipLaunchKernelGGL(HipKernel1D,GRID,BLCK,0,nullptr,N,d_body);
925 MFEM_GPU_CHECK(hipGetLastError());
926}
927
928template <typename DBODY>
929void HipWrap2D(const int N, DBODY &&d_body,
930 const int X, const int Y, const int BZ)
931{
932 if (N==0) { return; }
933 MFEM_VERIFY(BZ>0, "");
934 const int GRID = (N+BZ-1)/BZ;
935 const dim3 BLCK(X,Y,BZ);
936 hipLaunchKernelGGL(HipKernel2D,GRID,BLCK,0,nullptr,N,d_body);
937 MFEM_GPU_CHECK(hipGetLastError());
938}
939
940template <int MAX_THREADS_PER_BLOCK, typename DBODY>
941void HipWrap2DLaunchBounds(const int N, DBODY &&d_body,
942 const int X, const int Y, const int BZ)
943{
944 if (N==0) { return; }
945 MFEM_VERIFY(BZ>0, "");
946 const int GRID = (N+BZ-1)/BZ;
947 const dim3 BLCK(X,Y,BZ);
948 static_assert(MAX_THREADS_PER_BLOCK > 0);
949 HipKernel2DLaunchBounds<MAX_THREADS_PER_BLOCK><<<dim3(GRID), dim3(BLCK), 0, 0>>>
950 (N, d_body);
951 MFEM_GPU_CHECK(hipGetLastError());
952}
953
954template <typename DBODY>
955void HipWrap3D(const int N, DBODY &&d_body,
956 const int X, const int Y, const int Z, const int G)
957{
958 if (N==0) { return; }
959 const int GRID = G == 0 ? N : G;
960 const dim3 BLCK(X,Y,Z);
961 hipLaunchKernelGGL(HipKernel3D,GRID,BLCK,0,nullptr,N,d_body);
962 MFEM_GPU_CHECK(hipGetLastError());
963}
964
965template <int MAX_THREADS_PER_BLOCK, typename DBODY>
966void HipWrap3DLaunchBounds(const int N, DBODY &&d_body,
967 const int X, const int Y, const int Z, const int G)
968{
969 if (N==0) { return; }
970 const int GRID = G == 0 ? N : G;
971 const dim3 BLCK(X,Y,Z);
972 static_assert(MAX_THREADS_PER_BLOCK > 0);
973 HipKernel3DLaunchBounds<MAX_THREADS_PER_BLOCK><<<dim3(GRID), dim3(BLCK), 0, 0>>>
974 (N, d_body);
975 MFEM_GPU_CHECK(hipGetLastError());
976}
977
978template <int Dim, int MAX_THREADS_PER_BLOCK> struct HipWrap;
979
980template <int MAX_THREADS_PER_BLOCK>
981struct HipWrap<1, MAX_THREADS_PER_BLOCK>
982{
983 template <typename DBODY>
984 static void run(const int N, DBODY &&d_body,
985 const int X, const int Y, const int Z, const int G)
986 {
987 HipWrap1D<MFEM_HIP_BLOCKS>(N, d_body);
988 }
989};
990
991template <>
992struct HipWrap<2, 0>
993{
994 template <typename DBODY>
995 static void run(const int N, DBODY &&d_body,
996 const int X, const int Y, const int Z, const int G)
997 {
998 HipWrap2D(N, d_body, X, Y, Z);
999 }
1000};
1001
1002template <int MAX_THREADS_PER_BLOCK>
1003struct HipWrap<2, MAX_THREADS_PER_BLOCK>
1004{
1005 template <typename DBODY>
1006 static void run(const int N, DBODY &&d_body,
1007 const int X, const int Y, const int Z, const int G)
1008 {
1009 HipWrap2DLaunchBounds<MAX_THREADS_PER_BLOCK>(N, d_body, X, Y, Z);
1010 }
1011};
1012
1013template <>
1014struct HipWrap<3, 0>
1015{
1016 template <typename DBODY>
1017 static void run(const int N, DBODY &&d_body,
1018 const int X, const int Y, const int Z, const int G)
1019 {
1020 HipWrap3D(N, d_body, X, Y, Z, G);
1021 }
1022};
1023
1024template <int MAX_THREADS_PER_BLOCK>
1025struct HipWrap<3, MAX_THREADS_PER_BLOCK>
1026{
1027 template <typename DBODY>
1028 static void run(const int N, DBODY &&d_body,
1029 const int X, const int Y, const int Z, const int G)
1030 {
1031 HipWrap3DLaunchBounds<MAX_THREADS_PER_BLOCK>(N, d_body, X, Y, Z, G);
1032 }
1033};
1034
1035#endif // defined(MFEM_USE_HIP) && defined(__HIP__)
1036
1037
1038///////////////////////////////////////////////////////////////////////////////
1039/// Forall host & device kernel dispatch
1040template <int DIM, int MAX_THREADS_PER_BLOCK = 0,
1041 typename d_lambda, typename h_lambda>
1042inline void ForallWrap(const bool use_dev, const int N,
1043 d_lambda &&d_body, h_lambda &&h_body,
1044 const int X=0, const int Y=0, const int Z=0,
1045 const int G=0)
1046{
1047 internal::RequireKernelCompilation();
1048
1049 MFEM_CONTRACT_VAR(X);
1050 MFEM_CONTRACT_VAR(Y);
1051 MFEM_CONTRACT_VAR(Z);
1052 MFEM_CONTRACT_VAR(G);
1053 MFEM_CONTRACT_VAR(d_body);
1054 if (!use_dev) { goto backend_cpu; }
1055
1056#if defined(MFEM_USE_RAJA) && defined(RAJA_ENABLE_CUDA) && defined(__CUDACC__)
1057 // If Backend::RAJA_CUDA is allowed, use it
1059 {
1060 return RajaCuWrap<DIM, MAX_THREADS_PER_BLOCK>::run(N, d_body, X, Y, Z, G);
1061 }
1062#endif
1063
1064#if defined(MFEM_USE_RAJA) && defined(RAJA_ENABLE_HIP) && defined(__HIP__)
1065 // If Backend::RAJA_HIP is allowed, use it
1067 {
1068 return RajaHipWrap<DIM, MAX_THREADS_PER_BLOCK>::run(N, d_body, X, Y, Z, G);
1069 }
1070#endif
1071
1072#if defined(MFEM_USE_CUDA) && defined(__CUDACC__)
1073 // If Backend::CUDA is allowed, use it
1075 {
1076 return CuWrap<DIM, MAX_THREADS_PER_BLOCK>::run(N, d_body, X, Y, Z, G);
1077 }
1078#endif
1079
1080#if defined(MFEM_USE_HIP) && defined(__HIP__)
1081 // If Backend::HIP is allowed, use it
1083 {
1084 return HipWrap<DIM, MAX_THREADS_PER_BLOCK>::run(N, d_body, X, Y, Z, G);
1085 }
1086#endif
1087
1088 // If Backend::DEBUG_DEVICE is allowed, use it
1089 if (Device::Allows(Backend::DEBUG_DEVICE)) { goto backend_cpu; }
1090
1091#if defined(MFEM_USE_RAJA) && defined(RAJA_ENABLE_OPENMP)
1092 // If Backend::RAJA_OMP is allowed, use it
1093 if (Device::Allows(Backend::RAJA_OMP)) { return RajaOmpWrap(N, h_body); }
1094#endif
1095
1096#ifdef MFEM_USE_OPENMP
1097 // If Backend::OMP is allowed, use it
1098 if (Device::Allows(Backend::OMP)) { return OmpWrap(N, h_body); }
1099#endif
1100
1101#ifdef MFEM_USE_RAJA
1102 // If Backend::RAJA_CPU is allowed, use it
1103 if (Device::Allows(Backend::RAJA_CPU)) { return RajaSeqWrap(N, h_body); }
1104#endif
1105
1106backend_cpu:
1107 // Handle Backend::CPU. This is also a fallback for any allowed backends not
1108 // handled above, e.g. OCCA_CPU with configuration 'occa-cpu,cpu', or
1109 // OCCA_OMP with configuration 'occa-omp,cpu'.
1110 for (int k = 0; k < N; k++) { h_body(k); }
1111}
1112
1113///////////////////////////////////////////////////////////////////////////////
1114/// Forall host & device kernel wrappers
1115template <int DIM, typename lambda>
1116inline void ForallWrap(const bool use_dev, const int N, lambda &&body,
1117 const int X=0, const int Y=0, const int Z=0,
1118 const int G=0)
1119{
1120 ForallWrap<DIM>(use_dev, N, body, body, X, Y, Z, G);
1121}
1122
1123template <int DIM, int MAX_THREADS_PER_BLOCK, typename lambda>
1124inline void ForallWrap(const bool use_dev, const int N, lambda &&body,
1125 const int X=0, const int Y=0, const int Z=0,
1126 const int G=0)
1127{
1128 ForallWrap<DIM, MAX_THREADS_PER_BLOCK>(use_dev, N, body, body, X, Y, Z, G);
1129}
1130
1131///////////////////////////////////////////////////////////////////////////////
1132// forall interfaces
1133template<typename lambda>
1134inline void forall(int N, lambda &&body) { ForallWrap<1>(true, N, body); }
1135
1136template<typename lambda>
1137inline void forall(int Nx, int Ny, lambda &&body)
1138{
1140 {
1141 mfem::forall(Nx * Ny, [=] MFEM_HOST_DEVICE(int idx)
1142 {
1143 int j = idx / Nx;
1144 int i = idx % Nx;
1145 body(i, j);
1146 });
1147 }
1148#if defined(MFEM_USE_RAJA) && defined(RAJA_ENABLE_OPENMP)
1150 {
1151 return RajaOmpWrap2D(Nx, Ny, body);
1152 }
1153#endif
1154#ifdef MFEM_USE_OPENMP
1155 else if (Device::Allows(Backend::OMP))
1156 {
1157 return OmpWrap2D(Nx, Ny, body);
1158 }
1159#endif
1160 else
1161 {
1162 for (int j = 0; j < Ny; ++j)
1163 {
1164 for (int i = 0; i < Nx; ++i)
1165 {
1166 body(i, j);
1167 }
1168 }
1169 }
1170}
1171
1172template<typename lambda>
1173inline void forall(int Nx, int Ny, int Nz, lambda &&body)
1174{
1176 {
1177 mfem::forall(Nx * Ny * Nz, [=] MFEM_HOST_DEVICE(int idx)
1178 {
1179 int i = idx % Nx;
1180 int j = idx / Nx;
1181 int k = j / Ny;
1182 j = j % Ny;
1183 body(i, j, k);
1184 });
1185 }
1186#if defined(MFEM_USE_RAJA) && defined(RAJA_ENABLE_OPENMP)
1188 {
1189 return RajaOmpWrap3D(Nx, Ny, Nz, body);
1190 }
1191#endif
1192#ifdef MFEM_USE_OPENMP
1193 else if (Device::Allows(Backend::OMP))
1194 {
1195 return OmpWrap3D(Nx, Ny, Nz, body);
1196 }
1197#endif
1198 else
1199 {
1200 for (int k = 0; k < Nz; ++k)
1201 {
1202 for (int j = 0; j < Ny; ++j)
1203 {
1204 for (int i = 0; i < Nx; ++i)
1205 {
1206 body(i, j, k);
1207 }
1208 }
1209 }
1210 }
1211}
1212
1213template<typename lambda>
1214inline void forall_switch(bool use_dev, int N, lambda &&body)
1215{
1216 ForallWrap<1>(use_dev, N, body);
1217}
1218
1219template<typename lambda>
1220inline void forall_2D(int N, int X, int Y, lambda &&body)
1221{
1222 ForallWrap<2>(true, N, body, X, Y, 1);
1223}
1224
1225template<int MAX_THREADS_PER_BLOCK, typename lambda>
1226inline void forall_2D(int N, int X, int Y, lambda &&body)
1227{
1228 ForallWrap<2, MAX_THREADS_PER_BLOCK>(true, N, body, X, Y, 1);
1229}
1230
1231template<typename lambda>
1232inline void forall_2D_batch(int N, int X, int Y, int BZ, lambda &&body)
1233{
1234 ForallWrap<2>(true, N, body, X, Y, BZ);
1235}
1236
1237template<int MAX_THREADS_PER_BLOCK, typename lambda>
1238inline void forall_2D_batch(int N, int X, int Y, int BZ, lambda &&body)
1239{
1240 ForallWrap<2, MAX_THREADS_PER_BLOCK>(true, N, body, X, Y, BZ);
1241}
1242
1243template<typename lambda>
1244inline void forall_3D(int N, int X, int Y, int Z, lambda &&body)
1245{
1246 ForallWrap<3>(true, N, body, X, Y, Z, 0);
1247}
1248
1249template<int MAX_THREADS_PER_BLOCK, typename lambda>
1250inline void forall_3D(int N, int X, int Y, int Z, lambda &&body)
1251{
1252 ForallWrap<3, MAX_THREADS_PER_BLOCK>(true, N, body, X, Y, Z, 0);
1253}
1254
1255template<typename lambda>
1256inline void forall_3D_grid(int N, int X, int Y, int Z, int G, lambda &&body)
1257{
1258 ForallWrap<3>(true, N, body, X, Y, Z, G);
1259}
1260
1261#ifdef MFEM_USE_MPI
1262
1263// Function mfem::hypre_forall_cpu() similar to mfem::forall, but it always
1264// executes on the CPU using sequential or OpenMP-parallel execution based on
1265// the hypre build time configuration.
1266template<typename lambda>
1267inline void hypre_forall_cpu(int N, lambda &&body)
1268{
1269#ifdef HYPRE_USING_OPENMP
1270 #pragma omp parallel for HYPRE_SMP_SCHEDULE
1271#endif
1272 for (int i = 0; i < N; i++) { body(i); }
1273}
1274
1275// Function mfem::hypre_forall_gpu() similar to mfem::forall, but it always
1276// executes on the GPU device that hypre was configured with at build time.
1277#if defined(HYPRE_USING_GPU)
1278template<typename lambda>
1279inline void hypre_forall_gpu(int N, lambda &&body)
1280{
1281 internal::RequireKernelCompilation();
1282
1283#if defined(MFEM_USE_CUDA_OR_HIP_LANG)
1284#if defined(HYPRE_USING_CUDA)
1285 CuWrap1D(N, body);
1286#elif defined(HYPRE_USING_HIP)
1287 HipWrap1D(N, body);
1288#else
1289#error Unknown HYPRE GPU backend!
1290#endif
1291#endif
1292}
1293#endif
1294
1295// Function mfem::hypre_forall() similar to mfem::forall, but it executes on the
1296// device, CPU or GPU, that hypre was configured with at build time (when the
1297// HYPRE version is < 2.31.0) or at runtime (when HYPRE was configured with GPU
1298// support at build time and HYPRE's version is >= 2.31.0). This selection is
1299// generally independent of what device was selected in MFEM's runtime
1300// configuration.
1301template<typename lambda>
1302inline void hypre_forall(int N, lambda &&body)
1303{
1304#if !defined(HYPRE_USING_GPU)
1306#elif MFEM_HYPRE_VERSION < 23100
1308#else // HYPRE_USING_GPU is defined and MFEM_HYPRE_VERSION >= 23100
1309 if (!HypreUsingGPU())
1310 {
1312 }
1313 else
1314 {
1316 }
1317#endif
1318}
1319
1320// Return the most general MemoryClass that can be used with mfem::hypre_forall
1321// kernels. The returned MemoryClass is the same as the one returned by
1322// GerHypreMemoryClass() except when hypre is configured to use UVM, in which
1323// case this function returns MemoryClass::HOST or MemoryClass::DEVICE depending
1324// on the result of HypreUsingGPU().
1329
1330#endif // MFEM_USE_MPI
1331
1332} // namespace mfem
1333
1334#endif // MFEM_FORALL_HPP
static auto GetRajaResource()
Definition device.hpp:276
static bool Allows(unsigned long b_mask)
Return true if any of the backends in the backend mask, b_mask, are allowed.
Definition device.hpp:271
struct LorentzContext ctx
constexpr int DIM
RAJA::LaunchPolicy< RAJA::cuda_launch_t< true > > cuda_launch_policy
Definition forall.hpp:295
void RajaOmpWrap(const int N, HBODY &&h_body)
RAJA OpenMP backend.
Definition forall.hpp:645
RAJA::LaunchPolicy< RAJA::hip_launch_t< true > > hip_launch_policy
Definition forall.hpp:304
void RajaCuWrap3DLaunchBounds(const int N, DBODY &&d_body, const int X, const int Y, const int Z, const int G)
Definition forall.hpp:404
void RajaSeqWrap(const int N, HBODY &&h_body)
RAJA sequential loop backend.
Definition forall.hpp:691
void ForallWrap(const bool use_dev, const int N, d_lambda &&d_body, h_lambda &&h_body, const int X=0, const int Y=0, const int Z=0, const int G=0)
Forall host & device kernel dispatch.
Definition forall.hpp:1042
MemoryClass GetHypreForallMemoryClass()
Definition forall.hpp:1325
void RajaOmpWrap3D(const int Nx, const int Ny, const int Nz, HBODY &&h_body)
Definition forall.hpp:669
void OmpWrap3D(const int Nx, const int Ny, const int Nz, HBODY &&h_body)
Definition forall.hpp:265
void RajaCuWrap1D(const int N, DBODY &&d_body)
Definition forall.hpp:317
void RajaHipWrap2D(const int N, DBODY &&d_body, const int X, const int Y, const int BZ)
Definition forall.hpp:488
void hypre_forall_cpu(int N, lambda &&body)
Definition forall.hpp:1267
void RajaCuWrap2D(const int N, DBODY &&d_body, const int X, const int Y, const int BZ)
Definition forall.hpp:325
RAJA::LoopPolicy< RAJA::cuda_thread_z_direct > cuda_threads_z
Definition forall.hpp:299
__global__ MFEM_LAUNCH_BOUNDS(MAX_THREADS_PER_BLOCK) static void CuKernel2DLaunchBounds(const int N
MemoryClass
Memory classes identify sets of memory types.
void RajaHipWrap1D(const int N, DBODY &&d_body)
Definition forall.hpp:480
void RajaOmpWrap2D(const int Nx, const int Ny, HBODY &&h_body)
Definition forall.hpp:651
void RajaCuWrap3D(const int N, DBODY &&d_body, const int X, const int Y, const int Z, const int G)
Definition forall.hpp:385
void forall_2D_batch(int N, int X, int Y, int BZ, lambda &&body)
Definition forall.hpp:1232
void hypre_forall_gpu(int N, lambda &&body)
Definition forall.hpp:1279
void OmpWrap2D(const int Nx, const int Ny, HBODY &&h_body)
Definition forall.hpp:244
internal::DofQuadLimits_CUDA DofQuadLimits
Maximum number of 1D DOFs or quadrature points for the architecture currently being compiled for (use...
Definition forall.hpp:108
__global__ BODY body
Definition forall.hpp:736
void forall_2D(int N, int X, int Y, lambda &&body)
Definition forall.hpp:1220
RAJA::LoopPolicy< RAJA::hip_thread_z_direct > hip_threads_z
Definition forall.hpp:311
void forall_3D(int N, int X, int Y, int Z, lambda &&body)
Definition forall.hpp:1244
void RajaHipWrap2DLaunchBounds(const int N, DBODY &&d_body, const int X, const int Y, const int BZ)
Definition forall.hpp:521
void hypre_forall(int N, lambda &&body)
Definition forall.hpp:1302
void OmpWrap(const int N, HBODY &&h_body)
OpenMP backend.
Definition forall.hpp:228
bool HypreUsingGPU()
Return true if HYPRE is configured to use GPU.
void forall_3D_grid(int N, int X, int Y, int Z, int G, lambda &&body)
Definition forall.hpp:1256
RAJA::LoopPolicy< RAJA::hip_block_x_direct > hip_teams_x
Definition forall.hpp:309
void RajaCuWrap2DLaunchBounds(const int N, DBODY &&d_body, const int X, const int Y, const int BZ)
Definition forall.hpp:358
void RajaHipWrap3DLaunchBounds(const int N, DBODY &&d_body, const int X, const int Y, const int Z, const int G)
Definition forall.hpp:567
RAJA::LaunchPolicy< RAJA::hip_launch_t< true, LB > > hip_launch_bounds_policy
Definition forall.hpp:307
void forall(int N, lambda &&body)
Definition forall.hpp:1134
void forall_switch(bool use_dev, int N, lambda &&body)
Definition forall.hpp:1214
RAJA::LaunchPolicy< RAJA::cuda_launch_t< true, LB > > cuda_launch_bounds_policy
RAJA Cuda and Hip backends.
Definition forall.hpp:293
RAJA::LoopPolicy< RAJA::cuda_block_x_direct > cuda_teams_x
Definition forall.hpp:297
void RajaHipWrap3D(const int N, DBODY &&d_body, const int X, const int Y, const int Z, const int G)
Definition forall.hpp:548
@ RAJA_OMP
[host] RAJA OpenMP backend. Enabled when MFEM_USE_RAJA = YES and MFEM_USE_OPENMP = YES.
Definition device.hpp:53
@ RAJA_CUDA
[device] RAJA CUDA backend. Enabled when MFEM_USE_RAJA = YES and MFEM_USE_CUDA = YES.
Definition device.hpp:56
@ DEBUG_DEVICE
[device] Debug backend: host memory is READ/WRITE protected while a device is in use....
Definition device.hpp:83
@ RAJA_CPU
[host] RAJA CPU backend: sequential execution on each MPI rank. Enabled when MFEM_USE_RAJA = YES.
Definition device.hpp:50
@ OMP
[host] OpenMP backend. Enabled when MFEM_USE_OPENMP = YES.
Definition device.hpp:43
@ HIP
[device] HIP backend. Enabled when MFEM_USE_HIP = YES.
Definition device.hpp:47
@ RAJA_HIP
[device] RAJA HIP backend. Enabled when MFEM_USE_RAJA = YES and MFEM_USE_HIP = YES.
Definition device.hpp:59
@ CUDA
[device] CUDA backend. Enabled when MFEM_USE_CUDA = YES.
Definition device.hpp:45
@ DEVICE_MASK
Biwise-OR of all device backends.
Definition device.hpp:104
@ HIP_MASK
Biwise-OR of all HIP backends.
Definition device.hpp:98
@ CUDA_MASK
Biwise-OR of all CUDA backends.
Definition device.hpp:96
static void run(const int N, DBODY &&d_body, const int X, const int Y, const int Z, const int G)
Definition forall.hpp:821
static void run(const int N, DBODY &&d_body, const int X, const int Y, const int Z, const int G)
Definition forall.hpp:832
static void run(const int N, DBODY &&d_body, const int X, const int Y, const int Z, const int G)
Definition forall.hpp:843
static void run(const int N, DBODY &&d_body, const int X, const int Y, const int Z, const int G)
Definition forall.hpp:855
static void run(const int N, DBODY &&d_body, const int X, const int Y, const int Z, const int G)
Definition forall.hpp:866
Maximum number of 1D DOFs or quadrature points for the current runtime configuration of the Device (u...
Definition forall.hpp:125
static const DeviceDofQuadLimits & Get()
Return a const reference to the DeviceDofQuadLimits singleton.
Definition forall.hpp:138
int HCURL_MAX_D1D
Maximum number of 1D nodal points for H(curl).
Definition forall.hpp:130
int HCURL_MAX_Q1D
Maximum number of 1D quadrature points for H(curl).
Definition forall.hpp:131
int HDIV_MAX_Q1D
Maximum number of 1D quadrature points for H(div).
Definition forall.hpp:133
int MAX_INTERP_1D
Maximum number of points for use in QuadratureInterpolator.
Definition forall.hpp:134
int HDIV_MAX_D1D
Maximum number of 1D nodal points for H(div).
Definition forall.hpp:132
int MAX_DET_1D
Maximum number of points for determinant computation in QuadratureInterpolator.
Definition forall.hpp:135
int MAX_D1D
Maximum number of 1D nodal points.
Definition forall.hpp:126
int MAX_D1D_SIMPLEX
Maximum number of 1D nodal points for simplices.
Definition forall.hpp:128
int MAX_Q1D_SIMPLEX
Maximum number of 1D quadrature points for simplices.
Definition forall.hpp:129
int MAX_Q1D
Maximum number of 1D quadrature points.
Definition forall.hpp:127
static void run(const int N, DBODY &&d_body, const int X, const int Y, const int Z, const int G)
Definition forall.hpp:984
static void run(const int N, DBODY &&d_body, const int X, const int Y, const int Z, const int G)
Definition forall.hpp:995
static void run(const int N, DBODY &&d_body, const int X, const int Y, const int Z, const int G)
Definition forall.hpp:1006
static void run(const int N, DBODY &&d_body, const int X, const int Y, const int Z, const int G)
Definition forall.hpp:1017
static void run(const int N, DBODY &&d_body, const int X, const int Y, const int Z, const int G)
Definition forall.hpp:1028
static void run(const int N, DBODY &&d_body, const int X, const int Y, const int Z, const int G)
Definition forall.hpp:425
static void run(const int N, DBODY &&d_body, const int X, const int Y, const int Z, const int G)
Definition forall.hpp:436
static void run(const int N, DBODY &&d_body, const int X, const int Y, const int Z, const int G)
Definition forall.hpp:447
static void run(const int N, DBODY &&d_body, const int X, const int Y, const int Z, const int G)
Definition forall.hpp:458
static void run(const int N, DBODY &&d_body, const int X, const int Y, const int Z, const int G)
Definition forall.hpp:469
static void run(const int N, DBODY &&d_body, const int X, const int Y, const int Z, const int G)
Definition forall.hpp:588
static void run(const int N, DBODY &&d_body, const int X, const int Y, const int Z, const int G)
Definition forall.hpp:599
static void run(const int N, DBODY &&d_body, const int X, const int Y, const int Z, const int G)
Definition forall.hpp:610
static void run(const int N, DBODY &&d_body, const int X, const int Y, const int Z, const int G)
Definition forall.hpp:621
static void run(const int N, DBODY &&d_body, const int X, const int Y, const int Z, const int G)
Definition forall.hpp:632