Actual source code: deviceimpl.h

  1: #pragma once

  3: #include <petscdevice.h>
  4: #include <petsc/private/petscimpl.h>
  5: #include <petscpkg_version.h>

  7: #if PetscDefined(HAVE_CUPM)
  8: PETSC_INTERN int PetscDeviceCUPMRuntimeArch; // The real CUDA/HIP arch the code is run with. For log view and error diagnosis
  9: #endif

 11: /* logging support */
 12: PETSC_INTERN PetscLogEvent CUBLAS_HANDLE_CREATE;
 13: PETSC_INTERN PetscLogEvent CUSOLVER_HANDLE_CREATE;
 14: PETSC_INTERN PetscLogEvent HIPSOLVER_HANDLE_CREATE;
 15: PETSC_INTERN PetscLogEvent HIPBLAS_HANDLE_CREATE;

 17: PETSC_INTERN PetscLogEvent DCONTEXT_Create;
 18: PETSC_INTERN PetscLogEvent DCONTEXT_Destroy;
 19: PETSC_INTERN PetscLogEvent DCONTEXT_ChangeStream;
 20: PETSC_INTERN PetscLogEvent DCONTEXT_SetDevice;
 21: PETSC_INTERN PetscLogEvent DCONTEXT_SetUp;
 22: PETSC_INTERN PetscLogEvent DCONTEXT_Duplicate;
 23: PETSC_INTERN PetscLogEvent DCONTEXT_QueryIdle;
 24: PETSC_INTERN PetscLogEvent DCONTEXT_WaitForCtx;
 25: PETSC_INTERN PetscLogEvent DCONTEXT_Fork;
 26: PETSC_INTERN PetscLogEvent DCONTEXT_Join;
 27: PETSC_INTERN PetscLogEvent DCONTEXT_Sync;
 28: PETSC_INTERN PetscLogEvent DCONTEXT_Mark;

 30: /* type cast macros for some additional type-safety in C++ land */
 31: #if defined(__cplusplus)
 32:   #define PetscStreamTypeCast(...)     static_cast<PetscStreamType>(__VA_ARGS__)
 33:   #define PetscDeviceTypeCast(...)     static_cast<PetscDeviceType>(__VA_ARGS__)
 34:   #define PetscDeviceInitTypeCast(...) static_cast<PetscDeviceInitType>(__VA_ARGS__)
 35: #else
 36:   #define PetscStreamTypeCast(...)     ((PetscStreamType)(__VA_ARGS__))
 37:   #define PetscDeviceTypeCast(...)     ((PetscDeviceType)(__VA_ARGS__))
 38:   #define PetscDeviceInitTypeCast(...) ((PetscDeviceInitType)(__VA_ARGS__))
 39: #endif

 41: #if PetscDefined(CLANG_STATIC_ANALYZER)
 42: template <typename T>
 44: template <typename T, typename U>
 45: extern void PetscCheckCompatibleDeviceTypes(T, int, U, int);
 46: template <typename T>
 48: template <typename T>
 50: template <typename T, typename U>
 51: extern void PetscCheckCompatibleDevices(T, int, U, int);
 52: template <typename T>
 54: template <typename T>
 56: template <typename T, typename U>
 57: extern void PetscCheckCompatibleDeviceContexts(T, int, U, int);
 58: #elif PetscDefined(DEVICELANGUAGE_CXX) && (PetscDefined(USE_DEBUG) || PetscDefined(DEVICE_KEEP_ERROR_CHECKING_MACROS))
 60:     do { \
 61:       PetscDeviceType pvdt_dtype_ = PetscDeviceTypeCast(dtype); \
 62:       int             pvdt_argno_ = (int)(argno); \
 63:       PetscCheck(((int)pvdt_dtype_ >= (int)PETSC_DEVICE_HOST) && ((int)pvdt_dtype_ <= (int)PETSC_DEVICE_MAX), PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscDeviceType '%d': Argument #%d", pvdt_dtype_, pvdt_argno_); \
 64:       if (PetscUnlikely(!PetscDeviceConfiguredFor_Internal(pvdt_dtype_))) { \
 65:         PetscCheck((int)pvdt_dtype_ != (int)PETSC_DEVICE_MAX, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Invalid PetscDeviceType '%s': Argument #%d", PetscDeviceTypes[pvdt_dtype_], pvdt_argno_); \
 66:         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, \
 67:                 "Not configured for PetscDeviceType '%s': Argument #%d;" \
 68:                 " run configure --help %s for available options", \
 69:                 PetscDeviceTypes[pvdt_dtype_], pvdt_argno_, PetscDeviceTypes[pvdt_dtype_]); \
 70:       } \
 71:     } while (0)

 73:   #define PetscCheckCompatibleDeviceTypes(dtype1, argno1, dtype2, argno2) \
 74:     do { \
 75:       PetscDeviceType pccdt_dtype1_ = PetscDeviceTypeCast(dtype1); \
 76:       PetscDeviceType pccdt_dtype2_ = PetscDeviceTypeCast(dtype2); \
 79:       PetscCheck(pccdt_dtype1_ == pccdt_dtype2_, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMETYPE, "PetscDeviceTypes are incompatible: Arguments #%d and #%d. Expected PetscDeviceType '%s' but have '%s' instead", argno1, argno2, PetscDeviceTypes[pccdt_dtype1_], PetscDeviceTypes[pccdt_dtype2_]); \
 80:     } while (0)

 83:     do { \
 84:       PetscDevice pvd_dev_   = dev; \
 85:       int         pvd_argno_ = (int)(argno); \
 86:       PetscAssertPointer(pvd_dev_, pvd_argno_); \
 88:       PetscCheck(pvd_dev_->id >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid PetscDevice: Argument #%d; id %" PetscInt_FMT " < 0", pvd_argno_, pvd_dev_->id); \
 89:       PetscCheck(pvd_dev_->refcnt >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid PetscDevice: Argument #%d; negative reference count %" PetscInt_FMT, pvd_argno_, pvd_dev_->refcnt); \
 90:     } while (0)

 93:     do { \
 94:       PetscDeviceAttribute pvda_attr_  = (dattr); \
 95:       int                  pvda_argno_ = (int)(argno); \
 96:       PetscCheck((((int)pvda_attr_) >= 0) && (pvda_attr_ <= PETSC_DEVICE_ATTR_MAX), PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscDeviceAttribute '%d': Argument #%d", (int)pvda_attr_, pvda_argno_); \
 97:       PetscCheck(pvda_attr_ != PETSC_DEVICE_ATTR_MAX, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Invalid PetscDeviceAttribute '%s': Argument #%d", PetscDeviceAttributes[pvda_attr_], pvda_argno_); \
 98:     } while (0)

100:   /*
101:   for now just checks strict equality, but this can be changed as some devices (i.e. kokkos and
102:   any cupm should be compatible once implemented)
103: */
104:   #define PetscCheckCompatibleDevices(dev1, argno1, dev2, argno2) \
105:     do { \
106:       PetscDevice pccd_dev1_ = (dev1), pccd_dev2_ = (dev2); \
107:       int         pccd_argno1_ = (int)(argno1), pccd_argno2_ = (int)(argno2); \
110:       PetscCheckCompatibleDeviceTypes(pccd_dev1_->type, pccd_argno1_, pccd_dev2_->type, pccd_argno2_); \
111:     } while (0)

114:     do { \
115:       PetscStreamType pvst_stype_ = PetscStreamTypeCast(stype); \
116:       int             pvst_argno_ = (int)(argno); \
117:       PetscCheck(((int)pvst_stype_ >= 0) && ((int)pvst_stype_ <= (int)PETSC_STREAM_MAX), PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscStreamType '%d': Argument #%d", pvst_stype_, pvst_argno_); \
118:       PetscCheck((int)pvst_stype_ != (int)PETSC_STREAM_MAX, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Invalid PetscStreamType '%s': Argument #%d", PetscStreamTypes[pvst_stype_], pvst_argno_); \
119:     } while (0)

122:     do { \
123:       PetscDeviceContext pvdc_dctx_  = dctx; \
124:       int                pvdc_argno_ = (int)(argno); \
127:       if (pvdc_dctx_->device) { \
129:       } else { \
130:         PetscCheck(!pvdc_dctx_->setup, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, \
131:                    "Invalid PetscDeviceContext: Argument #%d; " \
132:                    "PetscDeviceContext is setup but has no PetscDevice", \
133:                    pvdc_argno_); \
134:       } \
135:       PetscCheck(((PetscObject)pvdc_dctx_)->id >= 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid PetscDeviceContext: Argument #%d; id %" PetscInt64_FMT " < 1", pvdc_argno_, ((PetscObject)pvdc_dctx_)->id); \
136:       PetscCheck(pvdc_dctx_->numChildren <= pvdc_dctx_->maxNumChildren, PETSC_COMM_SELF, PETSC_ERR_ARG_CORRUPT, "Invalid PetscDeviceContext: Argument #%d; number of children %" PetscInt_FMT " > max number of children %" PetscInt_FMT, pvdc_argno_, \
137:                  pvdc_dctx_->numChildren, pvdc_dctx_->maxNumChildren); \
138:     } while (0)

140:   #define PetscCheckCompatibleDeviceContexts(dctx1, argno1, dctx2, argno2) \
141:     do { \
142:       PetscDeviceContext pccdc_dctx1_ = (dctx1), pccdc_dctx2_ = (dctx2); \
143:       int                pccdc_argno1_ = (int)(argno1), pccdc_argno2_ = (int)(argno2); \
146:       if (pccdc_dctx1_->device && pccdc_dctx2_->device) PetscCheckCompatibleDevices(pccdc_dctx1_->device, pccdc_argno1_, pccdc_dctx2_->device, pccdc_argno2_); \
147:     } while (0)
148: #else /* PetscDefined(USE_DEBUG) */
150:   #define PetscCheckCompatibleDeviceTypes(dtype1, argno1, dtype2, argno2)
153:   #define PetscCheckCompatibleDevices(dev1, argno1, dev2, argno2)
156:   #define PetscCheckCompatibleDeviceContexts(dctx1, argno1, dctx2, argno2) \
157:     do { \
158:     } while (0)
159: #endif /* PetscDefined(USE_DEBUG) */

161: /* if someone is ready to rock with more than 128 GPUs on hand then we're in real trouble */
162: #define PETSC_DEVICE_MAX_DEVICES 128

164: // If hwloc is not present, this macro will not be defined in petscpkg_version.h and block following will fail to compile
165: #if !defined(PETSC_PKG_HWLOC_VERSION_GE)
166:   #define PETSC_PKG_HWLOC_VERSION_GE(MAJ, MIN, PAT) 0
167: #endif

169: #if PetscDefined(HAVE_HWLOC) && PetscDefined(HAVE_CUPM) && PETSC_PKG_HWLOC_VERSION_GE(2, 0, 0)
170:   #define PETSC_DEVICE_TOPOLOGY_AWARE -2
171:   // help string and lower bound for the "-device_select" option, shared by device.cxx and impldevicebase.hpp
172:   #define PETSC_DEVICE_SELECT_HELP \
173:     "Which device to use. Pass " PetscStringize(PETSC_DECIDE) " to have PETSc decide, " PetscStringize(PETSC_DEVICE_TOPOLOGY_AWARE) " to use a topology-aware selection algorithm or (given they exist) [0-" PetscStringize(PETSC_DEVICE_MAX_DEVICES) ") for a specific device"
174:   #define PETSC_DEVICE_SELECT_LOWER_BOUND PETSC_DEVICE_TOPOLOGY_AWARE
175: #else
176:   #define PETSC_DEVICE_SELECT_HELP        "Which device to use. Pass " PetscStringize(PETSC_DECIDE) " to have PETSc decide or (given they exist) [0-" PetscStringize(PETSC_DEVICE_MAX_DEVICES) ") for a specific device"
177:   #define PETSC_DEVICE_SELECT_LOWER_BOUND PETSC_DECIDE
178: #endif

180: /*
181:   the configure-time default device type, used as the initial the value of
182:   PETSC_DEVICE_DEFAULT() as well as what it is restored to during PetscFinalize()
183: */
184: #if PetscDefined(HAVE_HIP)
185:   #define PETSC_DEVICE_HARDWARE_DEFAULT_TYPE PETSC_DEVICE_HIP
186: #elif PetscDefined(HAVE_CUDA)
187:   #define PETSC_DEVICE_HARDWARE_DEFAULT_TYPE PETSC_DEVICE_CUDA
188: #elif PetscDefined(HAVE_SYCL)
189:   #define PETSC_DEVICE_HARDWARE_DEFAULT_TYPE PETSC_DEVICE_SYCL
190: #else
191:   #define PETSC_DEVICE_HARDWARE_DEFAULT_TYPE PETSC_DEVICE_HOST
192: #endif

194: #define PETSC_DEVICE_CONTEXT_DEFAULT_DEVICE_TYPE PETSC_DEVICE_HARDWARE_DEFAULT_TYPE
195: // REMOVE ME (change)
196: #define PETSC_DEVICE_CONTEXT_DEFAULT_STREAM_TYPE PETSC_STREAM_DEFAULT

198: typedef struct _DeviceOps *DeviceOps;
199: struct _DeviceOps {
200:   /* the creation routine for the corresponding PetscDeviceContext, this is NOT intended
201:    * to be called by the PetscDevice itself */
202:   PetscErrorCode (*createcontext)(PetscDeviceContext);
203:   PetscErrorCode (*configure)(PetscDevice);
204:   PetscErrorCode (*view)(PetscDevice, PetscViewer);
205:   PetscErrorCode (*getattribute)(PetscDevice, PetscDeviceAttribute, void *);
206: };

208: struct _n_PetscDevice {
209:   struct _DeviceOps ops[1];
210:   void             *data;     /* placeholder */
211:   PetscInt          refcnt;   /* reference count for the device */
212:   PetscInt          id;       /* unique id per created PetscDevice */
213:   PetscInt          deviceId; /* the id of the underlying device, i.e. the return of
214:                                * cudaGetDevice() for example */
215:   PetscDeviceType   type;     /* type of device */
216: };

218: typedef struct _n_PetscEvent *PetscEvent;
219: struct _n_PetscEvent {
220:   PetscDeviceType  dtype;      // this cannot change for the lifetime of the event
221:   PetscObjectId    dctx_id;    // id of last dctx to record this event
222:   PetscObjectState dctx_state; // state of last dctx to record this event
223:   void            *data;       // event handle
224:   PetscErrorCode (*destroy)(PetscEvent);
225: };

227: typedef struct _DeviceContextOps *DeviceContextOps;
228: struct _DeviceContextOps {
229:   PetscErrorCode (*destroy)(PetscDeviceContext);
230:   PetscErrorCode (*changestreamtype)(PetscDeviceContext, PetscStreamType);
231:   PetscErrorCode (*setup)(PetscDeviceContext);
232:   PetscErrorCode (*query)(PetscDeviceContext, PetscBool *);
233:   PetscErrorCode (*waitforcontext)(PetscDeviceContext, PetscDeviceContext);
234:   PetscErrorCode (*synchronize)(PetscDeviceContext);
235:   PetscErrorCode (*getblashandle)(PetscDeviceContext, void *);
236:   PetscErrorCode (*getsolverhandle)(PetscDeviceContext, void *);
237:   PetscErrorCode (*getstreamhandle)(PetscDeviceContext, void **);
238:   PetscErrorCode (*begintimer)(PetscDeviceContext);
239:   PetscErrorCode (*endtimer)(PetscDeviceContext, PetscLogDouble *);
240:   PetscErrorCode (*getpower)(PetscDeviceContext, PetscLogDouble *);
241:   PetscErrorCode (*beginenergymeter)(PetscDeviceContext);
242:   PetscErrorCode (*endenergymeter)(PetscDeviceContext, PetscLogDouble *);
243:   PetscErrorCode (*memalloc)(PetscDeviceContext, PetscBool, PetscMemType, size_t, size_t, void **);                             // optional
244:   PetscErrorCode (*memfree)(PetscDeviceContext, PetscMemType, void **);                                                         // optional
245:   PetscErrorCode (*memcopy)(PetscDeviceContext, void *PETSC_RESTRICT, const void *PETSC_RESTRICT, size_t, PetscDeviceCopyMode); // optional
246:   PetscErrorCode (*memset)(PetscDeviceContext, PetscMemType, void *, PetscInt, size_t);                                         // optional
247:   PetscErrorCode (*createevent)(PetscDeviceContext, PetscEvent);                                                                // optional
248:   PetscErrorCode (*recordevent)(PetscDeviceContext, PetscEvent);                                                                // optional
249:   PetscErrorCode (*waitforevent)(PetscDeviceContext, PetscEvent);                                                               // optional
250: };

252: struct _p_PetscDeviceContext {
253:   PETSCHEADER(struct _DeviceContextOps);
254:   PetscDevice     device;         /* the device this context stems from */
255:   void           *data;           /* solver contexts, event, stream */
256:   PetscObjectId  *childIDs;       /* array containing ids of contexts currently forked from this one */
257:   PetscInt        numChildren;    /* how many children does this context expect to destroy */
258:   PetscInt        maxNumChildren; /* how many children can this context have room for without realloc'ing */
259:   PetscStreamType streamType;     /* how should this contexts stream behave around other streams? */
260:   PetscBool       setup;
261:   PetscBool       usersetdevice;
262: };

264: // ===================================================================================
265: //                            PetscDevice Internal Functions
266: // ===================================================================================
267: PETSC_INTERN PetscErrorCode                PetscDeviceInitializeFromOptions_Internal(MPI_Comm);
268: PETSC_SINGLE_LIBRARY_INTERN PetscErrorCode PetscDeviceGetDefaultForType_Internal(PetscDeviceType, PetscDevice *);

270: static inline PetscErrorCode PetscDeviceReference_Internal(PetscDevice device)
271: {
272:   PetscFunctionBegin;
273:   if (PetscDefined(DEVICELANGUAGE_CXX)) ++device->refcnt;
274:   PetscFunctionReturn(PETSC_SUCCESS);
275: }

277: #if PetscDefined(DEVICELANGUAGE_CXX)
278: static inline PetscErrorCode PetscDeviceDereference_Internal(PetscDevice device)
279: {
280:   PetscFunctionBegin;
281:   --device->refcnt;
282:   PetscAssert(device->refcnt >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_CORRUPT, "PetscDevice has negative reference count %" PetscInt_FMT, device->refcnt);
283:   PetscFunctionReturn(PETSC_SUCCESS);
284: }

286: static inline PetscErrorCode PetscDeviceCheckDeviceCount_Internal(PetscInt count)
287: {
288:   PetscFunctionBegin;
289:   PetscAssert(count < PETSC_DEVICE_MAX_DEVICES, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Detected %" PetscInt_FMT " devices, which is larger than maximum supported number of devices %d", count, PETSC_DEVICE_MAX_DEVICES);
290:   PetscFunctionReturn(PETSC_SUCCESS);
291: }
292: #endif /* PETSC_DEVICELANGUAGE_CXX for PetscDevice Internal Functions */

294: /* More general form of PetscDeviceDefaultType_Internal(), as it calls the former using
295:  * the automatically selected default PetscDeviceType */
296: #define PetscDeviceGetDefault_Internal(device) PetscDeviceGetDefaultForType_Internal(PETSC_DEVICE_DEFAULT(), device)

298: static inline PETSC_CONSTEXPR_14 PetscBool PetscDeviceConfiguredFor_Internal(PetscDeviceType type)
299: {
300:   switch (type) {
301:   case PETSC_DEVICE_HOST:
302:     return PETSC_TRUE;
303:     /* casts are needed in C++ */
304:   case PETSC_DEVICE_CUDA:
305:     return (PetscBool)PetscDefined(HAVE_CUDA);
306:   case PETSC_DEVICE_HIP:
307:     return (PetscBool)PetscDefined(HAVE_HIP);
308:   case PETSC_DEVICE_SYCL:
309:     return (PetscBool)PetscDefined(HAVE_SYCL);
310:   case PETSC_DEVICE_MAX:
311:     return PETSC_FALSE;
312:     /* Do not add default case! Will make compiler warn on new additions to PetscDeviceType! */
313:   }
314:   PetscUnreachable();
315:   return PETSC_FALSE;
316: }

318: // ===================================================================================
319: //                     PetscDeviceContext Internal Functions
320: // ===================================================================================
321: PETSC_SINGLE_LIBRARY_INTERN PetscErrorCode PetscDeviceContextGetNullContext_Internal(PetscDeviceContext *);
322: #if PetscDefined(DEVICELANGUAGE_CXX)
323: static inline PetscErrorCode PetscDeviceContextGetBLASHandle_Internal(PetscDeviceContext dctx, void *handle)
324: {
325:   PetscFunctionBegin;
326:   /* we do error checking here as this routine is an entry-point */
328:   PetscUseTypeMethod(dctx, getblashandle, handle);
329:   PetscFunctionReturn(PETSC_SUCCESS);
330: }

332: static inline PetscErrorCode PetscDeviceContextGetSOLVERHandle_Internal(PetscDeviceContext dctx, void *handle)
333: {
334:   PetscFunctionBegin;
335:   /* we do error checking here as this routine is an entry-point */
337:   PetscUseTypeMethod(dctx, getsolverhandle, handle);
338:   PetscFunctionReturn(PETSC_SUCCESS);
339: }

341: static inline PetscErrorCode PetscDeviceContextGetStreamHandle_Internal(PetscDeviceContext dctx, void **handle)
342: {
343:   PetscFunctionBegin;
344:   /* we do error checking here as this routine is an entry-point */
346:   PetscAssertPointer(handle, 2);
347:   PetscUseTypeMethod(dctx, getstreamhandle, handle);
348:   PetscFunctionReturn(PETSC_SUCCESS);
349: }

351: static inline PetscErrorCode PetscDeviceContextBeginTimer_Internal(PetscDeviceContext dctx)
352: {
353:   PetscFunctionBegin;
354:   /* we do error checking here as this routine is an entry-point */
356:   PetscUseTypeMethod(dctx, begintimer);
357:   PetscFunctionReturn(PETSC_SUCCESS);
358: }

360: static inline PetscErrorCode PetscDeviceContextEndTimer_Internal(PetscDeviceContext dctx, PetscLogDouble *elapsed)
361: {
362:   PetscFunctionBegin;
363:   /* we do error checking here as this routine is an entry-point */
365:   PetscAssertPointer(elapsed, 2);
366:   PetscUseTypeMethod(dctx, endtimer, elapsed);
367:   PetscFunctionReturn(PETSC_SUCCESS);
368: }

370:   #if PetscDefined(HAVE_NVML)
371: static inline PetscErrorCode PetscDeviceContextGetPower_Internal(PetscDeviceContext dctx, PetscLogDouble *power)
372: {
373:   PetscFunctionBegin;
375:   PetscAssertPointer(power, 2);
376:   PetscUseTypeMethod(dctx, getpower, power);
377:   PetscFunctionReturn(PETSC_SUCCESS);
378: }
379:   #endif

381: static inline PetscErrorCode PetscDeviceContextBeginEnergyMeter_Internal(PetscDeviceContext dctx)
382: {
383:   PetscFunctionBegin;
384:   /* we do error checking here as this routine is an entry-point */
386:   PetscUseTypeMethod(dctx, beginenergymeter);
387:   PetscFunctionReturn(PETSC_SUCCESS);
388: }

390: static inline PetscErrorCode PetscDeviceContextEndEnergyMeter_Internal(PetscDeviceContext dctx, PetscLogDouble *energy)
391: {
392:   PetscFunctionBegin;
393:   /* we do error checking here as this routine is an entry-point */
395:   PetscAssertPointer(energy, 2);
396:   PetscUseTypeMethod(dctx, endenergymeter, energy);
397:   PetscFunctionReturn(PETSC_SUCCESS);
398: }
399: #endif /* PETSC_DEVICELANGUAGE_CXX for PetscDeviceContext Internal Functions */

401: /* note, only does assertion checking in debug mode */
402: static inline PetscErrorCode PetscDeviceContextGetCurrentContextAssertType_Internal(PetscDeviceContext *dctx, PetscDeviceType type)
403: {
404:   PetscFunctionBegin;
405:   PetscCall(PetscDeviceContextGetCurrentContext(dctx));
406:   if (PetscDefined(USE_DEBUG)) {
407:     PetscDeviceType dtype;

410:     PetscCall(PetscDeviceContextGetDeviceType(*dctx, &dtype));
411:     PetscCheckCompatibleDeviceTypes(dtype, 1, type, 2);
412:   } else (void)type;
413:   PetscFunctionReturn(PETSC_SUCCESS);
414: }

416: static inline PetscErrorCode PetscDeviceContextGetOptionalNullContext_Internal(PetscDeviceContext *dctx)
417: {
418:   PetscFunctionBegin;
419:   PetscAssertPointer(dctx, 1);
420:   if (!*dctx) PetscCall(PetscDeviceContextGetNullContext_Internal(dctx));
422:   PetscFunctionReturn(PETSC_SUCCESS);
423: }

425: /* Experimental API -- it will eventually become public */
426: PETSC_EXTERN PetscErrorCode PetscDeviceRegisterMemory(const void *PETSC_RESTRICT, PetscMemType, size_t);
427: PETSC_EXTERN PetscErrorCode PetscDeviceGetAttribute(PetscDevice, PetscDeviceAttribute, void *);
428: #if PetscDefined(DEVICELANGUAGE_CXX)
429: PETSC_EXTERN PetscErrorCode PetscDeviceContextMarkIntentFromID(PetscDeviceContext, PetscObjectId, PetscMemoryAccessMode, const char name[]);
430: #endif
431: // Used for testing purposes, internal use ONLY
432: PETSC_EXTERN PetscErrorCode PetscGetMarkedObjectMap_Internal(size_t *, PetscObjectId **, PetscMemoryAccessMode **, size_t **, PetscEvent ***);
433: PETSC_EXTERN PetscErrorCode PetscRestoreMarkedObjectMap_Internal(size_t, PetscObjectId **, PetscMemoryAccessMode **, size_t **, PetscEvent ***);
434: #if PetscDefined(DEVICELANGUAGE_CXX) && defined(__cplusplus)
435: namespace
436: {

438: inline PetscErrorCode PetscDeviceContextMarkIntentFromID(PetscDeviceContext dctx, PetscObject obj, PetscMemoryAccessMode mode, const char name[])
439: {
440:   PetscFunctionBegin;
441:   PetscCall(PetscDeviceContextMarkIntentFromID(dctx, obj->id, mode, name));
442:   PetscFunctionReturn(PETSC_SUCCESS);
443: }

445: } // anonymous namespace
446: #endif

448: PETSC_INTERN PetscErrorCode PetscDeviceContextCreate_HOST(PetscDeviceContext);
449: #if PetscDefined(HAVE_CUDA)
450: PETSC_INTERN PetscErrorCode PetscDeviceContextCreate_CUDA(PetscDeviceContext);
451: #endif
452: #if PetscDefined(HAVE_HIP)
453: PETSC_INTERN PetscErrorCode PetscDeviceContextCreate_HIP(PetscDeviceContext);
454: #endif
455: #if PetscDefined(HAVE_SYCL)
456: PETSC_INTERN PetscErrorCode PetscDeviceContextCreate_SYCL(PetscDeviceContext);
457: #endif

459: static inline PetscErrorCode PetscDeviceContextSynchronizeIfWithBarrier_Internal(PetscDeviceContext dctx)
460: {
461:   PetscStreamType stream_type;

463:   PetscFunctionBegin;
464:   PetscCall(PetscDeviceContextGetStreamType(dctx, &stream_type));
465:   if (stream_type == PETSC_STREAM_DEFAULT_WITH_BARRIER || stream_type == PETSC_STREAM_NONBLOCKING_WITH_BARRIER) PetscCall(PetscDeviceContextSynchronize(dctx));
466:   PetscFunctionReturn(PETSC_SUCCESS);
467: }

469: #if PetscDefined(HAVE_NVML)

471:   #define PetscCallNVML(...) \
472:     do { \
473:       nvmlReturn_t nvmlerr = __VA_ARGS__; \
474:       PetscCheck(nvmlerr == NVML_SUCCESS, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in %s, error string: %s", __func__, nvmlErrorString(nvmlerr)); \
475:     } while (0)

477: #endif