xref: /petsc/include/petscdevice_cuda.h (revision 9d47de495d3c23378050c1b4a410c12a375cb6c6)
1a4963045SJacob Faibussowitsch #pragma once
20e6b6b59SJacob Faibussowitsch 
30e6b6b59SJacob Faibussowitsch #include <petscdevice.h>
40e6b6b59SJacob Faibussowitsch #include <petscpkg_version.h>
50e6b6b59SJacob Faibussowitsch 
61850900dSBarry Smith /* MANSEC = Sys */
71850900dSBarry Smith 
80e6b6b59SJacob Faibussowitsch #if defined(__NVCC__) || defined(__CUDACC__)
90e6b6b59SJacob Faibussowitsch   #define PETSC_USING_NVCC 1
100e6b6b59SJacob Faibussowitsch #endif
110e6b6b59SJacob Faibussowitsch 
120e6b6b59SJacob Faibussowitsch #if PetscDefined(HAVE_CUDA)
130e6b6b59SJacob Faibussowitsch   #include <cuda.h>
140e6b6b59SJacob Faibussowitsch   #include <cuda_runtime.h>
150e6b6b59SJacob Faibussowitsch   #include <cublas_v2.h>
162695cf96SNuno Nobre   #define DISABLE_CUSPARSE_DEPRECATED
172695cf96SNuno Nobre   #include <cusparse.h>
180e6b6b59SJacob Faibussowitsch   #include <cusolverDn.h>
190e6b6b59SJacob Faibussowitsch   #include <cusolverSp.h>
200e6b6b59SJacob Faibussowitsch   #include <cufft.h>
212695cf96SNuno Nobre   #include <curand.h>
225268dc8aSHong Zhang   #include <nvml.h> // NVML comes with the NVIDIA GPU driver
230e6b6b59SJacob Faibussowitsch 
240e6b6b59SJacob Faibussowitsch /* cuBLAS does not have cublasGetErrorName(). We create one on our own. */
250e6b6b59SJacob Faibussowitsch PETSC_EXTERN const char *PetscCUBLASGetErrorName(cublasStatus_t); /* PETSC_EXTERN since it is exposed by the CHKERRCUBLAS macro */
260e6b6b59SJacob Faibussowitsch PETSC_EXTERN const char *PetscCUSolverGetErrorName(cusolverStatus_t);
270e6b6b59SJacob Faibussowitsch PETSC_EXTERN const char *PetscCUFFTGetErrorName(cufftResult);
280e6b6b59SJacob Faibussowitsch 
290e6b6b59SJacob Faibussowitsch   /* REMOVE ME */
300e6b6b59SJacob Faibussowitsch   #define WaitForCUDA() cudaDeviceSynchronize()
310e6b6b59SJacob Faibussowitsch 
320e6b6b59SJacob Faibussowitsch   /* CUDART_VERSION = 1000 x major + 10 x minor version */
330e6b6b59SJacob Faibussowitsch 
340e6b6b59SJacob Faibussowitsch   /* Could not find exactly which CUDART_VERSION introduced cudaGetErrorName. At least it was in CUDA 8.0 (Sep. 2016) */
350e6b6b59SJacob Faibussowitsch   #if PETSC_PKG_CUDA_VERSION_GE(8, 0, 0)
360e6b6b59SJacob Faibussowitsch     #define PetscCallCUDAVoid(...) \
370e6b6b59SJacob Faibussowitsch       do { \
380e6b6b59SJacob Faibussowitsch         const cudaError_t _p_cuda_err__ = __VA_ARGS__; \
390e6b6b59SJacob 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__)); \
400e6b6b59SJacob Faibussowitsch       } while (0)
410e6b6b59SJacob Faibussowitsch 
420e6b6b59SJacob Faibussowitsch     #define PetscCallCUDA(...) \
430e6b6b59SJacob Faibussowitsch       do { \
440e6b6b59SJacob Faibussowitsch         const cudaError_t _p_cuda_err__ = __VA_ARGS__; \
450e6b6b59SJacob 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__)); \
460e6b6b59SJacob Faibussowitsch       } while (0)
470e6b6b59SJacob Faibussowitsch   #else /* PETSC_PKG_CUDA_VERSION_GE(8,0,0) */
480e6b6b59SJacob Faibussowitsch     #define PetscCallCUDA(...) \
490e6b6b59SJacob Faibussowitsch       do { \
500e6b6b59SJacob Faibussowitsch         const cudaError_t _p_cuda_err__ = __VA_ARGS__; \
510e6b6b59SJacob Faibussowitsch         PetscCheck(_p_cuda_err__ == cudaSuccess, PETSC_COMM_SELF, PETSC_ERR_GPU, "cuda error %d", (PetscErrorCode)_p_cuda_err__); \
520e6b6b59SJacob Faibussowitsch       } while (0)
530e6b6b59SJacob Faibussowitsch 
540e6b6b59SJacob Faibussowitsch     #define PetscCallCUDAVoid(...) \
550e6b6b59SJacob Faibussowitsch       do { \
560e6b6b59SJacob Faibussowitsch         const cudaError_t _p_cuda_err__ = __VA_ARGS__; \
570e6b6b59SJacob Faibussowitsch         PetscCheckAbort(_p_cuda_err__ == cudaSuccess, PETSC_COMM_SELF, PETSC_ERR_GPU, "cuda error %d", (PetscErrorCode)_p_cuda_err__); \
580e6b6b59SJacob Faibussowitsch       } while (0)
590e6b6b59SJacob Faibussowitsch   #endif /* PETSC_PKG_CUDA_VERSION_GE(8,0,0) */
600e6b6b59SJacob Faibussowitsch   #define CHKERRCUDA(...) PetscCallCUDA(__VA_ARGS__)
610e6b6b59SJacob Faibussowitsch 
620e6b6b59SJacob Faibussowitsch   #define PetscCUDACheckLaunch \
630e6b6b59SJacob Faibussowitsch     do { \
640e6b6b59SJacob Faibussowitsch       /* Check synchronous errors, i.e. pre-launch */ \
650e6b6b59SJacob Faibussowitsch       PetscCallCUDA(cudaGetLastError()); \
660e6b6b59SJacob Faibussowitsch       /* Check asynchronous errors, i.e. kernel failed (ULF) */ \
670e6b6b59SJacob Faibussowitsch       PetscCallCUDA(cudaDeviceSynchronize()); \
680e6b6b59SJacob Faibussowitsch     } while (0)
690e6b6b59SJacob Faibussowitsch 
700e6b6b59SJacob Faibussowitsch   #define PetscCallCUBLAS(...) \
710e6b6b59SJacob Faibussowitsch     do { \
720e6b6b59SJacob Faibussowitsch       const cublasStatus_t _p_cublas_stat__ = __VA_ARGS__; \
730e6b6b59SJacob Faibussowitsch       if (PetscUnlikely(_p_cublas_stat__ != CUBLAS_STATUS_SUCCESS)) { \
740e6b6b59SJacob Faibussowitsch         const char *name = PetscCUBLASGetErrorName(_p_cublas_stat__); \
750e6b6b59SJacob Faibussowitsch         if (((_p_cublas_stat__ == CUBLAS_STATUS_NOT_INITIALIZED) || (_p_cublas_stat__ == CUBLAS_STATUS_ALLOC_FAILED)) && PetscDeviceInitialized(PETSC_DEVICE_CUDA)) { \
760e6b6b59SJacob Faibussowitsch           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_GPU_RESOURCE, \
770e6b6b59SJacob Faibussowitsch                   "cuBLAS error %d (%s). " \
780e6b6b59SJacob Faibussowitsch                   "Reports not initialized or alloc failed; " \
790e6b6b59SJacob Faibussowitsch                   "this indicates the GPU may have run out resources", \
800e6b6b59SJacob Faibussowitsch                   (PetscErrorCode)_p_cublas_stat__, name); \
810e6b6b59SJacob Faibussowitsch         } else { \
820e6b6b59SJacob Faibussowitsch           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_GPU, "cuBLAS error %d (%s)", (PetscErrorCode)_p_cublas_stat__, name); \
830e6b6b59SJacob Faibussowitsch         } \
840e6b6b59SJacob Faibussowitsch       } \
850e6b6b59SJacob Faibussowitsch     } while (0)
860e6b6b59SJacob Faibussowitsch   #define CHKERRCUBLAS(...) PetscCallCUBLAS(__VA_ARGS__)
870e6b6b59SJacob Faibussowitsch 
880e6b6b59SJacob Faibussowitsch   #if (CUSPARSE_VER_MAJOR > 10 || CUSPARSE_VER_MAJOR == 10 && CUSPARSE_VER_MINOR >= 2) /* According to cuda/10.1.168 on OLCF Summit */
890e6b6b59SJacob Faibussowitsch     #define PetscCallCUSPARSE(...) \
900e6b6b59SJacob Faibussowitsch       do { \
910e6b6b59SJacob Faibussowitsch         const cusparseStatus_t _p_cusparse_stat__ = __VA_ARGS__; \
920e6b6b59SJacob Faibussowitsch         if (PetscUnlikely(_p_cusparse_stat__)) { \
930e6b6b59SJacob Faibussowitsch           const char *name  = cusparseGetErrorName(_p_cusparse_stat__); \
940e6b6b59SJacob Faibussowitsch           const char *descr = cusparseGetErrorString(_p_cusparse_stat__); \
950e6b6b59SJacob Faibussowitsch           PetscCheck((_p_cusparse_stat__ != CUSPARSE_STATUS_NOT_INITIALIZED) && (_p_cusparse_stat__ != CUSPARSE_STATUS_ALLOC_FAILED), PETSC_COMM_SELF, PETSC_ERR_GPU_RESOURCE, \
960e6b6b59SJacob Faibussowitsch                      "cuSPARSE errorcode %d (%s) : %s.; " \
970e6b6b59SJacob Faibussowitsch                      "this indicates the GPU has run out resources", \
980e6b6b59SJacob Faibussowitsch                      (int)_p_cusparse_stat__, name, descr); \
990e6b6b59SJacob Faibussowitsch           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_GPU, "cuSPARSE errorcode %d (%s) : %s", (int)_p_cusparse_stat__, name, descr); \
1000e6b6b59SJacob Faibussowitsch         } \
1010e6b6b59SJacob Faibussowitsch       } while (0)
1020e6b6b59SJacob Faibussowitsch   #else /* (CUSPARSE_VER_MAJOR > 10 || CUSPARSE_VER_MAJOR == 10 && CUSPARSE_VER_MINOR >= 2) */
1030e6b6b59SJacob Faibussowitsch     #define PetscCallCUSPARSE(...) \
1040e6b6b59SJacob Faibussowitsch       do { \
1050e6b6b59SJacob Faibussowitsch         const cusparseStatus_t _p_cusparse_stat__ = __VA_ARGS__; \
1060e6b6b59SJacob Faibussowitsch         PetscCheck(_p_cusparse_stat__ == CUSPARSE_STATUS_SUCCESS, PETSC_COMM_SELF, PETSC_ERR_GPU, "cuSPARSE errorcode %d", (PetscErrorCode)_p_cusparse_stat__); \
1070e6b6b59SJacob Faibussowitsch       } while (0)
1080e6b6b59SJacob Faibussowitsch   #endif /* (CUSPARSE_VER_MAJOR > 10 || CUSPARSE_VER_MAJOR == 10 && CUSPARSE_VER_MINOR >= 2) */
1090e6b6b59SJacob Faibussowitsch   #define CHKERRCUSPARSE(...) PetscCallCUSPARSE(__VA_ARGS__)
1100e6b6b59SJacob Faibussowitsch 
1110e6b6b59SJacob Faibussowitsch   #define PetscCallCUSOLVER(...) \
1120e6b6b59SJacob Faibussowitsch     do { \
1130e6b6b59SJacob Faibussowitsch       const cusolverStatus_t _p_cusolver_stat__ = __VA_ARGS__; \
1140e6b6b59SJacob Faibussowitsch       if (PetscUnlikely(_p_cusolver_stat__ != CUSOLVER_STATUS_SUCCESS)) { \
1150e6b6b59SJacob Faibussowitsch         const char *name = PetscCUSolverGetErrorName(_p_cusolver_stat__); \
1160e6b6b59SJacob 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)) { \
1170e6b6b59SJacob Faibussowitsch           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_GPU_RESOURCE, \
1180e6b6b59SJacob Faibussowitsch                   "cuSolver error %d (%s). " \
1190e6b6b59SJacob Faibussowitsch                   "This indicates the GPU may have run out resources", \
1200e6b6b59SJacob Faibussowitsch                   (PetscErrorCode)_p_cusolver_stat__, name); \
1210e6b6b59SJacob Faibussowitsch         } else { \
1220e6b6b59SJacob Faibussowitsch           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_GPU, "cuSolver error %d (%s)", (PetscErrorCode)_p_cusolver_stat__, name); \
1230e6b6b59SJacob Faibussowitsch         } \
1240e6b6b59SJacob Faibussowitsch       } \
1250e6b6b59SJacob Faibussowitsch     } while (0)
1260e6b6b59SJacob Faibussowitsch   #define CHKERRCUSOLVER(...) PetscCallCUSOLVER(__VA_ARGS__)
1270e6b6b59SJacob Faibussowitsch 
1280e6b6b59SJacob Faibussowitsch   #define PetscCallCUFFT(...) \
1290e6b6b59SJacob Faibussowitsch     do { \
1300e6b6b59SJacob Faibussowitsch       const cufftResult_t _p_cufft_stat__ = __VA_ARGS__; \
1310e6b6b59SJacob Faibussowitsch       if (PetscUnlikely(_p_cufft_stat__ != CUFFT_SUCCESS)) { \
1320e6b6b59SJacob Faibussowitsch         const char *name = PetscCUFFTGetErrorName(_p_cufft_stat__); \
1330e6b6b59SJacob Faibussowitsch         if (((_p_cufft_stat__ == CUFFT_SETUP_FAILED) || (_p_cufft_stat__ == CUFFT_ALLOC_FAILED)) && PetscDeviceInitialized(PETSC_DEVICE_CUDA)) { \
1340e6b6b59SJacob Faibussowitsch           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_GPU_RESOURCE, \
1350e6b6b59SJacob Faibussowitsch                   "cuFFT error %d (%s). " \
1360e6b6b59SJacob Faibussowitsch                   "Reports not initialized or alloc failed; " \
1370e6b6b59SJacob Faibussowitsch                   "this indicates the GPU has run out resources", \
1380e6b6b59SJacob Faibussowitsch                   (PetscErrorCode)_p_cufft_stat__, name); \
1390e6b6b59SJacob Faibussowitsch         } else { \
1400e6b6b59SJacob Faibussowitsch           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_GPU, "cuFFT error %d (%s)", (PetscErrorCode)_p_cufft_stat__, name); \
1410e6b6b59SJacob Faibussowitsch         } \
1420e6b6b59SJacob Faibussowitsch       } \
1430e6b6b59SJacob Faibussowitsch     } while (0)
1440e6b6b59SJacob Faibussowitsch   #define CHKERRCUFFT(...) PetscCallCUFFT(__VA_ARGS__)
1450e6b6b59SJacob Faibussowitsch 
1460e6b6b59SJacob Faibussowitsch   #define PetscCallCURAND(...) \
1470e6b6b59SJacob Faibussowitsch     do { \
1480e6b6b59SJacob Faibussowitsch       const curandStatus_t _p_curand_stat__ = __VA_ARGS__; \
1490e6b6b59SJacob Faibussowitsch       if (PetscUnlikely(_p_curand_stat__ != CURAND_STATUS_SUCCESS)) { \
1500e6b6b59SJacob Faibussowitsch         if (((_p_curand_stat__ == CURAND_STATUS_INITIALIZATION_FAILED) || (_p_curand_stat__ == CURAND_STATUS_ALLOCATION_FAILED)) && PetscDeviceInitialized(PETSC_DEVICE_CUDA)) { \
1510e6b6b59SJacob Faibussowitsch           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_GPU_RESOURCE, \
1520e6b6b59SJacob Faibussowitsch                   "cuRAND error %d. " \
1530e6b6b59SJacob Faibussowitsch                   "Reports not initialized or alloc failed; " \
1540e6b6b59SJacob Faibussowitsch                   "this indicates the GPU has run out resources", \
1550e6b6b59SJacob Faibussowitsch                   (PetscErrorCode)_p_curand_stat__); \
1560e6b6b59SJacob Faibussowitsch         } else { \
1570e6b6b59SJacob Faibussowitsch           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_GPU, "cuRand error %d", (PetscErrorCode)_p_curand_stat__); \
1580e6b6b59SJacob Faibussowitsch         } \
1590e6b6b59SJacob Faibussowitsch       } \
1600e6b6b59SJacob Faibussowitsch     } while (0)
1610e6b6b59SJacob Faibussowitsch   #define CHKERRCURAND(...) PetscCallCURAND(__VA_ARGS__)
1620e6b6b59SJacob Faibussowitsch 
1630e6b6b59SJacob Faibussowitsch PETSC_EXTERN cudaStream_t   PetscDefaultCudaStream; // The default stream used by PETSc
1640e6b6b59SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode PetscCUBLASGetHandle(cublasHandle_t *);
1650e6b6b59SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode PetscCUSOLVERDnGetHandle(cusolverDnHandle_t *);
1665c127019SJunchao Zhang PETSC_EXTERN PetscErrorCode PetscGetCurrentCUDAStream(cudaStream_t *);
1670e6b6b59SJacob Faibussowitsch 
1680e6b6b59SJacob Faibussowitsch #endif // PETSC_HAVE_CUDA
1690e6b6b59SJacob Faibussowitsch 
17015af11aaSJacob Faibussowitsch // these can also be defined in petscdevice_hip.h so we undef and define them *only* if the
17115af11aaSJacob Faibussowitsch // current compiler is NVCC. In this case if petscdevice_hip.h is included first, the macros
17215af11aaSJacob Faibussowitsch // would already be defined, but they would be empty since we cannot be using HCC at the same
17315af11aaSJacob Faibussowitsch // time.
1740e6b6b59SJacob Faibussowitsch #if PetscDefined(USING_NVCC)
17515af11aaSJacob Faibussowitsch   #undef PETSC_HOST_DECL
17615af11aaSJacob Faibussowitsch   #undef PETSC_DEVICE_DECL
17715af11aaSJacob Faibussowitsch   #undef PETSC_KERNEL_DECL
17815af11aaSJacob Faibussowitsch   #undef PETSC_SHAREDMEM_DECL
17915af11aaSJacob Faibussowitsch   #undef PETSC_FORCEINLINE
18015af11aaSJacob Faibussowitsch   #undef PETSC_CONSTMEM_DECL
18115af11aaSJacob Faibussowitsch 
1820e6b6b59SJacob Faibussowitsch   #define PETSC_HOST_DECL      __host__
1830e6b6b59SJacob Faibussowitsch   #define PETSC_DEVICE_DECL    __device__
1840e6b6b59SJacob Faibussowitsch   #define PETSC_KERNEL_DECL    __global__
1850e6b6b59SJacob Faibussowitsch   #define PETSC_SHAREDMEM_DECL __shared__
1860e6b6b59SJacob Faibussowitsch   #define PETSC_FORCEINLINE    __forceinline__
1870e6b6b59SJacob Faibussowitsch   #define PETSC_CONSTMEM_DECL  __constant__
18815af11aaSJacob Faibussowitsch #endif
18915af11aaSJacob Faibussowitsch 
190*beceaeb6SBarry Smith #if !defined(PETSC_HOST_DECL) // use HOST_DECL as canary
1910e6b6b59SJacob Faibussowitsch   #define PETSC_HOST_DECL
1920e6b6b59SJacob Faibussowitsch   #define PETSC_DEVICE_DECL
1930e6b6b59SJacob Faibussowitsch   #define PETSC_KERNEL_DECL
1940e6b6b59SJacob Faibussowitsch   #define PETSC_SHAREDMEM_DECL
1950e6b6b59SJacob Faibussowitsch   #define PETSC_FORCEINLINE inline
1960e6b6b59SJacob Faibussowitsch   #define PETSC_CONSTMEM_DECL
19715af11aaSJacob Faibussowitsch #endif
1980e6b6b59SJacob Faibussowitsch 
199*beceaeb6SBarry Smith #if !defined(PETSC_DEVICE_DEFINED_DECLS_PRIVATE)
20015af11aaSJacob Faibussowitsch   #define PETSC_DEVICE_DEFINED_DECLS_PRIVATE
2010e6b6b59SJacob Faibussowitsch   #define PETSC_HOSTDEVICE_DECL        PETSC_HOST_DECL PETSC_DEVICE_DECL
2020e6b6b59SJacob Faibussowitsch   #define PETSC_DEVICE_INLINE_DECL     PETSC_DEVICE_DECL PETSC_FORCEINLINE
2030e6b6b59SJacob Faibussowitsch   #define PETSC_HOSTDEVICE_INLINE_DECL PETSC_HOSTDEVICE_DECL PETSC_FORCEINLINE
20415af11aaSJacob Faibussowitsch #endif
205