xref: /petsc/src/sys/objects/device/interface/dcontext.cxx (revision 2126a61d222f4ba29a8a0187aa8dff219df55633)
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 */
120e6b6b59SJacob Faibussowitsch class PetscDeviceContextAllocator : public Petsc::AllocatorBase<PetscDeviceContext> {
130e6b6b59SJacob Faibussowitsch public:
14d71ae5a4SJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode create(PetscDeviceContext *dctx))
15d71ae5a4SJacob Faibussowitsch   {
16030f984aSJacob Faibussowitsch     PetscFunctionBegin;
170e6b6b59SJacob Faibussowitsch     PetscCall(PetscHeaderCreate(*dctx, PETSC_DEVICE_CONTEXT_CLASSID, "PetscDeviceContext", "PetscDeviceContext", "Sys", PETSC_COMM_SELF, PetscDeviceContextDestroy, PetscDeviceContextView));
180e6b6b59SJacob Faibussowitsch     PetscCallCXX(PetscObjectCast(*dctx)->cpp = new CxxData());
190e6b6b59SJacob Faibussowitsch     PetscCall(reset(*dctx, false));
20030f984aSJacob Faibussowitsch     PetscFunctionReturn(0);
21030f984aSJacob Faibussowitsch   }
22030f984aSJacob Faibussowitsch 
23d71ae5a4SJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode destroy(PetscDeviceContext dctx))
24d71ae5a4SJacob Faibussowitsch   {
25030f984aSJacob Faibussowitsch     PetscFunctionBegin;
26bf025ffbSJacob 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);
27dbbe0bcdSBarry Smith     PetscTryTypeMethod(dctx, destroy);
289566063dSJacob Faibussowitsch     PetscCall(PetscDeviceDestroy(&dctx->device));
299566063dSJacob Faibussowitsch     PetscCall(PetscFree(dctx->childIDs));
300e6b6b59SJacob Faibussowitsch     delete CxxDataCast(dctx);
310e6b6b59SJacob Faibussowitsch     PetscCall(PetscHeaderDestroy(&dctx));
32030f984aSJacob Faibussowitsch     PetscFunctionReturn(0);
33030f984aSJacob Faibussowitsch   }
34030f984aSJacob Faibussowitsch 
35d71ae5a4SJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode reset(PetscDeviceContext dctx, bool zero = true))
36d71ae5a4SJacob Faibussowitsch   {
37030f984aSJacob Faibussowitsch     PetscFunctionBegin;
380e6b6b59SJacob Faibussowitsch     if (zero) {
390e6b6b59SJacob Faibussowitsch       // reset the device if the user set it
400e6b6b59SJacob Faibussowitsch       if (auto &userset = dctx->usersetdevice) {
410e6b6b59SJacob Faibussowitsch         userset = 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;
55030f984aSJacob Faibussowitsch     PetscFunctionReturn(0);
56030f984aSJacob Faibussowitsch   }
57030f984aSJacob Faibussowitsch };
58030f984aSJacob Faibussowitsch 
59030f984aSJacob Faibussowitsch static Petsc::ObjectPool<PetscDeviceContext, PetscDeviceContextAllocator> contextPool;
60030f984aSJacob Faibussowitsch 
61030f984aSJacob Faibussowitsch /*@C
62811af0c4SBarry Smith   PetscDeviceContextCreate - Creates a `PetscDeviceContext`
63030f984aSJacob Faibussowitsch 
640e6b6b59SJacob Faibussowitsch   Not Collective
65030f984aSJacob Faibussowitsch 
6601d2d390SJose E. Roman   Output Paramemter:
67811af0c4SBarry Smith . dctx - The `PetscDeviceContext`
68030f984aSJacob Faibussowitsch 
69811af0c4SBarry Smith   Note:
70030f984aSJacob Faibussowitsch   Unlike almost every other PETSc class it is advised that most users use
710e6b6b59SJacob Faibussowitsch   `PetscDeviceContextDuplicate()` rather than this routine to create new contexts. Contexts of
720e6b6b59SJacob Faibussowitsch   different types are incompatible with one another; using `PetscDeviceContextDuplicate()`
730e6b6b59SJacob Faibussowitsch   ensures compatible types.
740e6b6b59SJacob Faibussowitsch 
750e6b6b59SJacob Faibussowitsch   DAG representation:
760e6b6b59SJacob Faibussowitsch .vb
770e6b6b59SJacob Faibussowitsch   time ->
780e6b6b59SJacob Faibussowitsch 
790e6b6b59SJacob Faibussowitsch   |= CALL =| - dctx ->
800e6b6b59SJacob Faibussowitsch .ve
81030f984aSJacob Faibussowitsch 
82030f984aSJacob Faibussowitsch   Level: beginner
83030f984aSJacob Faibussowitsch 
840e6b6b59SJacob Faibussowitsch .N ASYNC_API
850e6b6b59SJacob Faibussowitsch 
86db781477SPatrick Sanan .seealso: `PetscDeviceContextDuplicate()`, `PetscDeviceContextSetDevice()`,
87db781477SPatrick Sanan `PetscDeviceContextSetStreamType()`, `PetscDeviceContextSetUp()`,
880e6b6b59SJacob Faibussowitsch `PetscDeviceContextSetFromOptions()`, `PetscDeviceContextView()`, `PetscDeviceContextDestroy()`
89030f984aSJacob Faibussowitsch @*/
90d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextCreate(PetscDeviceContext *dctx)
91d71ae5a4SJacob Faibussowitsch {
92030f984aSJacob Faibussowitsch   PetscFunctionBegin;
93030f984aSJacob Faibussowitsch   PetscValidPointer(dctx, 1);
949566063dSJacob Faibussowitsch   PetscCall(PetscDeviceInitializePackage());
956a4a1270SPierre Jolivet   PetscCall(PetscLogEventBegin(DCONTEXT_Create, nullptr, nullptr, nullptr, nullptr));
960e6b6b59SJacob Faibussowitsch   PetscCall(contextPool.allocate(dctx));
976a4a1270SPierre Jolivet   PetscCall(PetscLogEventEnd(DCONTEXT_Create, nullptr, nullptr, nullptr, nullptr));
98030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
99030f984aSJacob Faibussowitsch }
100030f984aSJacob Faibussowitsch 
101030f984aSJacob Faibussowitsch /*@C
102811af0c4SBarry Smith   PetscDeviceContextDestroy - Frees a `PetscDeviceContext`
103030f984aSJacob Faibussowitsch 
1040e6b6b59SJacob Faibussowitsch   Not Collective
105030f984aSJacob Faibussowitsch 
106030f984aSJacob Faibussowitsch   Input Parameters:
107811af0c4SBarry Smith . dctx - The `PetscDeviceContext`
108030f984aSJacob Faibussowitsch 
1090e6b6b59SJacob Faibussowitsch   Notes:
1100e6b6b59SJacob Faibussowitsch   No implicit synchronization occurs due to this routine, all resources are released completely
1110e6b6b59SJacob Faibussowitsch   asynchronously w.r.t. the host. If one needs to guarantee access to the data produced on
1120e6b6b59SJacob Faibussowitsch   `dctx`'s stream the user is responsible for calling `PetscDeviceContextSynchronize()` before
1130e6b6b59SJacob Faibussowitsch   calling this routine.
114030f984aSJacob Faibussowitsch 
1150e6b6b59SJacob Faibussowitsch   DAG represetation:
1160e6b6b59SJacob Faibussowitsch .vb
1170e6b6b59SJacob Faibussowitsch   time ->
1180e6b6b59SJacob Faibussowitsch 
1190e6b6b59SJacob Faibussowitsch   -> dctx - |= CALL =|
1200e6b6b59SJacob Faibussowitsch .ve
1210e6b6b59SJacob Faibussowitsch 
1220e6b6b59SJacob Faibussowitsch   Developer Notes:
1230e6b6b59SJacob Faibussowitsch   `dctx` is never actually "destroyed" in the classical sense. It is returned to an ever
1240e6b6b59SJacob Faibussowitsch   growing pool of `PetscDeviceContext`s. There are currently no limits on the size of the pool,
1250e6b6b59SJacob Faibussowitsch   this should perhaps be implemented.
126030f984aSJacob Faibussowitsch 
127030f984aSJacob Faibussowitsch   Level: beginner
128030f984aSJacob Faibussowitsch 
1290e6b6b59SJacob Faibussowitsch .N ASYNC_API
1300e6b6b59SJacob Faibussowitsch 
1310e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextSetDevice()`,
1320e6b6b59SJacob Faibussowitsch `PetscDeviceContextSetUp()`, `PetscDeviceContextSynchronize()`
133030f984aSJacob Faibussowitsch @*/
134d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextDestroy(PetscDeviceContext *dctx)
135d71ae5a4SJacob Faibussowitsch {
136030f984aSJacob Faibussowitsch   PetscFunctionBegin;
1370e6b6b59SJacob Faibussowitsch   PetscValidPointer(dctx, 1);
138030f984aSJacob Faibussowitsch   if (!*dctx) PetscFunctionReturn(0);
1396a4a1270SPierre Jolivet   PetscCall(PetscLogEventBegin(DCONTEXT_Destroy, nullptr, nullptr, nullptr, nullptr));
1400e6b6b59SJacob Faibussowitsch   if (--(PetscObjectCast(*dctx)->refct) <= 0) {
1410e6b6b59SJacob Faibussowitsch     PetscCall(PetscDeviceContextCheckNotOrphaned_Internal(*dctx));
1420e6b6b59SJacob Faibussowitsch     // std::move of the expression of the trivially-copyable type 'PetscDeviceContext' (aka
1430e6b6b59SJacob Faibussowitsch     // '_n_PetscDeviceContext *') has no effect; remove std::move() [performance-move-const-arg]
1440e6b6b59SJacob Faibussowitsch     // can't remove std::move, since reclaim only takes r-value reference
1450e6b6b59SJacob Faibussowitsch     PetscCall(contextPool.deallocate(std::move(*dctx))); // NOLINT (performance-move-const-arg)
1460e6b6b59SJacob Faibussowitsch   }
1476a4a1270SPierre Jolivet   PetscCall(PetscLogEventEnd(DCONTEXT_Destroy, nullptr, nullptr, nullptr, nullptr));
148bf025ffbSJacob Faibussowitsch   *dctx = nullptr;
149030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
150030f984aSJacob Faibussowitsch }
151030f984aSJacob Faibussowitsch 
152030f984aSJacob Faibussowitsch /*@C
1530e6b6b59SJacob Faibussowitsch   PetscDeviceContextSetStreamType - Set the implementation type of the underlying stream for a
1540e6b6b59SJacob Faibussowitsch   `PetscDeviceContext`
155030f984aSJacob Faibussowitsch 
1560e6b6b59SJacob Faibussowitsch   Not Collective
157030f984aSJacob Faibussowitsch 
15801d2d390SJose E. Roman   Input Parameters:
159811af0c4SBarry Smith + dctx - The `PetscDeviceContext`
160811af0c4SBarry Smith - type - The `PetscStreamType`
161030f984aSJacob Faibussowitsch 
162030f984aSJacob Faibussowitsch   Notes:
163811af0c4SBarry Smith   See `PetscStreamType` in `include/petscdevicetypes.h` for more information on the available
1640e6b6b59SJacob Faibussowitsch   types and their interactions. If the `PetscDeviceContext` was previously set up and stream
165811af0c4SBarry Smith   type was changed, you must call `PetscDeviceContextSetUp()` again after this routine.
166030f984aSJacob Faibussowitsch 
1670e6b6b59SJacob Faibussowitsch   Level: beginner
168030f984aSJacob Faibussowitsch 
1690e6b6b59SJacob Faibussowitsch .seealso: `PetscStreamType`, `PetscDeviceContextGetStreamType()`, `PetscDeviceContextCreate()`,
1700e6b6b59SJacob Faibussowitsch `PetscDeviceContextSetUp()`, `PetscDeviceContextSetFromOptions()`
171030f984aSJacob Faibussowitsch @*/
172d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetStreamType(PetscDeviceContext dctx, PetscStreamType type)
173d71ae5a4SJacob Faibussowitsch {
174030f984aSJacob Faibussowitsch   PetscFunctionBegin;
1750e6b6b59SJacob Faibussowitsch   // do not use getoptionalnullcontext here since we do not want the user to change the stream
1760e6b6b59SJacob Faibussowitsch   // type
177030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx, 1);
178030f984aSJacob Faibussowitsch   PetscValidStreamType(type, 2);
1790e6b6b59SJacob Faibussowitsch   // only need to do complex swapping if the object has already been setup
180030f984aSJacob Faibussowitsch   if (dctx->setup && (dctx->streamType != type)) {
181030f984aSJacob Faibussowitsch     dctx->setup = PETSC_FALSE;
1826a4a1270SPierre Jolivet     PetscCall(PetscLogEventBegin(DCONTEXT_ChangeStream, dctx, nullptr, nullptr, nullptr));
1830e6b6b59SJacob Faibussowitsch     PetscUseTypeMethod(dctx, changestreamtype, type);
1846a4a1270SPierre Jolivet     PetscCall(PetscLogEventEnd(DCONTEXT_ChangeStream, dctx, nullptr, nullptr, nullptr));
185030f984aSJacob Faibussowitsch   }
186030f984aSJacob Faibussowitsch   dctx->streamType = type;
187030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
188030f984aSJacob Faibussowitsch }
189030f984aSJacob Faibussowitsch 
190030f984aSJacob Faibussowitsch /*@C
1910e6b6b59SJacob Faibussowitsch   PetscDeviceContextGetStreamType - Get the implementation type of the underlying stream for a
1920e6b6b59SJacob Faibussowitsch   `PetscDeviceContext`
193030f984aSJacob Faibussowitsch 
1940e6b6b59SJacob Faibussowitsch   Not Collective
195030f984aSJacob Faibussowitsch 
19601d2d390SJose E. Roman   Input Parameter:
197811af0c4SBarry Smith . dctx - The `PetscDeviceContext`
198030f984aSJacob Faibussowitsch 
199030f984aSJacob Faibussowitsch   Output Parameter:
200811af0c4SBarry Smith . type - The `PetscStreamType`
201030f984aSJacob Faibussowitsch 
2020e6b6b59SJacob Faibussowitsch   Notes:
2030e6b6b59SJacob Faibussowitsch   See `PetscStreamType` in `include/petscdevicetypes.h` for more information on the available
2040e6b6b59SJacob Faibussowitsch   types and their interactions
205030f984aSJacob Faibussowitsch 
2060e6b6b59SJacob Faibussowitsch   Level: beginner
207030f984aSJacob Faibussowitsch 
2080e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextSetStreamType()`, `PetscDeviceContextCreate()`,
2090e6b6b59SJacob Faibussowitsch `PetscDeviceContextSetFromOptions()`
210030f984aSJacob Faibussowitsch @*/
211d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextGetStreamType(PetscDeviceContext dctx, PetscStreamType *type)
212d71ae5a4SJacob Faibussowitsch {
213030f984aSJacob Faibussowitsch   PetscFunctionBegin;
2140e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
215030f984aSJacob Faibussowitsch   PetscValidIntPointer(type, 2);
216030f984aSJacob Faibussowitsch   *type = dctx->streamType;
217030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
218030f984aSJacob Faibussowitsch }
219030f984aSJacob Faibussowitsch 
2200e6b6b59SJacob Faibussowitsch /*
2210e6b6b59SJacob Faibussowitsch   Actual function to set the device.
222030f984aSJacob Faibussowitsch 
2230e6b6b59SJacob Faibussowitsch   1. Repeatedly destroying and recreating internal data structures (like streams and events)
2240e6b6b59SJacob Faibussowitsch      for recycled PetscDeviceContexts is not free. If done often, it does add up.
2250e6b6b59SJacob Faibussowitsch   2. The vast majority of PetscDeviceContexts are created by PETSc either as children or
2260e6b6b59SJacob Faibussowitsch      default contexts. The default contexts *never* change type, and the chilren are extremely
2270e6b6b59SJacob Faibussowitsch      unlikely to (chances are if you fork once, you will fork again very soon).
2280e6b6b59SJacob Faibussowitsch   3. The only time this calculus changes is if the user themselves sets the device type. In
2290e6b6b59SJacob Faibussowitsch      this case we do not know what the user has changed, so must always wipe the slate clean.
2300e6b6b59SJacob Faibussowitsch 
2310e6b6b59SJacob Faibussowitsch   Thus we need to keep track whether the user explicitly sets the device contexts device.
2320e6b6b59SJacob Faibussowitsch */
233d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDeviceContextSetDevice_Private(PetscDeviceContext dctx, PetscDevice device, PetscBool user_set)
234d71ae5a4SJacob Faibussowitsch {
2350e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
2360e6b6b59SJacob Faibussowitsch   // do not use getoptionalnullcontext here since we do not want the user to change its device
2370e6b6b59SJacob Faibussowitsch   PetscValidDeviceContext(dctx, 1);
2380e6b6b59SJacob Faibussowitsch   PetscValidDevice(device, 2);
2390e6b6b59SJacob Faibussowitsch   if (dctx->device && (dctx->device->id == device->id)) PetscFunctionReturn(0);
2406a4a1270SPierre Jolivet   PetscCall(PetscLogEventBegin(DCONTEXT_SetDevice, dctx, nullptr, nullptr, nullptr));
241*2126a61dSJacob Faibussowitsch   PetscTryTypeMethod(dctx, destroy);
2420e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceDestroy(&dctx->device));
2430e6b6b59SJacob Faibussowitsch   PetscCall(PetscMemzero(dctx->ops, sizeof(*dctx->ops)));
244*2126a61dSJacob Faibussowitsch   PetscCall(PetscDeviceReference_Internal(device));
245*2126a61dSJacob Faibussowitsch   // set it before calling the method
246*2126a61dSJacob Faibussowitsch   dctx->device = device;
2470e6b6b59SJacob Faibussowitsch   PetscCall((*device->ops->createcontext)(dctx));
2486a4a1270SPierre Jolivet   PetscCall(PetscLogEventEnd(DCONTEXT_SetDevice, dctx, nullptr, nullptr, nullptr));
2490e6b6b59SJacob Faibussowitsch   dctx->setup         = PETSC_FALSE;
2500e6b6b59SJacob Faibussowitsch   dctx->usersetdevice = user_set;
2510e6b6b59SJacob Faibussowitsch   PetscFunctionReturn(0);
2520e6b6b59SJacob Faibussowitsch }
2530e6b6b59SJacob Faibussowitsch 
254d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetDefaultDeviceForType_Internal(PetscDeviceContext dctx, PetscDeviceType type)
255d71ae5a4SJacob Faibussowitsch {
2560e6b6b59SJacob Faibussowitsch   PetscDevice device;
2570e6b6b59SJacob Faibussowitsch 
2580e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
2590e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceGetDefaultForType_Internal(type, &device));
2600e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextSetDevice_Private(dctx, device, PETSC_FALSE));
2610e6b6b59SJacob Faibussowitsch   PetscFunctionReturn(0);
2620e6b6b59SJacob Faibussowitsch }
2630e6b6b59SJacob Faibussowitsch 
2640e6b6b59SJacob Faibussowitsch /*@C
2650e6b6b59SJacob Faibussowitsch   PetscDeviceContextSetDevice - Set the underlying `PetscDevice` for a `PetscDeviceContext`
2660e6b6b59SJacob Faibussowitsch 
2670e6b6b59SJacob Faibussowitsch   Not Collective
268030f984aSJacob Faibussowitsch 
26901d2d390SJose E. Roman   Input Parameters:
270811af0c4SBarry Smith + dctx   - The `PetscDeviceContext`
271811af0c4SBarry Smith - device - The `PetscDevice`
272030f984aSJacob Faibussowitsch 
273030f984aSJacob Faibussowitsch   Notes:
2740e6b6b59SJacob Faibussowitsch   This routine is effectively `PetscDeviceContext`'s "set-type" (so every `PetscDeviceContext` must
2750e6b6b59SJacob Faibussowitsch   also have an attached `PetscDevice`). Unlike the usual set-type semantics, it is not stricly
2760e6b6b59SJacob Faibussowitsch   necessary to set a contexts device to enable usage, any created `PetscDeviceContext`s will
2770e6b6b59SJacob Faibussowitsch   always come equipped with the "default" device.
278030f984aSJacob Faibussowitsch 
2790e6b6b59SJacob Faibussowitsch   This routine is a no-op if `device` is already attached to `dctx`.
280a4af0ceeSJacob Faibussowitsch 
2810e6b6b59SJacob Faibussowitsch   This routine may (but is very unlikely to) initialize the backend device and may incur
2820e6b6b59SJacob Faibussowitsch   synchronization.
2835181c4f9SJacob Faibussowitsch 
284030f984aSJacob Faibussowitsch   Level: intermediate
285030f984aSJacob Faibussowitsch 
2860e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceCreate()`, `PetscDeviceConfigure()`, `PetscDeviceContextGetDevice()`,
2870e6b6b59SJacob Faibussowitsch `PetscDeviceContextGetDeviceType()`
288030f984aSJacob Faibussowitsch @*/
289d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetDevice(PetscDeviceContext dctx, PetscDevice device)
290d71ae5a4SJacob Faibussowitsch {
291030f984aSJacob Faibussowitsch   PetscFunctionBegin;
2920e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextSetDevice_Private(dctx, device, PETSC_TRUE));
293030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
294030f984aSJacob Faibussowitsch }
295030f984aSJacob Faibussowitsch 
296030f984aSJacob Faibussowitsch /*@C
297811af0c4SBarry Smith   PetscDeviceContextGetDevice - Get the underlying `PetscDevice` for a `PetscDeviceContext`
298030f984aSJacob Faibussowitsch 
2990e6b6b59SJacob Faibussowitsch   Not Collective
300030f984aSJacob Faibussowitsch 
301030f984aSJacob Faibussowitsch   Input Parameter:
302811af0c4SBarry Smith . dctx - the `PetscDeviceContext`
303030f984aSJacob Faibussowitsch 
304030f984aSJacob Faibussowitsch   Output Parameter:
305811af0c4SBarry Smith . device - The `PetscDevice`
306030f984aSJacob Faibussowitsch 
3070e6b6b59SJacob Faibussowitsch   Notes:
308811af0c4SBarry Smith   This is a borrowed reference, the user should not destroy `device`.
309030f984aSJacob Faibussowitsch 
310a375dbeeSPatrick Sanan   Level: intermediate
311a375dbeeSPatrick Sanan 
3120e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextSetDevice()`, `PetscDevice`, `PetscDeviceContextGetDeviceType()`
313030f984aSJacob Faibussowitsch @*/
314d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextGetDevice(PetscDeviceContext dctx, PetscDevice *device)
315d71ae5a4SJacob Faibussowitsch {
316030f984aSJacob Faibussowitsch   PetscFunctionBegin;
3170e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
318030f984aSJacob Faibussowitsch   PetscValidPointer(device, 2);
3190e6b6b59SJacob Faibussowitsch   PetscAssert(dctx->device, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "PetscDeviceContext %" PetscInt64_FMT " has no attached PetscDevice to get", PetscObjectCast(dctx)->id);
320030f984aSJacob Faibussowitsch   *device = dctx->device;
321030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
322030f984aSJacob Faibussowitsch }
323030f984aSJacob Faibussowitsch 
324030f984aSJacob Faibussowitsch /*@C
3250e6b6b59SJacob Faibussowitsch   PetscDeviceContextGetDeviceType - Get the `PetscDeviceType` for a `PetscDeviceContext`
3260e6b6b59SJacob Faibussowitsch 
3270e6b6b59SJacob Faibussowitsch   Not Collective
3280e6b6b59SJacob Faibussowitsch 
3290e6b6b59SJacob Faibussowitsch   Input Parameter:
3300e6b6b59SJacob Faibussowitsch . dctx - The `PetscDeviceContext`
3310e6b6b59SJacob Faibussowitsch 
3320e6b6b59SJacob Faibussowitsch   Output Parameter:
3330e6b6b59SJacob Faibussowitsch . type - The `PetscDeviceType`
3340e6b6b59SJacob Faibussowitsch 
3350e6b6b59SJacob Faibussowitsch   Notes:
3360e6b6b59SJacob Faibussowitsch   This routine is a convenience shorthand for `PetscDeviceContextGetDevice()` ->
3370e6b6b59SJacob Faibussowitsch   `PetscDeviceGetType()`.
3380e6b6b59SJacob Faibussowitsch 
3390e6b6b59SJacob Faibussowitsch   Level: beginner
3400e6b6b59SJacob Faibussowitsch 
3410e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceType`, `PetscDeviceContextGetDevice()`, `PetscDeviceGetType()`, `PetscDevice`
3420e6b6b59SJacob Faibussowitsch @*/
343d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextGetDeviceType(PetscDeviceContext dctx, PetscDeviceType *type)
344d71ae5a4SJacob Faibussowitsch {
3450e6b6b59SJacob Faibussowitsch   PetscDevice device = nullptr;
3460e6b6b59SJacob Faibussowitsch 
3470e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
3480e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
3490e6b6b59SJacob Faibussowitsch   PetscValidPointer(type, 2);
3500e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetDevice(dctx, &device));
3510e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceGetType(device, type));
3520e6b6b59SJacob Faibussowitsch   PetscFunctionReturn(0);
3530e6b6b59SJacob Faibussowitsch }
3540e6b6b59SJacob Faibussowitsch 
3550e6b6b59SJacob Faibussowitsch /*@C
356811af0c4SBarry Smith   PetscDeviceContextSetUp - Prepares a `PetscDeviceContext` for use
357030f984aSJacob Faibussowitsch 
3580e6b6b59SJacob Faibussowitsch   Not Collective
359030f984aSJacob Faibussowitsch 
36001d2d390SJose E. Roman   Input Parameter:
361811af0c4SBarry Smith . dctx - The `PetscDeviceContext`
362030f984aSJacob Faibussowitsch 
3630e6b6b59SJacob Faibussowitsch   Developer Notes:
3640e6b6b59SJacob Faibussowitsch   This routine is usually the stage where a `PetscDeviceContext` acquires device-side data
3650e6b6b59SJacob Faibussowitsch   structures such as streams, events, and (possibly) handles.
366030f984aSJacob Faibussowitsch 
367030f984aSJacob Faibussowitsch   Level: beginner
368030f984aSJacob Faibussowitsch 
3690e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextSetDevice()`,
3700e6b6b59SJacob Faibussowitsch `PetscDeviceContextDestroy()`, `PetscDeviceContextSetFromOptions()`
371030f984aSJacob Faibussowitsch @*/
372d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetUp(PetscDeviceContext dctx)
373d71ae5a4SJacob Faibussowitsch {
374030f984aSJacob Faibussowitsch   PetscFunctionBegin;
3750e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
376030f984aSJacob Faibussowitsch   if (dctx->setup) PetscFunctionReturn(0);
3770e6b6b59SJacob Faibussowitsch   if (!dctx->device) {
3780e6b6b59SJacob Faibussowitsch     const auto default_dtype = PETSC_DEVICE_DEFAULT();
3790e6b6b59SJacob Faibussowitsch 
3800e6b6b59SJacob 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]));
3810e6b6b59SJacob Faibussowitsch     PetscCall(PetscDeviceContextSetDefaultDeviceForType_Internal(dctx, default_dtype));
3820e6b6b59SJacob Faibussowitsch   }
3836a4a1270SPierre Jolivet   PetscCall(PetscLogEventBegin(DCONTEXT_SetUp, dctx, nullptr, nullptr, nullptr));
384dbbe0bcdSBarry Smith   PetscUseTypeMethod(dctx, setup);
3856a4a1270SPierre Jolivet   PetscCall(PetscLogEventEnd(DCONTEXT_SetUp, dctx, nullptr, nullptr, nullptr));
386030f984aSJacob Faibussowitsch   dctx->setup = PETSC_TRUE;
387030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
388030f984aSJacob Faibussowitsch }
389030f984aSJacob Faibussowitsch 
390d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDeviceContextDuplicate_Private(PetscDeviceContext dctx, PetscStreamType stype, PetscDeviceContext *dctxdup)
391d71ae5a4SJacob Faibussowitsch {
3920e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
3936a4a1270SPierre Jolivet   PetscCall(PetscLogEventBegin(DCONTEXT_Duplicate, dctx, nullptr, nullptr, nullptr));
3940e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextCreate(dctxdup));
3950e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextSetStreamType(*dctxdup, stype));
3960e6b6b59SJacob Faibussowitsch   if (const auto device = dctx->device) PetscCall(PetscDeviceContextSetDevice_Private(*dctxdup, device, dctx->usersetdevice));
3970e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextSetUp(*dctxdup));
3986a4a1270SPierre Jolivet   PetscCall(PetscLogEventEnd(DCONTEXT_Duplicate, dctx, nullptr, nullptr, nullptr));
3990e6b6b59SJacob Faibussowitsch   PetscFunctionReturn(0);
4000e6b6b59SJacob Faibussowitsch }
4010e6b6b59SJacob Faibussowitsch 
402030f984aSJacob Faibussowitsch /*@C
403811af0c4SBarry Smith   PetscDeviceContextDuplicate - Duplicates a `PetscDeviceContext` object
404030f984aSJacob Faibussowitsch 
4050e6b6b59SJacob Faibussowitsch   Not Collective
406030f984aSJacob Faibussowitsch 
407030f984aSJacob Faibussowitsch   Input Parameter:
408811af0c4SBarry Smith . dctx - The `PetscDeviceContext` to duplicate
409030f984aSJacob Faibussowitsch 
4106aad120cSJose E. Roman   Output Parameter:
411811af0c4SBarry Smith . dctxdup - The duplicated `PetscDeviceContext`
412030f984aSJacob Faibussowitsch 
4130e6b6b59SJacob Faibussowitsch   Notes:
4140e6b6b59SJacob Faibussowitsch   This is a shorthand method for creating a `PetscDeviceContext` with the exact same settings as
4150e6b6b59SJacob Faibussowitsch   another. Note however that `dctxdup` does not share any of the underlying data with `dctx`,
4160e6b6b59SJacob Faibussowitsch   (including its current stream-state) they are completely separate objects.
4170e6b6b59SJacob Faibussowitsch 
4180e6b6b59SJacob Faibussowitsch   There is no implied ordering between `dctx` or `dctxdup`.
4190e6b6b59SJacob Faibussowitsch 
4200e6b6b59SJacob Faibussowitsch   DAG representation:
4210e6b6b59SJacob Faibussowitsch .vb
4220e6b6b59SJacob Faibussowitsch   time ->
4230e6b6b59SJacob Faibussowitsch 
4240e6b6b59SJacob Faibussowitsch   -> dctx - |= CALL =| - dctx ---->
4250e6b6b59SJacob Faibussowitsch                        - dctxdup ->
4260e6b6b59SJacob Faibussowitsch .ve
427030f984aSJacob Faibussowitsch 
428030f984aSJacob Faibussowitsch   Level: beginner
429030f984aSJacob Faibussowitsch 
4300e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextSetDevice()`,
4310e6b6b59SJacob Faibussowitsch `PetscDeviceContextSetStreamType()`
432030f984aSJacob Faibussowitsch @*/
433d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextDuplicate(PetscDeviceContext dctx, PetscDeviceContext *dctxdup)
434d71ae5a4SJacob Faibussowitsch {
4350e6b6b59SJacob Faibussowitsch   auto stype = PETSC_STREAM_DEFAULT_BLOCKING;
436030f984aSJacob Faibussowitsch 
437030f984aSJacob Faibussowitsch   PetscFunctionBegin;
4380e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
439030f984aSJacob Faibussowitsch   PetscValidPointer(dctxdup, 2);
4400e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetStreamType(dctx, &stype));
4410e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextDuplicate_Private(dctx, stype, dctxdup));
442030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
443030f984aSJacob Faibussowitsch }
444030f984aSJacob Faibussowitsch 
445030f984aSJacob Faibussowitsch /*@C
446811af0c4SBarry Smith   PetscDeviceContextQueryIdle - Returns whether or not a `PetscDeviceContext` is idle
447030f984aSJacob Faibussowitsch 
4480e6b6b59SJacob Faibussowitsch   Not Collective
449030f984aSJacob Faibussowitsch 
450030f984aSJacob Faibussowitsch   Input Parameter:
4510e6b6b59SJacob Faibussowitsch . dctx - The `PetscDeviceContext`
452030f984aSJacob Faibussowitsch 
453030f984aSJacob Faibussowitsch   Output Parameter:
4540e6b6b59SJacob Faibussowitsch . idle - `PETSC_TRUE` if `dctx` has NO work, `PETSC_FALSE` if it has work
455030f984aSJacob Faibussowitsch 
456811af0c4SBarry Smith   Note:
457ef657721SJacob Faibussowitsch   This routine only refers a singular context and does NOT take any of its children into
4580e6b6b59SJacob Faibussowitsch   account. That is, if `dctx` is idle but has dependents who do have work this routine still
459811af0c4SBarry Smith   returns `PETSC_TRUE`.
460030f984aSJacob Faibussowitsch 
461030f984aSJacob Faibussowitsch   Level: intermediate
462030f984aSJacob Faibussowitsch 
463db781477SPatrick Sanan .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextWaitForContext()`, `PetscDeviceContextFork()`
464030f984aSJacob Faibussowitsch @*/
465d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextQueryIdle(PetscDeviceContext dctx, PetscBool *idle)
466d71ae5a4SJacob Faibussowitsch {
467030f984aSJacob Faibussowitsch   PetscFunctionBegin;
4680e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
469030f984aSJacob Faibussowitsch   PetscValidBoolPointer(idle, 2);
4706a4a1270SPierre Jolivet   PetscCall(PetscLogEventBegin(DCONTEXT_QueryIdle, dctx, nullptr, nullptr, nullptr));
471dbbe0bcdSBarry Smith   PetscUseTypeMethod(dctx, query, idle);
4726a4a1270SPierre Jolivet   PetscCall(PetscLogEventEnd(DCONTEXT_QueryIdle, dctx, nullptr, nullptr, nullptr));
4730e6b6b59SJacob 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"));
474030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
475030f984aSJacob Faibussowitsch }
476030f984aSJacob Faibussowitsch 
477030f984aSJacob Faibussowitsch /*@C
478030f984aSJacob Faibussowitsch   PetscDeviceContextWaitForContext - Make one context wait for another context to finish
479030f984aSJacob Faibussowitsch 
4800e6b6b59SJacob Faibussowitsch   Not Collective
481030f984aSJacob Faibussowitsch 
482030f984aSJacob Faibussowitsch   Input Parameters:
483811af0c4SBarry Smith + dctxa - The `PetscDeviceContext` object that is waiting
484811af0c4SBarry Smith - dctxb - The `PetscDeviceContext` object that is being waited on
485030f984aSJacob Faibussowitsch 
486030f984aSJacob Faibussowitsch   Notes:
4870e6b6b59SJacob Faibussowitsch   Serializes two `PetscDeviceContext`s. Serialization is performed asynchronously; the host
4880e6b6b59SJacob Faibussowitsch   does not wait for the serialization to actually occur.
489811af0c4SBarry Smith 
4900e6b6b59SJacob Faibussowitsch   This routine uses only the state of `dctxb` at the moment this routine was called, so any
4910e6b6b59SJacob Faibussowitsch   future work queued will not affect `dctxa`. It is safe to pass the same context to both
4920e6b6b59SJacob Faibussowitsch   arguments (in which case this routine does nothing).
4930e6b6b59SJacob Faibussowitsch 
4940e6b6b59SJacob Faibussowitsch   DAG representation:
4950e6b6b59SJacob Faibussowitsch .vb
4960e6b6b59SJacob Faibussowitsch   time ->
4970e6b6b59SJacob Faibussowitsch 
4980e6b6b59SJacob Faibussowitsch   -> dctxa ---/- |= CALL =| - dctxa ->
4990e6b6b59SJacob Faibussowitsch              /
5000e6b6b59SJacob Faibussowitsch   -> dctxb -/------------------------>
5010e6b6b59SJacob Faibussowitsch .ve
502030f984aSJacob Faibussowitsch 
503030f984aSJacob Faibussowitsch   Level: beginner
504030f984aSJacob Faibussowitsch 
5050e6b6b59SJacob Faibussowitsch .N ASYNC_API
5060e6b6b59SJacob Faibussowitsch 
507db781477SPatrick Sanan .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextQueryIdle()`, `PetscDeviceContextJoin()`
508030f984aSJacob Faibussowitsch @*/
509d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextWaitForContext(PetscDeviceContext dctxa, PetscDeviceContext dctxb)
510d71ae5a4SJacob Faibussowitsch {
5110e6b6b59SJacob Faibussowitsch   PetscObject aobj;
5120e6b6b59SJacob Faibussowitsch 
513030f984aSJacob Faibussowitsch   PetscFunctionBegin;
5140e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctxa));
5150e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctxb));
516030f984aSJacob Faibussowitsch   PetscCheckCompatibleDeviceContexts(dctxa, 1, dctxb, 2);
517030f984aSJacob Faibussowitsch   if (dctxa == dctxb) PetscFunctionReturn(0);
5180e6b6b59SJacob Faibussowitsch   aobj = PetscObjectCast(dctxa);
5196a4a1270SPierre Jolivet   PetscCall(PetscLogEventBegin(DCONTEXT_WaitForCtx, dctxa, dctxb, nullptr, nullptr));
520dbbe0bcdSBarry Smith   PetscUseTypeMethod(dctxa, waitforcontext, dctxb);
5210e6b6b59SJacob Faibussowitsch   PetscCallCXX(CxxDataCast(dctxa)->upstream[dctxb] = CxxData::parent_type(dctxb));
5226a4a1270SPierre Jolivet   PetscCall(PetscLogEventEnd(DCONTEXT_WaitForCtx, dctxa, dctxb, nullptr, nullptr));
5230e6b6b59SJacob Faibussowitsch   PetscCall(PetscInfo(dctxa, "dctx %" PetscInt64_FMT " waiting on dctx %" PetscInt64_FMT "\n", aobj->id, PetscObjectCast(dctxb)->id));
5240e6b6b59SJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease(aobj));
525030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
526030f984aSJacob Faibussowitsch }
527030f984aSJacob Faibussowitsch 
5280e6b6b59SJacob Faibussowitsch /*@C
5290e6b6b59SJacob Faibussowitsch   PetscDeviceContextForkWithStreamType - Create a set of dependent child contexts from a parent
5300e6b6b59SJacob Faibussowitsch   context with a prescribed `PetscStreamType`
5310e6b6b59SJacob Faibussowitsch 
5320e6b6b59SJacob Faibussowitsch   Not Collective, Asynchronous
5330e6b6b59SJacob Faibussowitsch 
5340e6b6b59SJacob Faibussowitsch   Input Parameters:
5350e6b6b59SJacob Faibussowitsch + dctx  - The parent `PetscDeviceContext`
5360e6b6b59SJacob Faibussowitsch . stype - The prescribed `PetscStreamType`
5370e6b6b59SJacob Faibussowitsch - n     - The number of children to create
5380e6b6b59SJacob Faibussowitsch 
5390e6b6b59SJacob Faibussowitsch   Output Parameter:
5400e6b6b59SJacob Faibussowitsch . dsub - The created child context(s)
5410e6b6b59SJacob Faibussowitsch 
5420e6b6b59SJacob Faibussowitsch   Notes:
5430e6b6b59SJacob Faibussowitsch   This routine creates `n` edges of a DAG from a source node which are causally dependent on the
5440e6b6b59SJacob Faibussowitsch   source node. This causal dependency is established as-if by calling
5450e6b6b59SJacob Faibussowitsch   `PetscDeviceContextWaitForContext()` on every child.
5460e6b6b59SJacob Faibussowitsch 
5470e6b6b59SJacob Faibussowitsch   `dsub` is allocated by this routine and has its lifetime bounded by `dctx`. That is, `dctx`
5480e6b6b59SJacob Faibussowitsch   expects to free `dsub` (via `PetscDeviceContextJoin()`) before it itself is destroyed.
5490e6b6b59SJacob Faibussowitsch 
5500e6b6b59SJacob Faibussowitsch   This routine only accounts for work queued on `dctx` up until calling this routine, any
5510e6b6b59SJacob Faibussowitsch   subsequent work enqueued on `dctx` has no effect on `dsub`.
5520e6b6b59SJacob Faibussowitsch 
5530e6b6b59SJacob Faibussowitsch   The `PetscStreamType` of `dctx` does not have to equal `stype`. In fact, it is often the case
5540e6b6b59SJacob Faibussowitsch   that they are different. This is useful in cases where a routine can locally exploit stream
5550e6b6b59SJacob Faibussowitsch   parallelism without needing to worry about what stream type the incoming `PetscDeviceContext`
5560e6b6b59SJacob Faibussowitsch   carries.
5570e6b6b59SJacob Faibussowitsch 
5580e6b6b59SJacob Faibussowitsch   DAG representation:
5590e6b6b59SJacob Faibussowitsch .vb
5600e6b6b59SJacob Faibussowitsch   time ->
5610e6b6b59SJacob Faibussowitsch 
5620e6b6b59SJacob Faibussowitsch   -> dctx - |= CALL =| -\----> dctx ------>
5630e6b6b59SJacob Faibussowitsch                          \---> dsub[0] --->
5640e6b6b59SJacob Faibussowitsch                           \--> ... ------->
5650e6b6b59SJacob Faibussowitsch                            \-> dsub[n-1] ->
5660e6b6b59SJacob Faibussowitsch .ve
5670e6b6b59SJacob Faibussowitsch 
5680e6b6b59SJacob Faibussowitsch   Level: intermediate
5690e6b6b59SJacob Faibussowitsch 
5700e6b6b59SJacob Faibussowitsch .N ASYNC_API
5710e6b6b59SJacob Faibussowitsch 
5720e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextJoin()`, `PetscDeviceContextSynchronize()`,
5730e6b6b59SJacob Faibussowitsch `PetscDeviceContextQueryIdle()`, `PetscDeviceContextWaitForContext()`
5740e6b6b59SJacob Faibussowitsch @*/
575d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextForkWithStreamType(PetscDeviceContext dctx, PetscStreamType stype, PetscInt n, PetscDeviceContext **dsub)
576d71ae5a4SJacob Faibussowitsch {
5770e6b6b59SJacob Faibussowitsch   // debugging only
5780e6b6b59SJacob Faibussowitsch   std::string idList;
5790e6b6b59SJacob Faibussowitsch   auto        ninput = n;
5800e6b6b59SJacob Faibussowitsch 
5810e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
5820e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
5830e6b6b59SJacob Faibussowitsch   PetscAssert(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of contexts requested %" PetscInt_FMT " < 0", n);
5840e6b6b59SJacob Faibussowitsch   PetscValidPointer(dsub, 4);
5850e6b6b59SJacob Faibussowitsch   *dsub = nullptr;
5860e6b6b59SJacob Faibussowitsch   /* reserve 4 chars per id, 2 for number and 2 for ', ' separator */
5870e6b6b59SJacob Faibussowitsch   if (PetscDefined(USE_DEBUG_AND_INFO)) PetscCallCXX(idList.reserve(4 * n));
5886a4a1270SPierre Jolivet   PetscCall(PetscLogEventBegin(DCONTEXT_Fork, dctx, nullptr, nullptr, nullptr));
5890e6b6b59SJacob Faibussowitsch   /* update child totals */
5900e6b6b59SJacob Faibussowitsch   dctx->numChildren += n;
5910e6b6b59SJacob Faibussowitsch   /* now to find out if we have room */
5920e6b6b59SJacob Faibussowitsch   if (dctx->numChildren > dctx->maxNumChildren) {
5930e6b6b59SJacob Faibussowitsch     const auto numChildren    = dctx->numChildren;
5940e6b6b59SJacob Faibussowitsch     auto      &maxNumChildren = dctx->maxNumChildren;
5950e6b6b59SJacob Faibussowitsch     auto       numAllocated   = numChildren;
5960e6b6b59SJacob Faibussowitsch 
5970e6b6b59SJacob Faibussowitsch     /* no room, either from having too many kids or not having any */
5980e6b6b59SJacob Faibussowitsch     if (auto &childIDs = dctx->childIDs) {
5990e6b6b59SJacob Faibussowitsch       // the difference is backwards because we have not updated maxNumChildren yet
6000e6b6b59SJacob Faibussowitsch       numAllocated -= maxNumChildren;
6010e6b6b59SJacob Faibussowitsch       /* have existing children, must reallocate them */
6020e6b6b59SJacob Faibussowitsch       PetscCall(PetscRealloc(numChildren * sizeof(*childIDs), &childIDs));
6030e6b6b59SJacob Faibussowitsch       /* clear the extra memory since realloc doesn't do it for us */
6040e6b6b59SJacob Faibussowitsch       PetscCall(PetscArrayzero(std::next(childIDs, maxNumChildren), numAllocated));
6050e6b6b59SJacob Faibussowitsch     } else {
6060e6b6b59SJacob Faibussowitsch       /* have no children */
6070e6b6b59SJacob Faibussowitsch       PetscCall(PetscCalloc1(numChildren, &childIDs));
6080e6b6b59SJacob Faibussowitsch     }
6090e6b6b59SJacob Faibussowitsch     /* update total number of children */
6100e6b6b59SJacob Faibussowitsch     maxNumChildren = numChildren;
6110e6b6b59SJacob Faibussowitsch   }
6120e6b6b59SJacob Faibussowitsch   PetscCall(PetscMalloc1(n, dsub));
6130e6b6b59SJacob Faibussowitsch   for (PetscInt i = 0; ninput && (i < dctx->numChildren); ++i) {
6140e6b6b59SJacob Faibussowitsch     auto &childID = dctx->childIDs[i];
6150e6b6b59SJacob Faibussowitsch     /* empty child slot */
6160e6b6b59SJacob Faibussowitsch     if (!childID) {
6170e6b6b59SJacob Faibussowitsch       auto &childctx = (*dsub)[i];
6180e6b6b59SJacob Faibussowitsch 
6190e6b6b59SJacob Faibussowitsch       /* create the child context in the image of its parent */
6200e6b6b59SJacob Faibussowitsch       PetscCall(PetscDeviceContextDuplicate_Private(dctx, stype, &childctx));
6210e6b6b59SJacob Faibussowitsch       PetscCall(PetscDeviceContextWaitForContext(childctx, dctx));
6220e6b6b59SJacob Faibussowitsch       /* register the child with its parent */
6230e6b6b59SJacob Faibussowitsch       PetscCall(PetscObjectGetId(PetscObjectCast(childctx), &childID));
6240e6b6b59SJacob Faibussowitsch       if (PetscDefined(USE_DEBUG_AND_INFO)) {
6250e6b6b59SJacob Faibussowitsch         PetscCallCXX(idList += std::to_string(childID));
6260e6b6b59SJacob Faibussowitsch         if (ninput != 1) PetscCallCXX(idList += ", ");
6270e6b6b59SJacob Faibussowitsch       }
6280e6b6b59SJacob Faibussowitsch       --ninput;
6290e6b6b59SJacob Faibussowitsch     }
6300e6b6b59SJacob Faibussowitsch   }
6316a4a1270SPierre Jolivet   PetscCall(PetscLogEventEnd(DCONTEXT_Fork, dctx, nullptr, nullptr, nullptr));
6320e6b6b59SJacob Faibussowitsch   PetscCall(PetscDebugInfo(dctx, "Forked %" PetscInt_FMT " children from parent %" PetscInt64_FMT " with IDs: %s\n", n, PetscObjectCast(dctx)->id, idList.c_str()));
6330e6b6b59SJacob Faibussowitsch   PetscFunctionReturn(0);
6340e6b6b59SJacob Faibussowitsch }
6350e6b6b59SJacob Faibussowitsch 
636030f984aSJacob Faibussowitsch /*@C
637030f984aSJacob Faibussowitsch   PetscDeviceContextFork - Create a set of dependent child contexts from a parent context
638030f984aSJacob Faibussowitsch 
639030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
640030f984aSJacob Faibussowitsch 
641030f984aSJacob Faibussowitsch   Input Parameters:
642811af0c4SBarry Smith + dctx - The parent `PetscDeviceContext`
643030f984aSJacob Faibussowitsch - n    - The number of children to create
644030f984aSJacob Faibussowitsch 
645030f984aSJacob Faibussowitsch   Output Parameter:
646030f984aSJacob Faibussowitsch . dsub - The created child context(s)
647030f984aSJacob Faibussowitsch 
648030f984aSJacob Faibussowitsch   Notes:
6490e6b6b59SJacob Faibussowitsch   Behaves identically to `PetscDeviceContextForkWithStreamType()` except that the prescribed
6500e6b6b59SJacob Faibussowitsch   `PetscStreamType` is taken from `dctx`. In effect this routine is shorthand for\:
651030f984aSJacob Faibussowitsch 
652030f984aSJacob Faibussowitsch .vb
6530e6b6b59SJacob Faibussowitsch   PetscStreamType stype;
654030f984aSJacob Faibussowitsch 
6550e6b6b59SJacob Faibussowitsch   PetscDeviceContextGetStreamType(dctx, &stype);
6560e6b6b59SJacob Faibussowitsch   PetscDeviceContextForkWithStreamType(dctx, stype, ...);
657030f984aSJacob Faibussowitsch .ve
658030f984aSJacob Faibussowitsch 
6590e6b6b59SJacob Faibussowitsch   Level: beginner
660030f984aSJacob Faibussowitsch 
6610e6b6b59SJacob Faibussowitsch .N ASYNC_API
6620e6b6b59SJacob Faibussowitsch 
6630e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextForkWithStreamType()`, `PetscDeviceContextJoin()`,
6640e6b6b59SJacob Faibussowitsch `PetscDeviceContextSynchronize()`, `PetscDeviceContextQueryIdle()`
665030f984aSJacob Faibussowitsch @*/
666d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextFork(PetscDeviceContext dctx, PetscInt n, PetscDeviceContext **dsub)
667d71ae5a4SJacob Faibussowitsch {
6680e6b6b59SJacob Faibussowitsch   auto stype = PETSC_STREAM_DEFAULT_BLOCKING;
669030f984aSJacob Faibussowitsch 
670030f984aSJacob Faibussowitsch   PetscFunctionBegin;
6710e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
6720e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetStreamType(dctx, &stype));
6730e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextForkWithStreamType(dctx, stype, n, dsub));
674030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
675030f984aSJacob Faibussowitsch }
676030f984aSJacob Faibussowitsch 
677030f984aSJacob Faibussowitsch /*@C
6785181c4f9SJacob Faibussowitsch   PetscDeviceContextJoin - Converge a set of child contexts
679030f984aSJacob Faibussowitsch 
680030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
681030f984aSJacob Faibussowitsch 
682030f984aSJacob Faibussowitsch   Input Parameters:
683811af0c4SBarry Smith + dctx         - A `PetscDeviceContext` to converge on
684030f984aSJacob Faibussowitsch . n            - The number of sub contexts to converge
685030f984aSJacob Faibussowitsch . joinMode     - The type of join to perform
686030f984aSJacob Faibussowitsch - dsub         - The sub contexts to converge
687030f984aSJacob Faibussowitsch 
688030f984aSJacob Faibussowitsch   Notes:
6890e6b6b59SJacob Faibussowitsch   If `PetscDeviceContextFork()` creates `n` edges from a source node which all depend on the source
6900e6b6b59SJacob Faibussowitsch   node, then this routine is the exact mirror. That is, it creates a node (represented in `dctx`)
6910e6b6b59SJacob Faibussowitsch   which recieves `n` edges (and optionally destroys them) which is dependent on the completion
6920e6b6b59SJacob Faibussowitsch   of all incoming edges.
693030f984aSJacob Faibussowitsch 
6940e6b6b59SJacob Faibussowitsch   If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_DESTROY`. All contexts in `dsub` will be
6950e6b6b59SJacob Faibussowitsch   destroyed by this routine. Thus all sub contexts must have been created with the `dctx`
6960e6b6b59SJacob Faibussowitsch   passed to this routine.
697030f984aSJacob Faibussowitsch 
6980e6b6b59SJacob Faibussowitsch   If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_SYNC`. All sub contexts will additionally wait on
6990e6b6b59SJacob Faibussowitsch   `dctx` after converging. This has the effect of "synchronizing" the outgoing edges. Note the
7000e6b6b59SJacob Faibussowitsch   sync suffix does NOT refer to the host, i.e. this routine does NOT call
7010e6b6b59SJacob Faibussowitsch   `PetscDeviceSynchronize()`.
702030f984aSJacob Faibussowitsch 
7030e6b6b59SJacob Faibussowitsch   If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC`. `dctx` waits for all sub contexts but
7040e6b6b59SJacob Faibussowitsch   the sub contexts do not wait for one another or `dctx` afterwards.
705030f984aSJacob Faibussowitsch 
706030f984aSJacob Faibussowitsch   DAG representations:
707811af0c4SBarry Smith   If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_DESTROY`
708030f984aSJacob Faibussowitsch .vb
709030f984aSJacob Faibussowitsch   time ->
710030f984aSJacob Faibussowitsch 
7110e6b6b59SJacob Faibussowitsch   -> dctx ---------/- |= CALL =| - dctx ->
712030f984aSJacob Faibussowitsch   -> dsub[0] -----/
713030f984aSJacob Faibussowitsch   ->  ... -------/
714030f984aSJacob Faibussowitsch   -> dsub[n-1] -/
715030f984aSJacob Faibussowitsch .ve
716811af0c4SBarry Smith   If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_SYNC`
717030f984aSJacob Faibussowitsch .vb
718030f984aSJacob Faibussowitsch   time ->
719030f984aSJacob Faibussowitsch 
7200e6b6b59SJacob Faibussowitsch   -> dctx ---------/- |= CALL =| -\----> dctx ------>
721030f984aSJacob Faibussowitsch   -> dsub[0] -----/                \---> dsub[0] --->
722030f984aSJacob Faibussowitsch   ->  ... -------/                  \--> ... ------->
723030f984aSJacob Faibussowitsch   -> dsub[n-1] -/                    \-> dsub[n-1] ->
724030f984aSJacob Faibussowitsch .ve
7250e6b6b59SJacob Faibussowitsch   If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC`
7260e6b6b59SJacob Faibussowitsch .vb
7270e6b6b59SJacob Faibussowitsch   time ->
728030f984aSJacob Faibussowitsch 
7290e6b6b59SJacob Faibussowitsch   -> dctx ----------/- |= CALL =| - dctx ->
7300e6b6b59SJacob Faibussowitsch   -> dsub[0] ------/----------------------->
7310e6b6b59SJacob Faibussowitsch   ->  ... --------/------------------------>
7320e6b6b59SJacob Faibussowitsch   -> dsub[n-1] --/------------------------->
7330e6b6b59SJacob Faibussowitsch .ve
734030f984aSJacob Faibussowitsch 
7350e6b6b59SJacob Faibussowitsch   Level: beginner
7360e6b6b59SJacob Faibussowitsch 
7370e6b6b59SJacob Faibussowitsch .N ASYNC_API
7380e6b6b59SJacob Faibussowitsch 
7390e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextFork()`, `PetscDeviceContextForkWithStreamType()`,
7400e6b6b59SJacob Faibussowitsch `PetscDeviceContextSynchronize()`, `PetscDeviceContextJoinMode`
741030f984aSJacob Faibussowitsch @*/
742d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextJoin(PetscDeviceContext dctx, PetscInt n, PetscDeviceContextJoinMode joinMode, PetscDeviceContext **dsub)
743d71ae5a4SJacob Faibussowitsch {
7440e6b6b59SJacob Faibussowitsch   // debugging only
7450e6b6b59SJacob Faibussowitsch   std::string idList;
746030f984aSJacob Faibussowitsch 
747030f984aSJacob Faibussowitsch   PetscFunctionBegin;
7480e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
749030f984aSJacob Faibussowitsch   /* validity of dctx is checked in the wait-for loop */
750030f984aSJacob Faibussowitsch   PetscValidPointer(dsub, 4);
751bf025ffbSJacob Faibussowitsch   PetscAssert(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of contexts merged %" PetscInt_FMT " < 0", n);
752030f984aSJacob Faibussowitsch   /* reserve 4 chars per id, 2 for number and 2 for ', ' separator */
7530e6b6b59SJacob Faibussowitsch   if (PetscDefined(USE_DEBUG_AND_INFO)) PetscCallCXX(idList.reserve(4 * n));
754030f984aSJacob Faibussowitsch   /* first dctx waits on all the incoming edges */
7556a4a1270SPierre Jolivet   PetscCall(PetscLogEventBegin(DCONTEXT_Join, dctx, nullptr, nullptr, nullptr));
756030f984aSJacob Faibussowitsch   for (PetscInt i = 0; i < n; ++i) {
757030f984aSJacob Faibussowitsch     PetscCheckCompatibleDeviceContexts(dctx, 1, (*dsub)[i], 4);
7589566063dSJacob Faibussowitsch     PetscCall(PetscDeviceContextWaitForContext(dctx, (*dsub)[i]));
7590e6b6b59SJacob Faibussowitsch     if (PetscDefined(USE_DEBUG_AND_INFO)) {
7600e6b6b59SJacob Faibussowitsch       PetscCallCXX(idList += std::to_string(PetscObjectCast((*dsub)[i])->id));
7610e6b6b59SJacob Faibussowitsch       if (i + 1 < n) PetscCallCXX(idList += ", ");
7620e6b6b59SJacob Faibussowitsch     }
763030f984aSJacob Faibussowitsch   }
764030f984aSJacob Faibussowitsch 
765030f984aSJacob Faibussowitsch   /* now we handle the aftermath */
766030f984aSJacob Faibussowitsch   switch (joinMode) {
7679371c9d4SSatish Balay   case PETSC_DEVICE_CONTEXT_JOIN_DESTROY: {
7680e6b6b59SJacob Faibussowitsch     const auto children = dctx->childIDs;
7690e6b6b59SJacob Faibussowitsch     const auto maxchild = dctx->maxNumChildren;
7700e6b6b59SJacob Faibussowitsch     auto      &nchild   = dctx->numChildren;
771030f984aSJacob Faibussowitsch     PetscInt   j        = 0;
772030f984aSJacob Faibussowitsch 
7730e6b6b59SJacob 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);
774030f984aSJacob Faibussowitsch     /* update child count while it's still fresh in memory */
7750e6b6b59SJacob Faibussowitsch     nchild -= n;
7760e6b6b59SJacob Faibussowitsch     for (PetscInt i = 0; i < maxchild; ++i) {
7770e6b6b59SJacob Faibussowitsch       if (children[i] && (children[i] == PetscObjectCast((*dsub)[j])->id)) {
778030f984aSJacob Faibussowitsch         /* child is one of ours, can destroy it */
7799566063dSJacob Faibussowitsch         PetscCall(PetscDeviceContextDestroy((*dsub) + j));
780030f984aSJacob Faibussowitsch         /* reset the child slot */
7810e6b6b59SJacob Faibussowitsch         children[i] = 0;
782030f984aSJacob Faibussowitsch         if (++j == n) break;
783030f984aSJacob Faibussowitsch       }
784030f984aSJacob Faibussowitsch     }
7850e6b6b59SJacob Faibussowitsch     /* gone through the loop but did not find every child */
7860e6b6b59SJacob 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);
7879566063dSJacob Faibussowitsch     PetscCall(PetscFree(*dsub));
7889371c9d4SSatish Balay   } break;
789030f984aSJacob Faibussowitsch   case PETSC_DEVICE_CONTEXT_JOIN_SYNC:
7909566063dSJacob Faibussowitsch     for (PetscInt i = 0; i < n; ++i) PetscCall(PetscDeviceContextWaitForContext((*dsub)[i], dctx));
791d71ae5a4SJacob Faibussowitsch   case PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC:
792d71ae5a4SJacob Faibussowitsch     break;
793d71ae5a4SJacob Faibussowitsch   default:
794d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown PetscDeviceContextJoinMode given");
795030f984aSJacob Faibussowitsch   }
7966a4a1270SPierre Jolivet   PetscCall(PetscLogEventEnd(DCONTEXT_Join, dctx, nullptr, nullptr, nullptr));
797030f984aSJacob Faibussowitsch 
7980e6b6b59SJacob 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()));
799030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
800030f984aSJacob Faibussowitsch }
801030f984aSJacob Faibussowitsch 
802030f984aSJacob Faibussowitsch /*@C
8030e6b6b59SJacob Faibussowitsch   PetscDeviceContextSynchronize - Block the host until all work queued on a
8040e6b6b59SJacob Faibussowitsch   `PetscDeviceContext` has finished
805030f984aSJacob Faibussowitsch 
8060e6b6b59SJacob Faibussowitsch   Not Collective
807030f984aSJacob Faibussowitsch 
808030f984aSJacob Faibussowitsch   Input Parameters:
809811af0c4SBarry Smith . dctx - The `PetscDeviceContext` to synchronize
810030f984aSJacob Faibussowitsch 
8110e6b6b59SJacob Faibussowitsch   Notes:
8120e6b6b59SJacob Faibussowitsch   The host will not return from this routine until `dctx` is idle. Any and all memory
8130e6b6b59SJacob Faibussowitsch   operations queued on or otherwise associated with (either explicitly or implicitly via
8140e6b6b59SJacob Faibussowitsch   dependencies) are guaranteed to have finished and be globally visible on return.
8150e6b6b59SJacob Faibussowitsch 
8160e6b6b59SJacob Faibussowitsch   In effect, this routine serves as memory and execution barrier.
8170e6b6b59SJacob Faibussowitsch 
8180e6b6b59SJacob Faibussowitsch   DAG representation:
8190e6b6b59SJacob Faibussowitsch .vb
8200e6b6b59SJacob Faibussowitsch   time ->
8210e6b6b59SJacob Faibussowitsch 
8220e6b6b59SJacob Faibussowitsch   -> dctx - |= CALL =| - dctx ->
8230e6b6b59SJacob Faibussowitsch .ve
8240e6b6b59SJacob Faibussowitsch 
825030f984aSJacob Faibussowitsch   Level: beginner
826030f984aSJacob Faibussowitsch 
827db781477SPatrick Sanan .seealso: `PetscDeviceContextFork()`, `PetscDeviceContextJoin()`, `PetscDeviceContextQueryIdle()`
828030f984aSJacob Faibussowitsch @*/
829d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextSynchronize(PetscDeviceContext dctx)
830d71ae5a4SJacob Faibussowitsch {
831030f984aSJacob Faibussowitsch   PetscFunctionBegin;
8320e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
8336a4a1270SPierre Jolivet   PetscCall(PetscLogEventBegin(DCONTEXT_Sync, dctx, nullptr, nullptr, nullptr));
834030f984aSJacob Faibussowitsch   /* if it isn't setup there is nothing to sync on */
8350e6b6b59SJacob Faibussowitsch   if (dctx->setup) {
8360e6b6b59SJacob Faibussowitsch     PetscCall((*dctx->ops->synchronize)(dctx));
8370e6b6b59SJacob Faibussowitsch     PetscCall(PetscDeviceContextSyncClearMap_Internal(dctx));
8380e6b6b59SJacob Faibussowitsch   }
8396a4a1270SPierre Jolivet   PetscCall(PetscLogEventEnd(DCONTEXT_Sync, dctx, nullptr, nullptr, nullptr));
840030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
841030f984aSJacob Faibussowitsch }
842030f984aSJacob Faibussowitsch 
8430e6b6b59SJacob Faibussowitsch /* every device type has a vector of null PetscDeviceContexts -- one for each device */
8440e6b6b59SJacob Faibussowitsch static auto nullContexts          = std::array<std::vector<PetscDeviceContext>, PETSC_DEVICE_MAX>{};
8450e6b6b59SJacob Faibussowitsch static auto nullContextsFinalizer = false;
846030f984aSJacob Faibussowitsch 
847d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDeviceContextGetNullContextForDevice_Private(PetscBool user_set_device, PetscDevice device, PetscDeviceContext *dctx)
848d71ae5a4SJacob Faibussowitsch {
8490e6b6b59SJacob Faibussowitsch   PetscInt        devid;
8500e6b6b59SJacob Faibussowitsch   PetscDeviceType dtype;
851a4af0ceeSJacob Faibussowitsch 
852030f984aSJacob Faibussowitsch   PetscFunctionBegin;
8530e6b6b59SJacob Faibussowitsch   PetscValidDevice(device, 2);
8540e6b6b59SJacob Faibussowitsch   PetscValidPointer(dctx, 3);
8550e6b6b59SJacob Faibussowitsch   if (PetscUnlikely(!nullContextsFinalizer)) {
8560e6b6b59SJacob Faibussowitsch     const auto finalizer = [] {
8570e6b6b59SJacob Faibussowitsch       PetscFunctionBegin;
8580e6b6b59SJacob Faibussowitsch       for (auto &&dvec : nullContexts) {
8590e6b6b59SJacob Faibussowitsch         for (auto &&dctx : dvec) PetscCall(PetscDeviceContextDestroy(&dctx));
8600e6b6b59SJacob Faibussowitsch         PetscCallCXX(dvec.clear());
861030f984aSJacob Faibussowitsch       }
8620e6b6b59SJacob Faibussowitsch       nullContextsFinalizer = false;
863a4af0ceeSJacob Faibussowitsch       PetscFunctionReturn(0);
864a4af0ceeSJacob Faibussowitsch     };
865a4af0ceeSJacob Faibussowitsch 
8660e6b6b59SJacob Faibussowitsch     nullContextsFinalizer = true;
8670e6b6b59SJacob Faibussowitsch     PetscCall(PetscRegisterFinalize(std::move(finalizer)));
8680e6b6b59SJacob Faibussowitsch   }
8690e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceGetDeviceId(device, &devid));
8700e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceGetType(device, &dtype));
8710e6b6b59SJacob Faibussowitsch   {
8720e6b6b59SJacob Faibussowitsch     auto &ctxlist = nullContexts[dtype];
8730e6b6b59SJacob Faibussowitsch 
8740e6b6b59SJacob Faibussowitsch     PetscCheck(devid >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Device ID (%" PetscInt_FMT ") must be positive", devid);
8750e6b6b59SJacob Faibussowitsch     // need to resize the container if not big enough because incrementing the iterator in
8760e6b6b59SJacob Faibussowitsch     // std::next() (if we haven't initialized that ctx yet) may cause it to fall outside the
8770e6b6b59SJacob Faibussowitsch     // current size of the container.
8780e6b6b59SJacob Faibussowitsch     if (static_cast<std::size_t>(devid) >= ctxlist.size()) PetscCallCXX(ctxlist.resize(devid + 1));
8790e6b6b59SJacob Faibussowitsch     if (PetscUnlikely(!ctxlist[devid])) {
8800e6b6b59SJacob Faibussowitsch       // we have not seen this device before
8810e6b6b59SJacob Faibussowitsch       PetscCall(PetscDeviceContextCreate(dctx));
882403f9ca4SJacob Faibussowitsch       PetscCall(PetscInfo(*dctx, "Initializing null PetscDeviceContext (of type %s) for device %" PetscInt_FMT "\n", PetscDeviceTypes[dtype], devid));
8830e6b6b59SJacob Faibussowitsch       {
8840e6b6b59SJacob Faibussowitsch         const auto pobj   = PetscObjectCast(*dctx);
8850e6b6b59SJacob Faibussowitsch         const auto name   = "null context " + std::to_string(devid);
8860e6b6b59SJacob Faibussowitsch         const auto prefix = "null_context_" + std::to_string(devid) + '_';
8870e6b6b59SJacob Faibussowitsch 
8880e6b6b59SJacob Faibussowitsch         PetscCall(PetscObjectSetName(pobj, name.c_str()));
8890e6b6b59SJacob Faibussowitsch         PetscCall(PetscObjectSetOptionsPrefix(pobj, prefix.c_str()));
8900e6b6b59SJacob Faibussowitsch       }
8910e6b6b59SJacob Faibussowitsch       PetscCall(PetscDeviceContextSetStreamType(*dctx, PETSC_STREAM_GLOBAL_BLOCKING));
8920e6b6b59SJacob Faibussowitsch       PetscCall(PetscDeviceContextSetDevice_Private(*dctx, device, user_set_device));
8930e6b6b59SJacob Faibussowitsch       PetscCall(PetscDeviceContextSetUp(*dctx));
8940e6b6b59SJacob Faibussowitsch       // would use ctxlist.cbegin() but GCC 4.8 can't handle const iterator insert!
8950e6b6b59SJacob Faibussowitsch       PetscCallCXX(ctxlist.insert(std::next(ctxlist.begin(), devid), *dctx));
8960e6b6b59SJacob Faibussowitsch     } else *dctx = ctxlist[devid];
8970e6b6b59SJacob Faibussowitsch   }
898030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
899030f984aSJacob Faibussowitsch }
900030f984aSJacob Faibussowitsch 
9010e6b6b59SJacob Faibussowitsch /*
9020e6b6b59SJacob Faibussowitsch   Gets the "NULL" context for the current PetscDeviceType and PetscDevice. NULL contexts are
9030e6b6b59SJacob Faibussowitsch   guaranteed to always be globally blocking.
9040e6b6b59SJacob Faibussowitsch */
905d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextGetNullContext_Internal(PetscDeviceContext *dctx)
906d71ae5a4SJacob Faibussowitsch {
9070e6b6b59SJacob Faibussowitsch   PetscDeviceContext gctx;
9080e6b6b59SJacob Faibussowitsch   PetscDevice        gdev = nullptr;
909030f984aSJacob Faibussowitsch 
910a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
911a4af0ceeSJacob Faibussowitsch   PetscValidPointer(dctx, 1);
9120e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetCurrentContext(&gctx));
9130e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetDevice(gctx, &gdev));
9140e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetNullContextForDevice_Private(gctx->usersetdevice, gdev, dctx));
915030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
916030f984aSJacob Faibussowitsch }
917030f984aSJacob Faibussowitsch 
918030f984aSJacob Faibussowitsch /*@C
919811af0c4SBarry Smith   PetscDeviceContextSetFromOptions - Configure a `PetscDeviceContext` from the options database
920030f984aSJacob Faibussowitsch 
9210e6b6b59SJacob Faibussowitsch   Collective on `comm` or `dctx`
922030f984aSJacob Faibussowitsch 
923030f984aSJacob Faibussowitsch   Input Parameters:
9240e6b6b59SJacob Faibussowitsch + comm - MPI communicator on which to query the options database (optional)
925811af0c4SBarry Smith - dctx - The `PetscDeviceContext` to configure
926030f984aSJacob Faibussowitsch 
927030f984aSJacob Faibussowitsch   Output Parameter:
928811af0c4SBarry Smith . dctx - The `PetscDeviceContext`
929030f984aSJacob Faibussowitsch 
9300e6b6b59SJacob Faibussowitsch   Options Database:
9310e6b6b59SJacob Faibussowitsch + -device_context_stream_type - type of stream to create inside the `PetscDeviceContext` -
9320e6b6b59SJacob Faibussowitsch    `PetscDeviceContextSetStreamType()`
933811af0c4SBarry Smith - -device_context_device_type - the type of `PetscDevice` to attach by default - `PetscDeviceType`
934030f984aSJacob Faibussowitsch 
9350e6b6b59SJacob Faibussowitsch   Notes:
9360e6b6b59SJacob Faibussowitsch   The user may pass `MPI_COMM_NULL` for `comm` in which case the communicator of `dctx` is
9370e6b6b59SJacob Faibussowitsch   used (which is always `PETSC_COMM_SELF`).
9380e6b6b59SJacob Faibussowitsch 
939030f984aSJacob Faibussowitsch   Level: beginner
940030f984aSJacob Faibussowitsch 
9410e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextSetStreamType()`, `PetscDeviceContextSetDevice()`,
9420e6b6b59SJacob Faibussowitsch `PetscDeviceContextView()`
943030f984aSJacob Faibussowitsch @*/
944d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetFromOptions(MPI_Comm comm, PetscDeviceContext dctx)
945d71ae5a4SJacob Faibussowitsch {
9460e6b6b59SJacob Faibussowitsch   const auto pobj     = PetscObjectCast(dctx);
9470e6b6b59SJacob Faibussowitsch   auto       dtype    = std::make_pair(PETSC_DEVICE_DEFAULT(), PETSC_FALSE);
9480e6b6b59SJacob Faibussowitsch   auto       stype    = std::make_pair(PETSC_DEVICE_CONTEXT_DEFAULT_STREAM_TYPE, PETSC_FALSE);
9490e6b6b59SJacob Faibussowitsch   auto       old_comm = PETSC_COMM_SELF;
950030f984aSJacob Faibussowitsch 
951030f984aSJacob Faibussowitsch   PetscFunctionBegin;
9520e6b6b59SJacob Faibussowitsch   // do not user getoptionalnullcontext here, the user is not allowed to set it from options!
9530e6b6b59SJacob Faibussowitsch   PetscValidDeviceContext(dctx, 2);
9540e6b6b59SJacob Faibussowitsch   /* set the device type first */
9550e6b6b59SJacob Faibussowitsch   if (const auto device = dctx->device) PetscCall(PetscDeviceGetType(device, &dtype.first));
9560e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetStreamType(dctx, &stype.first));
9570e6b6b59SJacob Faibussowitsch 
9580e6b6b59SJacob Faibussowitsch   if (comm == MPI_COMM_NULL) {
9590e6b6b59SJacob Faibussowitsch     PetscCall(PetscObjectGetComm(pobj, &comm));
9600e6b6b59SJacob Faibussowitsch   } else {
9610e6b6b59SJacob Faibussowitsch     // briefly set the communicator for dctx (it is always PETSC_COMM_SELF) so
9620e6b6b59SJacob Faibussowitsch     // PetscObjectOptionsBegin() behaves as if dctx had comm
9630e6b6b59SJacob Faibussowitsch     old_comm = Petsc::util::exchange(pobj->comm, comm);
9640e6b6b59SJacob Faibussowitsch   }
9650e6b6b59SJacob Faibussowitsch 
9660e6b6b59SJacob Faibussowitsch   PetscObjectOptionsBegin(pobj);
9670e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextQueryOptions_Internal(PetscOptionsObject, dtype, stype));
968d0609cedSBarry Smith   PetscOptionsEnd();
9690e6b6b59SJacob Faibussowitsch   // reset the comm (should be PETSC_COMM_SELF)
9700e6b6b59SJacob Faibussowitsch   if (comm != MPI_COMM_NULL) pobj->comm = old_comm;
9710e6b6b59SJacob Faibussowitsch   if (dtype.second) PetscCall(PetscDeviceContextSetDefaultDeviceForType_Internal(dctx, dtype.first));
9720e6b6b59SJacob Faibussowitsch   if (stype.second) PetscCall(PetscDeviceContextSetStreamType(dctx, stype.first));
9730e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextSetUp(dctx));
9740e6b6b59SJacob Faibussowitsch   PetscFunctionReturn(0);
9750e6b6b59SJacob Faibussowitsch }
9760e6b6b59SJacob Faibussowitsch 
9770e6b6b59SJacob Faibussowitsch /*@C
9780e6b6b59SJacob Faibussowitsch   PetscDeviceContextView - View a `PetscDeviceContext`
9790e6b6b59SJacob Faibussowitsch 
9800e6b6b59SJacob Faibussowitsch   Collective on `viewer`
9810e6b6b59SJacob Faibussowitsch 
9820e6b6b59SJacob Faibussowitsch   Input Parameters:
9830e6b6b59SJacob Faibussowitsch + dctx - The `PetscDeviceContext`
9840e6b6b59SJacob Faibussowitsch - viewer - The `PetscViewer` to view `dctx` with (may be `NULL`)
9850e6b6b59SJacob Faibussowitsch 
9860e6b6b59SJacob Faibussowitsch   Notes:
9870e6b6b59SJacob Faibussowitsch   If `viewer` is `NULL`, `PETSC_VIEWER_STDOUT_WORLD` is used instead, in which case this
9880e6b6b59SJacob Faibussowitsch   routine is collective on `PETSC_COMM_WORLD`.
9890e6b6b59SJacob Faibussowitsch 
9900e6b6b59SJacob Faibussowitsch   Level: beginner
9910e6b6b59SJacob Faibussowitsch 
9920e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextViewFromOptions()`, `PetscDeviceView()`, `PETSC_VIEWER_STDOUT_WORLD`, `PetscDeviceContextCreate()`
9930e6b6b59SJacob Faibussowitsch @*/
994d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextView(PetscDeviceContext dctx, PetscViewer viewer)
995d71ae5a4SJacob Faibussowitsch {
9960e6b6b59SJacob Faibussowitsch   PetscBool iascii;
9970e6b6b59SJacob Faibussowitsch 
9980e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
9990e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
10000e6b6b59SJacob Faibussowitsch   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PETSC_COMM_WORLD, &viewer));
10010e6b6b59SJacob Faibussowitsch   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
10020e6b6b59SJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare(PetscObjectCast(viewer), PETSCVIEWERASCII, &iascii));
10030e6b6b59SJacob Faibussowitsch   if (iascii) {
10040e6b6b59SJacob Faibussowitsch     auto        stype = PETSC_STREAM_DEFAULT_BLOCKING;
10050e6b6b59SJacob Faibussowitsch     PetscViewer sub;
10060e6b6b59SJacob Faibussowitsch 
10070e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sub));
10080e6b6b59SJacob Faibussowitsch     PetscCall(PetscObjectPrintClassNamePrefixType(PetscObjectCast(dctx), sub));
10090e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(sub));
10100e6b6b59SJacob Faibussowitsch     PetscCall(PetscDeviceContextGetStreamType(dctx, &stype));
10110e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(sub, "stream type: %s\n", PetscStreamTypes[stype]));
10120e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(sub, "children: %" PetscInt_FMT "\n", dctx->numChildren));
10130e6b6b59SJacob Faibussowitsch     if (const auto nchild = dctx->numChildren) {
10140e6b6b59SJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushTab(sub));
10150e6b6b59SJacob Faibussowitsch       for (PetscInt i = 0; i < nchild; ++i) {
10160e6b6b59SJacob Faibussowitsch         if (i == nchild - 1) {
10170e6b6b59SJacob Faibussowitsch           PetscCall(PetscViewerASCIIPrintf(sub, "%" PetscInt64_FMT, dctx->childIDs[i]));
10180e6b6b59SJacob Faibussowitsch         } else {
10190e6b6b59SJacob Faibussowitsch           PetscCall(PetscViewerASCIIPrintf(sub, "%" PetscInt64_FMT ", ", dctx->childIDs[i]));
10200e6b6b59SJacob Faibussowitsch         }
10210e6b6b59SJacob Faibussowitsch       }
10220e6b6b59SJacob Faibussowitsch     }
10230e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(sub));
10240e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sub));
10250e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerFlush(viewer));
10260e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(viewer));
10270e6b6b59SJacob Faibussowitsch   }
10280e6b6b59SJacob Faibussowitsch   if (const auto device = dctx->device) PetscCall(PetscDeviceView(device, viewer));
10290e6b6b59SJacob Faibussowitsch   if (iascii) PetscCall(PetscViewerASCIIPopTab(viewer));
10300e6b6b59SJacob Faibussowitsch   PetscFunctionReturn(0);
10310e6b6b59SJacob Faibussowitsch }
10320e6b6b59SJacob Faibussowitsch 
10330e6b6b59SJacob Faibussowitsch /*@C
10340e6b6b59SJacob Faibussowitsch   PetscDeviceContextViewFromOptions - View a `PetscDeviceContext` from options
10350e6b6b59SJacob Faibussowitsch 
10360e6b6b59SJacob Faibussowitsch   Input Parameters:
10370e6b6b59SJacob Faibussowitsch + dctx - The `PetscDeviceContext` to view
10380e6b6b59SJacob Faibussowitsch . obj  - Optional `PetscObject` to associate (may be `NULL`)
10390e6b6b59SJacob Faibussowitsch - name - The command line option
10400e6b6b59SJacob Faibussowitsch 
10410e6b6b59SJacob Faibussowitsch   Level: beginner
10420e6b6b59SJacob Faibussowitsch 
10430e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextView()`, `PetscObjectViewFromOptions()`, `PetscDeviceContextCreate()`
10440e6b6b59SJacob Faibussowitsch @*/
1045d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextViewFromOptions(PetscDeviceContext dctx, PetscObject obj, const char name[])
1046d71ae5a4SJacob Faibussowitsch {
10470e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
10480e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
10490e6b6b59SJacob Faibussowitsch   if (obj) PetscValidHeader(obj, 2);
10500e6b6b59SJacob Faibussowitsch   PetscValidCharPointer(name, 3);
10510e6b6b59SJacob Faibussowitsch   PetscCall(PetscObjectViewFromOptions(PetscObjectCast(dctx), obj, name));
1052030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
1053030f984aSJacob Faibussowitsch }
1054