MFEM v4.10.0
Finite element discretization library
Loading...
Searching...
No Matches
backends.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_BACKENDS_HPP
13#define MFEM_BACKENDS_HPP
14
15#include "../config/config.hpp"
16
17#if defined(MFEM_USE_CUDA)
18#include <cusparse.h>
19#include <library_types.h>
20#include <cuda_runtime.h>
21#include <cuda.h>
22#endif
23#include "cuda.hpp"
24
25#if defined(MFEM_USE_HIP)
26#include <hip/hip_runtime.h>
27#endif
28#include "hip.hpp"
29
30#ifdef MFEM_USE_OCCA
31#include "occa.hpp"
32#endif
33
34#ifdef MFEM_USE_RAJA
35// The following two definitions suppress CUB and THRUST deprecation warnings
36// about requiring c++14 with c++11 deprecated but still supported (to be
37// removed in a future release).
38#define CUB_IGNORE_DEPRECATED_CPP_DIALECT
39#define THRUST_IGNORE_DEPRECATED_CPP_DIALECT
40
41#include "RAJA/RAJA.hpp"
42#if defined(RAJA_ENABLE_CUDA) && !defined(MFEM_USE_CUDA)
43#error When RAJA is built with CUDA, MFEM_USE_CUDA=YES is required
44#endif
45#endif
46
47#if !defined(MFEM_USE_CUDA_OR_HIP)
48// MFEM_DEVICE_SYNC is made available for debugging purposes
49#define MFEM_DEVICE_SYNC
50// MFEM_STREAM_SYNC is used for UVM and MPI GPU-Aware kernels
51#define MFEM_STREAM_SYNC
52#endif
53
54#if !defined(MFEM_USE_CUDA_OR_HIP_LANG)
55#define MFEM_DEVICE
56#define MFEM_HOST
57#define MFEM_LAMBDA
58// #define MFEM_HOST_DEVICE // defined in config/config.hpp
59#define MFEM_LAUNCH_BOUNDS(...)
60#endif
61
62#if !((defined(MFEM_USE_CUDA) && defined(__CUDA_ARCH__)) || \
63 (defined(MFEM_USE_HIP) && defined(__HIP_DEVICE_COMPILE__)))
64#define MFEM_SHARED
65#define MFEM_SYNC_THREAD
66#define MFEM_BLOCK_ID(k) 0
67#define MFEM_THREAD_ID(k) 0
68#define MFEM_THREAD_SIZE(k) 1
69#define MFEM_FOREACH_THREAD(i,k,N) for(int i=0; i<N; i++)
70#define MFEM_FOREACH_THREAD_DIRECT(i,k,N) MFEM_FOREACH_THREAD(i,k,N)
71// Assigns a thread block shaped (SX,SY,SZ) contiguous in x.
72// Example (3,2,1) block:
73// 0 (0,0), 1 (1,0), 2 (2,0)
74// 3 (1,0), 4 (1,1), 5 (2,1)
75#define MFEM_FOREACH_THREAD_DIRECT_3D(ix, iy, iz, k, SX, SY, SZ) \
76 for (int iz = 0; iz < SZ; ++iz) \
77 for (int iy = 0; iy < SY; ++iy) \
78 for (int ix = 0; ix < SX; ++ix)
79// Assigns a thread block shaped (OX,OY,OZ) to work on items (SX,SY,SZ),
80// contiguous in x. This intentionally offsets threads within the block to avoid
81// shared memory bank conflicts.
82// Example (3,2,1) block assigned to work on (2,2,1) items:
83// 0 (0,0), 1 (1,0), 2 (N/A)
84// 3 (1,0), 4 (1,1), 5 (N/A)
85#define MFEM_FOREACH_THREAD_DIRECT_3D_OFFSET(ix, iy, iz, k, SX, SY, SZ, OX, \
86 OY, OZ) \
87 MFEM_FOREACH_THREAD_DIRECT_3D(ix, iy, iz, k, SX, SY, SZ)
88#endif
89
90// 'double' and 'float' atomicAdd implementation for previous versions of CUDA
91#if defined(MFEM_USE_CUDA) && defined(__CUDA_ARCH__) && (__CUDA_ARCH__ < 600)
92MFEM_DEVICE inline mfem::real_t atomicAdd(mfem::real_t *add, mfem::real_t val)
93{
94 unsigned long long int *ptr = (unsigned long long int *) add;
95 unsigned long long int old = *ptr, reg;
96 do
97 {
98 reg = old;
99 old = atomicCAS(ptr, reg,
100#ifdef MFEM_USE_SINGLE
101 __float_as_int(val + __int_as_float(reg)));
102#else
103 __double_as_longlong(val + __longlong_as_double(reg)));
104#endif
105 }
106 while (reg != old);
107#ifdef MFEM_USE_SINGLE
108 return __int_as_float(old);
109#else
110 return __longlong_as_double(old);
111#endif
112}
113#endif
114
115template <typename T>
116MFEM_HOST_DEVICE T AtomicAdd(T &add, const T val)
117{
118#if ((defined(MFEM_USE_CUDA) && defined(__CUDA_ARCH__)) || \
119 (defined(MFEM_USE_HIP) && defined(__HIP_DEVICE_COMPILE__)))
120 return atomicAdd(&add,val);
121#else
122 T old = add;
123#ifdef MFEM_USE_OPENMP
124 #pragma omp atomic
125#endif
126 add += val;
127 return old;
128#endif
129}
130
131namespace mfem::internal
132{
133
134#if defined(MFEM_USE_CUDA_OR_HIP) && !defined(MFEM_USE_CUDA_OR_HIP_LANG)
135static constexpr bool can_compile_kernels = false;
136#else
137static constexpr bool can_compile_kernels = true;
138#endif
139
140template <bool can_compile_kernels = can_compile_kernels>
141void RequireKernelCompilation()
142{
143 static_assert(
144 can_compile_kernels,
145 "The calling function needs to be compiled with CUDA/HIP language!");
146}
147
148}
149
150#endif // MFEM_BACKENDS_HPP
MFEM_HOST_DEVICE T AtomicAdd(T &add, const T val)
Definition backends.hpp:116
MFEM_DEVICE mfem::real_t atomicAdd(mfem::real_t *add, mfem::real_t val)
Definition backends.hpp:92
float real_t
Definition config.hpp:46