xref: /petsc/src/sys/objects/device/interface/dcontext.cxx (revision 10450e9e44b354a0a3da7bbd573407bdf051df10)
10e6b6b59SJacob Faibussowitsch #include "petscdevice_interface_internal.hpp" /*I <petscdevice.h> I*/
20e6b6b59SJacob Faibussowitsch #include <petsc/private/viewerimpl.h>         // _p_PetscViewer for PetscObjectCast()
3030f984aSJacob Faibussowitsch 
40e6b6b59SJacob Faibussowitsch #include <petsc/private/cpp/object_pool.hpp>
50e6b6b59SJacob Faibussowitsch #include <petsc/private/cpp/utility.hpp>
60e6b6b59SJacob Faibussowitsch #include <petsc/private/cpp/array.hpp>
7a4af0ceeSJacob Faibussowitsch 
80e6b6b59SJacob Faibussowitsch #include <vector>
90e6b6b59SJacob Faibussowitsch #include <string> // std::to_string among other things
10a4af0ceeSJacob Faibussowitsch 
11030f984aSJacob Faibussowitsch /* Define the allocator */
12146a86ebSJacob Faibussowitsch class PetscDeviceContextConstructor : public Petsc::ConstructorInterface<_p_PetscDeviceContext, PetscDeviceContextConstructor> {
130e6b6b59SJacob Faibussowitsch public:
14089fb57cSJacob Faibussowitsch   PetscErrorCode construct_(PetscDeviceContext dctx) const noexcept
15d71ae5a4SJacob Faibussowitsch   {
16030f984aSJacob Faibussowitsch     PetscFunctionBegin;
17146a86ebSJacob Faibussowitsch     PetscCall(PetscArrayzero(dctx, 1));
18146a86ebSJacob Faibussowitsch     PetscCall(PetscHeaderInitialize_Private(dctx, PETSC_DEVICE_CONTEXT_CLASSID, "PetscDeviceContext", "PetscDeviceContext", "Sys", PETSC_COMM_SELF, PetscDeviceContextDestroy, PetscDeviceContextView));
19146a86ebSJacob Faibussowitsch     PetscCallCXX(PetscObjectCast(dctx)->cpp = new CxxData());
20146a86ebSJacob Faibussowitsch     PetscCall(underlying().reset(dctx, false));
213ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
22030f984aSJacob Faibussowitsch   }
23030f984aSJacob Faibussowitsch 
24089fb57cSJacob Faibussowitsch   static PetscErrorCode destroy_(PetscDeviceContext dctx) noexcept
25d71ae5a4SJacob Faibussowitsch   {
26030f984aSJacob Faibussowitsch     PetscFunctionBegin;
27bf025ffbSJacob Faibussowitsch     PetscAssert(!dctx->numChildren, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Device context still has %" PetscInt_FMT " un-joined children, must call PetscDeviceContextJoin() with all children before destroying", dctx->numChildren);
28dbbe0bcdSBarry Smith     PetscTryTypeMethod(dctx, destroy);
299566063dSJacob Faibussowitsch     PetscCall(PetscDeviceDestroy(&dctx->device));
309566063dSJacob Faibussowitsch     PetscCall(PetscFree(dctx->childIDs));
310e6b6b59SJacob Faibussowitsch     delete CxxDataCast(dctx);
32146a86ebSJacob Faibussowitsch     PetscCall(PetscHeaderDestroy_Private(PetscObjectCast(dctx), PETSC_FALSE));
333ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
34030f984aSJacob Faibussowitsch   }
35030f984aSJacob Faibussowitsch 
36089fb57cSJacob Faibussowitsch   static PetscErrorCode reset_(PetscDeviceContext dctx, bool zero = true) noexcept
37d71ae5a4SJacob Faibussowitsch   {
38030f984aSJacob Faibussowitsch     PetscFunctionBegin;
390e6b6b59SJacob Faibussowitsch     if (zero) {
400e6b6b59SJacob Faibussowitsch       // reset the device if the user set it
41146a86ebSJacob Faibussowitsch       if (Petsc::util::exchange(dctx->usersetdevice, PETSC_FALSE)) {
420e6b6b59SJacob Faibussowitsch         PetscTryTypeMethod(dctx, destroy);
430e6b6b59SJacob Faibussowitsch         PetscCall(PetscDeviceDestroy(&dctx->device));
440e6b6b59SJacob Faibussowitsch         PetscCall(PetscArrayzero(dctx->ops, 1));
450e6b6b59SJacob Faibussowitsch         dctx->data = nullptr;
460e6b6b59SJacob Faibussowitsch       }
470e6b6b59SJacob Faibussowitsch       PetscCall(PetscHeaderReset_Internal(PetscObjectCast(dctx)));
48030f984aSJacob Faibussowitsch       dctx->numChildren = 0;
490e6b6b59SJacob Faibussowitsch       dctx->setup       = PETSC_FALSE;
500e6b6b59SJacob Faibussowitsch       // don't deallocate the child array, rather just zero it out
510e6b6b59SJacob Faibussowitsch       PetscCall(PetscArrayzero(dctx->childIDs, dctx->maxNumChildren));
520e6b6b59SJacob Faibussowitsch       PetscCall(CxxDataCast(dctx)->clear());
530e6b6b59SJacob Faibussowitsch     }
54030f984aSJacob Faibussowitsch     dctx->streamType = PETSC_STREAM_DEFAULT_BLOCKING;
553ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
56030f984aSJacob Faibussowitsch   }
57146a86ebSJacob Faibussowitsch 
58089fb57cSJacob Faibussowitsch   static PetscErrorCode invalidate_(PetscDeviceContext) noexcept { return PETSC_SUCCESS; }
59030f984aSJacob Faibussowitsch };
60030f984aSJacob Faibussowitsch 
61146a86ebSJacob Faibussowitsch static Petsc::ObjectPool<_p_PetscDeviceContext, PetscDeviceContextConstructor> contextPool;
62030f984aSJacob Faibussowitsch 
63*10450e9eSJacob Faibussowitsch // PetscClangLinter pragma disable: -fdoc-section-header-unknown
64030f984aSJacob Faibussowitsch /*@C
65811af0c4SBarry Smith   PetscDeviceContextCreate - Creates a `PetscDeviceContext`
66030f984aSJacob Faibussowitsch 
670e6b6b59SJacob Faibussowitsch   Not Collective
68030f984aSJacob Faibussowitsch 
69d5b43468SJose E. Roman   Output Parameter:
70811af0c4SBarry Smith . dctx - The `PetscDeviceContext`
71030f984aSJacob Faibussowitsch 
722fe279fdSBarry Smith   Level: beginner
732fe279fdSBarry Smith 
74811af0c4SBarry Smith   Note:
75030f984aSJacob Faibussowitsch   Unlike almost every other PETSc class it is advised that most users use
760e6b6b59SJacob Faibussowitsch   `PetscDeviceContextDuplicate()` rather than this routine to create new contexts. Contexts of
770e6b6b59SJacob Faibussowitsch   different types are incompatible with one another; using `PetscDeviceContextDuplicate()`
780e6b6b59SJacob Faibussowitsch   ensures compatible types.
790e6b6b59SJacob Faibussowitsch 
800e6b6b59SJacob Faibussowitsch   DAG representation:
810e6b6b59SJacob Faibussowitsch .vb
820e6b6b59SJacob Faibussowitsch   time ->
830e6b6b59SJacob Faibussowitsch 
840e6b6b59SJacob Faibussowitsch   |= CALL =| - dctx ->
850e6b6b59SJacob Faibussowitsch .ve
86030f984aSJacob Faibussowitsch 
870e6b6b59SJacob Faibussowitsch .N ASYNC_API
880e6b6b59SJacob Faibussowitsch 
89db781477SPatrick Sanan .seealso: `PetscDeviceContextDuplicate()`, `PetscDeviceContextSetDevice()`,
90db781477SPatrick Sanan `PetscDeviceContextSetStreamType()`, `PetscDeviceContextSetUp()`,
910e6b6b59SJacob Faibussowitsch `PetscDeviceContextSetFromOptions()`, `PetscDeviceContextView()`, `PetscDeviceContextDestroy()`
92030f984aSJacob Faibussowitsch @*/
93d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextCreate(PetscDeviceContext *dctx)
94d71ae5a4SJacob Faibussowitsch {
95030f984aSJacob Faibussowitsch   PetscFunctionBegin;
96030f984aSJacob Faibussowitsch   PetscValidPointer(dctx, 1);
979566063dSJacob Faibussowitsch   PetscCall(PetscDeviceInitializePackage());
986a4a1270SPierre Jolivet   PetscCall(PetscLogEventBegin(DCONTEXT_Create, nullptr, nullptr, nullptr, nullptr));
990e6b6b59SJacob Faibussowitsch   PetscCall(contextPool.allocate(dctx));
1006a4a1270SPierre Jolivet   PetscCall(PetscLogEventEnd(DCONTEXT_Create, nullptr, nullptr, nullptr, nullptr));
1013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
102030f984aSJacob Faibussowitsch }
103030f984aSJacob Faibussowitsch 
104*10450e9eSJacob Faibussowitsch // PetscClangLinter pragma disable: -fdoc-section-header-unknown
105030f984aSJacob Faibussowitsch /*@C
106811af0c4SBarry Smith   PetscDeviceContextDestroy - Frees a `PetscDeviceContext`
107030f984aSJacob Faibussowitsch 
1080e6b6b59SJacob Faibussowitsch   Not Collective
109030f984aSJacob Faibussowitsch 
1102fe279fdSBarry Smith   Input Parameter:
111811af0c4SBarry Smith . dctx - The `PetscDeviceContext`
112030f984aSJacob Faibussowitsch 
1132fe279fdSBarry Smith   Level: beginner
1142fe279fdSBarry Smith 
1150e6b6b59SJacob Faibussowitsch   Notes:
1160e6b6b59SJacob Faibussowitsch   No implicit synchronization occurs due to this routine, all resources are released completely
1170e6b6b59SJacob Faibussowitsch   asynchronously w.r.t. the host. If one needs to guarantee access to the data produced on
1180e6b6b59SJacob Faibussowitsch   `dctx`'s stream the user is responsible for calling `PetscDeviceContextSynchronize()` before
1190e6b6b59SJacob Faibussowitsch   calling this routine.
120030f984aSJacob Faibussowitsch 
121da81f932SPierre Jolivet   DAG representation:
1220e6b6b59SJacob Faibussowitsch .vb
1230e6b6b59SJacob Faibussowitsch   time ->
1240e6b6b59SJacob Faibussowitsch 
1250e6b6b59SJacob Faibussowitsch   -> dctx - |= CALL =|
1260e6b6b59SJacob Faibussowitsch .ve
1270e6b6b59SJacob Faibussowitsch 
1280e6b6b59SJacob Faibussowitsch   Developer Notes:
1290e6b6b59SJacob Faibussowitsch   `dctx` is never actually "destroyed" in the classical sense. It is returned to an ever
1300e6b6b59SJacob Faibussowitsch   growing pool of `PetscDeviceContext`s. There are currently no limits on the size of the pool,
1310e6b6b59SJacob Faibussowitsch   this should perhaps be implemented.
132030f984aSJacob Faibussowitsch 
1330e6b6b59SJacob Faibussowitsch .N ASYNC_API
1340e6b6b59SJacob Faibussowitsch 
1350e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextSetDevice()`,
1360e6b6b59SJacob Faibussowitsch `PetscDeviceContextSetUp()`, `PetscDeviceContextSynchronize()`
137030f984aSJacob Faibussowitsch @*/
138d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextDestroy(PetscDeviceContext *dctx)
139d71ae5a4SJacob Faibussowitsch {
140030f984aSJacob Faibussowitsch   PetscFunctionBegin;
1410e6b6b59SJacob Faibussowitsch   PetscValidPointer(dctx, 1);
1423ba16761SJacob Faibussowitsch   if (!*dctx) PetscFunctionReturn(PETSC_SUCCESS);
1436a4a1270SPierre Jolivet   PetscCall(PetscLogEventBegin(DCONTEXT_Destroy, nullptr, nullptr, nullptr, nullptr));
1440e6b6b59SJacob Faibussowitsch   if (--(PetscObjectCast(*dctx)->refct) <= 0) {
1450e6b6b59SJacob Faibussowitsch     PetscCall(PetscDeviceContextCheckNotOrphaned_Internal(*dctx));
146146a86ebSJacob Faibussowitsch     PetscCall(contextPool.deallocate(dctx));
1470e6b6b59SJacob Faibussowitsch   }
1486a4a1270SPierre Jolivet   PetscCall(PetscLogEventEnd(DCONTEXT_Destroy, nullptr, nullptr, nullptr, nullptr));
149bf025ffbSJacob Faibussowitsch   *dctx = nullptr;
1503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
151030f984aSJacob Faibussowitsch }
152030f984aSJacob Faibussowitsch 
153030f984aSJacob Faibussowitsch /*@C
1540e6b6b59SJacob Faibussowitsch   PetscDeviceContextSetStreamType - Set the implementation type of the underlying stream for a
1550e6b6b59SJacob Faibussowitsch   `PetscDeviceContext`
156030f984aSJacob Faibussowitsch 
1570e6b6b59SJacob Faibussowitsch   Not Collective
158030f984aSJacob Faibussowitsch 
15901d2d390SJose E. Roman   Input Parameters:
160811af0c4SBarry Smith + dctx - The `PetscDeviceContext`
161811af0c4SBarry Smith - type - The `PetscStreamType`
162030f984aSJacob Faibussowitsch 
1632fe279fdSBarry Smith   Level: beginner
1642fe279fdSBarry Smith 
1652fe279fdSBarry Smith   Note:
166811af0c4SBarry Smith   See `PetscStreamType` in `include/petscdevicetypes.h` for more information on the available
1670e6b6b59SJacob Faibussowitsch   types and their interactions. If the `PetscDeviceContext` was previously set up and stream
168811af0c4SBarry Smith   type was changed, you must call `PetscDeviceContextSetUp()` again after this routine.
169030f984aSJacob Faibussowitsch 
1700e6b6b59SJacob Faibussowitsch .seealso: `PetscStreamType`, `PetscDeviceContextGetStreamType()`, `PetscDeviceContextCreate()`,
1710e6b6b59SJacob Faibussowitsch `PetscDeviceContextSetUp()`, `PetscDeviceContextSetFromOptions()`
172030f984aSJacob Faibussowitsch @*/
173d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetStreamType(PetscDeviceContext dctx, PetscStreamType type)
174d71ae5a4SJacob Faibussowitsch {
175030f984aSJacob Faibussowitsch   PetscFunctionBegin;
1760e6b6b59SJacob Faibussowitsch   // do not use getoptionalnullcontext here since we do not want the user to change the stream
1770e6b6b59SJacob Faibussowitsch   // type
178030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx, 1);
179030f984aSJacob Faibussowitsch   PetscValidStreamType(type, 2);
1800e6b6b59SJacob Faibussowitsch   // only need to do complex swapping if the object has already been setup
181030f984aSJacob Faibussowitsch   if (dctx->setup && (dctx->streamType != type)) {
182030f984aSJacob Faibussowitsch     dctx->setup = PETSC_FALSE;
1836a4a1270SPierre Jolivet     PetscCall(PetscLogEventBegin(DCONTEXT_ChangeStream, dctx, nullptr, nullptr, nullptr));
1840e6b6b59SJacob Faibussowitsch     PetscUseTypeMethod(dctx, changestreamtype, type);
1856a4a1270SPierre Jolivet     PetscCall(PetscLogEventEnd(DCONTEXT_ChangeStream, dctx, nullptr, nullptr, nullptr));
186030f984aSJacob Faibussowitsch   }
187030f984aSJacob Faibussowitsch   dctx->streamType = type;
1883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
189030f984aSJacob Faibussowitsch }
190030f984aSJacob Faibussowitsch 
191030f984aSJacob Faibussowitsch /*@C
1920e6b6b59SJacob Faibussowitsch   PetscDeviceContextGetStreamType - Get the implementation type of the underlying stream for a
1930e6b6b59SJacob Faibussowitsch   `PetscDeviceContext`
194030f984aSJacob Faibussowitsch 
1950e6b6b59SJacob Faibussowitsch   Not Collective
196030f984aSJacob Faibussowitsch 
19701d2d390SJose E. Roman   Input Parameter:
198811af0c4SBarry Smith . dctx - The `PetscDeviceContext`
199030f984aSJacob Faibussowitsch 
200030f984aSJacob Faibussowitsch   Output Parameter:
201811af0c4SBarry Smith . type - The `PetscStreamType`
202030f984aSJacob Faibussowitsch 
2032fe279fdSBarry Smith   Level: beginner
2042fe279fdSBarry Smith 
2052fe279fdSBarry Smith   Note:
2060e6b6b59SJacob Faibussowitsch   See `PetscStreamType` in `include/petscdevicetypes.h` for more information on the available
2070e6b6b59SJacob Faibussowitsch   types and their interactions
208030f984aSJacob Faibussowitsch 
2090e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextSetStreamType()`, `PetscDeviceContextCreate()`,
2100e6b6b59SJacob Faibussowitsch `PetscDeviceContextSetFromOptions()`
211030f984aSJacob Faibussowitsch @*/
212d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextGetStreamType(PetscDeviceContext dctx, PetscStreamType *type)
213d71ae5a4SJacob Faibussowitsch {
214030f984aSJacob Faibussowitsch   PetscFunctionBegin;
2150e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
216030f984aSJacob Faibussowitsch   PetscValidIntPointer(type, 2);
217030f984aSJacob Faibussowitsch   *type = dctx->streamType;
2183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
219030f984aSJacob Faibussowitsch }
220030f984aSJacob Faibussowitsch 
2210e6b6b59SJacob Faibussowitsch /*
2220e6b6b59SJacob Faibussowitsch   Actual function to set the device.
223030f984aSJacob Faibussowitsch 
2240e6b6b59SJacob Faibussowitsch   1. Repeatedly destroying and recreating internal data structures (like streams and events)
2250e6b6b59SJacob Faibussowitsch      for recycled PetscDeviceContexts is not free. If done often, it does add up.
2260e6b6b59SJacob Faibussowitsch   2. The vast majority of PetscDeviceContexts are created by PETSc either as children or
22735cb6cd3SPierre Jolivet      default contexts. The default contexts *never* change type, and the children are extremely
2280e6b6b59SJacob Faibussowitsch      unlikely to (chances are if you fork once, you will fork again very soon).
2290e6b6b59SJacob Faibussowitsch   3. The only time this calculus changes is if the user themselves sets the device type. In
2300e6b6b59SJacob Faibussowitsch      this case we do not know what the user has changed, so must always wipe the slate clean.
2310e6b6b59SJacob Faibussowitsch 
2320e6b6b59SJacob Faibussowitsch   Thus we need to keep track whether the user explicitly sets the device contexts device.
2330e6b6b59SJacob Faibussowitsch */
234d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDeviceContextSetDevice_Private(PetscDeviceContext dctx, PetscDevice device, PetscBool user_set)
235d71ae5a4SJacob Faibussowitsch {
2360e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
2370e6b6b59SJacob Faibussowitsch   // do not use getoptionalnullcontext here since we do not want the user to change its device
2380e6b6b59SJacob Faibussowitsch   PetscValidDeviceContext(dctx, 1);
2390e6b6b59SJacob Faibussowitsch   PetscValidDevice(device, 2);
2403ba16761SJacob Faibussowitsch   if (dctx->device && (dctx->device->id == device->id)) PetscFunctionReturn(PETSC_SUCCESS);
2416a4a1270SPierre Jolivet   PetscCall(PetscLogEventBegin(DCONTEXT_SetDevice, dctx, nullptr, nullptr, nullptr));
2422126a61dSJacob Faibussowitsch   PetscTryTypeMethod(dctx, destroy);
2430e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceDestroy(&dctx->device));
2440e6b6b59SJacob Faibussowitsch   PetscCall(PetscMemzero(dctx->ops, sizeof(*dctx->ops)));
2452126a61dSJacob Faibussowitsch   PetscCall(PetscDeviceReference_Internal(device));
2462126a61dSJacob Faibussowitsch   // set it before calling the method
2472126a61dSJacob Faibussowitsch   dctx->device = device;
2480e6b6b59SJacob Faibussowitsch   PetscCall((*device->ops->createcontext)(dctx));
2496a4a1270SPierre Jolivet   PetscCall(PetscLogEventEnd(DCONTEXT_SetDevice, dctx, nullptr, nullptr, nullptr));
2500e6b6b59SJacob Faibussowitsch   dctx->setup         = PETSC_FALSE;
2510e6b6b59SJacob Faibussowitsch   dctx->usersetdevice = user_set;
2523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2530e6b6b59SJacob Faibussowitsch }
2540e6b6b59SJacob Faibussowitsch 
255d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetDefaultDeviceForType_Internal(PetscDeviceContext dctx, PetscDeviceType type)
256d71ae5a4SJacob Faibussowitsch {
2570e6b6b59SJacob Faibussowitsch   PetscDevice device;
2580e6b6b59SJacob Faibussowitsch 
2590e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
2600e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceGetDefaultForType_Internal(type, &device));
2610e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextSetDevice_Private(dctx, device, PETSC_FALSE));
2623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2630e6b6b59SJacob Faibussowitsch }
2640e6b6b59SJacob Faibussowitsch 
2650e6b6b59SJacob Faibussowitsch /*@C
2660e6b6b59SJacob Faibussowitsch   PetscDeviceContextSetDevice - Set the underlying `PetscDevice` for a `PetscDeviceContext`
2670e6b6b59SJacob Faibussowitsch 
2680e6b6b59SJacob Faibussowitsch   Not Collective
269030f984aSJacob Faibussowitsch 
27001d2d390SJose E. Roman   Input Parameters:
271811af0c4SBarry Smith + dctx   - The `PetscDeviceContext`
272811af0c4SBarry Smith - device - The `PetscDevice`
273030f984aSJacob Faibussowitsch 
2742fe279fdSBarry Smith   Level: intermediate
2752fe279fdSBarry Smith 
276030f984aSJacob Faibussowitsch   Notes:
2770e6b6b59SJacob Faibussowitsch   This routine is effectively `PetscDeviceContext`'s "set-type" (so every `PetscDeviceContext` must
278da81f932SPierre Jolivet   also have an attached `PetscDevice`). Unlike the usual set-type semantics, it is not strictly
2790e6b6b59SJacob Faibussowitsch   necessary to set a contexts device to enable usage, any created `PetscDeviceContext`s will
2800e6b6b59SJacob Faibussowitsch   always come equipped with the "default" device.
281030f984aSJacob Faibussowitsch 
2820e6b6b59SJacob Faibussowitsch   This routine is a no-op if `device` is already attached to `dctx`.
283a4af0ceeSJacob Faibussowitsch 
2840e6b6b59SJacob Faibussowitsch   This routine may (but is very unlikely to) initialize the backend device and may incur
2850e6b6b59SJacob Faibussowitsch   synchronization.
2865181c4f9SJacob Faibussowitsch 
2870e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceCreate()`, `PetscDeviceConfigure()`, `PetscDeviceContextGetDevice()`,
2880e6b6b59SJacob Faibussowitsch `PetscDeviceContextGetDeviceType()`
289030f984aSJacob Faibussowitsch @*/
290d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetDevice(PetscDeviceContext dctx, PetscDevice device)
291d71ae5a4SJacob Faibussowitsch {
292030f984aSJacob Faibussowitsch   PetscFunctionBegin;
2930e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextSetDevice_Private(dctx, device, PETSC_TRUE));
2943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
295030f984aSJacob Faibussowitsch }
296030f984aSJacob Faibussowitsch 
297030f984aSJacob Faibussowitsch /*@C
298811af0c4SBarry Smith   PetscDeviceContextGetDevice - Get the underlying `PetscDevice` for a `PetscDeviceContext`
299030f984aSJacob Faibussowitsch 
3000e6b6b59SJacob Faibussowitsch   Not Collective
301030f984aSJacob Faibussowitsch 
302030f984aSJacob Faibussowitsch   Input Parameter:
303811af0c4SBarry Smith . dctx - the `PetscDeviceContext`
304030f984aSJacob Faibussowitsch 
305030f984aSJacob Faibussowitsch   Output Parameter:
306811af0c4SBarry Smith . device - The `PetscDevice`
307030f984aSJacob Faibussowitsch 
308a375dbeeSPatrick Sanan   Level: intermediate
309a375dbeeSPatrick Sanan 
3102fe279fdSBarry Smith   Note:
3112fe279fdSBarry Smith   This is a borrowed reference, the user should not destroy `device`.
3122fe279fdSBarry Smith 
3130e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextSetDevice()`, `PetscDevice`, `PetscDeviceContextGetDeviceType()`
314030f984aSJacob Faibussowitsch @*/
315d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextGetDevice(PetscDeviceContext dctx, PetscDevice *device)
316d71ae5a4SJacob Faibussowitsch {
317030f984aSJacob Faibussowitsch   PetscFunctionBegin;
3180e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
319030f984aSJacob Faibussowitsch   PetscValidPointer(device, 2);
3200e6b6b59SJacob Faibussowitsch   PetscAssert(dctx->device, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "PetscDeviceContext %" PetscInt64_FMT " has no attached PetscDevice to get", PetscObjectCast(dctx)->id);
321030f984aSJacob Faibussowitsch   *device = dctx->device;
3223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
323030f984aSJacob Faibussowitsch }
324030f984aSJacob Faibussowitsch 
325030f984aSJacob Faibussowitsch /*@C
3260e6b6b59SJacob Faibussowitsch   PetscDeviceContextGetDeviceType - Get the `PetscDeviceType` for a `PetscDeviceContext`
3270e6b6b59SJacob Faibussowitsch 
3280e6b6b59SJacob Faibussowitsch   Not Collective
3290e6b6b59SJacob Faibussowitsch 
3300e6b6b59SJacob Faibussowitsch   Input Parameter:
3310e6b6b59SJacob Faibussowitsch . dctx - The `PetscDeviceContext`
3320e6b6b59SJacob Faibussowitsch 
3330e6b6b59SJacob Faibussowitsch   Output Parameter:
3340e6b6b59SJacob Faibussowitsch . type - The `PetscDeviceType`
3350e6b6b59SJacob Faibussowitsch 
3362fe279fdSBarry Smith   Level: beginner
3372fe279fdSBarry Smith 
3382fe279fdSBarry Smith   Note:
3390e6b6b59SJacob Faibussowitsch   This routine is a convenience shorthand for `PetscDeviceContextGetDevice()` ->
3400e6b6b59SJacob Faibussowitsch   `PetscDeviceGetType()`.
3410e6b6b59SJacob Faibussowitsch 
3420e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceType`, `PetscDeviceContextGetDevice()`, `PetscDeviceGetType()`, `PetscDevice`
3430e6b6b59SJacob Faibussowitsch @*/
344d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextGetDeviceType(PetscDeviceContext dctx, PetscDeviceType *type)
345d71ae5a4SJacob Faibussowitsch {
3460e6b6b59SJacob Faibussowitsch   PetscDevice device = nullptr;
3470e6b6b59SJacob Faibussowitsch 
3480e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
3490e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
3500e6b6b59SJacob Faibussowitsch   PetscValidPointer(type, 2);
3510e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetDevice(dctx, &device));
3520e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceGetType(device, type));
3533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3540e6b6b59SJacob Faibussowitsch }
3550e6b6b59SJacob Faibussowitsch 
3560e6b6b59SJacob Faibussowitsch /*@C
357811af0c4SBarry Smith   PetscDeviceContextSetUp - Prepares a `PetscDeviceContext` for use
358030f984aSJacob Faibussowitsch 
3590e6b6b59SJacob Faibussowitsch   Not Collective
360030f984aSJacob Faibussowitsch 
36101d2d390SJose E. Roman   Input Parameter:
362811af0c4SBarry Smith . dctx - The `PetscDeviceContext`
363030f984aSJacob Faibussowitsch 
3642fe279fdSBarry Smith   Level: beginner
3652fe279fdSBarry Smith 
366aec76313SJacob Faibussowitsch   Developer Notes:
3670e6b6b59SJacob Faibussowitsch   This routine is usually the stage where a `PetscDeviceContext` acquires device-side data
3680e6b6b59SJacob Faibussowitsch   structures such as streams, events, and (possibly) handles.
369030f984aSJacob Faibussowitsch 
3700e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextSetDevice()`,
3710e6b6b59SJacob Faibussowitsch `PetscDeviceContextDestroy()`, `PetscDeviceContextSetFromOptions()`
372030f984aSJacob Faibussowitsch @*/
373d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetUp(PetscDeviceContext dctx)
374d71ae5a4SJacob Faibussowitsch {
375030f984aSJacob Faibussowitsch   PetscFunctionBegin;
3760e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
3773ba16761SJacob Faibussowitsch   if (dctx->setup) PetscFunctionReturn(PETSC_SUCCESS);
3780e6b6b59SJacob Faibussowitsch   if (!dctx->device) {
3790e6b6b59SJacob Faibussowitsch     const auto default_dtype = PETSC_DEVICE_DEFAULT();
3800e6b6b59SJacob Faibussowitsch 
3810e6b6b59SJacob Faibussowitsch     PetscCall(PetscInfo(dctx, "PetscDeviceContext %" PetscInt64_FMT " did not have an explicitly attached PetscDevice, using default with type %s\n", PetscObjectCast(dctx)->id, PetscDeviceTypes[default_dtype]));
3820e6b6b59SJacob Faibussowitsch     PetscCall(PetscDeviceContextSetDefaultDeviceForType_Internal(dctx, default_dtype));
3830e6b6b59SJacob Faibussowitsch   }
3846a4a1270SPierre Jolivet   PetscCall(PetscLogEventBegin(DCONTEXT_SetUp, dctx, nullptr, nullptr, nullptr));
385dbbe0bcdSBarry Smith   PetscUseTypeMethod(dctx, setup);
3866a4a1270SPierre Jolivet   PetscCall(PetscLogEventEnd(DCONTEXT_SetUp, dctx, nullptr, nullptr, nullptr));
387030f984aSJacob Faibussowitsch   dctx->setup = PETSC_TRUE;
3883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
389030f984aSJacob Faibussowitsch }
390030f984aSJacob Faibussowitsch 
391d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDeviceContextDuplicate_Private(PetscDeviceContext dctx, PetscStreamType stype, PetscDeviceContext *dctxdup)
392d71ae5a4SJacob Faibussowitsch {
3930e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
3946a4a1270SPierre Jolivet   PetscCall(PetscLogEventBegin(DCONTEXT_Duplicate, dctx, nullptr, nullptr, nullptr));
3950e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextCreate(dctxdup));
3960e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextSetStreamType(*dctxdup, stype));
3970e6b6b59SJacob Faibussowitsch   if (const auto device = dctx->device) PetscCall(PetscDeviceContextSetDevice_Private(*dctxdup, device, dctx->usersetdevice));
3980e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextSetUp(*dctxdup));
3996a4a1270SPierre Jolivet   PetscCall(PetscLogEventEnd(DCONTEXT_Duplicate, dctx, nullptr, nullptr, nullptr));
4003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4010e6b6b59SJacob Faibussowitsch }
4020e6b6b59SJacob Faibussowitsch 
403*10450e9eSJacob Faibussowitsch // PetscClangLinter pragma disable: -fdoc-section-header-unknown
404030f984aSJacob Faibussowitsch /*@C
405811af0c4SBarry Smith   PetscDeviceContextDuplicate - Duplicates a `PetscDeviceContext` object
406030f984aSJacob Faibussowitsch 
4070e6b6b59SJacob Faibussowitsch   Not Collective
408030f984aSJacob Faibussowitsch 
409030f984aSJacob Faibussowitsch   Input Parameter:
410811af0c4SBarry Smith . dctx - The `PetscDeviceContext` to duplicate
411030f984aSJacob Faibussowitsch 
4126aad120cSJose E. Roman   Output Parameter:
413811af0c4SBarry Smith . dctxdup - The duplicated `PetscDeviceContext`
414030f984aSJacob Faibussowitsch 
4152fe279fdSBarry Smith   Level: beginner
4162fe279fdSBarry Smith 
4170e6b6b59SJacob Faibussowitsch   Notes:
4180e6b6b59SJacob Faibussowitsch   This is a shorthand method for creating a `PetscDeviceContext` with the exact same settings as
4190e6b6b59SJacob Faibussowitsch   another. Note however that `dctxdup` does not share any of the underlying data with `dctx`,
4200e6b6b59SJacob Faibussowitsch   (including its current stream-state) they are completely separate objects.
4210e6b6b59SJacob Faibussowitsch 
4220e6b6b59SJacob Faibussowitsch   There is no implied ordering between `dctx` or `dctxdup`.
4230e6b6b59SJacob Faibussowitsch 
4240e6b6b59SJacob Faibussowitsch   DAG representation:
4250e6b6b59SJacob Faibussowitsch .vb
4260e6b6b59SJacob Faibussowitsch   time ->
4270e6b6b59SJacob Faibussowitsch 
4280e6b6b59SJacob Faibussowitsch   -> dctx - |= CALL =| - dctx ---->
4290e6b6b59SJacob Faibussowitsch                        - dctxdup ->
4300e6b6b59SJacob Faibussowitsch .ve
431030f984aSJacob Faibussowitsch 
4320e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextSetDevice()`,
4330e6b6b59SJacob Faibussowitsch `PetscDeviceContextSetStreamType()`
434030f984aSJacob Faibussowitsch @*/
435d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextDuplicate(PetscDeviceContext dctx, PetscDeviceContext *dctxdup)
436d71ae5a4SJacob Faibussowitsch {
4370e6b6b59SJacob Faibussowitsch   auto stype = PETSC_STREAM_DEFAULT_BLOCKING;
438030f984aSJacob Faibussowitsch 
439030f984aSJacob Faibussowitsch   PetscFunctionBegin;
4400e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
441030f984aSJacob Faibussowitsch   PetscValidPointer(dctxdup, 2);
4420e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetStreamType(dctx, &stype));
4430e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextDuplicate_Private(dctx, stype, dctxdup));
4443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
445030f984aSJacob Faibussowitsch }
446030f984aSJacob Faibussowitsch 
447030f984aSJacob Faibussowitsch /*@C
448811af0c4SBarry Smith   PetscDeviceContextQueryIdle - Returns whether or not a `PetscDeviceContext` is idle
449030f984aSJacob Faibussowitsch 
4500e6b6b59SJacob Faibussowitsch   Not Collective
451030f984aSJacob Faibussowitsch 
452030f984aSJacob Faibussowitsch   Input Parameter:
4530e6b6b59SJacob Faibussowitsch . dctx - The `PetscDeviceContext`
454030f984aSJacob Faibussowitsch 
455030f984aSJacob Faibussowitsch   Output Parameter:
4560e6b6b59SJacob Faibussowitsch . idle - `PETSC_TRUE` if `dctx` has NO work, `PETSC_FALSE` if it has work
457030f984aSJacob Faibussowitsch 
4582fe279fdSBarry Smith   Level: intermediate
4592fe279fdSBarry Smith 
460811af0c4SBarry Smith   Note:
461ef657721SJacob Faibussowitsch   This routine only refers a singular context and does NOT take any of its children into
4620e6b6b59SJacob Faibussowitsch   account. That is, if `dctx` is idle but has dependents who do have work this routine still
463811af0c4SBarry Smith   returns `PETSC_TRUE`.
464030f984aSJacob Faibussowitsch 
465db781477SPatrick Sanan .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextWaitForContext()`, `PetscDeviceContextFork()`
466030f984aSJacob Faibussowitsch @*/
467d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextQueryIdle(PetscDeviceContext dctx, PetscBool *idle)
468d71ae5a4SJacob Faibussowitsch {
469030f984aSJacob Faibussowitsch   PetscFunctionBegin;
4700e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
471030f984aSJacob Faibussowitsch   PetscValidBoolPointer(idle, 2);
4726a4a1270SPierre Jolivet   PetscCall(PetscLogEventBegin(DCONTEXT_QueryIdle, dctx, nullptr, nullptr, nullptr));
473dbbe0bcdSBarry Smith   PetscUseTypeMethod(dctx, query, idle);
4746a4a1270SPierre Jolivet   PetscCall(PetscLogEventEnd(DCONTEXT_QueryIdle, dctx, nullptr, nullptr, nullptr));
4750e6b6b59SJacob Faibussowitsch   PetscCall(PetscInfo(dctx, "PetscDeviceContext ('%s', id %" PetscInt64_FMT ") %s idle\n", PetscObjectCast(dctx)->name ? PetscObjectCast(dctx)->name : "unnamed", PetscObjectCast(dctx)->id, *idle ? "was" : "was not"));
4763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
477030f984aSJacob Faibussowitsch }
478030f984aSJacob Faibussowitsch 
479*10450e9eSJacob Faibussowitsch // PetscClangLinter pragma disable: -fdoc-section-header-unknown
480030f984aSJacob Faibussowitsch /*@C
481030f984aSJacob Faibussowitsch   PetscDeviceContextWaitForContext - Make one context wait for another context to finish
482030f984aSJacob Faibussowitsch 
4830e6b6b59SJacob Faibussowitsch   Not Collective
484030f984aSJacob Faibussowitsch 
485030f984aSJacob Faibussowitsch   Input Parameters:
486811af0c4SBarry Smith + dctxa - The `PetscDeviceContext` object that is waiting
487811af0c4SBarry Smith - dctxb - The `PetscDeviceContext` object that is being waited on
488030f984aSJacob Faibussowitsch 
4892fe279fdSBarry Smith   Level: beginner
4902fe279fdSBarry Smith 
491030f984aSJacob Faibussowitsch   Notes:
4920e6b6b59SJacob Faibussowitsch   Serializes two `PetscDeviceContext`s. Serialization is performed asynchronously; the host
4930e6b6b59SJacob Faibussowitsch   does not wait for the serialization to actually occur.
494811af0c4SBarry Smith 
4950e6b6b59SJacob Faibussowitsch   This routine uses only the state of `dctxb` at the moment this routine was called, so any
4960e6b6b59SJacob Faibussowitsch   future work queued will not affect `dctxa`. It is safe to pass the same context to both
4970e6b6b59SJacob Faibussowitsch   arguments (in which case this routine does nothing).
4980e6b6b59SJacob Faibussowitsch 
4990e6b6b59SJacob Faibussowitsch   DAG representation:
5000e6b6b59SJacob Faibussowitsch .vb
5010e6b6b59SJacob Faibussowitsch   time ->
5020e6b6b59SJacob Faibussowitsch 
5030e6b6b59SJacob Faibussowitsch   -> dctxa ---/- |= CALL =| - dctxa ->
5040e6b6b59SJacob Faibussowitsch              /
5050e6b6b59SJacob Faibussowitsch   -> dctxb -/------------------------>
5060e6b6b59SJacob Faibussowitsch .ve
507030f984aSJacob Faibussowitsch 
5080e6b6b59SJacob Faibussowitsch .N ASYNC_API
5090e6b6b59SJacob Faibussowitsch 
510db781477SPatrick Sanan .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextQueryIdle()`, `PetscDeviceContextJoin()`
511030f984aSJacob Faibussowitsch @*/
512d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextWaitForContext(PetscDeviceContext dctxa, PetscDeviceContext dctxb)
513d71ae5a4SJacob Faibussowitsch {
5140e6b6b59SJacob Faibussowitsch   PetscObject aobj;
5150e6b6b59SJacob Faibussowitsch 
516030f984aSJacob Faibussowitsch   PetscFunctionBegin;
5170e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctxa));
5180e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctxb));
519030f984aSJacob Faibussowitsch   PetscCheckCompatibleDeviceContexts(dctxa, 1, dctxb, 2);
5203ba16761SJacob Faibussowitsch   if (dctxa == dctxb) PetscFunctionReturn(PETSC_SUCCESS);
5210e6b6b59SJacob Faibussowitsch   aobj = PetscObjectCast(dctxa);
5226a4a1270SPierre Jolivet   PetscCall(PetscLogEventBegin(DCONTEXT_WaitForCtx, dctxa, dctxb, nullptr, nullptr));
523dbbe0bcdSBarry Smith   PetscUseTypeMethod(dctxa, waitforcontext, dctxb);
5243398534bSJacob Faibussowitsch   PetscCallCXX(CxxDataCast(dctxa)->upstream[dctxb] = CxxDataParent(dctxb));
5256a4a1270SPierre Jolivet   PetscCall(PetscLogEventEnd(DCONTEXT_WaitForCtx, dctxa, dctxb, nullptr, nullptr));
5260e6b6b59SJacob Faibussowitsch   PetscCall(PetscInfo(dctxa, "dctx %" PetscInt64_FMT " waiting on dctx %" PetscInt64_FMT "\n", aobj->id, PetscObjectCast(dctxb)->id));
5270e6b6b59SJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease(aobj));
5283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
529030f984aSJacob Faibussowitsch }
530030f984aSJacob Faibussowitsch 
531*10450e9eSJacob Faibussowitsch // PetscClangLinter pragma disable: -fdoc-section-header-unknown
5320e6b6b59SJacob Faibussowitsch /*@C
5330e6b6b59SJacob Faibussowitsch   PetscDeviceContextForkWithStreamType - Create a set of dependent child contexts from a parent
5340e6b6b59SJacob Faibussowitsch   context with a prescribed `PetscStreamType`
5350e6b6b59SJacob Faibussowitsch 
5360e6b6b59SJacob Faibussowitsch   Not Collective, Asynchronous
5370e6b6b59SJacob Faibussowitsch 
5380e6b6b59SJacob Faibussowitsch   Input Parameters:
5390e6b6b59SJacob Faibussowitsch + dctx  - The parent `PetscDeviceContext`
5400e6b6b59SJacob Faibussowitsch . stype - The prescribed `PetscStreamType`
5410e6b6b59SJacob Faibussowitsch - n     - The number of children to create
5420e6b6b59SJacob Faibussowitsch 
5430e6b6b59SJacob Faibussowitsch   Output Parameter:
5440e6b6b59SJacob Faibussowitsch . dsub - The created child context(s)
5450e6b6b59SJacob Faibussowitsch 
5462fe279fdSBarry Smith   Level: intermediate
5472fe279fdSBarry Smith 
5480e6b6b59SJacob Faibussowitsch   Notes:
5490e6b6b59SJacob Faibussowitsch   This routine creates `n` edges of a DAG from a source node which are causally dependent on the
5500e6b6b59SJacob Faibussowitsch   source node. This causal dependency is established as-if by calling
5510e6b6b59SJacob Faibussowitsch   `PetscDeviceContextWaitForContext()` on every child.
5520e6b6b59SJacob Faibussowitsch 
5530e6b6b59SJacob Faibussowitsch   `dsub` is allocated by this routine and has its lifetime bounded by `dctx`. That is, `dctx`
5540e6b6b59SJacob Faibussowitsch   expects to free `dsub` (via `PetscDeviceContextJoin()`) before it itself is destroyed.
5550e6b6b59SJacob Faibussowitsch 
5560e6b6b59SJacob Faibussowitsch   This routine only accounts for work queued on `dctx` up until calling this routine, any
5570e6b6b59SJacob Faibussowitsch   subsequent work enqueued on `dctx` has no effect on `dsub`.
5580e6b6b59SJacob Faibussowitsch 
5590e6b6b59SJacob Faibussowitsch   The `PetscStreamType` of `dctx` does not have to equal `stype`. In fact, it is often the case
5600e6b6b59SJacob Faibussowitsch   that they are different. This is useful in cases where a routine can locally exploit stream
5610e6b6b59SJacob Faibussowitsch   parallelism without needing to worry about what stream type the incoming `PetscDeviceContext`
5620e6b6b59SJacob Faibussowitsch   carries.
5630e6b6b59SJacob Faibussowitsch 
5640e6b6b59SJacob Faibussowitsch   DAG representation:
5650e6b6b59SJacob Faibussowitsch .vb
5660e6b6b59SJacob Faibussowitsch   time ->
5670e6b6b59SJacob Faibussowitsch 
5680e6b6b59SJacob Faibussowitsch   -> dctx - |= CALL =| -\----> dctx ------>
5690e6b6b59SJacob Faibussowitsch                          \---> dsub[0] --->
5700e6b6b59SJacob Faibussowitsch                           \--> ... ------->
5710e6b6b59SJacob Faibussowitsch                            \-> dsub[n-1] ->
5720e6b6b59SJacob Faibussowitsch .ve
5730e6b6b59SJacob Faibussowitsch 
5740e6b6b59SJacob Faibussowitsch .N ASYNC_API
5750e6b6b59SJacob Faibussowitsch 
5760e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextJoin()`, `PetscDeviceContextSynchronize()`,
5770e6b6b59SJacob Faibussowitsch `PetscDeviceContextQueryIdle()`, `PetscDeviceContextWaitForContext()`
5780e6b6b59SJacob Faibussowitsch @*/
579d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextForkWithStreamType(PetscDeviceContext dctx, PetscStreamType stype, PetscInt n, PetscDeviceContext **dsub)
580d71ae5a4SJacob Faibussowitsch {
5810e6b6b59SJacob Faibussowitsch   // debugging only
5820e6b6b59SJacob Faibussowitsch   std::string idList;
5830e6b6b59SJacob Faibussowitsch   auto        ninput = n;
5840e6b6b59SJacob Faibussowitsch 
5850e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
5860e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
5870e6b6b59SJacob Faibussowitsch   PetscAssert(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of contexts requested %" PetscInt_FMT " < 0", n);
5880e6b6b59SJacob Faibussowitsch   PetscValidPointer(dsub, 4);
5890e6b6b59SJacob Faibussowitsch   *dsub = nullptr;
5900e6b6b59SJacob Faibussowitsch   /* reserve 4 chars per id, 2 for number and 2 for ', ' separator */
5910e6b6b59SJacob Faibussowitsch   if (PetscDefined(USE_DEBUG_AND_INFO)) PetscCallCXX(idList.reserve(4 * n));
5926a4a1270SPierre Jolivet   PetscCall(PetscLogEventBegin(DCONTEXT_Fork, dctx, nullptr, nullptr, nullptr));
5930e6b6b59SJacob Faibussowitsch   /* update child totals */
5940e6b6b59SJacob Faibussowitsch   dctx->numChildren += n;
5950e6b6b59SJacob Faibussowitsch   /* now to find out if we have room */
5960e6b6b59SJacob Faibussowitsch   if (dctx->numChildren > dctx->maxNumChildren) {
5970e6b6b59SJacob Faibussowitsch     const auto numChildren    = dctx->numChildren;
5980e6b6b59SJacob Faibussowitsch     auto      &maxNumChildren = dctx->maxNumChildren;
5990e6b6b59SJacob Faibussowitsch     auto       numAllocated   = numChildren;
6000e6b6b59SJacob Faibussowitsch 
6010e6b6b59SJacob Faibussowitsch     /* no room, either from having too many kids or not having any */
6020e6b6b59SJacob Faibussowitsch     if (auto &childIDs = dctx->childIDs) {
6030e6b6b59SJacob Faibussowitsch       // the difference is backwards because we have not updated maxNumChildren yet
6040e6b6b59SJacob Faibussowitsch       numAllocated -= maxNumChildren;
6050e6b6b59SJacob Faibussowitsch       /* have existing children, must reallocate them */
6060e6b6b59SJacob Faibussowitsch       PetscCall(PetscRealloc(numChildren * sizeof(*childIDs), &childIDs));
6070e6b6b59SJacob Faibussowitsch       /* clear the extra memory since realloc doesn't do it for us */
6080e6b6b59SJacob Faibussowitsch       PetscCall(PetscArrayzero(std::next(childIDs, maxNumChildren), numAllocated));
6090e6b6b59SJacob Faibussowitsch     } else {
6100e6b6b59SJacob Faibussowitsch       /* have no children */
6110e6b6b59SJacob Faibussowitsch       PetscCall(PetscCalloc1(numChildren, &childIDs));
6120e6b6b59SJacob Faibussowitsch     }
6130e6b6b59SJacob Faibussowitsch     /* update total number of children */
6140e6b6b59SJacob Faibussowitsch     maxNumChildren = numChildren;
6150e6b6b59SJacob Faibussowitsch   }
6160e6b6b59SJacob Faibussowitsch   PetscCall(PetscMalloc1(n, dsub));
6170e6b6b59SJacob Faibussowitsch   for (PetscInt i = 0; ninput && (i < dctx->numChildren); ++i) {
6180e6b6b59SJacob Faibussowitsch     auto &childID = dctx->childIDs[i];
6190e6b6b59SJacob Faibussowitsch     /* empty child slot */
6200e6b6b59SJacob Faibussowitsch     if (!childID) {
6210e6b6b59SJacob Faibussowitsch       auto &childctx = (*dsub)[i];
6220e6b6b59SJacob Faibussowitsch 
6230e6b6b59SJacob Faibussowitsch       /* create the child context in the image of its parent */
6240e6b6b59SJacob Faibussowitsch       PetscCall(PetscDeviceContextDuplicate_Private(dctx, stype, &childctx));
6250e6b6b59SJacob Faibussowitsch       PetscCall(PetscDeviceContextWaitForContext(childctx, dctx));
6260e6b6b59SJacob Faibussowitsch       /* register the child with its parent */
6270e6b6b59SJacob Faibussowitsch       PetscCall(PetscObjectGetId(PetscObjectCast(childctx), &childID));
6280e6b6b59SJacob Faibussowitsch       if (PetscDefined(USE_DEBUG_AND_INFO)) {
6290e6b6b59SJacob Faibussowitsch         PetscCallCXX(idList += std::to_string(childID));
6300e6b6b59SJacob Faibussowitsch         if (ninput != 1) PetscCallCXX(idList += ", ");
6310e6b6b59SJacob Faibussowitsch       }
6320e6b6b59SJacob Faibussowitsch       --ninput;
6330e6b6b59SJacob Faibussowitsch     }
6340e6b6b59SJacob Faibussowitsch   }
6356a4a1270SPierre Jolivet   PetscCall(PetscLogEventEnd(DCONTEXT_Fork, dctx, nullptr, nullptr, nullptr));
6360e6b6b59SJacob Faibussowitsch   PetscCall(PetscDebugInfo(dctx, "Forked %" PetscInt_FMT " children from parent %" PetscInt64_FMT " with IDs: %s\n", n, PetscObjectCast(dctx)->id, idList.c_str()));
6373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6380e6b6b59SJacob Faibussowitsch }
6390e6b6b59SJacob Faibussowitsch 
640030f984aSJacob Faibussowitsch /*@C
641030f984aSJacob Faibussowitsch   PetscDeviceContextFork - Create a set of dependent child contexts from a parent context
642030f984aSJacob Faibussowitsch 
643030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
644030f984aSJacob Faibussowitsch 
645030f984aSJacob Faibussowitsch   Input Parameters:
646811af0c4SBarry Smith + dctx - The parent `PetscDeviceContext`
647030f984aSJacob Faibussowitsch - n    - The number of children to create
648030f984aSJacob Faibussowitsch 
649030f984aSJacob Faibussowitsch   Output Parameter:
650030f984aSJacob Faibussowitsch . dsub - The created child context(s)
651030f984aSJacob Faibussowitsch 
6522fe279fdSBarry Smith   Level: beginner
6532fe279fdSBarry Smith 
654030f984aSJacob Faibussowitsch   Notes:
6550e6b6b59SJacob Faibussowitsch   Behaves identically to `PetscDeviceContextForkWithStreamType()` except that the prescribed
6560e6b6b59SJacob Faibussowitsch   `PetscStreamType` is taken from `dctx`. In effect this routine is shorthand for\:
657030f984aSJacob Faibussowitsch 
658030f984aSJacob Faibussowitsch .vb
6590e6b6b59SJacob Faibussowitsch   PetscStreamType stype;
660030f984aSJacob Faibussowitsch 
6610e6b6b59SJacob Faibussowitsch   PetscDeviceContextGetStreamType(dctx, &stype);
6620e6b6b59SJacob Faibussowitsch   PetscDeviceContextForkWithStreamType(dctx, stype, ...);
663030f984aSJacob Faibussowitsch .ve
664030f984aSJacob Faibussowitsch 
6650e6b6b59SJacob Faibussowitsch .N ASYNC_API
6660e6b6b59SJacob Faibussowitsch 
6670e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextForkWithStreamType()`, `PetscDeviceContextJoin()`,
6680e6b6b59SJacob Faibussowitsch `PetscDeviceContextSynchronize()`, `PetscDeviceContextQueryIdle()`
669030f984aSJacob Faibussowitsch @*/
670d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextFork(PetscDeviceContext dctx, PetscInt n, PetscDeviceContext **dsub)
671d71ae5a4SJacob Faibussowitsch {
6720e6b6b59SJacob Faibussowitsch   auto stype = PETSC_STREAM_DEFAULT_BLOCKING;
673030f984aSJacob Faibussowitsch 
674030f984aSJacob Faibussowitsch   PetscFunctionBegin;
6750e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
6760e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetStreamType(dctx, &stype));
6770e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextForkWithStreamType(dctx, stype, n, dsub));
6783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
679030f984aSJacob Faibussowitsch }
680030f984aSJacob Faibussowitsch 
681*10450e9eSJacob Faibussowitsch // PetscClangLinter pragma disable: -fdoc-section-header-unknown
682030f984aSJacob Faibussowitsch /*@C
6835181c4f9SJacob Faibussowitsch   PetscDeviceContextJoin - Converge a set of child contexts
684030f984aSJacob Faibussowitsch 
685030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
686030f984aSJacob Faibussowitsch 
687030f984aSJacob Faibussowitsch   Input Parameters:
688811af0c4SBarry Smith + dctx     - A `PetscDeviceContext` to converge on
689030f984aSJacob Faibussowitsch . n        - The number of sub contexts to converge
690030f984aSJacob Faibussowitsch . joinMode - The type of join to perform
691030f984aSJacob Faibussowitsch - dsub     - The sub contexts to converge
692030f984aSJacob Faibussowitsch 
6932fe279fdSBarry Smith   Level: beginner
6942fe279fdSBarry Smith 
695030f984aSJacob Faibussowitsch   Notes:
6960e6b6b59SJacob Faibussowitsch   If `PetscDeviceContextFork()` creates `n` edges from a source node which all depend on the source
6970e6b6b59SJacob Faibussowitsch   node, then this routine is the exact mirror. That is, it creates a node (represented in `dctx`)
69835cb6cd3SPierre Jolivet   which receives `n` edges (and optionally destroys them) which is dependent on the completion
6990e6b6b59SJacob Faibussowitsch   of all incoming edges.
700030f984aSJacob Faibussowitsch 
7010e6b6b59SJacob Faibussowitsch   If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_DESTROY`. All contexts in `dsub` will be
7020e6b6b59SJacob Faibussowitsch   destroyed by this routine. Thus all sub contexts must have been created with the `dctx`
7030e6b6b59SJacob Faibussowitsch   passed to this routine.
704030f984aSJacob Faibussowitsch 
7050e6b6b59SJacob Faibussowitsch   If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_SYNC`. All sub contexts will additionally wait on
7060e6b6b59SJacob Faibussowitsch   `dctx` after converging. This has the effect of "synchronizing" the outgoing edges. Note the
7070e6b6b59SJacob Faibussowitsch   sync suffix does NOT refer to the host, i.e. this routine does NOT call
7080e6b6b59SJacob Faibussowitsch   `PetscDeviceSynchronize()`.
709030f984aSJacob Faibussowitsch 
7100e6b6b59SJacob Faibussowitsch   If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC`. `dctx` waits for all sub contexts but
7110e6b6b59SJacob Faibussowitsch   the sub contexts do not wait for one another or `dctx` afterwards.
712030f984aSJacob Faibussowitsch 
713030f984aSJacob Faibussowitsch   DAG representations:
714811af0c4SBarry Smith   If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_DESTROY`
715030f984aSJacob Faibussowitsch .vb
716030f984aSJacob Faibussowitsch   time ->
717030f984aSJacob Faibussowitsch 
7180e6b6b59SJacob Faibussowitsch   -> dctx ---------/- |= CALL =| - dctx ->
719030f984aSJacob Faibussowitsch   -> dsub[0] -----/
720030f984aSJacob Faibussowitsch   ->  ... -------/
721030f984aSJacob Faibussowitsch   -> dsub[n-1] -/
722030f984aSJacob Faibussowitsch .ve
723811af0c4SBarry Smith   If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_SYNC`
724030f984aSJacob Faibussowitsch .vb
725030f984aSJacob Faibussowitsch   time ->
726030f984aSJacob Faibussowitsch 
7270e6b6b59SJacob Faibussowitsch   -> dctx ---------/- |= CALL =| -\----> dctx ------>
728030f984aSJacob Faibussowitsch   -> dsub[0] -----/                \---> dsub[0] --->
729030f984aSJacob Faibussowitsch   ->  ... -------/                  \--> ... ------->
730030f984aSJacob Faibussowitsch   -> dsub[n-1] -/                    \-> dsub[n-1] ->
731030f984aSJacob Faibussowitsch .ve
7320e6b6b59SJacob Faibussowitsch   If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC`
7330e6b6b59SJacob Faibussowitsch .vb
7340e6b6b59SJacob Faibussowitsch   time ->
735030f984aSJacob Faibussowitsch 
7360e6b6b59SJacob Faibussowitsch   -> dctx ----------/- |= CALL =| - dctx ->
7370e6b6b59SJacob Faibussowitsch   -> dsub[0] ------/----------------------->
7380e6b6b59SJacob Faibussowitsch   ->  ... --------/------------------------>
7390e6b6b59SJacob Faibussowitsch   -> dsub[n-1] --/------------------------->
7400e6b6b59SJacob Faibussowitsch .ve
741030f984aSJacob Faibussowitsch 
7420e6b6b59SJacob Faibussowitsch .N ASYNC_API
7430e6b6b59SJacob Faibussowitsch 
7440e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextFork()`, `PetscDeviceContextForkWithStreamType()`,
7450e6b6b59SJacob Faibussowitsch `PetscDeviceContextSynchronize()`, `PetscDeviceContextJoinMode`
746030f984aSJacob Faibussowitsch @*/
747d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextJoin(PetscDeviceContext dctx, PetscInt n, PetscDeviceContextJoinMode joinMode, PetscDeviceContext **dsub)
748d71ae5a4SJacob Faibussowitsch {
7490e6b6b59SJacob Faibussowitsch   // debugging only
7500e6b6b59SJacob Faibussowitsch   std::string idList;
751030f984aSJacob Faibussowitsch 
752030f984aSJacob Faibussowitsch   PetscFunctionBegin;
7530e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
754030f984aSJacob Faibussowitsch   /* validity of dctx is checked in the wait-for loop */
755030f984aSJacob Faibussowitsch   PetscValidPointer(dsub, 4);
756bf025ffbSJacob Faibussowitsch   PetscAssert(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of contexts merged %" PetscInt_FMT " < 0", n);
757030f984aSJacob Faibussowitsch   /* reserve 4 chars per id, 2 for number and 2 for ', ' separator */
7580e6b6b59SJacob Faibussowitsch   if (PetscDefined(USE_DEBUG_AND_INFO)) PetscCallCXX(idList.reserve(4 * n));
759030f984aSJacob Faibussowitsch   /* first dctx waits on all the incoming edges */
7606a4a1270SPierre Jolivet   PetscCall(PetscLogEventBegin(DCONTEXT_Join, dctx, nullptr, nullptr, nullptr));
761030f984aSJacob Faibussowitsch   for (PetscInt i = 0; i < n; ++i) {
762030f984aSJacob Faibussowitsch     PetscCheckCompatibleDeviceContexts(dctx, 1, (*dsub)[i], 4);
7639566063dSJacob Faibussowitsch     PetscCall(PetscDeviceContextWaitForContext(dctx, (*dsub)[i]));
7640e6b6b59SJacob Faibussowitsch     if (PetscDefined(USE_DEBUG_AND_INFO)) {
7650e6b6b59SJacob Faibussowitsch       PetscCallCXX(idList += std::to_string(PetscObjectCast((*dsub)[i])->id));
7660e6b6b59SJacob Faibussowitsch       if (i + 1 < n) PetscCallCXX(idList += ", ");
7670e6b6b59SJacob Faibussowitsch     }
768030f984aSJacob Faibussowitsch   }
769030f984aSJacob Faibussowitsch 
770030f984aSJacob Faibussowitsch   /* now we handle the aftermath */
771030f984aSJacob Faibussowitsch   switch (joinMode) {
7729371c9d4SSatish Balay   case PETSC_DEVICE_CONTEXT_JOIN_DESTROY: {
7730e6b6b59SJacob Faibussowitsch     const auto children = dctx->childIDs;
7740e6b6b59SJacob Faibussowitsch     const auto maxchild = dctx->maxNumChildren;
7750e6b6b59SJacob Faibussowitsch     auto      &nchild   = dctx->numChildren;
776030f984aSJacob Faibussowitsch     PetscInt   j        = 0;
777030f984aSJacob Faibussowitsch 
7780e6b6b59SJacob Faibussowitsch     PetscCheck(n <= nchild, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Trying to destroy %" PetscInt_FMT " children of a parent context that only has %" PetscInt_FMT " children, likely trying to restore to wrong parent", n, nchild);
779030f984aSJacob Faibussowitsch     /* update child count while it's still fresh in memory */
7800e6b6b59SJacob Faibussowitsch     nchild -= n;
7810e6b6b59SJacob Faibussowitsch     for (PetscInt i = 0; i < maxchild; ++i) {
7820e6b6b59SJacob Faibussowitsch       if (children[i] && (children[i] == PetscObjectCast((*dsub)[j])->id)) {
783030f984aSJacob Faibussowitsch         /* child is one of ours, can destroy it */
7849566063dSJacob Faibussowitsch         PetscCall(PetscDeviceContextDestroy((*dsub) + j));
785030f984aSJacob Faibussowitsch         /* reset the child slot */
7860e6b6b59SJacob Faibussowitsch         children[i] = 0;
787030f984aSJacob Faibussowitsch         if (++j == n) break;
788030f984aSJacob Faibussowitsch       }
789030f984aSJacob Faibussowitsch     }
7900e6b6b59SJacob Faibussowitsch     /* gone through the loop but did not find every child */
7910e6b6b59SJacob Faibussowitsch     PetscCheck(j == n, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "%" PetscInt_FMT " contexts still remain after destroy, this may be because you are trying to restore to the wrong parent context, or the device contexts are not in the same order as they were checked out out in", n - j);
7929566063dSJacob Faibussowitsch     PetscCall(PetscFree(*dsub));
7939371c9d4SSatish Balay   } break;
794030f984aSJacob Faibussowitsch   case PETSC_DEVICE_CONTEXT_JOIN_SYNC:
7959566063dSJacob Faibussowitsch     for (PetscInt i = 0; i < n; ++i) PetscCall(PetscDeviceContextWaitForContext((*dsub)[i], dctx));
796d71ae5a4SJacob Faibussowitsch   case PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC:
797d71ae5a4SJacob Faibussowitsch     break;
798d71ae5a4SJacob Faibussowitsch   default:
799d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown PetscDeviceContextJoinMode given");
800030f984aSJacob Faibussowitsch   }
8016a4a1270SPierre Jolivet   PetscCall(PetscLogEventEnd(DCONTEXT_Join, dctx, nullptr, nullptr, nullptr));
802030f984aSJacob Faibussowitsch 
8030e6b6b59SJacob Faibussowitsch   PetscCall(PetscDebugInfo(dctx, "Joined %" PetscInt_FMT " ctxs to ctx %" PetscInt64_FMT ", mode %s with IDs: %s\n", n, PetscObjectCast(dctx)->id, PetscDeviceContextJoinModes[joinMode], idList.c_str()));
8043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
805030f984aSJacob Faibussowitsch }
806030f984aSJacob Faibussowitsch 
807*10450e9eSJacob Faibussowitsch // PetscClangLinter pragma disable: -fdoc-section-header-unknown
808030f984aSJacob Faibussowitsch /*@C
8090e6b6b59SJacob Faibussowitsch   PetscDeviceContextSynchronize - Block the host until all work queued on a
8100e6b6b59SJacob Faibussowitsch   `PetscDeviceContext` has finished
811030f984aSJacob Faibussowitsch 
8120e6b6b59SJacob Faibussowitsch   Not Collective
813030f984aSJacob Faibussowitsch 
8142fe279fdSBarry Smith   Input Parameter:
815811af0c4SBarry Smith . dctx - The `PetscDeviceContext` to synchronize
816030f984aSJacob Faibussowitsch 
8172fe279fdSBarry Smith   Level: beginner
8182fe279fdSBarry Smith 
8190e6b6b59SJacob Faibussowitsch   Notes:
8200e6b6b59SJacob Faibussowitsch   The host will not return from this routine until `dctx` is idle. Any and all memory
8210e6b6b59SJacob Faibussowitsch   operations queued on or otherwise associated with (either explicitly or implicitly via
8220e6b6b59SJacob Faibussowitsch   dependencies) are guaranteed to have finished and be globally visible on return.
8230e6b6b59SJacob Faibussowitsch 
8240e6b6b59SJacob Faibussowitsch   In effect, this routine serves as memory and execution barrier.
8250e6b6b59SJacob Faibussowitsch 
8260e6b6b59SJacob Faibussowitsch   DAG representation:
8270e6b6b59SJacob Faibussowitsch .vb
8280e6b6b59SJacob Faibussowitsch   time ->
8290e6b6b59SJacob Faibussowitsch 
8300e6b6b59SJacob Faibussowitsch   -> dctx - |= CALL =| - dctx ->
8310e6b6b59SJacob Faibussowitsch .ve
8320e6b6b59SJacob Faibussowitsch 
833db781477SPatrick Sanan .seealso: `PetscDeviceContextFork()`, `PetscDeviceContextJoin()`, `PetscDeviceContextQueryIdle()`
834030f984aSJacob Faibussowitsch @*/
835d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextSynchronize(PetscDeviceContext dctx)
836d71ae5a4SJacob Faibussowitsch {
837030f984aSJacob Faibussowitsch   PetscFunctionBegin;
8380e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
8396a4a1270SPierre Jolivet   PetscCall(PetscLogEventBegin(DCONTEXT_Sync, dctx, nullptr, nullptr, nullptr));
840030f984aSJacob Faibussowitsch   /* if it isn't setup there is nothing to sync on */
8410e6b6b59SJacob Faibussowitsch   if (dctx->setup) {
8422f85e401SJacob Faibussowitsch     PetscUseTypeMethod(dctx, synchronize);
8430e6b6b59SJacob Faibussowitsch     PetscCall(PetscDeviceContextSyncClearMap_Internal(dctx));
8440e6b6b59SJacob Faibussowitsch   }
8456a4a1270SPierre Jolivet   PetscCall(PetscLogEventEnd(DCONTEXT_Sync, dctx, nullptr, nullptr, nullptr));
8463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
847030f984aSJacob Faibussowitsch }
848030f984aSJacob Faibussowitsch 
8490e6b6b59SJacob Faibussowitsch /* every device type has a vector of null PetscDeviceContexts -- one for each device */
8500e6b6b59SJacob Faibussowitsch static auto nullContexts          = std::array<std::vector<PetscDeviceContext>, PETSC_DEVICE_MAX>{};
8510e6b6b59SJacob Faibussowitsch static auto nullContextsFinalizer = false;
852030f984aSJacob Faibussowitsch 
853d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDeviceContextGetNullContextForDevice_Private(PetscBool user_set_device, PetscDevice device, PetscDeviceContext *dctx)
854d71ae5a4SJacob Faibussowitsch {
8550e6b6b59SJacob Faibussowitsch   PetscInt        devid;
8560e6b6b59SJacob Faibussowitsch   PetscDeviceType dtype;
857a4af0ceeSJacob Faibussowitsch 
858030f984aSJacob Faibussowitsch   PetscFunctionBegin;
8590e6b6b59SJacob Faibussowitsch   PetscValidDevice(device, 2);
8600e6b6b59SJacob Faibussowitsch   PetscValidPointer(dctx, 3);
8610e6b6b59SJacob Faibussowitsch   if (PetscUnlikely(!nullContextsFinalizer)) {
8620e6b6b59SJacob Faibussowitsch     const auto finalizer = [] {
8630e6b6b59SJacob Faibussowitsch       PetscFunctionBegin;
8640e6b6b59SJacob Faibussowitsch       for (auto &&dvec : nullContexts) {
8650e6b6b59SJacob Faibussowitsch         for (auto &&dctx : dvec) PetscCall(PetscDeviceContextDestroy(&dctx));
8660e6b6b59SJacob Faibussowitsch         PetscCallCXX(dvec.clear());
867030f984aSJacob Faibussowitsch       }
8680e6b6b59SJacob Faibussowitsch       nullContextsFinalizer = false;
8693ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
870a4af0ceeSJacob Faibussowitsch     };
871a4af0ceeSJacob Faibussowitsch 
8720e6b6b59SJacob Faibussowitsch     nullContextsFinalizer = true;
8730e6b6b59SJacob Faibussowitsch     PetscCall(PetscRegisterFinalize(std::move(finalizer)));
8740e6b6b59SJacob Faibussowitsch   }
8750e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceGetDeviceId(device, &devid));
8760e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceGetType(device, &dtype));
8770e6b6b59SJacob Faibussowitsch   {
8780e6b6b59SJacob Faibussowitsch     auto &ctxlist = nullContexts[dtype];
8790e6b6b59SJacob Faibussowitsch 
8800e6b6b59SJacob Faibussowitsch     PetscCheck(devid >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Device ID (%" PetscInt_FMT ") must be positive", devid);
8810e6b6b59SJacob Faibussowitsch     // need to resize the container if not big enough because incrementing the iterator in
8820e6b6b59SJacob Faibussowitsch     // std::next() (if we haven't initialized that ctx yet) may cause it to fall outside the
8830e6b6b59SJacob Faibussowitsch     // current size of the container.
8840e6b6b59SJacob Faibussowitsch     if (static_cast<std::size_t>(devid) >= ctxlist.size()) PetscCallCXX(ctxlist.resize(devid + 1));
8850e6b6b59SJacob Faibussowitsch     if (PetscUnlikely(!ctxlist[devid])) {
8860e6b6b59SJacob Faibussowitsch       // we have not seen this device before
8870e6b6b59SJacob Faibussowitsch       PetscCall(PetscDeviceContextCreate(dctx));
888403f9ca4SJacob Faibussowitsch       PetscCall(PetscInfo(*dctx, "Initializing null PetscDeviceContext (of type %s) for device %" PetscInt_FMT "\n", PetscDeviceTypes[dtype], devid));
8890e6b6b59SJacob Faibussowitsch       {
8900e6b6b59SJacob Faibussowitsch         const auto pobj   = PetscObjectCast(*dctx);
8910e6b6b59SJacob Faibussowitsch         const auto name   = "null context " + std::to_string(devid);
8920e6b6b59SJacob Faibussowitsch         const auto prefix = "null_context_" + std::to_string(devid) + '_';
8930e6b6b59SJacob Faibussowitsch 
8940e6b6b59SJacob Faibussowitsch         PetscCall(PetscObjectSetName(pobj, name.c_str()));
8950e6b6b59SJacob Faibussowitsch         PetscCall(PetscObjectSetOptionsPrefix(pobj, prefix.c_str()));
8960e6b6b59SJacob Faibussowitsch       }
8970e6b6b59SJacob Faibussowitsch       PetscCall(PetscDeviceContextSetStreamType(*dctx, PETSC_STREAM_GLOBAL_BLOCKING));
8980e6b6b59SJacob Faibussowitsch       PetscCall(PetscDeviceContextSetDevice_Private(*dctx, device, user_set_device));
8990e6b6b59SJacob Faibussowitsch       PetscCall(PetscDeviceContextSetUp(*dctx));
9000e6b6b59SJacob Faibussowitsch       // would use ctxlist.cbegin() but GCC 4.8 can't handle const iterator insert!
9010e6b6b59SJacob Faibussowitsch       PetscCallCXX(ctxlist.insert(std::next(ctxlist.begin(), devid), *dctx));
9020e6b6b59SJacob Faibussowitsch     } else *dctx = ctxlist[devid];
9030e6b6b59SJacob Faibussowitsch   }
9043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
905030f984aSJacob Faibussowitsch }
906030f984aSJacob Faibussowitsch 
9070e6b6b59SJacob Faibussowitsch /*
9080e6b6b59SJacob Faibussowitsch   Gets the "NULL" context for the current PetscDeviceType and PetscDevice. NULL contexts are
9090e6b6b59SJacob Faibussowitsch   guaranteed to always be globally blocking.
9100e6b6b59SJacob Faibussowitsch */
911d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextGetNullContext_Internal(PetscDeviceContext *dctx)
912d71ae5a4SJacob Faibussowitsch {
9130e6b6b59SJacob Faibussowitsch   PetscDeviceContext gctx;
9140e6b6b59SJacob Faibussowitsch   PetscDevice        gdev = nullptr;
915030f984aSJacob Faibussowitsch 
916a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
917a4af0ceeSJacob Faibussowitsch   PetscValidPointer(dctx, 1);
9180e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetCurrentContext(&gctx));
9190e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetDevice(gctx, &gdev));
9200e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetNullContextForDevice_Private(gctx->usersetdevice, gdev, dctx));
9213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
922030f984aSJacob Faibussowitsch }
923030f984aSJacob Faibussowitsch 
924030f984aSJacob Faibussowitsch /*@C
925811af0c4SBarry Smith   PetscDeviceContextSetFromOptions - Configure a `PetscDeviceContext` from the options database
926030f984aSJacob Faibussowitsch 
9270e6b6b59SJacob Faibussowitsch   Collective on `comm` or `dctx`
928030f984aSJacob Faibussowitsch 
929030f984aSJacob Faibussowitsch   Input Parameters:
9300e6b6b59SJacob Faibussowitsch + comm - MPI communicator on which to query the options database (optional)
931811af0c4SBarry Smith - dctx - The `PetscDeviceContext` to configure
932030f984aSJacob Faibussowitsch 
933030f984aSJacob Faibussowitsch   Output Parameter:
934811af0c4SBarry Smith . dctx - The `PetscDeviceContext`
935030f984aSJacob Faibussowitsch 
9363c7db156SBarry Smith   Options Database Keys:
9370e6b6b59SJacob Faibussowitsch + -device_context_stream_type - type of stream to create inside the `PetscDeviceContext` -
9380e6b6b59SJacob Faibussowitsch    `PetscDeviceContextSetStreamType()`
939811af0c4SBarry Smith - -device_context_device_type - the type of `PetscDevice` to attach by default - `PetscDeviceType`
940030f984aSJacob Faibussowitsch 
9412fe279fdSBarry Smith   Level: beginner
9422fe279fdSBarry Smith 
9432fe279fdSBarry Smith   Note:
9440e6b6b59SJacob Faibussowitsch   The user may pass `MPI_COMM_NULL` for `comm` in which case the communicator of `dctx` is
9450e6b6b59SJacob Faibussowitsch   used (which is always `PETSC_COMM_SELF`).
9460e6b6b59SJacob Faibussowitsch 
9470e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextSetStreamType()`, `PetscDeviceContextSetDevice()`,
9480e6b6b59SJacob Faibussowitsch `PetscDeviceContextView()`
949030f984aSJacob Faibussowitsch @*/
950d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetFromOptions(MPI_Comm comm, PetscDeviceContext dctx)
951d71ae5a4SJacob Faibussowitsch {
9520e6b6b59SJacob Faibussowitsch   const auto pobj     = PetscObjectCast(dctx);
9530e6b6b59SJacob Faibussowitsch   auto       dtype    = std::make_pair(PETSC_DEVICE_DEFAULT(), PETSC_FALSE);
9540e6b6b59SJacob Faibussowitsch   auto       stype    = std::make_pair(PETSC_DEVICE_CONTEXT_DEFAULT_STREAM_TYPE, PETSC_FALSE);
955e6b8bd2aSJacob Faibussowitsch   MPI_Comm   old_comm = PETSC_COMM_SELF;
956030f984aSJacob Faibussowitsch 
957030f984aSJacob Faibussowitsch   PetscFunctionBegin;
9580e6b6b59SJacob Faibussowitsch   // do not user getoptionalnullcontext here, the user is not allowed to set it from options!
9590e6b6b59SJacob Faibussowitsch   PetscValidDeviceContext(dctx, 2);
9600e6b6b59SJacob Faibussowitsch   /* set the device type first */
9610e6b6b59SJacob Faibussowitsch   if (const auto device = dctx->device) PetscCall(PetscDeviceGetType(device, &dtype.first));
9620e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetStreamType(dctx, &stype.first));
9630e6b6b59SJacob Faibussowitsch 
9640e6b6b59SJacob Faibussowitsch   if (comm == MPI_COMM_NULL) {
9650e6b6b59SJacob Faibussowitsch     PetscCall(PetscObjectGetComm(pobj, &comm));
9660e6b6b59SJacob Faibussowitsch   } else {
9670e6b6b59SJacob Faibussowitsch     // briefly set the communicator for dctx (it is always PETSC_COMM_SELF) so
9680e6b6b59SJacob Faibussowitsch     // PetscObjectOptionsBegin() behaves as if dctx had comm
9690e6b6b59SJacob Faibussowitsch     old_comm = Petsc::util::exchange(pobj->comm, comm);
9700e6b6b59SJacob Faibussowitsch   }
9710e6b6b59SJacob Faibussowitsch 
9720e6b6b59SJacob Faibussowitsch   PetscObjectOptionsBegin(pobj);
9730e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextQueryOptions_Internal(PetscOptionsObject, dtype, stype));
974d0609cedSBarry Smith   PetscOptionsEnd();
9750e6b6b59SJacob Faibussowitsch   // reset the comm (should be PETSC_COMM_SELF)
9760e6b6b59SJacob Faibussowitsch   if (comm != MPI_COMM_NULL) pobj->comm = old_comm;
9770e6b6b59SJacob Faibussowitsch   if (dtype.second) PetscCall(PetscDeviceContextSetDefaultDeviceForType_Internal(dctx, dtype.first));
9780e6b6b59SJacob Faibussowitsch   if (stype.second) PetscCall(PetscDeviceContextSetStreamType(dctx, stype.first));
9790e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextSetUp(dctx));
9803ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9810e6b6b59SJacob Faibussowitsch }
9820e6b6b59SJacob Faibussowitsch 
9830e6b6b59SJacob Faibussowitsch /*@C
9840e6b6b59SJacob Faibussowitsch   PetscDeviceContextView - View a `PetscDeviceContext`
9850e6b6b59SJacob Faibussowitsch 
9860e6b6b59SJacob Faibussowitsch   Collective on `viewer`
9870e6b6b59SJacob Faibussowitsch 
9880e6b6b59SJacob Faibussowitsch   Input Parameters:
9890e6b6b59SJacob Faibussowitsch + dctx   - The `PetscDeviceContext`
9900e6b6b59SJacob Faibussowitsch - viewer - The `PetscViewer` to view `dctx` with (may be `NULL`)
9910e6b6b59SJacob Faibussowitsch 
9922fe279fdSBarry Smith   Level: beginner
9932fe279fdSBarry Smith 
9942fe279fdSBarry Smith   Note:
9950e6b6b59SJacob Faibussowitsch   If `viewer` is `NULL`, `PETSC_VIEWER_STDOUT_WORLD` is used instead, in which case this
9960e6b6b59SJacob Faibussowitsch   routine is collective on `PETSC_COMM_WORLD`.
9970e6b6b59SJacob Faibussowitsch 
9980e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextViewFromOptions()`, `PetscDeviceView()`, `PETSC_VIEWER_STDOUT_WORLD`, `PetscDeviceContextCreate()`
9990e6b6b59SJacob Faibussowitsch @*/
1000d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextView(PetscDeviceContext dctx, PetscViewer viewer)
1001d71ae5a4SJacob Faibussowitsch {
10020e6b6b59SJacob Faibussowitsch   PetscBool iascii;
10030e6b6b59SJacob Faibussowitsch 
10040e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
10050e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
10060e6b6b59SJacob Faibussowitsch   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PETSC_COMM_WORLD, &viewer));
10070e6b6b59SJacob Faibussowitsch   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
10080e6b6b59SJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare(PetscObjectCast(viewer), PETSCVIEWERASCII, &iascii));
10090e6b6b59SJacob Faibussowitsch   if (iascii) {
10100e6b6b59SJacob Faibussowitsch     auto        stype = PETSC_STREAM_DEFAULT_BLOCKING;
10110e6b6b59SJacob Faibussowitsch     PetscViewer sub;
10120e6b6b59SJacob Faibussowitsch 
10130e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sub));
10140e6b6b59SJacob Faibussowitsch     PetscCall(PetscObjectPrintClassNamePrefixType(PetscObjectCast(dctx), sub));
10150e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(sub));
10160e6b6b59SJacob Faibussowitsch     PetscCall(PetscDeviceContextGetStreamType(dctx, &stype));
10170e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(sub, "stream type: %s\n", PetscStreamTypes[stype]));
10180e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(sub, "children: %" PetscInt_FMT "\n", dctx->numChildren));
10190e6b6b59SJacob Faibussowitsch     if (const auto nchild = dctx->numChildren) {
10200e6b6b59SJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushTab(sub));
10210e6b6b59SJacob Faibussowitsch       for (PetscInt i = 0; i < nchild; ++i) {
10220e6b6b59SJacob Faibussowitsch         if (i == nchild - 1) {
10230e6b6b59SJacob Faibussowitsch           PetscCall(PetscViewerASCIIPrintf(sub, "%" PetscInt64_FMT, dctx->childIDs[i]));
10240e6b6b59SJacob Faibussowitsch         } else {
10250e6b6b59SJacob Faibussowitsch           PetscCall(PetscViewerASCIIPrintf(sub, "%" PetscInt64_FMT ", ", dctx->childIDs[i]));
10260e6b6b59SJacob Faibussowitsch         }
10270e6b6b59SJacob Faibussowitsch       }
10280e6b6b59SJacob Faibussowitsch     }
10290e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(sub));
10300e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sub));
10310e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerFlush(viewer));
10320e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(viewer));
10330e6b6b59SJacob Faibussowitsch   }
10340e6b6b59SJacob Faibussowitsch   if (const auto device = dctx->device) PetscCall(PetscDeviceView(device, viewer));
10350e6b6b59SJacob Faibussowitsch   if (iascii) PetscCall(PetscViewerASCIIPopTab(viewer));
10363ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10370e6b6b59SJacob Faibussowitsch }
10380e6b6b59SJacob Faibussowitsch 
10390e6b6b59SJacob Faibussowitsch /*@C
10400e6b6b59SJacob Faibussowitsch   PetscDeviceContextViewFromOptions - View a `PetscDeviceContext` from options
10410e6b6b59SJacob Faibussowitsch 
10420e6b6b59SJacob Faibussowitsch   Input Parameters:
10430e6b6b59SJacob Faibussowitsch + dctx - The `PetscDeviceContext` to view
10440e6b6b59SJacob Faibussowitsch . obj  - Optional `PetscObject` to associate (may be `NULL`)
10450e6b6b59SJacob Faibussowitsch - name - The command line option
10460e6b6b59SJacob Faibussowitsch 
10470e6b6b59SJacob Faibussowitsch   Level: beginner
10480e6b6b59SJacob Faibussowitsch 
10490e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextView()`, `PetscObjectViewFromOptions()`, `PetscDeviceContextCreate()`
10500e6b6b59SJacob Faibussowitsch @*/
1051d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextViewFromOptions(PetscDeviceContext dctx, PetscObject obj, const char name[])
1052d71ae5a4SJacob Faibussowitsch {
10530e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
10540e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
10550e6b6b59SJacob Faibussowitsch   if (obj) PetscValidHeader(obj, 2);
10560e6b6b59SJacob Faibussowitsch   PetscValidCharPointer(name, 3);
10570e6b6b59SJacob Faibussowitsch   PetscCall(PetscObjectViewFromOptions(PetscObjectCast(dctx), obj, name));
10583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1059030f984aSJacob Faibussowitsch }
106031d47070SJunchao Zhang 
106131d47070SJunchao Zhang /*@C
106231d47070SJunchao Zhang   PetscDeviceContextGetStreamHandle - Return a handle to the underlying stream of the current device context
106331d47070SJunchao Zhang 
106431d47070SJunchao Zhang   Input Parameters:
106531d47070SJunchao Zhang + dctx   - The `PetscDeviceContext` to get the stream from
106631d47070SJunchao Zhang - handle - A handle to the stream
106731d47070SJunchao Zhang 
106831d47070SJunchao Zhang   Level: developer
106931d47070SJunchao Zhang 
107031d47070SJunchao Zhang   Note:
107131d47070SJunchao Zhang   This routine is dangerous. It exists only for the most experienced users and
107231d47070SJunchao Zhang   internal PETSc developement.
107331d47070SJunchao Zhang 
107431d47070SJunchao Zhang   There is no way for PETSc's auto-dependency system to track what the caller does with the
107531d47070SJunchao Zhang   stream.
107631d47070SJunchao Zhang 
107731d47070SJunchao Zhang   If the user uses the stream to copy memory that was previously modified by PETSc, or launches
107831d47070SJunchao Zhang   kernels that modify memory with the stream, it is the users responsibility to inform PETSc of
107931d47070SJunchao Zhang   their actions via `PetscDeviceContextMarkIntentFromID()`. Failure to do so may introduce a
108031d47070SJunchao Zhang   race condition. This race condition may manifest in nondeterministic ways.
108131d47070SJunchao Zhang 
108231d47070SJunchao Zhang   Alternatively, the user may synchronize the stream immediately before and after use. This is
108331d47070SJunchao Zhang   the safest option.
108431d47070SJunchao Zhang 
108531d47070SJunchao Zhang   Example Usage:
108631d47070SJunchao Zhang .vb
108731d47070SJunchao Zhang   PetscDeviceContext dctx;
108831d47070SJunchao Zhang   PetscDeviceType    type;
108931d47070SJunchao Zhang   void               *handle;
109031d47070SJunchao Zhang 
109131d47070SJunchao Zhang   PetscDeviceContextGetCurrentContext(&dctx);
109231d47070SJunchao Zhang   PetscDeviceContextGetStreamHandle(dctx, &handle);
109331d47070SJunchao Zhang   PetscDeviceContextGetDeviceType(dctx, &type);
109431d47070SJunchao Zhang 
109531d47070SJunchao Zhang   if (type == PETSC_DEVICE_CUDA) {
109631d47070SJunchao Zhang     cudsStream_t stream = *(cudaStream_t*)handle;
109731d47070SJunchao Zhang 
109831d47070SJunchao Zhang     my_cuda_kernel<<<1, 2, 3, stream>>>();
109931d47070SJunchao Zhang   }
110031d47070SJunchao Zhang .ve
110131d47070SJunchao Zhang 
110231d47070SJunchao Zhang .N ASYNC_API
110331d47070SJunchao Zhang 
110431d47070SJunchao Zhang .seealso: `PetscDeviceContext`
110531d47070SJunchao Zhang @*/
110631d47070SJunchao Zhang PetscErrorCode PetscDeviceContextGetStreamHandle(PetscDeviceContext dctx, void *handle)
110731d47070SJunchao Zhang {
110831d47070SJunchao Zhang   PetscFunctionBegin;
110931d47070SJunchao Zhang   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
111031d47070SJunchao Zhang   PetscValidPointer(handle, 2);
111197cd0981SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetStreamHandle_Internal(dctx, (void **)handle));
111231d47070SJunchao Zhang   PetscFunctionReturn(PETSC_SUCCESS);
111331d47070SJunchao Zhang }
1114