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