Actual source code: global_dcontext.cxx

  1: #include "petscdevice_interface_internal.hpp" /*I <petscdevice.h> I*/
  2: #include <petscdevice_cupm.h>

  4: /* rootContext holds the default context created by PETSc, for cleanup during PetscFinalize().
  5:    globalContext selects the current context, which may instead be supplied by the application.
  6:    PetscDeviceContextSetCurrentContext() changes this selection without transferring ownership,
  7:    so rootContext must be kept separately for PETSc to clean up the context it created. */
  8: static auto               rootDeviceType = PETSC_DEVICE_CONTEXT_DEFAULT_DEVICE_TYPE;
  9: static auto               rootStreamType = PETSC_DEVICE_CONTEXT_DEFAULT_STREAM_TYPE;
 10: static PetscDeviceContext globalContext  = nullptr;
 11: static PetscDeviceContext rootContext    = nullptr;

 13: /* when PetscDevice initializes PetscDeviceContext eagerly the type of device created should
 14:  * match whatever device is eagerly initialized */
 15: PetscErrorCode PetscDeviceContextSetRootDeviceType_Internal(PetscDeviceType type)
 16: {
 17:   PetscFunctionBegin;
 19:   rootDeviceType = type;
 20:   PetscFunctionReturn(PETSC_SUCCESS);
 21: }

 23: PetscErrorCode PetscDeviceContextSetRootStreamType_Internal(PetscStreamType type)
 24: {
 25:   PetscFunctionBegin;
 27:   rootStreamType = type;
 28:   PetscFunctionReturn(PETSC_SUCCESS);
 29: }

 31: static inline PetscErrorCode PetscSetDefaultCUPMStreamFromDeviceContext(PetscDeviceContext dctx, PetscDeviceType dtype)
 32: {
 33:   PetscFunctionBegin;
 34: #if PetscDefined(HAVE_CUDA)
 35:   if (dtype == PETSC_DEVICE_CUDA) {
 36:     void *handle;

 38:     PetscCall(PetscDeviceContextGetStreamHandle_Internal(dctx, &handle));
 39:     PetscDefaultCudaStream = *static_cast<cudaStream_t *>(handle);
 40:   }
 41: #endif
 42: #if PetscDefined(HAVE_HIP)
 43:   if (dtype == PETSC_DEVICE_HIP) {
 44:     void *handle;

 46:     PetscCall(PetscDeviceContextGetStreamHandle_Internal(dctx, &handle));
 47:     PetscDefaultHipStream = *static_cast<hipStream_t *>(handle);
 48:   }
 49: #endif
 50: #if !PetscDefined(HAVE_CUDA) && !PetscDefined(HAVE_HIP)
 51:   (void)dctx, (void)dtype;
 52: #endif
 53:   PetscFunctionReturn(PETSC_SUCCESS);
 54: }

 56: static PetscErrorCode PetscDeviceContextSetupGlobalContext_Private() noexcept
 57: {
 58:   PetscFunctionBegin;
 59:   if (PetscUnlikely(!globalContext)) {
 60:     PetscObject pobj;
 61:     const auto  dtype     = rootDeviceType;
 62:     const auto  finalizer = [] {
 63:       PetscDeviceType dtype;

 65:       PetscFunctionBegin;
 66:       PetscCall(PetscDeviceContextGetDeviceType(rootContext, &dtype));
 67:       PetscCall(PetscInfo(rootContext, "Destroying global PetscDeviceContext with device type %s\n", PetscDeviceTypes[dtype]));
 68:       PetscCall(PetscDeviceContextDestroy(&rootContext));
 69:       globalContext  = nullptr;
 70:       rootDeviceType = PETSC_DEVICE_CONTEXT_DEFAULT_DEVICE_TYPE;
 71:       rootStreamType = PETSC_DEVICE_CONTEXT_DEFAULT_STREAM_TYPE;
 72:       PetscFunctionReturn(PETSC_SUCCESS);
 73:     };

 75:     /* this exists purely as a valid device check. */
 76:     PetscCall(PetscDeviceInitializePackage());
 77:     PetscCall(PetscRegisterFinalize(std::move(finalizer)));
 78:     PetscCall(PetscDeviceContextCreate(&globalContext));
 79:     rootContext = globalContext;
 80:     PetscCall(PetscInfo(globalContext, "Initializing global PetscDeviceContext with device type %s\n", PetscDeviceTypes[dtype]));
 81:     pobj = PetscObjectCast(globalContext);
 82:     PetscCall(PetscObjectSetName(pobj, "global root"));
 83:     PetscCall(PetscObjectSetOptionsPrefix(pobj, "root_"));
 84:     PetscCall(PetscDeviceContextSetStreamType(globalContext, rootStreamType));
 85:     PetscCall(PetscDeviceContextSetDefaultDeviceForType_Internal(globalContext, dtype));
 86:     PetscCall(PetscDeviceContextSetUp(globalContext));
 87:     PetscCall(PetscSetDefaultCUPMStreamFromDeviceContext(globalContext, dtype));
 88:   }
 89:   PetscFunctionReturn(PETSC_SUCCESS);
 90: }

 92: /*@
 93:   PetscDeviceContextGetCurrentContext - Get the current active `PetscDeviceContext`

 95:   Not Collective

 97:   Output Parameter:
 98: . dctx - The `PetscDeviceContext`

100:   Notes:
101:   The user generally should not destroy contexts retrieved with this routine unless they
102:   themselves have created them. There exists no protection against destroying the root
103:   context.

105:   Developer Notes:
106:   Unless the user has set their own, this routine creates the "root" context the first time it
107:   is called, registering its destructor to `PetscFinalize()`.

109:   Level: beginner

111: .seealso: `PetscDeviceContextSetCurrentContext()`, `PetscDeviceContextFork()`,
112:           `PetscDeviceContextJoin()`, `PetscDeviceContextCreate()`
113: @*/
114: PetscErrorCode PetscDeviceContextGetCurrentContext(PetscDeviceContext *dctx)
115: {
116:   PetscFunctionBegin;
117:   PetscAssertPointer(dctx, 1);
118:   PetscCall(PetscDeviceContextSetupGlobalContext_Private());
119:   /* while the static analyzer can find global variables, it will throw a warning about not
120:    * being able to connect this back to the function arguments */
122:   *dctx = globalContext;
123:   PetscFunctionReturn(PETSC_SUCCESS);
124: }

126: /*@
127:   PetscDeviceContextSetCurrentContext - Set the current active `PetscDeviceContext`

129:   Not Collective

131:   Input Parameter:
132: . dctx - The `PetscDeviceContext`

134:   Notes:
135:   This routine can be used to set the defacto "root" `PetscDeviceContext` to a user-defined
136:   implementation by calling this routine immediately after `PetscInitialize()` and ensuring that
137:   `PetscDevice` is not greedily initialized. In this case the user is responsible for destroying
138:   their `PetscDeviceContext` before `PetscFinalize()` returns.

140:   The old context is not stored in any way by this routine; if one is overriding a context that
141:   they themselves do not control, one should take care to temporarily store it by calling
142:   `PetscDeviceContextGetCurrentContext()` before calling this routine.

144:   Level: beginner

146: .seealso: `PetscDeviceContextGetCurrentContext()`, `PetscDeviceContextFork()`,
147:           `PetscDeviceContextJoin()`, `PetscDeviceContextCreate()`
148: @*/
149: PetscErrorCode PetscDeviceContextSetCurrentContext(PetscDeviceContext dctx)
150: {
151:   PetscDeviceType dtype;

153:   PetscFunctionBegin;
154:   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
155:   PetscAssert(dctx->setup, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "PetscDeviceContext %" PetscInt64_FMT " must be set up before being set as global context", PetscObjectCast(dctx)->id);
156:   PetscCall(PetscDeviceContextGetDeviceType(dctx, &dtype));
157:   PetscCall(PetscDeviceSetDefaultDeviceType(dtype));
158:   globalContext = dctx;
159:   PetscCall(PetscInfo(dctx, "Set global PetscDeviceContext id %" PetscInt64_FMT "\n", PetscObjectCast(dctx)->id));
160:   PetscCall(PetscSetDefaultCUPMStreamFromDeviceContext(globalContext, dtype));
161:   PetscFunctionReturn(PETSC_SUCCESS);
162: }