Actual source code: petscdevice_cuda.h

  1: #pragma once

  3: #include <petscdevice.h>
  4: #include <petscpkg_version.h>

  6: /* MANSEC = Sys */

  8: #if defined(__NVCC__) || defined(__CUDACC__)
  9:   #define PETSC_USING_NVCC 1
 10: #endif

 12: #if PetscDefined(HAVE_CUDA)
 13: PETSC_PRAGMA_DIAGNOSTIC_IGNORED_BEGIN("-Wdeprecated-declarations")
 14:   #include <cuda.h>
 15:   #include <cuda_runtime.h>
 16:   #include <cublas_v2.h>
 17:   #include <cusolverDn.h>
 18:   #include <cusolverSp.h>
 19:   #include <cufft.h>
 20: PETSC_PRAGMA_DIAGNOSTIC_IGNORED_END()

 22: /* cuBLAS does not have cublasGetErrorName(). We create one on our own. */
 23: PETSC_EXTERN const char *PetscCUBLASGetErrorName(cublasStatus_t); /* PETSC_EXTERN since it is exposed by the CHKERRCUBLAS macro */
 24: PETSC_EXTERN const char *PetscCUSolverGetErrorName(cusolverStatus_t);
 25: PETSC_EXTERN const char *PetscCUFFTGetErrorName(cufftResult);

 27:   /* REMOVE ME */
 28:   #define WaitForCUDA() cudaDeviceSynchronize()

 30:   /* CUDART_VERSION = 1000 x major + 10 x minor version */

 32:   /* Could not find exactly which CUDART_VERSION introduced cudaGetErrorName. At least it was in CUDA 8.0 (Sep. 2016) */
 33:   #if PETSC_PKG_CUDA_VERSION_GE(8, 0, 0)
 34:     #define PetscCallCUDAVoid(...) \
 35:       do { \
 36:         const cudaError_t _p_cuda_err__ = __VA_ARGS__; \
 37:         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__)); \
 38:       } while (0)

 40:     #define PetscCallCUDA(...) \
 41:       do { \
 42:         const cudaError_t _p_cuda_err__ = __VA_ARGS__; \
 43:         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__)); \
 44:       } while (0)
 45:   #else /* PETSC_PKG_CUDA_VERSION_GE(8,0,0) */
 46:     #define PetscCallCUDA(...) \
 47:       do { \
 48:         const cudaError_t _p_cuda_err__ = __VA_ARGS__; \
 49:         PetscCheck(_p_cuda_err__ == cudaSuccess, PETSC_COMM_SELF, PETSC_ERR_GPU, "cuda error %d", (PetscErrorCode)_p_cuda_err__); \
 50:       } while (0)

 52:     #define PetscCallCUDAVoid(...) \
 53:       do { \
 54:         const cudaError_t _p_cuda_err__ = __VA_ARGS__; \
 55:         PetscCheckAbort(_p_cuda_err__ == cudaSuccess, PETSC_COMM_SELF, PETSC_ERR_GPU, "cuda error %d", (PetscErrorCode)_p_cuda_err__); \
 56:       } while (0)
 57:   #endif /* PETSC_PKG_CUDA_VERSION_GE(8,0,0) */
 58:   #define CHKERRCUDA(...) PetscCallCUDA(__VA_ARGS__)

 60:   #define PetscCUDACheckLaunch \
 61:     do { \
 62:       /* Check synchronous errors, i.e. pre-launch */ \
 63:       PetscCallCUDA(cudaGetLastError()); \
 64:       /* Check asynchronous errors, i.e. kernel failed (ULF) */ \
 65:       PetscCallCUDA(cudaDeviceSynchronize()); \
 66:     } while (0)

 68:   #define PetscCallCUBLAS(...) \
 69:     do { \
 70:       const cublasStatus_t _p_cublas_stat__ = __VA_ARGS__; \
 71:       if (PetscUnlikely(_p_cublas_stat__ != CUBLAS_STATUS_SUCCESS)) { \
 72:         const char *name = PetscCUBLASGetErrorName(_p_cublas_stat__); \
 73:         if (((_p_cublas_stat__ == CUBLAS_STATUS_NOT_INITIALIZED) || (_p_cublas_stat__ == CUBLAS_STATUS_ALLOC_FAILED)) && PetscDeviceInitialized(PETSC_DEVICE_CUDA)) { \
 74:           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_GPU_RESOURCE, \
 75:                   "cuBLAS error %d (%s). " \
 76:                   "Reports not initialized or alloc failed; " \
 77:                   "this indicates the GPU may have run out resources", \
 78:                   (PetscErrorCode)_p_cublas_stat__, name); \
 79:         } else { \
 80:           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_GPU, "cuBLAS error %d (%s)", (PetscErrorCode)_p_cublas_stat__, name); \
 81:         } \
 82:       } \
 83:     } while (0)
 84:   #define CHKERRCUBLAS(...) PetscCallCUBLAS(__VA_ARGS__)

 86:   #if (CUSPARSE_VER_MAJOR > 10 || CUSPARSE_VER_MAJOR == 10 && CUSPARSE_VER_MINOR >= 2) /* According to cuda/10.1.168 on OLCF Summit */
 87:     #define PetscCallCUSPARSE(...) \
 88:       do { \
 89:         const cusparseStatus_t _p_cusparse_stat__ = __VA_ARGS__; \
 90:         if (PetscUnlikely(_p_cusparse_stat__)) { \
 91:           const char *name  = cusparseGetErrorName(_p_cusparse_stat__); \
 92:           const char *descr = cusparseGetErrorString(_p_cusparse_stat__); \
 93:           PetscCheck((_p_cusparse_stat__ != CUSPARSE_STATUS_NOT_INITIALIZED) && (_p_cusparse_stat__ != CUSPARSE_STATUS_ALLOC_FAILED), PETSC_COMM_SELF, PETSC_ERR_GPU_RESOURCE, \
 94:                      "cuSPARSE errorcode %d (%s) : %s.; " \
 95:                      "this indicates the GPU has run out resources", \
 96:                      (int)_p_cusparse_stat__, name, descr); \
 97:           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_GPU, "cuSPARSE errorcode %d (%s) : %s", (int)_p_cusparse_stat__, name, descr); \
 98:         } \
 99:       } while (0)
100:   #else /* (CUSPARSE_VER_MAJOR > 10 || CUSPARSE_VER_MAJOR == 10 && CUSPARSE_VER_MINOR >= 2) */
101:     #define PetscCallCUSPARSE(...) \
102:       do { \
103:         const cusparseStatus_t _p_cusparse_stat__ = __VA_ARGS__; \
104:         PetscCheck(_p_cusparse_stat__ == CUSPARSE_STATUS_SUCCESS, PETSC_COMM_SELF, PETSC_ERR_GPU, "cuSPARSE errorcode %d", (PetscErrorCode)_p_cusparse_stat__); \
105:       } while (0)
106:   #endif /* (CUSPARSE_VER_MAJOR > 10 || CUSPARSE_VER_MAJOR == 10 && CUSPARSE_VER_MINOR >= 2) */
107:   #define CHKERRCUSPARSE(...) PetscCallCUSPARSE(__VA_ARGS__)

109:   #define PetscCallCUSOLVER(...) \
110:     do { \
111:       const cusolverStatus_t _p_cusolver_stat__ = __VA_ARGS__; \
112:       if (PetscUnlikely(_p_cusolver_stat__ != CUSOLVER_STATUS_SUCCESS)) { \
113:         const char *name = PetscCUSolverGetErrorName(_p_cusolver_stat__); \
114:         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)) { \
115:           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_GPU_RESOURCE, \
116:                   "cuSolver error %d (%s). " \
117:                   "This indicates the GPU may have run out resources", \
118:                   (PetscErrorCode)_p_cusolver_stat__, name); \
119:         } else { \
120:           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_GPU, "cuSolver error %d (%s)", (PetscErrorCode)_p_cusolver_stat__, name); \
121:         } \
122:       } \
123:     } while (0)
124:   #define CHKERRCUSOLVER(...) PetscCallCUSOLVER(__VA_ARGS__)

126:   #define PetscCallCUFFT(...) \
127:     do { \
128:       const cufftResult_t _p_cufft_stat__ = __VA_ARGS__; \
129:       if (PetscUnlikely(_p_cufft_stat__ != CUFFT_SUCCESS)) { \
130:         const char *name = PetscCUFFTGetErrorName(_p_cufft_stat__); \
131:         if (((_p_cufft_stat__ == CUFFT_SETUP_FAILED) || (_p_cufft_stat__ == CUFFT_ALLOC_FAILED)) && PetscDeviceInitialized(PETSC_DEVICE_CUDA)) { \
132:           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_GPU_RESOURCE, \
133:                   "cuFFT error %d (%s). " \
134:                   "Reports not initialized or alloc failed; " \
135:                   "this indicates the GPU has run out resources", \
136:                   (PetscErrorCode)_p_cufft_stat__, name); \
137:         } else { \
138:           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_GPU, "cuFFT error %d (%s)", (PetscErrorCode)_p_cufft_stat__, name); \
139:         } \
140:       } \
141:     } while (0)
142:   #define CHKERRCUFFT(...) PetscCallCUFFT(__VA_ARGS__)

144:   #define PetscCallCURAND(...) \
145:     do { \
146:       const curandStatus_t _p_curand_stat__ = __VA_ARGS__; \
147:       if (PetscUnlikely(_p_curand_stat__ != CURAND_STATUS_SUCCESS)) { \
148:         if (((_p_curand_stat__ == CURAND_STATUS_INITIALIZATION_FAILED) || (_p_curand_stat__ == CURAND_STATUS_ALLOCATION_FAILED)) && PetscDeviceInitialized(PETSC_DEVICE_CUDA)) { \
149:           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_GPU_RESOURCE, \
150:                   "cuRAND error %d. " \
151:                   "Reports not initialized or alloc failed; " \
152:                   "this indicates the GPU has run out resources", \
153:                   (PetscErrorCode)_p_curand_stat__); \
154:         } else { \
155:           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_GPU, "cuRand error %d", (PetscErrorCode)_p_curand_stat__); \
156:         } \
157:       } \
158:     } while (0)
159:   #define CHKERRCURAND(...) PetscCallCURAND(__VA_ARGS__)

161: PETSC_EXTERN cudaStream_t   PetscDefaultCudaStream; // The default stream used by PETSc
162: PETSC_EXTERN PetscErrorCode PetscCUBLASGetHandle(cublasHandle_t *);
163: PETSC_EXTERN PetscErrorCode PetscCUSOLVERDnGetHandle(cusolverDnHandle_t *);
164: PETSC_EXTERN PetscErrorCode PetscGetCurrentCUDAStream(cudaStream_t *);

166: #endif // PETSC_HAVE_CUDA

168: // these can also be defined in petscdevice_hip.h so we undef and define them *only* if the
169: // current compiler is NVCC. In this case if petscdevice_hip.h is included first, the macros
170: // would already be defined, but they would be empty since we cannot be using HCC at the same
171: // time.
172: #if PetscDefined(USING_NVCC)
173:   #undef PETSC_HOST_DECL
174:   #undef PETSC_DEVICE_DECL
175:   #undef PETSC_KERNEL_DECL
176:   #undef PETSC_SHAREDMEM_DECL
177:   #undef PETSC_FORCEINLINE
178:   #undef PETSC_CONSTMEM_DECL

180:   #define PETSC_HOST_DECL      __host__
181:   #define PETSC_DEVICE_DECL    __device__
182:   #define PETSC_KERNEL_DECL    __global__
183:   #define PETSC_SHAREDMEM_DECL __shared__
184:   #define PETSC_FORCEINLINE    __forceinline__
185:   #define PETSC_CONSTMEM_DECL  __constant__
186: #endif

188: #ifndef PETSC_HOST_DECL // use HOST_DECL as canary
189:   #define PETSC_HOST_DECL
190:   #define PETSC_DEVICE_DECL
191:   #define PETSC_KERNEL_DECL
192:   #define PETSC_SHAREDMEM_DECL
193:   #define PETSC_FORCEINLINE inline
194:   #define PETSC_CONSTMEM_DECL
195: #endif

197: #ifndef PETSC_DEVICE_DEFINED_DECLS_PRIVATE
198:   #define PETSC_DEVICE_DEFINED_DECLS_PRIVATE
199:   #define PETSC_HOSTDEVICE_DECL        PETSC_HOST_DECL PETSC_DEVICE_DECL
200:   #define PETSC_DEVICE_INLINE_DECL     PETSC_DEVICE_DECL PETSC_FORCEINLINE
201:   #define PETSC_HOSTDEVICE_INLINE_DECL PETSC_HOSTDEVICE_DECL PETSC_FORCEINLINE
202: #endif