Date: 2025-03-29T05:58:18+00:00

Actual source code: deviceimpl.h

      1: #pragma once

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

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

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

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

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

     40: #if defined(PETSC_CLANG_STATIC_ANALYZER)
     41: template <typename T>
     43: template <typename T, typename U>
     44: extern void PetscCheckCompatibleDeviceTypes(T, int, U, int);
     45: template <typename T>
     47: template <typename T>
     49: template <typename T, typename U>
     50: extern void PetscCheckCompatibleDevices(T, int, U, int);
     51: template <typename T>
     53: template <typename T>
     55: template <typename T, typename U>
     56: extern void PetscCheckCompatibleDeviceContexts(T, int, U, int);
     57: #elif PetscDefined(HAVE_CXX) && (PetscDefined(USE_DEBUG) || PetscDefined(DEVICE_KEEP_ERROR_CHECKING_MACROS))
     59:     do { \
     60:       PetscDeviceType pvdt_dtype_ = PetscDeviceTypeCast(dtype); \
     61:       int             pvdt_argno_ = (int)(argno); \
     62:       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_); \
     63:       if (PetscUnlikely(!PetscDeviceConfiguredFor_Internal(pvdt_dtype_))) { \
     64:         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_); \
     65:         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, \
     66:                 "Not configured for PetscDeviceType '%s': Argument #%d;" \
     67:                 " run configure --help %s for available options", \
     68:                 PetscDeviceTypes[pvdt_dtype_], pvdt_argno_, PetscDeviceTypes[pvdt_dtype_]); \
     69:       } \
     70:     } while (0)

     72:   #define PetscCheckCompatibleDeviceTypes(dtype1, argno1, dtype2, argno2) \
     73:     do { \
     74:       PetscDeviceType pccdt_dtype1_ = PetscDeviceTypeCast(dtype1); \
     75:       PetscDeviceType pccdt_dtype2_ = PetscDeviceTypeCast(dtype2); \
     78:       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_]); \
     79:     } while (0)

     82:     do { \
     83:       PetscDevice pvd_dev_   = dev; \
     84:       int         pvd_argno_ = (int)(argno); \
     85:       PetscAssertPointer(pvd_dev_, pvd_argno_); \
     87:       PetscCheck(pvd_dev_->id >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid PetscDevice: Argument #%d; id %" PetscInt_FMT " < 0", pvd_argno_, pvd_dev_->id); \
     88:       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); \
     89:     } while (0)

     92:     do { \
     93:       PetscDeviceAttribute pvda_attr_  = (dattr); \
     94:       int                  pvda_argno_ = (int)(argno); \
     95:       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_); \
     96:       PetscCheck(pvda_attr_ != PETSC_DEVICE_ATTR_MAX, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Invalid PetscDeviceAttribute '%s': Argument #%d", PetscDeviceAttributes[pvda_attr_], pvda_argno_); \
     97:     } while (0)

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

    113:     do { \
    114:       PetscStreamType pvst_stype_ = PetscStreamTypeCast(stype); \
    115:       int             pvst_argno_ = (int)(argno); \
    116:       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_); \
    117:       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_); \
    118:     } while (0)

    121:     do { \
    122:       PetscDeviceContext pvdc_dctx_  = dctx; \
    123:       int                pvdc_argno_ = (int)(argno); \
    126:       if (pvdc_dctx_->device) { \
    128:       } else { \
    129:         PetscCheck(!pvdc_dctx_->setup, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, \
    130:                    "Invalid PetscDeviceContext: Argument #%d; " \
    131:                    "PetscDeviceContext is setup but has no PetscDevice", \
    132:                    pvdc_argno_); \
    133:       } \
    134:       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); \
    135:       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_, \
    136:                  pvdc_dctx_->numChildren, pvdc_dctx_->maxNumChildren); \
    137:     } while (0)

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

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

    161: /*
    162:   the configure-time default device type, used as the initial the value of
    163:   PETSC_DEVICE_DEFAULT() as well as what it is restored to during PetscFinalize()
    164: */
    165: #if PetscDefined(HAVE_HIP)
    166:   #define PETSC_DEVICE_HARDWARE_DEFAULT_TYPE PETSC_DEVICE_HIP
    167: #elif PetscDefined(HAVE_CUDA)
    168:   #define PETSC_DEVICE_HARDWARE_DEFAULT_TYPE PETSC_DEVICE_CUDA
    169: #elif PetscDefined(HAVE_SYCL)
    170:   #define PETSC_DEVICE_HARDWARE_DEFAULT_TYPE PETSC_DEVICE_SYCL
    171: #else
    172:   #define PETSC_DEVICE_HARDWARE_DEFAULT_TYPE PETSC_DEVICE_HOST
    173: #endif

    175: #define PETSC_DEVICE_CONTEXT_DEFAULT_DEVICE_TYPE PETSC_DEVICE_HARDWARE_DEFAULT_TYPE
    176: // REMOVE ME (change)
    177: #define PETSC_DEVICE_CONTEXT_DEFAULT_STREAM_TYPE PETSC_STREAM_DEFAULT

    179: typedef struct _DeviceOps *DeviceOps;
    180: struct _DeviceOps {
    181:   /* the creation routine for the corresponding PetscDeviceContext, this is NOT intended
    182:    * to be called by the PetscDevice itself */
    183:   PetscErrorCode (*createcontext)(PetscDeviceContext);
    184:   PetscErrorCode (*configure)(PetscDevice);
    185:   PetscErrorCode (*view)(PetscDevice, PetscViewer);
    186:   PetscErrorCode (*getattribute)(PetscDevice, PetscDeviceAttribute, void *);
    187: };

    189: struct _n_PetscDevice {
    190:   struct _DeviceOps ops[1];
    191:   void             *data;     /* placeholder */
    192:   PetscInt          refcnt;   /* reference count for the device */
    193:   PetscInt          id;       /* unique id per created PetscDevice */
    194:   PetscInt          deviceId; /* the id of the underlying device, i.e. the return of
    195:                                * cudaGetDevice() for example */
    196:   PetscDeviceType   type;     /* type of device */
    197: };

    199: typedef struct _n_PetscEvent *PetscEvent;
    200: struct _n_PetscEvent {
    201:   PetscDeviceType  dtype;      // this cannot change for the lifetime of the event
    202:   PetscObjectId    dctx_id;    // id of last dctx to record this event
    203:   PetscObjectState dctx_state; // state of last dctx to record this event
    204:   void            *data;       // event handle
    205:   PetscErrorCode (*destroy)(PetscEvent);
    206: };

    208: typedef struct _DeviceContextOps *DeviceContextOps;
    209: struct _DeviceContextOps {
    210:   PetscErrorCode (*destroy)(PetscDeviceContext);
    211:   PetscErrorCode (*changestreamtype)(PetscDeviceContext, PetscStreamType);
    212:   PetscErrorCode (*setup)(PetscDeviceContext);
    213:   PetscErrorCode (*query)(PetscDeviceContext, PetscBool *);
    214:   PetscErrorCode (*waitforcontext)(PetscDeviceContext, PetscDeviceContext);
    215:   PetscErrorCode (*synchronize)(PetscDeviceContext);
    216:   PetscErrorCode (*getblashandle)(PetscDeviceContext, void *);
    217:   PetscErrorCode (*getsolverhandle)(PetscDeviceContext, void *);
    218:   PetscErrorCode (*getstreamhandle)(PetscDeviceContext, void **);
    219:   PetscErrorCode (*begintimer)(PetscDeviceContext);
    220:   PetscErrorCode (*endtimer)(PetscDeviceContext, PetscLogDouble *);
    221:   PetscErrorCode (*memalloc)(PetscDeviceContext, PetscBool, PetscMemType, size_t, size_t, void **);                             // optional
    222:   PetscErrorCode (*memfree)(PetscDeviceContext, PetscMemType, void **);                                                         // optional
    223:   PetscErrorCode (*memcopy)(PetscDeviceContext, void *PETSC_RESTRICT, const void *PETSC_RESTRICT, size_t, PetscDeviceCopyMode); // optional
    224:   PetscErrorCode (*memset)(PetscDeviceContext, PetscMemType, void *, PetscInt, size_t);                                         // optional
    225:   PetscErrorCode (*createevent)(PetscDeviceContext, PetscEvent);                                                                // optional
    226:   PetscErrorCode (*recordevent)(PetscDeviceContext, PetscEvent);                                                                // optional
    227:   PetscErrorCode (*waitforevent)(PetscDeviceContext, PetscEvent);                                                               // optional
    228: };

    230: struct _p_PetscDeviceContext {
    231:   PETSCHEADER(struct _DeviceContextOps);
    232:   PetscDevice     device;         /* the device this context stems from */
    233:   void           *data;           /* solver contexts, event, stream */
    234:   PetscObjectId  *childIDs;       /* array containing ids of contexts currently forked from this one */
    235:   PetscInt        numChildren;    /* how many children does this context expect to destroy */
    236:   PetscInt        maxNumChildren; /* how many children can this context have room for without realloc'ing */
    237:   PetscStreamType streamType;     /* how should this contexts stream behave around other streams? */
    238:   PetscBool       setup;
    239:   PetscBool       usersetdevice;
    240: };

    242: // ===================================================================================
    243: //                            PetscDevice Internal Functions
    244: // ===================================================================================
    245: #if PetscDefined(HAVE_CXX)
    246: PETSC_INTERN PetscErrorCode                PetscDeviceInitializeFromOptions_Internal(MPI_Comm);
    247: PETSC_SINGLE_LIBRARY_INTERN PetscErrorCode PetscDeviceGetDefaultForType_Internal(PetscDeviceType, PetscDevice *);

    249: static inline PetscErrorCode PetscDeviceReference_Internal(PetscDevice device)
    250: {
    251:   PetscFunctionBegin;
    252:   ++(device->refcnt);
    253:   PetscFunctionReturn(PETSC_SUCCESS);
    254: }

    256: static inline PetscErrorCode PetscDeviceDereference_Internal(PetscDevice device)
    257: {
    258:   PetscFunctionBegin;
    259:   --(device->refcnt);
    260:   PetscAssert(device->refcnt >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_CORRUPT, "PetscDevice has negative reference count %" PetscInt_FMT, device->refcnt);
    261:   PetscFunctionReturn(PETSC_SUCCESS);
    262: }
    263: #else /* PETSC_HAVE_CXX for PetscDevice Internal Functions */
    264:   #define PetscDeviceInitializeFromOptions_Internal(comm)     PETSC_SUCCESS
    265:   #define PetscDeviceGetDefaultForType_Internal(Type, device) (*(device) = PETSC_NULLPTR, PETSC_SUCCESS)
    266:   #define PetscDeviceReference_Internal(device)               PETSC_SUCCESS
    267:   #define PetscDeviceDereference_Internal(device)             PETSC_SUCCESS
    268: #endif /* PETSC_HAVE_CXX for PetscDevice Internal Functions */

    270: static inline PetscErrorCode PetscDeviceCheckDeviceCount_Internal(PetscInt count)
    271: {
    272:   PetscFunctionBegin;
    273:   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);
    274:   PetscFunctionReturn(PETSC_SUCCESS);
    275: }

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

    281: static inline PETSC_CONSTEXPR_14 PetscBool PetscDeviceConfiguredFor_Internal(PetscDeviceType type)
    282: {
    283:   switch (type) {
    284:   case PETSC_DEVICE_HOST:
    285:     return PETSC_TRUE;
    286:     /* casts are needed in C++ */
    287:   case PETSC_DEVICE_CUDA:
    288:     return (PetscBool)PetscDefined(HAVE_CUDA);
    289:   case PETSC_DEVICE_HIP:
    290:     return (PetscBool)PetscDefined(HAVE_HIP);
    291:   case PETSC_DEVICE_SYCL:
    292:     return (PetscBool)PetscDefined(HAVE_SYCL);
    293:   case PETSC_DEVICE_MAX:
    294:     return PETSC_FALSE;
    295:     /* Do not add default case! Will make compiler warn on new additions to PetscDeviceType! */
    296:   }
    297:   PetscUnreachable();
    298:   return PETSC_FALSE;
    299: }

    301: // ===================================================================================
    302: //                     PetscDeviceContext Internal Functions
    303: // ===================================================================================
    304: #if PetscDefined(HAVE_CXX)
    305: PETSC_SINGLE_LIBRARY_INTERN PetscErrorCode PetscDeviceContextGetNullContext_Internal(PetscDeviceContext *);

    307: static inline PetscErrorCode PetscDeviceContextGetBLASHandle_Internal(PetscDeviceContext dctx, void *handle)
    308: {
    309:   PetscFunctionBegin;
    310:   /* we do error checking here as this routine is an entry-point */
    312:   PetscUseTypeMethod(dctx, getblashandle, handle);
    313:   PetscFunctionReturn(PETSC_SUCCESS);
    314: }

    316: static inline PetscErrorCode PetscDeviceContextGetSOLVERHandle_Internal(PetscDeviceContext dctx, void *handle)
    317: {
    318:   PetscFunctionBegin;
    319:   /* we do error checking here as this routine is an entry-point */
    321:   PetscUseTypeMethod(dctx, getsolverhandle, handle);
    322:   PetscFunctionReturn(PETSC_SUCCESS);
    323: }

    325: static inline PetscErrorCode PetscDeviceContextGetStreamHandle_Internal(PetscDeviceContext dctx, void **handle)
    326: {
    327:   PetscFunctionBegin;
    328:   /* we do error checking here as this routine is an entry-point */
    330:   PetscAssertPointer(handle, 2);
    331:   PetscUseTypeMethod(dctx, getstreamhandle, handle);
    332:   PetscFunctionReturn(PETSC_SUCCESS);
    333: }

    335: static inline PetscErrorCode PetscDeviceContextBeginTimer_Internal(PetscDeviceContext dctx)
    336: {
    337:   PetscFunctionBegin;
    338:   /* we do error checking here as this routine is an entry-point */
    340:   PetscUseTypeMethod(dctx, begintimer);
    341:   PetscFunctionReturn(PETSC_SUCCESS);
    342: }

    344: static inline PetscErrorCode PetscDeviceContextEndTimer_Internal(PetscDeviceContext dctx, PetscLogDouble *elapsed)
    345: {
    346:   PetscFunctionBegin;
    347:   /* we do error checking here as this routine is an entry-point */
    349:   PetscAssertPointer(elapsed, 2);
    350:   PetscUseTypeMethod(dctx, endtimer, elapsed);
    351:   PetscFunctionReturn(PETSC_SUCCESS);
    352: }
    353: #else /* PETSC_HAVE_CXX for PetscDeviceContext Internal Functions */
    354:   #define PetscDeviceContextGetNullContext_Internal(dctx)          (*(dctx) = PETSC_NULLPTR, PETSC_SUCCESS)
    355:   #define PetscDeviceContextGetBLASHandle_Internal(dctx, handle)   (*(handle) = PETSC_NULLPTR, PETSC_SUCCESS)
    356:   #define PetscDeviceContextGetSOLVERHandle_Internal(dctx, handle) (*(handle) = PETSC_NULLPTR, PETSC_SUCCESS)
    357:   #define PetscDeviceContextGetStreamHandle_Internal(dctx, handle) (*(handle) = PETSC_NULLPTR, PETSC_SUCCESS)
    358:   #define PetscDeviceContextBeginTimer_Internal(dctx)              PETSC_SUCCESS
    359:   #define PetscDeviceContextEndTimer_Internal(dctx, elapsed)       PETSC_SUCCESS
    360: #endif /* PETSC_HAVE_CXX for PetscDeviceContext Internal Functions */

    362: /* note, only does assertion checking in debug mode */
    363: static inline PetscErrorCode PetscDeviceContextGetCurrentContextAssertType_Internal(PetscDeviceContext *dctx, PetscDeviceType type)
    364: {
    365:   PetscFunctionBegin;
    366:   PetscCall(PetscDeviceContextGetCurrentContext(dctx));
    367:   if (PetscDefined(USE_DEBUG)) {
    368:     PetscDeviceType dtype;

    371:     PetscCall(PetscDeviceContextGetDeviceType(*dctx, &dtype));
    372:     PetscCheckCompatibleDeviceTypes(dtype, 1, type, 2);
    373:   } else (void)type;
    374:   PetscFunctionReturn(PETSC_SUCCESS);
    375: }

    377: static inline PetscErrorCode PetscDeviceContextGetOptionalNullContext_Internal(PetscDeviceContext *dctx)
    378: {
    379:   PetscFunctionBegin;
    380:   PetscAssertPointer(dctx, 1);
    381:   if (!*dctx) PetscCall(PetscDeviceContextGetNullContext_Internal(dctx));
    383:   PetscFunctionReturn(PETSC_SUCCESS);
    384: }

    386: /* Experimental API -- it will eventually become public */
    387: #if PetscDefined(HAVE_CXX)
    388: PETSC_EXTERN PetscErrorCode PetscDeviceRegisterMemory(const void *PETSC_RESTRICT, PetscMemType, size_t);
    389: PETSC_EXTERN PetscErrorCode PetscDeviceGetAttribute(PetscDevice, PetscDeviceAttribute, void *);
    390: PETSC_EXTERN PetscErrorCode PetscDeviceContextMarkIntentFromID(PetscDeviceContext, PetscObjectId, PetscMemoryAccessMode, const char name[]);
    391:   #if defined(__cplusplus)
    392: namespace
    393: {

    395: inline PetscErrorCode PetscDeviceContextMarkIntentFromID(PetscDeviceContext dctx, PetscObject obj, PetscMemoryAccessMode mode, const char name[])
    396: {
    397:   PetscFunctionBegin;
    398:   PetscCall(PetscDeviceContextMarkIntentFromID(dctx, obj->id, mode, name));
    399:   PetscFunctionReturn(PETSC_SUCCESS);
    400: }

    402: } // anonymous namespace
    403:   #endif // __cplusplus
    404: #else
    405:   #define PetscDeviceRegisterMemory(void_ptr, PetscMemType, size)                                           PETSC_SUCCESS
    406:   #define PetscDeviceGetAttribute(PetscDevice, PetscDeviceAttribute, void_star)                             ((*((int *)(void_star)) = 0), PETSC_SUCCESS)
    407:   #define PetscDeviceContextMarkIntentFromID(PetscDeviceContext, PetscObjectId, PetscMemoryAccessMode, ptr) PETSC_SUCCESS
    408: #endif

    410: PETSC_INTERN PetscErrorCode PetscDeviceContextCreate_HOST(PetscDeviceContext);
    411: #if PetscDefined(HAVE_CUDA)
    412: PETSC_INTERN PetscErrorCode PetscDeviceContextCreate_CUDA(PetscDeviceContext);
    413: #endif
    414: #if PetscDefined(HAVE_HIP)
    415: PETSC_INTERN PetscErrorCode PetscDeviceContextCreate_HIP(PetscDeviceContext);
    416: #endif
    417: #if PetscDefined(HAVE_SYCL)
    418: PETSC_INTERN PetscErrorCode PetscDeviceContextCreate_SYCL(PetscDeviceContext);
    419: #endif

    421: // Used for testing purposes, internal use ONLY
    422: PETSC_EXTERN PetscErrorCode PetscGetMarkedObjectMap_Internal(size_t *, PetscObjectId **, PetscMemoryAccessMode **, size_t **, PetscEvent ***);
    423: PETSC_EXTERN PetscErrorCode PetscRestoreMarkedObjectMap_Internal(size_t, PetscObjectId **, PetscMemoryAccessMode **, size_t **, PetscEvent ***);

    425: static inline PetscErrorCode PetscDeviceContextSynchronizeIfWithBarrier_Internal(PetscDeviceContext dctx)
    426: {
    427:   PetscStreamType stream_type;

    429:   PetscFunctionBegin;
    430:   PetscCall(PetscDeviceContextGetStreamType(dctx, &stream_type));
    431:   if (stream_type == PETSC_STREAM_DEFAULT_WITH_BARRIER || stream_type == PETSC_STREAM_NONBLOCKING_WITH_BARRIER) PetscCall(PetscDeviceContextSynchronize(dctx));
    432:   PetscFunctionReturn(PETSC_SUCCESS);
    433: }