xref: /petsc/src/sys/objects/device/interface/dcontext.cxx (revision dcf958e2725ed5b45a9e2d55931865b30238645c)
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));
19*dcf958e2SJacob Faibussowitsch     PetscCallCXX(PetscObjectCast(dctx)->cpp = new CxxData{dctx});
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());
53*dcf958e2SJacob Faibussowitsch       PetscCall(CxxDataCast(dctx)->reset_self(dctx));
540e6b6b59SJacob Faibussowitsch     }
55030f984aSJacob Faibussowitsch     dctx->streamType = PETSC_STREAM_DEFAULT_BLOCKING;
563ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
57030f984aSJacob Faibussowitsch   }
58146a86ebSJacob Faibussowitsch 
59*dcf958e2SJacob Faibussowitsch   static PetscErrorCode invalidate_(PetscDeviceContext dctx) noexcept
60*dcf958e2SJacob Faibussowitsch   {
61*dcf958e2SJacob Faibussowitsch     PetscFunctionBegin;
62*dcf958e2SJacob Faibussowitsch     PetscCall(CxxDataCast(dctx)->reset_self(dctx));
63*dcf958e2SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
64*dcf958e2SJacob Faibussowitsch   }
65030f984aSJacob Faibussowitsch };
66030f984aSJacob Faibussowitsch 
67146a86ebSJacob Faibussowitsch static Petsc::ObjectPool<_p_PetscDeviceContext, PetscDeviceContextConstructor> contextPool;
68030f984aSJacob Faibussowitsch 
6910450e9eSJacob Faibussowitsch // PetscClangLinter pragma disable: -fdoc-section-header-unknown
70030f984aSJacob Faibussowitsch /*@C
71811af0c4SBarry Smith   PetscDeviceContextCreate - Creates a `PetscDeviceContext`
72030f984aSJacob Faibussowitsch 
730e6b6b59SJacob Faibussowitsch   Not Collective
74030f984aSJacob Faibussowitsch 
75d5b43468SJose E. Roman   Output Parameter:
76811af0c4SBarry Smith . dctx - The `PetscDeviceContext`
77030f984aSJacob Faibussowitsch 
782fe279fdSBarry Smith   Level: beginner
792fe279fdSBarry Smith 
80811af0c4SBarry Smith   Note:
81030f984aSJacob Faibussowitsch   Unlike almost every other PETSc class it is advised that most users use
820e6b6b59SJacob Faibussowitsch   `PetscDeviceContextDuplicate()` rather than this routine to create new contexts. Contexts of
830e6b6b59SJacob Faibussowitsch   different types are incompatible with one another; using `PetscDeviceContextDuplicate()`
840e6b6b59SJacob Faibussowitsch   ensures compatible types.
850e6b6b59SJacob Faibussowitsch 
860e6b6b59SJacob Faibussowitsch   DAG representation:
870e6b6b59SJacob Faibussowitsch .vb
880e6b6b59SJacob Faibussowitsch   time ->
890e6b6b59SJacob Faibussowitsch 
900e6b6b59SJacob Faibussowitsch   |= CALL =| - dctx ->
910e6b6b59SJacob Faibussowitsch .ve
92030f984aSJacob Faibussowitsch 
930e6b6b59SJacob Faibussowitsch .N ASYNC_API
940e6b6b59SJacob Faibussowitsch 
95db781477SPatrick Sanan .seealso: `PetscDeviceContextDuplicate()`, `PetscDeviceContextSetDevice()`,
96db781477SPatrick Sanan `PetscDeviceContextSetStreamType()`, `PetscDeviceContextSetUp()`,
970e6b6b59SJacob Faibussowitsch `PetscDeviceContextSetFromOptions()`, `PetscDeviceContextView()`, `PetscDeviceContextDestroy()`
98030f984aSJacob Faibussowitsch @*/
99d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextCreate(PetscDeviceContext *dctx)
100d71ae5a4SJacob Faibussowitsch {
101030f984aSJacob Faibussowitsch   PetscFunctionBegin;
1024f572ea9SToby Isaac   PetscAssertPointer(dctx, 1);
1039566063dSJacob Faibussowitsch   PetscCall(PetscDeviceInitializePackage());
1046a4a1270SPierre Jolivet   PetscCall(PetscLogEventBegin(DCONTEXT_Create, nullptr, nullptr, nullptr, nullptr));
1050e6b6b59SJacob Faibussowitsch   PetscCall(contextPool.allocate(dctx));
1066a4a1270SPierre Jolivet   PetscCall(PetscLogEventEnd(DCONTEXT_Create, nullptr, nullptr, nullptr, nullptr));
1073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
108030f984aSJacob Faibussowitsch }
109030f984aSJacob Faibussowitsch 
11010450e9eSJacob Faibussowitsch // PetscClangLinter pragma disable: -fdoc-section-header-unknown
111030f984aSJacob Faibussowitsch /*@C
112811af0c4SBarry Smith   PetscDeviceContextDestroy - Frees a `PetscDeviceContext`
113030f984aSJacob Faibussowitsch 
1140e6b6b59SJacob Faibussowitsch   Not Collective
115030f984aSJacob Faibussowitsch 
1162fe279fdSBarry Smith   Input Parameter:
117811af0c4SBarry Smith . dctx - The `PetscDeviceContext`
118030f984aSJacob Faibussowitsch 
1192fe279fdSBarry Smith   Level: beginner
1202fe279fdSBarry Smith 
1210e6b6b59SJacob Faibussowitsch   Notes:
1220e6b6b59SJacob Faibussowitsch   No implicit synchronization occurs due to this routine, all resources are released completely
1230e6b6b59SJacob Faibussowitsch   asynchronously w.r.t. the host. If one needs to guarantee access to the data produced on
1240e6b6b59SJacob Faibussowitsch   `dctx`'s stream the user is responsible for calling `PetscDeviceContextSynchronize()` before
1250e6b6b59SJacob Faibussowitsch   calling this routine.
126030f984aSJacob Faibussowitsch 
127da81f932SPierre Jolivet   DAG representation:
1280e6b6b59SJacob Faibussowitsch .vb
1290e6b6b59SJacob Faibussowitsch   time ->
1300e6b6b59SJacob Faibussowitsch 
1310e6b6b59SJacob Faibussowitsch   -> dctx - |= CALL =|
1320e6b6b59SJacob Faibussowitsch .ve
1330e6b6b59SJacob Faibussowitsch 
1340e6b6b59SJacob Faibussowitsch   Developer Notes:
1350e6b6b59SJacob Faibussowitsch   `dctx` is never actually "destroyed" in the classical sense. It is returned to an ever
1360e6b6b59SJacob Faibussowitsch   growing pool of `PetscDeviceContext`s. There are currently no limits on the size of the pool,
1370e6b6b59SJacob Faibussowitsch   this should perhaps be implemented.
138030f984aSJacob Faibussowitsch 
1390e6b6b59SJacob Faibussowitsch .N ASYNC_API
1400e6b6b59SJacob Faibussowitsch 
1410e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextSetDevice()`,
1420e6b6b59SJacob Faibussowitsch `PetscDeviceContextSetUp()`, `PetscDeviceContextSynchronize()`
143030f984aSJacob Faibussowitsch @*/
144d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextDestroy(PetscDeviceContext *dctx)
145d71ae5a4SJacob Faibussowitsch {
146030f984aSJacob Faibussowitsch   PetscFunctionBegin;
1474f572ea9SToby Isaac   PetscAssertPointer(dctx, 1);
1483ba16761SJacob Faibussowitsch   if (!*dctx) PetscFunctionReturn(PETSC_SUCCESS);
1496a4a1270SPierre Jolivet   PetscCall(PetscLogEventBegin(DCONTEXT_Destroy, nullptr, nullptr, nullptr, nullptr));
1500e6b6b59SJacob Faibussowitsch   if (--(PetscObjectCast(*dctx)->refct) <= 0) {
1510e6b6b59SJacob Faibussowitsch     PetscCall(PetscDeviceContextCheckNotOrphaned_Internal(*dctx));
152146a86ebSJacob Faibussowitsch     PetscCall(contextPool.deallocate(dctx));
1530e6b6b59SJacob Faibussowitsch   }
1546a4a1270SPierre Jolivet   PetscCall(PetscLogEventEnd(DCONTEXT_Destroy, nullptr, nullptr, nullptr, nullptr));
155bf025ffbSJacob Faibussowitsch   *dctx = nullptr;
1563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
157030f984aSJacob Faibussowitsch }
158030f984aSJacob Faibussowitsch 
159030f984aSJacob Faibussowitsch /*@C
1600e6b6b59SJacob Faibussowitsch   PetscDeviceContextSetStreamType - Set the implementation type of the underlying stream for a
1610e6b6b59SJacob Faibussowitsch   `PetscDeviceContext`
162030f984aSJacob Faibussowitsch 
1630e6b6b59SJacob Faibussowitsch   Not Collective
164030f984aSJacob Faibussowitsch 
16501d2d390SJose E. Roman   Input Parameters:
166811af0c4SBarry Smith + dctx - The `PetscDeviceContext`
167811af0c4SBarry Smith - type - The `PetscStreamType`
168030f984aSJacob Faibussowitsch 
1692fe279fdSBarry Smith   Level: beginner
1702fe279fdSBarry Smith 
1712fe279fdSBarry Smith   Note:
172811af0c4SBarry Smith   See `PetscStreamType` in `include/petscdevicetypes.h` for more information on the available
1730e6b6b59SJacob Faibussowitsch   types and their interactions. If the `PetscDeviceContext` was previously set up and stream
174811af0c4SBarry Smith   type was changed, you must call `PetscDeviceContextSetUp()` again after this routine.
175030f984aSJacob Faibussowitsch 
1760e6b6b59SJacob Faibussowitsch .seealso: `PetscStreamType`, `PetscDeviceContextGetStreamType()`, `PetscDeviceContextCreate()`,
1770e6b6b59SJacob Faibussowitsch `PetscDeviceContextSetUp()`, `PetscDeviceContextSetFromOptions()`
178030f984aSJacob Faibussowitsch @*/
179d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetStreamType(PetscDeviceContext dctx, PetscStreamType type)
180d71ae5a4SJacob Faibussowitsch {
181030f984aSJacob Faibussowitsch   PetscFunctionBegin;
1820e6b6b59SJacob Faibussowitsch   // do not use getoptionalnullcontext here since we do not want the user to change the stream
1830e6b6b59SJacob Faibussowitsch   // type
184030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx, 1);
185030f984aSJacob Faibussowitsch   PetscValidStreamType(type, 2);
1860e6b6b59SJacob Faibussowitsch   // only need to do complex swapping if the object has already been setup
187030f984aSJacob Faibussowitsch   if (dctx->setup && (dctx->streamType != type)) {
188030f984aSJacob Faibussowitsch     dctx->setup = PETSC_FALSE;
1896a4a1270SPierre Jolivet     PetscCall(PetscLogEventBegin(DCONTEXT_ChangeStream, dctx, nullptr, nullptr, nullptr));
1900e6b6b59SJacob Faibussowitsch     PetscUseTypeMethod(dctx, changestreamtype, type);
1916a4a1270SPierre Jolivet     PetscCall(PetscLogEventEnd(DCONTEXT_ChangeStream, dctx, nullptr, nullptr, nullptr));
192030f984aSJacob Faibussowitsch   }
193030f984aSJacob Faibussowitsch   dctx->streamType = type;
1943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
195030f984aSJacob Faibussowitsch }
196030f984aSJacob Faibussowitsch 
197030f984aSJacob Faibussowitsch /*@C
1980e6b6b59SJacob Faibussowitsch   PetscDeviceContextGetStreamType - Get the implementation type of the underlying stream for a
1990e6b6b59SJacob Faibussowitsch   `PetscDeviceContext`
200030f984aSJacob Faibussowitsch 
2010e6b6b59SJacob Faibussowitsch   Not Collective
202030f984aSJacob Faibussowitsch 
20301d2d390SJose E. Roman   Input Parameter:
204811af0c4SBarry Smith . dctx - The `PetscDeviceContext`
205030f984aSJacob Faibussowitsch 
206030f984aSJacob Faibussowitsch   Output Parameter:
207811af0c4SBarry Smith . type - The `PetscStreamType`
208030f984aSJacob Faibussowitsch 
2092fe279fdSBarry Smith   Level: beginner
2102fe279fdSBarry Smith 
2112fe279fdSBarry Smith   Note:
2120e6b6b59SJacob Faibussowitsch   See `PetscStreamType` in `include/petscdevicetypes.h` for more information on the available
2130e6b6b59SJacob Faibussowitsch   types and their interactions
214030f984aSJacob Faibussowitsch 
2150e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextSetStreamType()`, `PetscDeviceContextCreate()`,
2160e6b6b59SJacob Faibussowitsch `PetscDeviceContextSetFromOptions()`
217030f984aSJacob Faibussowitsch @*/
218d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextGetStreamType(PetscDeviceContext dctx, PetscStreamType *type)
219d71ae5a4SJacob Faibussowitsch {
220030f984aSJacob Faibussowitsch   PetscFunctionBegin;
2210e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
2224f572ea9SToby Isaac   PetscAssertPointer(type, 2);
223030f984aSJacob Faibussowitsch   *type = dctx->streamType;
2243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
225030f984aSJacob Faibussowitsch }
226030f984aSJacob Faibussowitsch 
2270e6b6b59SJacob Faibussowitsch /*
2280e6b6b59SJacob Faibussowitsch   Actual function to set the device.
229030f984aSJacob Faibussowitsch 
2300e6b6b59SJacob Faibussowitsch   1. Repeatedly destroying and recreating internal data structures (like streams and events)
2310e6b6b59SJacob Faibussowitsch      for recycled PetscDeviceContexts is not free. If done often, it does add up.
2320e6b6b59SJacob Faibussowitsch   2. The vast majority of PetscDeviceContexts are created by PETSc either as children or
23335cb6cd3SPierre Jolivet      default contexts. The default contexts *never* change type, and the children are extremely
2340e6b6b59SJacob Faibussowitsch      unlikely to (chances are if you fork once, you will fork again very soon).
2350e6b6b59SJacob Faibussowitsch   3. The only time this calculus changes is if the user themselves sets the device type. In
2360e6b6b59SJacob Faibussowitsch      this case we do not know what the user has changed, so must always wipe the slate clean.
2370e6b6b59SJacob Faibussowitsch 
2380e6b6b59SJacob Faibussowitsch   Thus we need to keep track whether the user explicitly sets the device contexts device.
2390e6b6b59SJacob Faibussowitsch */
240d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDeviceContextSetDevice_Private(PetscDeviceContext dctx, PetscDevice device, PetscBool user_set)
241d71ae5a4SJacob Faibussowitsch {
2420e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
2430e6b6b59SJacob Faibussowitsch   // do not use getoptionalnullcontext here since we do not want the user to change its device
2440e6b6b59SJacob Faibussowitsch   PetscValidDeviceContext(dctx, 1);
2450e6b6b59SJacob Faibussowitsch   PetscValidDevice(device, 2);
2463ba16761SJacob Faibussowitsch   if (dctx->device && (dctx->device->id == device->id)) PetscFunctionReturn(PETSC_SUCCESS);
2476a4a1270SPierre Jolivet   PetscCall(PetscLogEventBegin(DCONTEXT_SetDevice, dctx, nullptr, nullptr, nullptr));
2482126a61dSJacob Faibussowitsch   PetscTryTypeMethod(dctx, destroy);
2490e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceDestroy(&dctx->device));
2500e6b6b59SJacob Faibussowitsch   PetscCall(PetscMemzero(dctx->ops, sizeof(*dctx->ops)));
2512126a61dSJacob Faibussowitsch   PetscCall(PetscDeviceReference_Internal(device));
2522126a61dSJacob Faibussowitsch   // set it before calling the method
2532126a61dSJacob Faibussowitsch   dctx->device = device;
2540e6b6b59SJacob Faibussowitsch   PetscCall((*device->ops->createcontext)(dctx));
2556a4a1270SPierre Jolivet   PetscCall(PetscLogEventEnd(DCONTEXT_SetDevice, dctx, nullptr, nullptr, nullptr));
2560e6b6b59SJacob Faibussowitsch   dctx->setup         = PETSC_FALSE;
2570e6b6b59SJacob Faibussowitsch   dctx->usersetdevice = user_set;
2583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2590e6b6b59SJacob Faibussowitsch }
2600e6b6b59SJacob Faibussowitsch 
261d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetDefaultDeviceForType_Internal(PetscDeviceContext dctx, PetscDeviceType type)
262d71ae5a4SJacob Faibussowitsch {
2630e6b6b59SJacob Faibussowitsch   PetscDevice device;
2640e6b6b59SJacob Faibussowitsch 
2650e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
2660e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceGetDefaultForType_Internal(type, &device));
2670e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextSetDevice_Private(dctx, device, PETSC_FALSE));
2683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2690e6b6b59SJacob Faibussowitsch }
2700e6b6b59SJacob Faibussowitsch 
2710e6b6b59SJacob Faibussowitsch /*@C
2720e6b6b59SJacob Faibussowitsch   PetscDeviceContextSetDevice - Set the underlying `PetscDevice` for a `PetscDeviceContext`
2730e6b6b59SJacob Faibussowitsch 
2740e6b6b59SJacob Faibussowitsch   Not Collective
275030f984aSJacob Faibussowitsch 
27601d2d390SJose E. Roman   Input Parameters:
277811af0c4SBarry Smith + dctx   - The `PetscDeviceContext`
278811af0c4SBarry Smith - device - The `PetscDevice`
279030f984aSJacob Faibussowitsch 
2802fe279fdSBarry Smith   Level: intermediate
2812fe279fdSBarry Smith 
282030f984aSJacob Faibussowitsch   Notes:
2830e6b6b59SJacob Faibussowitsch   This routine is effectively `PetscDeviceContext`'s "set-type" (so every `PetscDeviceContext` must
284da81f932SPierre Jolivet   also have an attached `PetscDevice`). Unlike the usual set-type semantics, it is not strictly
2850e6b6b59SJacob Faibussowitsch   necessary to set a contexts device to enable usage, any created `PetscDeviceContext`s will
2860e6b6b59SJacob Faibussowitsch   always come equipped with the "default" device.
287030f984aSJacob Faibussowitsch 
2880e6b6b59SJacob Faibussowitsch   This routine is a no-op if `device` is already attached to `dctx`.
289a4af0ceeSJacob Faibussowitsch 
2900e6b6b59SJacob Faibussowitsch   This routine may (but is very unlikely to) initialize the backend device and may incur
2910e6b6b59SJacob Faibussowitsch   synchronization.
2925181c4f9SJacob Faibussowitsch 
2930e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceCreate()`, `PetscDeviceConfigure()`, `PetscDeviceContextGetDevice()`,
2940e6b6b59SJacob Faibussowitsch `PetscDeviceContextGetDeviceType()`
295030f984aSJacob Faibussowitsch @*/
296d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetDevice(PetscDeviceContext dctx, PetscDevice device)
297d71ae5a4SJacob Faibussowitsch {
298030f984aSJacob Faibussowitsch   PetscFunctionBegin;
2990e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextSetDevice_Private(dctx, device, PETSC_TRUE));
3003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
301030f984aSJacob Faibussowitsch }
302030f984aSJacob Faibussowitsch 
303030f984aSJacob Faibussowitsch /*@C
304811af0c4SBarry Smith   PetscDeviceContextGetDevice - Get the underlying `PetscDevice` for a `PetscDeviceContext`
305030f984aSJacob Faibussowitsch 
3060e6b6b59SJacob Faibussowitsch   Not Collective
307030f984aSJacob Faibussowitsch 
308030f984aSJacob Faibussowitsch   Input Parameter:
309811af0c4SBarry Smith . dctx - the `PetscDeviceContext`
310030f984aSJacob Faibussowitsch 
311030f984aSJacob Faibussowitsch   Output Parameter:
312811af0c4SBarry Smith . device - The `PetscDevice`
313030f984aSJacob Faibussowitsch 
314a375dbeeSPatrick Sanan   Level: intermediate
315a375dbeeSPatrick Sanan 
3162fe279fdSBarry Smith   Note:
3172fe279fdSBarry Smith   This is a borrowed reference, the user should not destroy `device`.
3182fe279fdSBarry Smith 
3190e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextSetDevice()`, `PetscDevice`, `PetscDeviceContextGetDeviceType()`
320030f984aSJacob Faibussowitsch @*/
321d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextGetDevice(PetscDeviceContext dctx, PetscDevice *device)
322d71ae5a4SJacob Faibussowitsch {
323030f984aSJacob Faibussowitsch   PetscFunctionBegin;
3240e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
3254f572ea9SToby Isaac   PetscAssertPointer(device, 2);
3260e6b6b59SJacob Faibussowitsch   PetscAssert(dctx->device, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "PetscDeviceContext %" PetscInt64_FMT " has no attached PetscDevice to get", PetscObjectCast(dctx)->id);
327030f984aSJacob Faibussowitsch   *device = dctx->device;
3283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
329030f984aSJacob Faibussowitsch }
330030f984aSJacob Faibussowitsch 
331030f984aSJacob Faibussowitsch /*@C
3320e6b6b59SJacob Faibussowitsch   PetscDeviceContextGetDeviceType - Get the `PetscDeviceType` for a `PetscDeviceContext`
3330e6b6b59SJacob Faibussowitsch 
3340e6b6b59SJacob Faibussowitsch   Not Collective
3350e6b6b59SJacob Faibussowitsch 
3360e6b6b59SJacob Faibussowitsch   Input Parameter:
3370e6b6b59SJacob Faibussowitsch . dctx - The `PetscDeviceContext`
3380e6b6b59SJacob Faibussowitsch 
3390e6b6b59SJacob Faibussowitsch   Output Parameter:
3400e6b6b59SJacob Faibussowitsch . type - The `PetscDeviceType`
3410e6b6b59SJacob Faibussowitsch 
3422fe279fdSBarry Smith   Level: beginner
3432fe279fdSBarry Smith 
3442fe279fdSBarry Smith   Note:
3450e6b6b59SJacob Faibussowitsch   This routine is a convenience shorthand for `PetscDeviceContextGetDevice()` ->
3460e6b6b59SJacob Faibussowitsch   `PetscDeviceGetType()`.
3470e6b6b59SJacob Faibussowitsch 
3480e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceType`, `PetscDeviceContextGetDevice()`, `PetscDeviceGetType()`, `PetscDevice`
3490e6b6b59SJacob Faibussowitsch @*/
350d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextGetDeviceType(PetscDeviceContext dctx, PetscDeviceType *type)
351d71ae5a4SJacob Faibussowitsch {
3520e6b6b59SJacob Faibussowitsch   PetscDevice device = nullptr;
3530e6b6b59SJacob Faibussowitsch 
3540e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
3550e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
3564f572ea9SToby Isaac   PetscAssertPointer(type, 2);
3570e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetDevice(dctx, &device));
3580e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceGetType(device, type));
3593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3600e6b6b59SJacob Faibussowitsch }
3610e6b6b59SJacob Faibussowitsch 
3620e6b6b59SJacob Faibussowitsch /*@C
363811af0c4SBarry Smith   PetscDeviceContextSetUp - Prepares a `PetscDeviceContext` for use
364030f984aSJacob Faibussowitsch 
3650e6b6b59SJacob Faibussowitsch   Not Collective
366030f984aSJacob Faibussowitsch 
36701d2d390SJose E. Roman   Input Parameter:
368811af0c4SBarry Smith . dctx - The `PetscDeviceContext`
369030f984aSJacob Faibussowitsch 
3702fe279fdSBarry Smith   Level: beginner
3712fe279fdSBarry Smith 
372aec76313SJacob Faibussowitsch   Developer Notes:
3730e6b6b59SJacob Faibussowitsch   This routine is usually the stage where a `PetscDeviceContext` acquires device-side data
3740e6b6b59SJacob Faibussowitsch   structures such as streams, events, and (possibly) handles.
375030f984aSJacob Faibussowitsch 
3760e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextSetDevice()`,
3770e6b6b59SJacob Faibussowitsch `PetscDeviceContextDestroy()`, `PetscDeviceContextSetFromOptions()`
378030f984aSJacob Faibussowitsch @*/
379d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetUp(PetscDeviceContext dctx)
380d71ae5a4SJacob Faibussowitsch {
381030f984aSJacob Faibussowitsch   PetscFunctionBegin;
3820e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
3833ba16761SJacob Faibussowitsch   if (dctx->setup) PetscFunctionReturn(PETSC_SUCCESS);
3840e6b6b59SJacob Faibussowitsch   if (!dctx->device) {
3850e6b6b59SJacob Faibussowitsch     const auto default_dtype = PETSC_DEVICE_DEFAULT();
3860e6b6b59SJacob Faibussowitsch 
3870e6b6b59SJacob 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]));
3880e6b6b59SJacob Faibussowitsch     PetscCall(PetscDeviceContextSetDefaultDeviceForType_Internal(dctx, default_dtype));
3890e6b6b59SJacob Faibussowitsch   }
3906a4a1270SPierre Jolivet   PetscCall(PetscLogEventBegin(DCONTEXT_SetUp, dctx, nullptr, nullptr, nullptr));
391dbbe0bcdSBarry Smith   PetscUseTypeMethod(dctx, setup);
3926a4a1270SPierre Jolivet   PetscCall(PetscLogEventEnd(DCONTEXT_SetUp, dctx, nullptr, nullptr, nullptr));
393030f984aSJacob Faibussowitsch   dctx->setup = PETSC_TRUE;
3943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
395030f984aSJacob Faibussowitsch }
396030f984aSJacob Faibussowitsch 
397d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDeviceContextDuplicate_Private(PetscDeviceContext dctx, PetscStreamType stype, PetscDeviceContext *dctxdup)
398d71ae5a4SJacob Faibussowitsch {
3990e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
4006a4a1270SPierre Jolivet   PetscCall(PetscLogEventBegin(DCONTEXT_Duplicate, dctx, nullptr, nullptr, nullptr));
4010e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextCreate(dctxdup));
4020e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextSetStreamType(*dctxdup, stype));
4030e6b6b59SJacob Faibussowitsch   if (const auto device = dctx->device) PetscCall(PetscDeviceContextSetDevice_Private(*dctxdup, device, dctx->usersetdevice));
4040e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextSetUp(*dctxdup));
4056a4a1270SPierre Jolivet   PetscCall(PetscLogEventEnd(DCONTEXT_Duplicate, dctx, nullptr, nullptr, nullptr));
4063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4070e6b6b59SJacob Faibussowitsch }
4080e6b6b59SJacob Faibussowitsch 
40910450e9eSJacob Faibussowitsch // PetscClangLinter pragma disable: -fdoc-section-header-unknown
410030f984aSJacob Faibussowitsch /*@C
411811af0c4SBarry Smith   PetscDeviceContextDuplicate - Duplicates a `PetscDeviceContext` object
412030f984aSJacob Faibussowitsch 
4130e6b6b59SJacob Faibussowitsch   Not Collective
414030f984aSJacob Faibussowitsch 
415030f984aSJacob Faibussowitsch   Input Parameter:
416811af0c4SBarry Smith . dctx - The `PetscDeviceContext` to duplicate
417030f984aSJacob Faibussowitsch 
4186aad120cSJose E. Roman   Output Parameter:
419811af0c4SBarry Smith . dctxdup - The duplicated `PetscDeviceContext`
420030f984aSJacob Faibussowitsch 
4212fe279fdSBarry Smith   Level: beginner
4222fe279fdSBarry Smith 
4230e6b6b59SJacob Faibussowitsch   Notes:
4240e6b6b59SJacob Faibussowitsch   This is a shorthand method for creating a `PetscDeviceContext` with the exact same settings as
4250e6b6b59SJacob Faibussowitsch   another. Note however that `dctxdup` does not share any of the underlying data with `dctx`,
4260e6b6b59SJacob Faibussowitsch   (including its current stream-state) they are completely separate objects.
4270e6b6b59SJacob Faibussowitsch 
4280e6b6b59SJacob Faibussowitsch   There is no implied ordering between `dctx` or `dctxdup`.
4290e6b6b59SJacob Faibussowitsch 
4300e6b6b59SJacob Faibussowitsch   DAG representation:
4310e6b6b59SJacob Faibussowitsch .vb
4320e6b6b59SJacob Faibussowitsch   time ->
4330e6b6b59SJacob Faibussowitsch 
4340e6b6b59SJacob Faibussowitsch   -> dctx - |= CALL =| - dctx ---->
4350e6b6b59SJacob Faibussowitsch                        - dctxdup ->
4360e6b6b59SJacob Faibussowitsch .ve
437030f984aSJacob Faibussowitsch 
4380e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextSetDevice()`,
4390e6b6b59SJacob Faibussowitsch `PetscDeviceContextSetStreamType()`
440030f984aSJacob Faibussowitsch @*/
441d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextDuplicate(PetscDeviceContext dctx, PetscDeviceContext *dctxdup)
442d71ae5a4SJacob Faibussowitsch {
4430e6b6b59SJacob Faibussowitsch   auto stype = PETSC_STREAM_DEFAULT_BLOCKING;
444030f984aSJacob Faibussowitsch 
445030f984aSJacob Faibussowitsch   PetscFunctionBegin;
4460e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
4474f572ea9SToby Isaac   PetscAssertPointer(dctxdup, 2);
4480e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetStreamType(dctx, &stype));
4490e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextDuplicate_Private(dctx, stype, dctxdup));
4503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
451030f984aSJacob Faibussowitsch }
452030f984aSJacob Faibussowitsch 
453030f984aSJacob Faibussowitsch /*@C
454811af0c4SBarry Smith   PetscDeviceContextQueryIdle - Returns whether or not a `PetscDeviceContext` is idle
455030f984aSJacob Faibussowitsch 
4560e6b6b59SJacob Faibussowitsch   Not Collective
457030f984aSJacob Faibussowitsch 
458030f984aSJacob Faibussowitsch   Input Parameter:
4590e6b6b59SJacob Faibussowitsch . dctx - The `PetscDeviceContext`
460030f984aSJacob Faibussowitsch 
461030f984aSJacob Faibussowitsch   Output Parameter:
4620e6b6b59SJacob Faibussowitsch . idle - `PETSC_TRUE` if `dctx` has NO work, `PETSC_FALSE` if it has work
463030f984aSJacob Faibussowitsch 
4642fe279fdSBarry Smith   Level: intermediate
4652fe279fdSBarry Smith 
466811af0c4SBarry Smith   Note:
467ef657721SJacob Faibussowitsch   This routine only refers a singular context and does NOT take any of its children into
4680e6b6b59SJacob Faibussowitsch   account. That is, if `dctx` is idle but has dependents who do have work this routine still
469811af0c4SBarry Smith   returns `PETSC_TRUE`.
470030f984aSJacob Faibussowitsch 
471db781477SPatrick Sanan .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextWaitForContext()`, `PetscDeviceContextFork()`
472030f984aSJacob Faibussowitsch @*/
473d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextQueryIdle(PetscDeviceContext dctx, PetscBool *idle)
474d71ae5a4SJacob Faibussowitsch {
475030f984aSJacob Faibussowitsch   PetscFunctionBegin;
4760e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
4774f572ea9SToby Isaac   PetscAssertPointer(idle, 2);
4786a4a1270SPierre Jolivet   PetscCall(PetscLogEventBegin(DCONTEXT_QueryIdle, dctx, nullptr, nullptr, nullptr));
479dbbe0bcdSBarry Smith   PetscUseTypeMethod(dctx, query, idle);
4806a4a1270SPierre Jolivet   PetscCall(PetscLogEventEnd(DCONTEXT_QueryIdle, dctx, nullptr, nullptr, nullptr));
4810e6b6b59SJacob 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"));
4823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
483030f984aSJacob Faibussowitsch }
484030f984aSJacob Faibussowitsch 
48510450e9eSJacob Faibussowitsch // PetscClangLinter pragma disable: -fdoc-section-header-unknown
486030f984aSJacob Faibussowitsch /*@C
487030f984aSJacob Faibussowitsch   PetscDeviceContextWaitForContext - Make one context wait for another context to finish
488030f984aSJacob Faibussowitsch 
4890e6b6b59SJacob Faibussowitsch   Not Collective
490030f984aSJacob Faibussowitsch 
491030f984aSJacob Faibussowitsch   Input Parameters:
492811af0c4SBarry Smith + dctxa - The `PetscDeviceContext` object that is waiting
493811af0c4SBarry Smith - dctxb - The `PetscDeviceContext` object that is being waited on
494030f984aSJacob Faibussowitsch 
4952fe279fdSBarry Smith   Level: beginner
4962fe279fdSBarry Smith 
497030f984aSJacob Faibussowitsch   Notes:
4980e6b6b59SJacob Faibussowitsch   Serializes two `PetscDeviceContext`s. Serialization is performed asynchronously; the host
4990e6b6b59SJacob Faibussowitsch   does not wait for the serialization to actually occur.
500811af0c4SBarry Smith 
5010e6b6b59SJacob Faibussowitsch   This routine uses only the state of `dctxb` at the moment this routine was called, so any
5020e6b6b59SJacob Faibussowitsch   future work queued will not affect `dctxa`. It is safe to pass the same context to both
5030e6b6b59SJacob Faibussowitsch   arguments (in which case this routine does nothing).
5040e6b6b59SJacob Faibussowitsch 
5050e6b6b59SJacob Faibussowitsch   DAG representation:
5060e6b6b59SJacob Faibussowitsch .vb
5070e6b6b59SJacob Faibussowitsch   time ->
5080e6b6b59SJacob Faibussowitsch 
5090e6b6b59SJacob Faibussowitsch   -> dctxa ---/- |= CALL =| - dctxa ->
5100e6b6b59SJacob Faibussowitsch              /
5110e6b6b59SJacob Faibussowitsch   -> dctxb -/------------------------>
5120e6b6b59SJacob Faibussowitsch .ve
513030f984aSJacob Faibussowitsch 
5140e6b6b59SJacob Faibussowitsch .N ASYNC_API
5150e6b6b59SJacob Faibussowitsch 
516db781477SPatrick Sanan .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextQueryIdle()`, `PetscDeviceContextJoin()`
517030f984aSJacob Faibussowitsch @*/
518d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextWaitForContext(PetscDeviceContext dctxa, PetscDeviceContext dctxb)
519d71ae5a4SJacob Faibussowitsch {
520*dcf958e2SJacob Faibussowitsch   PetscObjectId bid;
5210e6b6b59SJacob Faibussowitsch 
522030f984aSJacob Faibussowitsch   PetscFunctionBegin;
5230e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctxa));
5240e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctxb));
525030f984aSJacob Faibussowitsch   PetscCheckCompatibleDeviceContexts(dctxa, 1, dctxb, 2);
5263ba16761SJacob Faibussowitsch   if (dctxa == dctxb) PetscFunctionReturn(PETSC_SUCCESS);
527*dcf958e2SJacob Faibussowitsch   bid = PetscObjectCast(dctxb)->id;
5286a4a1270SPierre Jolivet   PetscCall(PetscLogEventBegin(DCONTEXT_WaitForCtx, dctxa, dctxb, nullptr, nullptr));
529dbbe0bcdSBarry Smith   PetscUseTypeMethod(dctxa, waitforcontext, dctxb);
530*dcf958e2SJacob Faibussowitsch   PetscCallCXX(CxxDataCast(dctxa)->upstream()[bid] = CxxDataCast(dctxb)->weak_snapshot());
5316a4a1270SPierre Jolivet   PetscCall(PetscLogEventEnd(DCONTEXT_WaitForCtx, dctxa, dctxb, nullptr, nullptr));
532*dcf958e2SJacob Faibussowitsch   PetscCall(PetscInfo(dctxa, "dctx %" PetscInt64_FMT " waiting on dctx %" PetscInt64_FMT "\n", PetscObjectCast(dctxa)->id, bid));
533*dcf958e2SJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease(PetscObjectCast(dctxa)));
5343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
535030f984aSJacob Faibussowitsch }
536030f984aSJacob Faibussowitsch 
53710450e9eSJacob Faibussowitsch // PetscClangLinter pragma disable: -fdoc-section-header-unknown
5380e6b6b59SJacob Faibussowitsch /*@C
5390e6b6b59SJacob Faibussowitsch   PetscDeviceContextForkWithStreamType - Create a set of dependent child contexts from a parent
5400e6b6b59SJacob Faibussowitsch   context with a prescribed `PetscStreamType`
5410e6b6b59SJacob Faibussowitsch 
5420e6b6b59SJacob Faibussowitsch   Not Collective, Asynchronous
5430e6b6b59SJacob Faibussowitsch 
5440e6b6b59SJacob Faibussowitsch   Input Parameters:
5450e6b6b59SJacob Faibussowitsch + dctx  - The parent `PetscDeviceContext`
5460e6b6b59SJacob Faibussowitsch . stype - The prescribed `PetscStreamType`
5470e6b6b59SJacob Faibussowitsch - n     - The number of children to create
5480e6b6b59SJacob Faibussowitsch 
5490e6b6b59SJacob Faibussowitsch   Output Parameter:
5500e6b6b59SJacob Faibussowitsch . dsub - The created child context(s)
5510e6b6b59SJacob Faibussowitsch 
5522fe279fdSBarry Smith   Level: intermediate
5532fe279fdSBarry Smith 
5540e6b6b59SJacob Faibussowitsch   Notes:
5550e6b6b59SJacob Faibussowitsch   This routine creates `n` edges of a DAG from a source node which are causally dependent on the
5560e6b6b59SJacob Faibussowitsch   source node. This causal dependency is established as-if by calling
5570e6b6b59SJacob Faibussowitsch   `PetscDeviceContextWaitForContext()` on every child.
5580e6b6b59SJacob Faibussowitsch 
5590e6b6b59SJacob Faibussowitsch   `dsub` is allocated by this routine and has its lifetime bounded by `dctx`. That is, `dctx`
5600e6b6b59SJacob Faibussowitsch   expects to free `dsub` (via `PetscDeviceContextJoin()`) before it itself is destroyed.
5610e6b6b59SJacob Faibussowitsch 
5620e6b6b59SJacob Faibussowitsch   This routine only accounts for work queued on `dctx` up until calling this routine, any
5630e6b6b59SJacob Faibussowitsch   subsequent work enqueued on `dctx` has no effect on `dsub`.
5640e6b6b59SJacob Faibussowitsch 
5650e6b6b59SJacob Faibussowitsch   The `PetscStreamType` of `dctx` does not have to equal `stype`. In fact, it is often the case
5660e6b6b59SJacob Faibussowitsch   that they are different. This is useful in cases where a routine can locally exploit stream
5670e6b6b59SJacob Faibussowitsch   parallelism without needing to worry about what stream type the incoming `PetscDeviceContext`
5680e6b6b59SJacob Faibussowitsch   carries.
5690e6b6b59SJacob Faibussowitsch 
5700e6b6b59SJacob Faibussowitsch   DAG representation:
5710e6b6b59SJacob Faibussowitsch .vb
5720e6b6b59SJacob Faibussowitsch   time ->
5730e6b6b59SJacob Faibussowitsch 
5740e6b6b59SJacob Faibussowitsch   -> dctx - |= CALL =| -\----> dctx ------>
5750e6b6b59SJacob Faibussowitsch                          \---> dsub[0] --->
5760e6b6b59SJacob Faibussowitsch                           \--> ... ------->
5770e6b6b59SJacob Faibussowitsch                            \-> dsub[n-1] ->
5780e6b6b59SJacob Faibussowitsch .ve
5790e6b6b59SJacob Faibussowitsch 
5800e6b6b59SJacob Faibussowitsch .N ASYNC_API
5810e6b6b59SJacob Faibussowitsch 
5820e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextJoin()`, `PetscDeviceContextSynchronize()`,
5830e6b6b59SJacob Faibussowitsch `PetscDeviceContextQueryIdle()`, `PetscDeviceContextWaitForContext()`
5840e6b6b59SJacob Faibussowitsch @*/
585d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextForkWithStreamType(PetscDeviceContext dctx, PetscStreamType stype, PetscInt n, PetscDeviceContext **dsub)
586d71ae5a4SJacob Faibussowitsch {
5870e6b6b59SJacob Faibussowitsch   // debugging only
5880e6b6b59SJacob Faibussowitsch   std::string idList;
5890e6b6b59SJacob Faibussowitsch   auto        ninput = n;
5900e6b6b59SJacob Faibussowitsch 
5910e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
5920e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
5930e6b6b59SJacob Faibussowitsch   PetscAssert(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of contexts requested %" PetscInt_FMT " < 0", n);
5944f572ea9SToby Isaac   PetscAssertPointer(dsub, 4);
5950e6b6b59SJacob Faibussowitsch   *dsub = nullptr;
5960e6b6b59SJacob Faibussowitsch   /* reserve 4 chars per id, 2 for number and 2 for ', ' separator */
5970e6b6b59SJacob Faibussowitsch   if (PetscDefined(USE_DEBUG_AND_INFO)) PetscCallCXX(idList.reserve(4 * n));
5986a4a1270SPierre Jolivet   PetscCall(PetscLogEventBegin(DCONTEXT_Fork, dctx, nullptr, nullptr, nullptr));
5990e6b6b59SJacob Faibussowitsch   /* update child totals */
6000e6b6b59SJacob Faibussowitsch   dctx->numChildren += n;
6010e6b6b59SJacob Faibussowitsch   /* now to find out if we have room */
6020e6b6b59SJacob Faibussowitsch   if (dctx->numChildren > dctx->maxNumChildren) {
6030e6b6b59SJacob Faibussowitsch     const auto numChildren    = dctx->numChildren;
6040e6b6b59SJacob Faibussowitsch     auto      &maxNumChildren = dctx->maxNumChildren;
6050e6b6b59SJacob Faibussowitsch     auto       numAllocated   = numChildren;
6060e6b6b59SJacob Faibussowitsch 
6070e6b6b59SJacob Faibussowitsch     /* no room, either from having too many kids or not having any */
6080e6b6b59SJacob Faibussowitsch     if (auto &childIDs = dctx->childIDs) {
6090e6b6b59SJacob Faibussowitsch       // the difference is backwards because we have not updated maxNumChildren yet
6100e6b6b59SJacob Faibussowitsch       numAllocated -= maxNumChildren;
6110e6b6b59SJacob Faibussowitsch       /* have existing children, must reallocate them */
6120e6b6b59SJacob Faibussowitsch       PetscCall(PetscRealloc(numChildren * sizeof(*childIDs), &childIDs));
6130e6b6b59SJacob Faibussowitsch       /* clear the extra memory since realloc doesn't do it for us */
6140e6b6b59SJacob Faibussowitsch       PetscCall(PetscArrayzero(std::next(childIDs, maxNumChildren), numAllocated));
6150e6b6b59SJacob Faibussowitsch     } else {
6160e6b6b59SJacob Faibussowitsch       /* have no children */
6170e6b6b59SJacob Faibussowitsch       PetscCall(PetscCalloc1(numChildren, &childIDs));
6180e6b6b59SJacob Faibussowitsch     }
6190e6b6b59SJacob Faibussowitsch     /* update total number of children */
6200e6b6b59SJacob Faibussowitsch     maxNumChildren = numChildren;
6210e6b6b59SJacob Faibussowitsch   }
6220e6b6b59SJacob Faibussowitsch   PetscCall(PetscMalloc1(n, dsub));
6230e6b6b59SJacob Faibussowitsch   for (PetscInt i = 0; ninput && (i < dctx->numChildren); ++i) {
6240e6b6b59SJacob Faibussowitsch     auto &childID = dctx->childIDs[i];
6250e6b6b59SJacob Faibussowitsch     /* empty child slot */
6260e6b6b59SJacob Faibussowitsch     if (!childID) {
6270e6b6b59SJacob Faibussowitsch       auto &childctx = (*dsub)[i];
6280e6b6b59SJacob Faibussowitsch 
6290e6b6b59SJacob Faibussowitsch       /* create the child context in the image of its parent */
6300e6b6b59SJacob Faibussowitsch       PetscCall(PetscDeviceContextDuplicate_Private(dctx, stype, &childctx));
6310e6b6b59SJacob Faibussowitsch       PetscCall(PetscDeviceContextWaitForContext(childctx, dctx));
6320e6b6b59SJacob Faibussowitsch       /* register the child with its parent */
6330e6b6b59SJacob Faibussowitsch       PetscCall(PetscObjectGetId(PetscObjectCast(childctx), &childID));
6340e6b6b59SJacob Faibussowitsch       if (PetscDefined(USE_DEBUG_AND_INFO)) {
6350e6b6b59SJacob Faibussowitsch         PetscCallCXX(idList += std::to_string(childID));
6360e6b6b59SJacob Faibussowitsch         if (ninput != 1) PetscCallCXX(idList += ", ");
6370e6b6b59SJacob Faibussowitsch       }
6380e6b6b59SJacob Faibussowitsch       --ninput;
6390e6b6b59SJacob Faibussowitsch     }
6400e6b6b59SJacob Faibussowitsch   }
6416a4a1270SPierre Jolivet   PetscCall(PetscLogEventEnd(DCONTEXT_Fork, dctx, nullptr, nullptr, nullptr));
6420e6b6b59SJacob Faibussowitsch   PetscCall(PetscDebugInfo(dctx, "Forked %" PetscInt_FMT " children from parent %" PetscInt64_FMT " with IDs: %s\n", n, PetscObjectCast(dctx)->id, idList.c_str()));
6433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6440e6b6b59SJacob Faibussowitsch }
6450e6b6b59SJacob Faibussowitsch 
646030f984aSJacob Faibussowitsch /*@C
647030f984aSJacob Faibussowitsch   PetscDeviceContextFork - Create a set of dependent child contexts from a parent context
648030f984aSJacob Faibussowitsch 
649030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
650030f984aSJacob Faibussowitsch 
651030f984aSJacob Faibussowitsch   Input Parameters:
652811af0c4SBarry Smith + dctx - The parent `PetscDeviceContext`
653030f984aSJacob Faibussowitsch - n    - The number of children to create
654030f984aSJacob Faibussowitsch 
655030f984aSJacob Faibussowitsch   Output Parameter:
656030f984aSJacob Faibussowitsch . dsub - The created child context(s)
657030f984aSJacob Faibussowitsch 
6582fe279fdSBarry Smith   Level: beginner
6592fe279fdSBarry Smith 
660030f984aSJacob Faibussowitsch   Notes:
6610e6b6b59SJacob Faibussowitsch   Behaves identically to `PetscDeviceContextForkWithStreamType()` except that the prescribed
6620e6b6b59SJacob Faibussowitsch   `PetscStreamType` is taken from `dctx`. In effect this routine is shorthand for\:
663030f984aSJacob Faibussowitsch 
664030f984aSJacob Faibussowitsch .vb
6650e6b6b59SJacob Faibussowitsch   PetscStreamType stype;
666030f984aSJacob Faibussowitsch 
6670e6b6b59SJacob Faibussowitsch   PetscDeviceContextGetStreamType(dctx, &stype);
6680e6b6b59SJacob Faibussowitsch   PetscDeviceContextForkWithStreamType(dctx, stype, ...);
669030f984aSJacob Faibussowitsch .ve
670030f984aSJacob Faibussowitsch 
6710e6b6b59SJacob Faibussowitsch .N ASYNC_API
6720e6b6b59SJacob Faibussowitsch 
6730e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextForkWithStreamType()`, `PetscDeviceContextJoin()`,
6740e6b6b59SJacob Faibussowitsch `PetscDeviceContextSynchronize()`, `PetscDeviceContextQueryIdle()`
675030f984aSJacob Faibussowitsch @*/
676d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextFork(PetscDeviceContext dctx, PetscInt n, PetscDeviceContext **dsub)
677d71ae5a4SJacob Faibussowitsch {
6780e6b6b59SJacob Faibussowitsch   auto stype = PETSC_STREAM_DEFAULT_BLOCKING;
679030f984aSJacob Faibussowitsch 
680030f984aSJacob Faibussowitsch   PetscFunctionBegin;
6810e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
6820e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetStreamType(dctx, &stype));
6830e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextForkWithStreamType(dctx, stype, n, dsub));
6843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
685030f984aSJacob Faibussowitsch }
686030f984aSJacob Faibussowitsch 
68710450e9eSJacob Faibussowitsch // PetscClangLinter pragma disable: -fdoc-section-header-unknown
688030f984aSJacob Faibussowitsch /*@C
6895181c4f9SJacob Faibussowitsch   PetscDeviceContextJoin - Converge a set of child contexts
690030f984aSJacob Faibussowitsch 
691030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
692030f984aSJacob Faibussowitsch 
693030f984aSJacob Faibussowitsch   Input Parameters:
694811af0c4SBarry Smith + dctx     - A `PetscDeviceContext` to converge on
695030f984aSJacob Faibussowitsch . n        - The number of sub contexts to converge
696030f984aSJacob Faibussowitsch . joinMode - The type of join to perform
697030f984aSJacob Faibussowitsch - dsub     - The sub contexts to converge
698030f984aSJacob Faibussowitsch 
6992fe279fdSBarry Smith   Level: beginner
7002fe279fdSBarry Smith 
701030f984aSJacob Faibussowitsch   Notes:
7020e6b6b59SJacob Faibussowitsch   If `PetscDeviceContextFork()` creates `n` edges from a source node which all depend on the source
7030e6b6b59SJacob Faibussowitsch   node, then this routine is the exact mirror. That is, it creates a node (represented in `dctx`)
70435cb6cd3SPierre Jolivet   which receives `n` edges (and optionally destroys them) which is dependent on the completion
7050e6b6b59SJacob Faibussowitsch   of all incoming edges.
706030f984aSJacob Faibussowitsch 
7070e6b6b59SJacob Faibussowitsch   If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_DESTROY`. All contexts in `dsub` will be
7080e6b6b59SJacob Faibussowitsch   destroyed by this routine. Thus all sub contexts must have been created with the `dctx`
7090e6b6b59SJacob Faibussowitsch   passed to this routine.
710030f984aSJacob Faibussowitsch 
7110e6b6b59SJacob Faibussowitsch   If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_SYNC`. All sub contexts will additionally wait on
7120e6b6b59SJacob Faibussowitsch   `dctx` after converging. This has the effect of "synchronizing" the outgoing edges. Note the
7130e6b6b59SJacob Faibussowitsch   sync suffix does NOT refer to the host, i.e. this routine does NOT call
7140e6b6b59SJacob Faibussowitsch   `PetscDeviceSynchronize()`.
715030f984aSJacob Faibussowitsch 
7160e6b6b59SJacob Faibussowitsch   If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC`. `dctx` waits for all sub contexts but
7170e6b6b59SJacob Faibussowitsch   the sub contexts do not wait for one another or `dctx` afterwards.
718030f984aSJacob Faibussowitsch 
719030f984aSJacob Faibussowitsch   DAG representations:
720811af0c4SBarry Smith   If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_DESTROY`
721030f984aSJacob Faibussowitsch .vb
722030f984aSJacob Faibussowitsch   time ->
723030f984aSJacob Faibussowitsch 
7240e6b6b59SJacob Faibussowitsch   -> dctx ---------/- |= CALL =| - dctx ->
725030f984aSJacob Faibussowitsch   -> dsub[0] -----/
726030f984aSJacob Faibussowitsch   ->  ... -------/
727030f984aSJacob Faibussowitsch   -> dsub[n-1] -/
728030f984aSJacob Faibussowitsch .ve
729811af0c4SBarry Smith   If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_SYNC`
730030f984aSJacob Faibussowitsch .vb
731030f984aSJacob Faibussowitsch   time ->
732030f984aSJacob Faibussowitsch 
7330e6b6b59SJacob Faibussowitsch   -> dctx ---------/- |= CALL =| -\----> dctx ------>
734030f984aSJacob Faibussowitsch   -> dsub[0] -----/                \---> dsub[0] --->
735030f984aSJacob Faibussowitsch   ->  ... -------/                  \--> ... ------->
736030f984aSJacob Faibussowitsch   -> dsub[n-1] -/                    \-> dsub[n-1] ->
737030f984aSJacob Faibussowitsch .ve
7380e6b6b59SJacob Faibussowitsch   If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC`
7390e6b6b59SJacob Faibussowitsch .vb
7400e6b6b59SJacob Faibussowitsch   time ->
741030f984aSJacob Faibussowitsch 
7420e6b6b59SJacob Faibussowitsch   -> dctx ----------/- |= CALL =| - dctx ->
7430e6b6b59SJacob Faibussowitsch   -> dsub[0] ------/----------------------->
7440e6b6b59SJacob Faibussowitsch   ->  ... --------/------------------------>
7450e6b6b59SJacob Faibussowitsch   -> dsub[n-1] --/------------------------->
7460e6b6b59SJacob Faibussowitsch .ve
747030f984aSJacob Faibussowitsch 
7480e6b6b59SJacob Faibussowitsch .N ASYNC_API
7490e6b6b59SJacob Faibussowitsch 
7500e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextFork()`, `PetscDeviceContextForkWithStreamType()`,
7510e6b6b59SJacob Faibussowitsch `PetscDeviceContextSynchronize()`, `PetscDeviceContextJoinMode`
752030f984aSJacob Faibussowitsch @*/
753d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextJoin(PetscDeviceContext dctx, PetscInt n, PetscDeviceContextJoinMode joinMode, PetscDeviceContext **dsub)
754d71ae5a4SJacob Faibussowitsch {
7550e6b6b59SJacob Faibussowitsch   // debugging only
7560e6b6b59SJacob Faibussowitsch   std::string idList;
757030f984aSJacob Faibussowitsch 
758030f984aSJacob Faibussowitsch   PetscFunctionBegin;
7590e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
760030f984aSJacob Faibussowitsch   /* validity of dctx is checked in the wait-for loop */
7614f572ea9SToby Isaac   PetscAssertPointer(dsub, 4);
762bf025ffbSJacob Faibussowitsch   PetscAssert(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of contexts merged %" PetscInt_FMT " < 0", n);
763030f984aSJacob Faibussowitsch   /* reserve 4 chars per id, 2 for number and 2 for ', ' separator */
7640e6b6b59SJacob Faibussowitsch   if (PetscDefined(USE_DEBUG_AND_INFO)) PetscCallCXX(idList.reserve(4 * n));
765030f984aSJacob Faibussowitsch   /* first dctx waits on all the incoming edges */
7666a4a1270SPierre Jolivet   PetscCall(PetscLogEventBegin(DCONTEXT_Join, dctx, nullptr, nullptr, nullptr));
767030f984aSJacob Faibussowitsch   for (PetscInt i = 0; i < n; ++i) {
768030f984aSJacob Faibussowitsch     PetscCheckCompatibleDeviceContexts(dctx, 1, (*dsub)[i], 4);
7699566063dSJacob Faibussowitsch     PetscCall(PetscDeviceContextWaitForContext(dctx, (*dsub)[i]));
7700e6b6b59SJacob Faibussowitsch     if (PetscDefined(USE_DEBUG_AND_INFO)) {
7710e6b6b59SJacob Faibussowitsch       PetscCallCXX(idList += std::to_string(PetscObjectCast((*dsub)[i])->id));
7720e6b6b59SJacob Faibussowitsch       if (i + 1 < n) PetscCallCXX(idList += ", ");
7730e6b6b59SJacob Faibussowitsch     }
774030f984aSJacob Faibussowitsch   }
775030f984aSJacob Faibussowitsch 
776030f984aSJacob Faibussowitsch   /* now we handle the aftermath */
777030f984aSJacob Faibussowitsch   switch (joinMode) {
7789371c9d4SSatish Balay   case PETSC_DEVICE_CONTEXT_JOIN_DESTROY: {
7790e6b6b59SJacob Faibussowitsch     const auto children = dctx->childIDs;
7800e6b6b59SJacob Faibussowitsch     const auto maxchild = dctx->maxNumChildren;
7810e6b6b59SJacob Faibussowitsch     auto      &nchild   = dctx->numChildren;
782030f984aSJacob Faibussowitsch     PetscInt   j        = 0;
783030f984aSJacob Faibussowitsch 
7840e6b6b59SJacob 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);
785030f984aSJacob Faibussowitsch     /* update child count while it's still fresh in memory */
7860e6b6b59SJacob Faibussowitsch     nchild -= n;
7870e6b6b59SJacob Faibussowitsch     for (PetscInt i = 0; i < maxchild; ++i) {
7880e6b6b59SJacob Faibussowitsch       if (children[i] && (children[i] == PetscObjectCast((*dsub)[j])->id)) {
789030f984aSJacob Faibussowitsch         /* child is one of ours, can destroy it */
7909566063dSJacob Faibussowitsch         PetscCall(PetscDeviceContextDestroy((*dsub) + j));
791030f984aSJacob Faibussowitsch         /* reset the child slot */
7920e6b6b59SJacob Faibussowitsch         children[i] = 0;
793030f984aSJacob Faibussowitsch         if (++j == n) break;
794030f984aSJacob Faibussowitsch       }
795030f984aSJacob Faibussowitsch     }
7960e6b6b59SJacob Faibussowitsch     /* gone through the loop but did not find every child */
7970e6b6b59SJacob 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);
7989566063dSJacob Faibussowitsch     PetscCall(PetscFree(*dsub));
7999371c9d4SSatish Balay   } break;
800030f984aSJacob Faibussowitsch   case PETSC_DEVICE_CONTEXT_JOIN_SYNC:
8019566063dSJacob Faibussowitsch     for (PetscInt i = 0; i < n; ++i) PetscCall(PetscDeviceContextWaitForContext((*dsub)[i], dctx));
802d71ae5a4SJacob Faibussowitsch   case PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC:
803d71ae5a4SJacob Faibussowitsch     break;
804d71ae5a4SJacob Faibussowitsch   default:
805d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown PetscDeviceContextJoinMode given");
806030f984aSJacob Faibussowitsch   }
8076a4a1270SPierre Jolivet   PetscCall(PetscLogEventEnd(DCONTEXT_Join, dctx, nullptr, nullptr, nullptr));
808030f984aSJacob Faibussowitsch 
8090e6b6b59SJacob 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()));
8103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
811030f984aSJacob Faibussowitsch }
812030f984aSJacob Faibussowitsch 
81310450e9eSJacob Faibussowitsch // PetscClangLinter pragma disable: -fdoc-section-header-unknown
814030f984aSJacob Faibussowitsch /*@C
8150e6b6b59SJacob Faibussowitsch   PetscDeviceContextSynchronize - Block the host until all work queued on a
8160e6b6b59SJacob Faibussowitsch   `PetscDeviceContext` has finished
817030f984aSJacob Faibussowitsch 
8180e6b6b59SJacob Faibussowitsch   Not Collective
819030f984aSJacob Faibussowitsch 
8202fe279fdSBarry Smith   Input Parameter:
821811af0c4SBarry Smith . dctx - The `PetscDeviceContext` to synchronize
822030f984aSJacob Faibussowitsch 
8232fe279fdSBarry Smith   Level: beginner
8242fe279fdSBarry Smith 
8250e6b6b59SJacob Faibussowitsch   Notes:
8260e6b6b59SJacob Faibussowitsch   The host will not return from this routine until `dctx` is idle. Any and all memory
8270e6b6b59SJacob Faibussowitsch   operations queued on or otherwise associated with (either explicitly or implicitly via
8280e6b6b59SJacob Faibussowitsch   dependencies) are guaranteed to have finished and be globally visible on return.
8290e6b6b59SJacob Faibussowitsch 
8300e6b6b59SJacob Faibussowitsch   In effect, this routine serves as memory and execution barrier.
8310e6b6b59SJacob Faibussowitsch 
8320e6b6b59SJacob Faibussowitsch   DAG representation:
8330e6b6b59SJacob Faibussowitsch .vb
8340e6b6b59SJacob Faibussowitsch   time ->
8350e6b6b59SJacob Faibussowitsch 
8360e6b6b59SJacob Faibussowitsch   -> dctx - |= CALL =| - dctx ->
8370e6b6b59SJacob Faibussowitsch .ve
8380e6b6b59SJacob Faibussowitsch 
839db781477SPatrick Sanan .seealso: `PetscDeviceContextFork()`, `PetscDeviceContextJoin()`, `PetscDeviceContextQueryIdle()`
840030f984aSJacob Faibussowitsch @*/
841d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextSynchronize(PetscDeviceContext dctx)
842d71ae5a4SJacob Faibussowitsch {
843030f984aSJacob Faibussowitsch   PetscFunctionBegin;
8440e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
8456a4a1270SPierre Jolivet   PetscCall(PetscLogEventBegin(DCONTEXT_Sync, dctx, nullptr, nullptr, nullptr));
846030f984aSJacob Faibussowitsch   /* if it isn't setup there is nothing to sync on */
8470e6b6b59SJacob Faibussowitsch   if (dctx->setup) {
8482f85e401SJacob Faibussowitsch     PetscUseTypeMethod(dctx, synchronize);
8490e6b6b59SJacob Faibussowitsch     PetscCall(PetscDeviceContextSyncClearMap_Internal(dctx));
8500e6b6b59SJacob Faibussowitsch   }
8516a4a1270SPierre Jolivet   PetscCall(PetscLogEventEnd(DCONTEXT_Sync, dctx, nullptr, nullptr, nullptr));
8523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
853030f984aSJacob Faibussowitsch }
854030f984aSJacob Faibussowitsch 
8550e6b6b59SJacob Faibussowitsch /* every device type has a vector of null PetscDeviceContexts -- one for each device */
8560e6b6b59SJacob Faibussowitsch static auto nullContexts          = std::array<std::vector<PetscDeviceContext>, PETSC_DEVICE_MAX>{};
8570e6b6b59SJacob Faibussowitsch static auto nullContextsFinalizer = false;
858030f984aSJacob Faibussowitsch 
859d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDeviceContextGetNullContextForDevice_Private(PetscBool user_set_device, PetscDevice device, PetscDeviceContext *dctx)
860d71ae5a4SJacob Faibussowitsch {
8610e6b6b59SJacob Faibussowitsch   PetscInt        devid;
8620e6b6b59SJacob Faibussowitsch   PetscDeviceType dtype;
863a4af0ceeSJacob Faibussowitsch 
864030f984aSJacob Faibussowitsch   PetscFunctionBegin;
8650e6b6b59SJacob Faibussowitsch   PetscValidDevice(device, 2);
8664f572ea9SToby Isaac   PetscAssertPointer(dctx, 3);
8670e6b6b59SJacob Faibussowitsch   if (PetscUnlikely(!nullContextsFinalizer)) {
8683048253cSJacob Faibussowitsch     nullContextsFinalizer = true;
8693048253cSJacob Faibussowitsch     PetscCall(PetscRegisterFinalize([] {
8700e6b6b59SJacob Faibussowitsch       PetscFunctionBegin;
8710e6b6b59SJacob Faibussowitsch       for (auto &&dvec : nullContexts) {
8720e6b6b59SJacob Faibussowitsch         for (auto &&dctx : dvec) PetscCall(PetscDeviceContextDestroy(&dctx));
8730e6b6b59SJacob Faibussowitsch         PetscCallCXX(dvec.clear());
874030f984aSJacob Faibussowitsch       }
8750e6b6b59SJacob Faibussowitsch       nullContextsFinalizer = false;
8763ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
8773048253cSJacob Faibussowitsch     }));
8780e6b6b59SJacob Faibussowitsch   }
8790e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceGetDeviceId(device, &devid));
8800e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceGetType(device, &dtype));
8810e6b6b59SJacob Faibussowitsch   {
8820e6b6b59SJacob Faibussowitsch     auto &ctxlist = nullContexts[dtype];
8830e6b6b59SJacob Faibussowitsch 
8840e6b6b59SJacob Faibussowitsch     PetscCheck(devid >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Device ID (%" PetscInt_FMT ") must be positive", devid);
8850e6b6b59SJacob Faibussowitsch     // need to resize the container if not big enough because incrementing the iterator in
8860e6b6b59SJacob Faibussowitsch     // std::next() (if we haven't initialized that ctx yet) may cause it to fall outside the
8870e6b6b59SJacob Faibussowitsch     // current size of the container.
8880e6b6b59SJacob Faibussowitsch     if (static_cast<std::size_t>(devid) >= ctxlist.size()) PetscCallCXX(ctxlist.resize(devid + 1));
8890e6b6b59SJacob Faibussowitsch     if (PetscUnlikely(!ctxlist[devid])) {
8900e6b6b59SJacob Faibussowitsch       // we have not seen this device before
8910e6b6b59SJacob Faibussowitsch       PetscCall(PetscDeviceContextCreate(dctx));
892403f9ca4SJacob Faibussowitsch       PetscCall(PetscInfo(*dctx, "Initializing null PetscDeviceContext (of type %s) for device %" PetscInt_FMT "\n", PetscDeviceTypes[dtype], devid));
8930e6b6b59SJacob Faibussowitsch       {
8940e6b6b59SJacob Faibussowitsch         const auto pobj   = PetscObjectCast(*dctx);
8950e6b6b59SJacob Faibussowitsch         const auto name   = "null context " + std::to_string(devid);
8960e6b6b59SJacob Faibussowitsch         const auto prefix = "null_context_" + std::to_string(devid) + '_';
8970e6b6b59SJacob Faibussowitsch 
8980e6b6b59SJacob Faibussowitsch         PetscCall(PetscObjectSetName(pobj, name.c_str()));
8990e6b6b59SJacob Faibussowitsch         PetscCall(PetscObjectSetOptionsPrefix(pobj, prefix.c_str()));
9000e6b6b59SJacob Faibussowitsch       }
9010e6b6b59SJacob Faibussowitsch       PetscCall(PetscDeviceContextSetStreamType(*dctx, PETSC_STREAM_GLOBAL_BLOCKING));
9020e6b6b59SJacob Faibussowitsch       PetscCall(PetscDeviceContextSetDevice_Private(*dctx, device, user_set_device));
9030e6b6b59SJacob Faibussowitsch       PetscCall(PetscDeviceContextSetUp(*dctx));
9040e6b6b59SJacob Faibussowitsch       // would use ctxlist.cbegin() but GCC 4.8 can't handle const iterator insert!
9050e6b6b59SJacob Faibussowitsch       PetscCallCXX(ctxlist.insert(std::next(ctxlist.begin(), devid), *dctx));
9060e6b6b59SJacob Faibussowitsch     } else *dctx = ctxlist[devid];
9070e6b6b59SJacob Faibussowitsch   }
9083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
909030f984aSJacob Faibussowitsch }
910030f984aSJacob Faibussowitsch 
9110e6b6b59SJacob Faibussowitsch /*
9120e6b6b59SJacob Faibussowitsch   Gets the "NULL" context for the current PetscDeviceType and PetscDevice. NULL contexts are
9130e6b6b59SJacob Faibussowitsch   guaranteed to always be globally blocking.
9140e6b6b59SJacob Faibussowitsch */
915d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextGetNullContext_Internal(PetscDeviceContext *dctx)
916d71ae5a4SJacob Faibussowitsch {
9170e6b6b59SJacob Faibussowitsch   PetscDeviceContext gctx;
9180e6b6b59SJacob Faibussowitsch   PetscDevice        gdev = nullptr;
919030f984aSJacob Faibussowitsch 
920a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
9214f572ea9SToby Isaac   PetscAssertPointer(dctx, 1);
9220e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetCurrentContext(&gctx));
9230e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetDevice(gctx, &gdev));
9240e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetNullContextForDevice_Private(gctx->usersetdevice, gdev, dctx));
9253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
926030f984aSJacob Faibussowitsch }
927030f984aSJacob Faibussowitsch 
928030f984aSJacob Faibussowitsch /*@C
929811af0c4SBarry Smith   PetscDeviceContextSetFromOptions - Configure a `PetscDeviceContext` from the options database
930030f984aSJacob Faibussowitsch 
9310e6b6b59SJacob Faibussowitsch   Collective on `comm` or `dctx`
932030f984aSJacob Faibussowitsch 
933030f984aSJacob Faibussowitsch   Input Parameters:
9340e6b6b59SJacob Faibussowitsch + comm - MPI communicator on which to query the options database (optional)
935811af0c4SBarry Smith - dctx - The `PetscDeviceContext` to configure
936030f984aSJacob Faibussowitsch 
937030f984aSJacob Faibussowitsch   Output Parameter:
938811af0c4SBarry Smith . dctx - The `PetscDeviceContext`
939030f984aSJacob Faibussowitsch 
9403c7db156SBarry Smith   Options Database Keys:
9410e6b6b59SJacob Faibussowitsch + -device_context_stream_type - type of stream to create inside the `PetscDeviceContext` -
9420e6b6b59SJacob Faibussowitsch    `PetscDeviceContextSetStreamType()`
943811af0c4SBarry Smith - -device_context_device_type - the type of `PetscDevice` to attach by default - `PetscDeviceType`
944030f984aSJacob Faibussowitsch 
9452fe279fdSBarry Smith   Level: beginner
9462fe279fdSBarry Smith 
9472fe279fdSBarry Smith   Note:
9480e6b6b59SJacob Faibussowitsch   The user may pass `MPI_COMM_NULL` for `comm` in which case the communicator of `dctx` is
9490e6b6b59SJacob Faibussowitsch   used (which is always `PETSC_COMM_SELF`).
9500e6b6b59SJacob Faibussowitsch 
9510e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextSetStreamType()`, `PetscDeviceContextSetDevice()`,
9520e6b6b59SJacob Faibussowitsch `PetscDeviceContextView()`
953030f984aSJacob Faibussowitsch @*/
954d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetFromOptions(MPI_Comm comm, PetscDeviceContext dctx)
955d71ae5a4SJacob Faibussowitsch {
9560e6b6b59SJacob Faibussowitsch   const auto pobj     = PetscObjectCast(dctx);
9570e6b6b59SJacob Faibussowitsch   auto       dtype    = std::make_pair(PETSC_DEVICE_DEFAULT(), PETSC_FALSE);
9580e6b6b59SJacob Faibussowitsch   auto       stype    = std::make_pair(PETSC_DEVICE_CONTEXT_DEFAULT_STREAM_TYPE, PETSC_FALSE);
959e6b8bd2aSJacob Faibussowitsch   MPI_Comm   old_comm = PETSC_COMM_SELF;
960030f984aSJacob Faibussowitsch 
961030f984aSJacob Faibussowitsch   PetscFunctionBegin;
9620e6b6b59SJacob Faibussowitsch   // do not user getoptionalnullcontext here, the user is not allowed to set it from options!
9630e6b6b59SJacob Faibussowitsch   PetscValidDeviceContext(dctx, 2);
9640e6b6b59SJacob Faibussowitsch   /* set the device type first */
9650e6b6b59SJacob Faibussowitsch   if (const auto device = dctx->device) PetscCall(PetscDeviceGetType(device, &dtype.first));
9660e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetStreamType(dctx, &stype.first));
9670e6b6b59SJacob Faibussowitsch 
9680e6b6b59SJacob Faibussowitsch   if (comm == MPI_COMM_NULL) {
9690e6b6b59SJacob Faibussowitsch     PetscCall(PetscObjectGetComm(pobj, &comm));
9700e6b6b59SJacob Faibussowitsch   } else {
9710e6b6b59SJacob Faibussowitsch     // briefly set the communicator for dctx (it is always PETSC_COMM_SELF) so
9720e6b6b59SJacob Faibussowitsch     // PetscObjectOptionsBegin() behaves as if dctx had comm
9730e6b6b59SJacob Faibussowitsch     old_comm = Petsc::util::exchange(pobj->comm, comm);
9740e6b6b59SJacob Faibussowitsch   }
9750e6b6b59SJacob Faibussowitsch 
9760e6b6b59SJacob Faibussowitsch   PetscObjectOptionsBegin(pobj);
9770e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextQueryOptions_Internal(PetscOptionsObject, dtype, stype));
978d0609cedSBarry Smith   PetscOptionsEnd();
9790e6b6b59SJacob Faibussowitsch   // reset the comm (should be PETSC_COMM_SELF)
9800e6b6b59SJacob Faibussowitsch   if (comm != MPI_COMM_NULL) pobj->comm = old_comm;
9810e6b6b59SJacob Faibussowitsch   if (dtype.second) PetscCall(PetscDeviceContextSetDefaultDeviceForType_Internal(dctx, dtype.first));
9820e6b6b59SJacob Faibussowitsch   if (stype.second) PetscCall(PetscDeviceContextSetStreamType(dctx, stype.first));
9830e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextSetUp(dctx));
9843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9850e6b6b59SJacob Faibussowitsch }
9860e6b6b59SJacob Faibussowitsch 
9870e6b6b59SJacob Faibussowitsch /*@C
9880e6b6b59SJacob Faibussowitsch   PetscDeviceContextView - View a `PetscDeviceContext`
9890e6b6b59SJacob Faibussowitsch 
9900e6b6b59SJacob Faibussowitsch   Collective on `viewer`
9910e6b6b59SJacob Faibussowitsch 
9920e6b6b59SJacob Faibussowitsch   Input Parameters:
9930e6b6b59SJacob Faibussowitsch + dctx   - The `PetscDeviceContext`
9940e6b6b59SJacob Faibussowitsch - viewer - The `PetscViewer` to view `dctx` with (may be `NULL`)
9950e6b6b59SJacob Faibussowitsch 
9962fe279fdSBarry Smith   Level: beginner
9972fe279fdSBarry Smith 
9982fe279fdSBarry Smith   Note:
9990e6b6b59SJacob Faibussowitsch   If `viewer` is `NULL`, `PETSC_VIEWER_STDOUT_WORLD` is used instead, in which case this
10000e6b6b59SJacob Faibussowitsch   routine is collective on `PETSC_COMM_WORLD`.
10010e6b6b59SJacob Faibussowitsch 
10020e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextViewFromOptions()`, `PetscDeviceView()`, `PETSC_VIEWER_STDOUT_WORLD`, `PetscDeviceContextCreate()`
10030e6b6b59SJacob Faibussowitsch @*/
1004d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextView(PetscDeviceContext dctx, PetscViewer viewer)
1005d71ae5a4SJacob Faibussowitsch {
10060e6b6b59SJacob Faibussowitsch   PetscBool iascii;
10070e6b6b59SJacob Faibussowitsch 
10080e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
10090e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
10100e6b6b59SJacob Faibussowitsch   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PETSC_COMM_WORLD, &viewer));
10110e6b6b59SJacob Faibussowitsch   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
10120e6b6b59SJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare(PetscObjectCast(viewer), PETSCVIEWERASCII, &iascii));
10130e6b6b59SJacob Faibussowitsch   if (iascii) {
10140e6b6b59SJacob Faibussowitsch     auto        stype = PETSC_STREAM_DEFAULT_BLOCKING;
10150e6b6b59SJacob Faibussowitsch     PetscViewer sub;
10160e6b6b59SJacob Faibussowitsch 
10170e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sub));
10180e6b6b59SJacob Faibussowitsch     PetscCall(PetscObjectPrintClassNamePrefixType(PetscObjectCast(dctx), sub));
10190e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(sub));
10200e6b6b59SJacob Faibussowitsch     PetscCall(PetscDeviceContextGetStreamType(dctx, &stype));
10210e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(sub, "stream type: %s\n", PetscStreamTypes[stype]));
10220e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(sub, "children: %" PetscInt_FMT "\n", dctx->numChildren));
10230e6b6b59SJacob Faibussowitsch     if (const auto nchild = dctx->numChildren) {
10240e6b6b59SJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushTab(sub));
10250e6b6b59SJacob Faibussowitsch       for (PetscInt i = 0; i < nchild; ++i) {
10260e6b6b59SJacob Faibussowitsch         if (i == nchild - 1) {
10270e6b6b59SJacob Faibussowitsch           PetscCall(PetscViewerASCIIPrintf(sub, "%" PetscInt64_FMT, dctx->childIDs[i]));
10280e6b6b59SJacob Faibussowitsch         } else {
10290e6b6b59SJacob Faibussowitsch           PetscCall(PetscViewerASCIIPrintf(sub, "%" PetscInt64_FMT ", ", dctx->childIDs[i]));
10300e6b6b59SJacob Faibussowitsch         }
10310e6b6b59SJacob Faibussowitsch       }
10320e6b6b59SJacob Faibussowitsch     }
10330e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(sub));
10340e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sub));
10350e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerFlush(viewer));
10360e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(viewer));
10370e6b6b59SJacob Faibussowitsch   }
10380e6b6b59SJacob Faibussowitsch   if (const auto device = dctx->device) PetscCall(PetscDeviceView(device, viewer));
10390e6b6b59SJacob Faibussowitsch   if (iascii) PetscCall(PetscViewerASCIIPopTab(viewer));
10403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10410e6b6b59SJacob Faibussowitsch }
10420e6b6b59SJacob Faibussowitsch 
10430e6b6b59SJacob Faibussowitsch /*@C
10440e6b6b59SJacob Faibussowitsch   PetscDeviceContextViewFromOptions - View a `PetscDeviceContext` from options
10450e6b6b59SJacob Faibussowitsch 
10460e6b6b59SJacob Faibussowitsch   Input Parameters:
10470e6b6b59SJacob Faibussowitsch + dctx - The `PetscDeviceContext` to view
10480e6b6b59SJacob Faibussowitsch . obj  - Optional `PetscObject` to associate (may be `NULL`)
10490e6b6b59SJacob Faibussowitsch - name - The command line option
10500e6b6b59SJacob Faibussowitsch 
10510e6b6b59SJacob Faibussowitsch   Level: beginner
10520e6b6b59SJacob Faibussowitsch 
10530e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextView()`, `PetscObjectViewFromOptions()`, `PetscDeviceContextCreate()`
10540e6b6b59SJacob Faibussowitsch @*/
1055d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextViewFromOptions(PetscDeviceContext dctx, PetscObject obj, const char name[])
1056d71ae5a4SJacob Faibussowitsch {
10570e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
10580e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
10590e6b6b59SJacob Faibussowitsch   if (obj) PetscValidHeader(obj, 2);
10604f572ea9SToby Isaac   PetscAssertPointer(name, 3);
10610e6b6b59SJacob Faibussowitsch   PetscCall(PetscObjectViewFromOptions(PetscObjectCast(dctx), obj, name));
10623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1063030f984aSJacob Faibussowitsch }
106431d47070SJunchao Zhang 
106531d47070SJunchao Zhang /*@C
106631d47070SJunchao Zhang   PetscDeviceContextGetStreamHandle - Return a handle to the underlying stream of the current device context
106731d47070SJunchao Zhang 
106831d47070SJunchao Zhang   Input Parameters:
106931d47070SJunchao Zhang + dctx   - The `PetscDeviceContext` to get the stream from
107031d47070SJunchao Zhang - handle - A handle to the stream
107131d47070SJunchao Zhang 
107231d47070SJunchao Zhang   Level: developer
107331d47070SJunchao Zhang 
107431d47070SJunchao Zhang   Note:
107531d47070SJunchao Zhang   This routine is dangerous. It exists only for the most experienced users and
107631d47070SJunchao Zhang   internal PETSc developement.
107731d47070SJunchao Zhang 
107831d47070SJunchao Zhang   There is no way for PETSc's auto-dependency system to track what the caller does with the
107931d47070SJunchao Zhang   stream.
108031d47070SJunchao Zhang 
108131d47070SJunchao Zhang   If the user uses the stream to copy memory that was previously modified by PETSc, or launches
108231d47070SJunchao Zhang   kernels that modify memory with the stream, it is the users responsibility to inform PETSc of
108331d47070SJunchao Zhang   their actions via `PetscDeviceContextMarkIntentFromID()`. Failure to do so may introduce a
108431d47070SJunchao Zhang   race condition. This race condition may manifest in nondeterministic ways.
108531d47070SJunchao Zhang 
108631d47070SJunchao Zhang   Alternatively, the user may synchronize the stream immediately before and after use. This is
108731d47070SJunchao Zhang   the safest option.
108831d47070SJunchao Zhang 
108931d47070SJunchao Zhang   Example Usage:
109031d47070SJunchao Zhang .vb
109131d47070SJunchao Zhang   PetscDeviceContext dctx;
109231d47070SJunchao Zhang   PetscDeviceType    type;
109331d47070SJunchao Zhang   void               *handle;
109431d47070SJunchao Zhang 
109531d47070SJunchao Zhang   PetscDeviceContextGetCurrentContext(&dctx);
109631d47070SJunchao Zhang   PetscDeviceContextGetStreamHandle(dctx, &handle);
109731d47070SJunchao Zhang   PetscDeviceContextGetDeviceType(dctx, &type);
109831d47070SJunchao Zhang 
109931d47070SJunchao Zhang   if (type == PETSC_DEVICE_CUDA) {
110031d47070SJunchao Zhang     cudsStream_t stream = *(cudaStream_t*)handle;
110131d47070SJunchao Zhang 
110231d47070SJunchao Zhang     my_cuda_kernel<<<1, 2, 3, stream>>>();
110331d47070SJunchao Zhang   }
110431d47070SJunchao Zhang .ve
110531d47070SJunchao Zhang 
110631d47070SJunchao Zhang .N ASYNC_API
110731d47070SJunchao Zhang 
110831d47070SJunchao Zhang .seealso: `PetscDeviceContext`
110931d47070SJunchao Zhang @*/
111031d47070SJunchao Zhang PetscErrorCode PetscDeviceContextGetStreamHandle(PetscDeviceContext dctx, void *handle)
111131d47070SJunchao Zhang {
111231d47070SJunchao Zhang   PetscFunctionBegin;
111331d47070SJunchao Zhang   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
11144f572ea9SToby Isaac   PetscAssertPointer(handle, 2);
111597cd0981SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetStreamHandle_Internal(dctx, (void **)handle));
111631d47070SJunchao Zhang   PetscFunctionReturn(PETSC_SUCCESS);
111731d47070SJunchao Zhang }
1118