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