xref: /petsc/include/petscdevice_cuda.h (revision 0e6b6b5985dd9b1172860d21fb88bd3966bf7c54)
1*0e6b6b59SJacob Faibussowitsch #ifndef PETSCDEVICE_CUDA_H
2*0e6b6b59SJacob Faibussowitsch #define PETSCDEVICE_CUDA_H
3*0e6b6b59SJacob Faibussowitsch 
4*0e6b6b59SJacob Faibussowitsch #include <petscdevice.h>
5*0e6b6b59SJacob Faibussowitsch #include <petscpkg_version.h>
6*0e6b6b59SJacob Faibussowitsch 
7*0e6b6b59SJacob Faibussowitsch #if defined(__NVCC__) || defined(__CUDACC__)
8*0e6b6b59SJacob Faibussowitsch #define PETSC_USING_NVCC 1
9*0e6b6b59SJacob Faibussowitsch #endif
10*0e6b6b59SJacob Faibussowitsch 
11*0e6b6b59SJacob Faibussowitsch #if PetscDefined(HAVE_CUDA)
12*0e6b6b59SJacob Faibussowitsch #include <cuda.h>
13*0e6b6b59SJacob Faibussowitsch #include <cuda_runtime.h>
14*0e6b6b59SJacob Faibussowitsch #include <cublas_v2.h>
15*0e6b6b59SJacob Faibussowitsch #include <cusolverDn.h>
16*0e6b6b59SJacob Faibussowitsch #include <cusolverSp.h>
17*0e6b6b59SJacob Faibussowitsch #include <cufft.h>
18*0e6b6b59SJacob Faibussowitsch 
19*0e6b6b59SJacob Faibussowitsch /* cuBLAS does not have cublasGetErrorName(). We create one on our own. */
20*0e6b6b59SJacob Faibussowitsch PETSC_EXTERN const char *PetscCUBLASGetErrorName(cublasStatus_t); /* PETSC_EXTERN since it is exposed by the CHKERRCUBLAS macro */
21*0e6b6b59SJacob Faibussowitsch PETSC_EXTERN const char *PetscCUSolverGetErrorName(cusolverStatus_t);
22*0e6b6b59SJacob Faibussowitsch PETSC_EXTERN const char *PetscCUFFTGetErrorName(cufftResult);
23*0e6b6b59SJacob Faibussowitsch 
24*0e6b6b59SJacob Faibussowitsch /* REMOVE ME */
25*0e6b6b59SJacob Faibussowitsch #define WaitForCUDA() cudaDeviceSynchronize()
26*0e6b6b59SJacob Faibussowitsch 
27*0e6b6b59SJacob Faibussowitsch /* CUDART_VERSION = 1000 x major + 10 x minor version */
28*0e6b6b59SJacob Faibussowitsch 
29*0e6b6b59SJacob Faibussowitsch /* Could not find exactly which CUDART_VERSION introduced cudaGetErrorName. At least it was in CUDA 8.0 (Sep. 2016) */
30*0e6b6b59SJacob Faibussowitsch #if PETSC_PKG_CUDA_VERSION_GE(8, 0, 0)
31*0e6b6b59SJacob Faibussowitsch #define PetscCallCUDAVoid(...) \
32*0e6b6b59SJacob Faibussowitsch   do { \
33*0e6b6b59SJacob Faibussowitsch     const cudaError_t _p_cuda_err__ = __VA_ARGS__; \
34*0e6b6b59SJacob Faibussowitsch     PetscCheckAbort(_p_cuda_err__ == cudaSuccess, PETSC_COMM_SELF, PETSC_ERR_GPU, "cuda error %d (%s) : %s", (PetscErrorCode)_p_cuda_err__, cudaGetErrorName(_p_cuda_err__), cudaGetErrorString(_p_cuda_err__)); \
35*0e6b6b59SJacob Faibussowitsch   } while (0)
36*0e6b6b59SJacob Faibussowitsch 
37*0e6b6b59SJacob Faibussowitsch #define PetscCallCUDA(...) \
38*0e6b6b59SJacob Faibussowitsch   do { \
39*0e6b6b59SJacob Faibussowitsch     const cudaError_t _p_cuda_err__ = __VA_ARGS__; \
40*0e6b6b59SJacob Faibussowitsch     PetscCheck(_p_cuda_err__ == cudaSuccess, PETSC_COMM_SELF, PETSC_ERR_GPU, "cuda error %d (%s) : %s", (PetscErrorCode)_p_cuda_err__, cudaGetErrorName(_p_cuda_err__), cudaGetErrorString(_p_cuda_err__)); \
41*0e6b6b59SJacob Faibussowitsch   } while (0)
42*0e6b6b59SJacob Faibussowitsch #else /* PETSC_PKG_CUDA_VERSION_GE(8,0,0) */
43*0e6b6b59SJacob Faibussowitsch #define PetscCallCUDA(...) \
44*0e6b6b59SJacob Faibussowitsch   do { \
45*0e6b6b59SJacob Faibussowitsch     const cudaError_t _p_cuda_err__ = __VA_ARGS__; \
46*0e6b6b59SJacob Faibussowitsch     PetscCheck(_p_cuda_err__ == cudaSuccess, PETSC_COMM_SELF, PETSC_ERR_GPU, "cuda error %d", (PetscErrorCode)_p_cuda_err__); \
47*0e6b6b59SJacob Faibussowitsch   } while (0)
48*0e6b6b59SJacob Faibussowitsch 
49*0e6b6b59SJacob Faibussowitsch #define PetscCallCUDAVoid(...) \
50*0e6b6b59SJacob Faibussowitsch   do { \
51*0e6b6b59SJacob Faibussowitsch     const cudaError_t _p_cuda_err__ = __VA_ARGS__; \
52*0e6b6b59SJacob Faibussowitsch     PetscCheckAbort(_p_cuda_err__ == cudaSuccess, PETSC_COMM_SELF, PETSC_ERR_GPU, "cuda error %d", (PetscErrorCode)_p_cuda_err__); \
53*0e6b6b59SJacob Faibussowitsch   } while (0)
54*0e6b6b59SJacob Faibussowitsch #endif /* PETSC_PKG_CUDA_VERSION_GE(8,0,0) */
55*0e6b6b59SJacob Faibussowitsch #define CHKERRCUDA(...) PetscCallCUDA(__VA_ARGS__)
56*0e6b6b59SJacob Faibussowitsch 
57*0e6b6b59SJacob Faibussowitsch #define PetscCUDACheckLaunch \
58*0e6b6b59SJacob Faibussowitsch   do { \
59*0e6b6b59SJacob Faibussowitsch     /* Check synchronous errors, i.e. pre-launch */ \
60*0e6b6b59SJacob Faibussowitsch     PetscCallCUDA(cudaGetLastError()); \
61*0e6b6b59SJacob Faibussowitsch     /* Check asynchronous errors, i.e. kernel failed (ULF) */ \
62*0e6b6b59SJacob Faibussowitsch     PetscCallCUDA(cudaDeviceSynchronize()); \
63*0e6b6b59SJacob Faibussowitsch   } while (0)
64*0e6b6b59SJacob Faibussowitsch 
65*0e6b6b59SJacob Faibussowitsch #define PetscCallCUBLAS(...) \
66*0e6b6b59SJacob Faibussowitsch   do { \
67*0e6b6b59SJacob Faibussowitsch     const cublasStatus_t _p_cublas_stat__ = __VA_ARGS__; \
68*0e6b6b59SJacob Faibussowitsch     if (PetscUnlikely(_p_cublas_stat__ != CUBLAS_STATUS_SUCCESS)) { \
69*0e6b6b59SJacob Faibussowitsch       const char *name = PetscCUBLASGetErrorName(_p_cublas_stat__); \
70*0e6b6b59SJacob Faibussowitsch       if (((_p_cublas_stat__ == CUBLAS_STATUS_NOT_INITIALIZED) || (_p_cublas_stat__ == CUBLAS_STATUS_ALLOC_FAILED)) && PetscDeviceInitialized(PETSC_DEVICE_CUDA)) { \
71*0e6b6b59SJacob Faibussowitsch         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_GPU_RESOURCE, \
72*0e6b6b59SJacob Faibussowitsch                 "cuBLAS error %d (%s). " \
73*0e6b6b59SJacob Faibussowitsch                 "Reports not initialized or alloc failed; " \
74*0e6b6b59SJacob Faibussowitsch                 "this indicates the GPU may have run out resources", \
75*0e6b6b59SJacob Faibussowitsch                 (PetscErrorCode)_p_cublas_stat__, name); \
76*0e6b6b59SJacob Faibussowitsch       } else { \
77*0e6b6b59SJacob Faibussowitsch         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_GPU, "cuBLAS error %d (%s)", (PetscErrorCode)_p_cublas_stat__, name); \
78*0e6b6b59SJacob Faibussowitsch       } \
79*0e6b6b59SJacob Faibussowitsch     } \
80*0e6b6b59SJacob Faibussowitsch   } while (0)
81*0e6b6b59SJacob Faibussowitsch #define CHKERRCUBLAS(...) PetscCallCUBLAS(__VA_ARGS__)
82*0e6b6b59SJacob Faibussowitsch 
83*0e6b6b59SJacob Faibussowitsch #if (CUSPARSE_VER_MAJOR > 10 || CUSPARSE_VER_MAJOR == 10 && CUSPARSE_VER_MINOR >= 2) /* According to cuda/10.1.168 on OLCF Summit */
84*0e6b6b59SJacob Faibussowitsch #define PetscCallCUSPARSE(...) \
85*0e6b6b59SJacob Faibussowitsch   do { \
86*0e6b6b59SJacob Faibussowitsch     const cusparseStatus_t _p_cusparse_stat__ = __VA_ARGS__; \
87*0e6b6b59SJacob Faibussowitsch     if (PetscUnlikely(_p_cusparse_stat__)) { \
88*0e6b6b59SJacob Faibussowitsch       const char *name  = cusparseGetErrorName(_p_cusparse_stat__); \
89*0e6b6b59SJacob Faibussowitsch       const char *descr = cusparseGetErrorString(_p_cusparse_stat__); \
90*0e6b6b59SJacob Faibussowitsch       PetscCheck((_p_cusparse_stat__ != CUSPARSE_STATUS_NOT_INITIALIZED) && (_p_cusparse_stat__ != CUSPARSE_STATUS_ALLOC_FAILED), PETSC_COMM_SELF, PETSC_ERR_GPU_RESOURCE, \
91*0e6b6b59SJacob Faibussowitsch                  "cuSPARSE errorcode %d (%s) : %s.; " \
92*0e6b6b59SJacob Faibussowitsch                  "this indicates the GPU has run out resources", \
93*0e6b6b59SJacob Faibussowitsch                  (int)_p_cusparse_stat__, name, descr); \
94*0e6b6b59SJacob Faibussowitsch       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_GPU, "cuSPARSE errorcode %d (%s) : %s", (int)_p_cusparse_stat__, name, descr); \
95*0e6b6b59SJacob Faibussowitsch     } \
96*0e6b6b59SJacob Faibussowitsch   } while (0)
97*0e6b6b59SJacob Faibussowitsch #else /* (CUSPARSE_VER_MAJOR > 10 || CUSPARSE_VER_MAJOR == 10 && CUSPARSE_VER_MINOR >= 2) */
98*0e6b6b59SJacob Faibussowitsch #define PetscCallCUSPARSE(...) \
99*0e6b6b59SJacob Faibussowitsch   do { \
100*0e6b6b59SJacob Faibussowitsch     const cusparseStatus_t _p_cusparse_stat__ = __VA_ARGS__; \
101*0e6b6b59SJacob Faibussowitsch     PetscCheck(_p_cusparse_stat__ == CUSPARSE_STATUS_SUCCESS, PETSC_COMM_SELF, PETSC_ERR_GPU, "cuSPARSE errorcode %d", (PetscErrorCode)_p_cusparse_stat__); \
102*0e6b6b59SJacob Faibussowitsch   } while (0)
103*0e6b6b59SJacob Faibussowitsch #endif /* (CUSPARSE_VER_MAJOR > 10 || CUSPARSE_VER_MAJOR == 10 && CUSPARSE_VER_MINOR >= 2) */
104*0e6b6b59SJacob Faibussowitsch #define CHKERRCUSPARSE(...) PetscCallCUSPARSE(__VA_ARGS__)
105*0e6b6b59SJacob Faibussowitsch 
106*0e6b6b59SJacob Faibussowitsch #define PetscCallCUSOLVER(...) \
107*0e6b6b59SJacob Faibussowitsch   do { \
108*0e6b6b59SJacob Faibussowitsch     const cusolverStatus_t _p_cusolver_stat__ = __VA_ARGS__; \
109*0e6b6b59SJacob Faibussowitsch     if (PetscUnlikely(_p_cusolver_stat__ != CUSOLVER_STATUS_SUCCESS)) { \
110*0e6b6b59SJacob Faibussowitsch       const char *name = PetscCUSolverGetErrorName(_p_cusolver_stat__); \
111*0e6b6b59SJacob Faibussowitsch       if (((_p_cusolver_stat__ == CUSOLVER_STATUS_NOT_INITIALIZED) || (_p_cusolver_stat__ == CUSOLVER_STATUS_ALLOC_FAILED) || (_p_cusolver_stat__ == CUSOLVER_STATUS_INTERNAL_ERROR)) && PetscDeviceInitialized(PETSC_DEVICE_CUDA)) { \
112*0e6b6b59SJacob Faibussowitsch         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_GPU_RESOURCE, \
113*0e6b6b59SJacob Faibussowitsch                 "cuSolver error %d (%s). " \
114*0e6b6b59SJacob Faibussowitsch                 "This indicates the GPU may have run out resources", \
115*0e6b6b59SJacob Faibussowitsch                 (PetscErrorCode)_p_cusolver_stat__, name); \
116*0e6b6b59SJacob Faibussowitsch       } else { \
117*0e6b6b59SJacob Faibussowitsch         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_GPU, "cuSolver error %d (%s)", (PetscErrorCode)_p_cusolver_stat__, name); \
118*0e6b6b59SJacob Faibussowitsch       } \
119*0e6b6b59SJacob Faibussowitsch     } \
120*0e6b6b59SJacob Faibussowitsch   } while (0)
121*0e6b6b59SJacob Faibussowitsch #define CHKERRCUSOLVER(...) PetscCallCUSOLVER(__VA_ARGS__)
122*0e6b6b59SJacob Faibussowitsch 
123*0e6b6b59SJacob Faibussowitsch #define PetscCallCUFFT(...) \
124*0e6b6b59SJacob Faibussowitsch   do { \
125*0e6b6b59SJacob Faibussowitsch     const cufftResult_t _p_cufft_stat__ = __VA_ARGS__; \
126*0e6b6b59SJacob Faibussowitsch     if (PetscUnlikely(_p_cufft_stat__ != CUFFT_SUCCESS)) { \
127*0e6b6b59SJacob Faibussowitsch       const char *name = PetscCUFFTGetErrorName(_p_cufft_stat__); \
128*0e6b6b59SJacob Faibussowitsch       if (((_p_cufft_stat__ == CUFFT_SETUP_FAILED) || (_p_cufft_stat__ == CUFFT_ALLOC_FAILED)) && PetscDeviceInitialized(PETSC_DEVICE_CUDA)) { \
129*0e6b6b59SJacob Faibussowitsch         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_GPU_RESOURCE, \
130*0e6b6b59SJacob Faibussowitsch                 "cuFFT error %d (%s). " \
131*0e6b6b59SJacob Faibussowitsch                 "Reports not initialized or alloc failed; " \
132*0e6b6b59SJacob Faibussowitsch                 "this indicates the GPU has run out resources", \
133*0e6b6b59SJacob Faibussowitsch                 (PetscErrorCode)_p_cufft_stat__, name); \
134*0e6b6b59SJacob Faibussowitsch       } else { \
135*0e6b6b59SJacob Faibussowitsch         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_GPU, "cuFFT error %d (%s)", (PetscErrorCode)_p_cufft_stat__, name); \
136*0e6b6b59SJacob Faibussowitsch       } \
137*0e6b6b59SJacob Faibussowitsch     } \
138*0e6b6b59SJacob Faibussowitsch   } while (0)
139*0e6b6b59SJacob Faibussowitsch #define CHKERRCUFFT(...) PetscCallCUFFT(__VA_ARGS__)
140*0e6b6b59SJacob Faibussowitsch 
141*0e6b6b59SJacob Faibussowitsch #define PetscCallCURAND(...) \
142*0e6b6b59SJacob Faibussowitsch   do { \
143*0e6b6b59SJacob Faibussowitsch     const curandStatus_t _p_curand_stat__ = __VA_ARGS__; \
144*0e6b6b59SJacob Faibussowitsch     if (PetscUnlikely(_p_curand_stat__ != CURAND_STATUS_SUCCESS)) { \
145*0e6b6b59SJacob Faibussowitsch       if (((_p_curand_stat__ == CURAND_STATUS_INITIALIZATION_FAILED) || (_p_curand_stat__ == CURAND_STATUS_ALLOCATION_FAILED)) && PetscDeviceInitialized(PETSC_DEVICE_CUDA)) { \
146*0e6b6b59SJacob Faibussowitsch         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_GPU_RESOURCE, \
147*0e6b6b59SJacob Faibussowitsch                 "cuRAND error %d. " \
148*0e6b6b59SJacob Faibussowitsch                 "Reports not initialized or alloc failed; " \
149*0e6b6b59SJacob Faibussowitsch                 "this indicates the GPU has run out resources", \
150*0e6b6b59SJacob Faibussowitsch                 (PetscErrorCode)_p_curand_stat__); \
151*0e6b6b59SJacob Faibussowitsch       } else { \
152*0e6b6b59SJacob Faibussowitsch         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_GPU, "cuRand error %d", (PetscErrorCode)_p_curand_stat__); \
153*0e6b6b59SJacob Faibussowitsch       } \
154*0e6b6b59SJacob Faibussowitsch     } \
155*0e6b6b59SJacob Faibussowitsch   } while (0)
156*0e6b6b59SJacob Faibussowitsch #define CHKERRCURAND(...) PetscCallCURAND(__VA_ARGS__)
157*0e6b6b59SJacob Faibussowitsch 
158*0e6b6b59SJacob Faibussowitsch PETSC_EXTERN cudaStream_t   PetscDefaultCudaStream; // The default stream used by PETSc
159*0e6b6b59SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode PetscCUBLASGetHandle(cublasHandle_t *);
160*0e6b6b59SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode PetscCUSOLVERDnGetHandle(cusolverDnHandle_t *);
161*0e6b6b59SJacob Faibussowitsch 
162*0e6b6b59SJacob Faibussowitsch #endif // PETSC_HAVE_CUDA
163*0e6b6b59SJacob Faibussowitsch 
164*0e6b6b59SJacob Faibussowitsch // these can also be defined in petscdevice_hip.h
165*0e6b6b59SJacob Faibussowitsch #ifndef PETSC_DEVICE_DEFINED_DECLS_PRIVATE
166*0e6b6b59SJacob Faibussowitsch #define PETSC_DEVICE_DEFINED_DECLS_PRIVATE
167*0e6b6b59SJacob Faibussowitsch #if PetscDefined(USING_NVCC)
168*0e6b6b59SJacob Faibussowitsch #define PETSC_HOST_DECL      __host__
169*0e6b6b59SJacob Faibussowitsch #define PETSC_DEVICE_DECL    __device__
170*0e6b6b59SJacob Faibussowitsch #define PETSC_KERNEL_DECL    __global__
171*0e6b6b59SJacob Faibussowitsch #define PETSC_SHAREDMEM_DECL __shared__
172*0e6b6b59SJacob Faibussowitsch #define PETSC_FORCEINLINE    __forceinline__
173*0e6b6b59SJacob Faibussowitsch #define PETSC_CONSTMEM_DECL  __constant__
174*0e6b6b59SJacob Faibussowitsch #else
175*0e6b6b59SJacob Faibussowitsch #define PETSC_HOST_DECL
176*0e6b6b59SJacob Faibussowitsch #define PETSC_DEVICE_DECL
177*0e6b6b59SJacob Faibussowitsch #define PETSC_KERNEL_DECL
178*0e6b6b59SJacob Faibussowitsch #define PETSC_SHAREDMEM_DECL
179*0e6b6b59SJacob Faibussowitsch #define PETSC_FORCEINLINE inline
180*0e6b6b59SJacob Faibussowitsch #define PETSC_CONSTMEM_DECL
181*0e6b6b59SJacob Faibussowitsch #endif // PETSC_USING_NVCC
182*0e6b6b59SJacob Faibussowitsch 
183*0e6b6b59SJacob Faibussowitsch #define PETSC_HOSTDEVICE_DECL        PETSC_HOST_DECL PETSC_DEVICE_DECL
184*0e6b6b59SJacob Faibussowitsch #define PETSC_DEVICE_INLINE_DECL     PETSC_DEVICE_DECL PETSC_FORCEINLINE
185*0e6b6b59SJacob Faibussowitsch #define PETSC_HOSTDEVICE_INLINE_DECL PETSC_HOSTDEVICE_DECL PETSC_FORCEINLINE
186*0e6b6b59SJacob Faibussowitsch #endif // PETSC_DEVICE_DEFINED_DECLS_PRIVATE
187*0e6b6b59SJacob Faibussowitsch 
188*0e6b6b59SJacob Faibussowitsch #endif // PETSCDEVICE_CUDA_H
189