xref: /petsc/src/sys/objects/device/interface/dcontext.cxx (revision 0e6b6b5985dd9b1172860d21fb88bd3966bf7c54)
1*0e6b6b59SJacob Faibussowitsch #include "petscdevice_interface_internal.hpp" /*I <petscdevice.h> I*/
2*0e6b6b59SJacob Faibussowitsch #include <petsc/private/viewerimpl.h>         // _p_PetscViewer for PetscObjectCast()
3030f984aSJacob Faibussowitsch 
4*0e6b6b59SJacob Faibussowitsch #include <petsc/private/cpp/object_pool.hpp>
5*0e6b6b59SJacob Faibussowitsch #include <petsc/private/cpp/utility.hpp>
6*0e6b6b59SJacob Faibussowitsch #include <petsc/private/cpp/array.hpp>
7a4af0ceeSJacob Faibussowitsch 
8*0e6b6b59SJacob Faibussowitsch #include <vector>
9*0e6b6b59SJacob Faibussowitsch #include <string> // std::to_string among other things
10a4af0ceeSJacob Faibussowitsch 
11030f984aSJacob Faibussowitsch /* Define the allocator */
12*0e6b6b59SJacob Faibussowitsch class PetscDeviceContextAllocator : public Petsc::AllocatorBase<PetscDeviceContext> {
13*0e6b6b59SJacob Faibussowitsch public:
14*0e6b6b59SJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode create(PetscDeviceContext *dctx)) {
15030f984aSJacob Faibussowitsch     PetscFunctionBegin;
16*0e6b6b59SJacob Faibussowitsch     PetscCall(PetscHeaderCreate(*dctx, PETSC_DEVICE_CONTEXT_CLASSID, "PetscDeviceContext", "PetscDeviceContext", "Sys", PETSC_COMM_SELF, PetscDeviceContextDestroy, PetscDeviceContextView));
17*0e6b6b59SJacob Faibussowitsch     PetscCallCXX(PetscObjectCast(*dctx)->cpp = new CxxData());
18*0e6b6b59SJacob Faibussowitsch     PetscCall(reset(*dctx, false));
19030f984aSJacob Faibussowitsch     PetscFunctionReturn(0);
20030f984aSJacob Faibussowitsch   }
21030f984aSJacob Faibussowitsch 
22*0e6b6b59SJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode destroy(PetscDeviceContext dctx)) {
23030f984aSJacob Faibussowitsch     PetscFunctionBegin;
24bf025ffbSJacob 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);
25dbbe0bcdSBarry Smith     PetscTryTypeMethod(dctx, destroy);
269566063dSJacob Faibussowitsch     PetscCall(PetscDeviceDestroy(&dctx->device));
279566063dSJacob Faibussowitsch     PetscCall(PetscFree(dctx->childIDs));
28*0e6b6b59SJacob Faibussowitsch     delete CxxDataCast(dctx);
29*0e6b6b59SJacob Faibussowitsch     PetscCall(PetscHeaderDestroy(&dctx));
30030f984aSJacob Faibussowitsch     PetscFunctionReturn(0);
31030f984aSJacob Faibussowitsch   }
32030f984aSJacob Faibussowitsch 
33*0e6b6b59SJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode reset(PetscDeviceContext dctx, bool zero = true)) {
34030f984aSJacob Faibussowitsch     PetscFunctionBegin;
35*0e6b6b59SJacob Faibussowitsch     if (zero) {
36*0e6b6b59SJacob Faibussowitsch       // reset the device if the user set it
37*0e6b6b59SJacob Faibussowitsch       if (auto &userset = dctx->usersetdevice) {
38*0e6b6b59SJacob Faibussowitsch         userset = PETSC_FALSE;
39*0e6b6b59SJacob Faibussowitsch         PetscTryTypeMethod(dctx, destroy);
40*0e6b6b59SJacob Faibussowitsch         PetscCall(PetscDeviceDestroy(&dctx->device));
41*0e6b6b59SJacob Faibussowitsch         PetscCall(PetscArrayzero(dctx->ops, 1));
42*0e6b6b59SJacob Faibussowitsch         dctx->data = nullptr;
43*0e6b6b59SJacob Faibussowitsch       }
44*0e6b6b59SJacob Faibussowitsch       PetscCall(PetscHeaderReset_Internal(PetscObjectCast(dctx)));
45030f984aSJacob Faibussowitsch       dctx->numChildren = 0;
46*0e6b6b59SJacob Faibussowitsch       dctx->setup       = PETSC_FALSE;
47*0e6b6b59SJacob Faibussowitsch       // don't deallocate the child array, rather just zero it out
48*0e6b6b59SJacob Faibussowitsch       PetscCall(PetscArrayzero(dctx->childIDs, dctx->maxNumChildren));
49*0e6b6b59SJacob Faibussowitsch       PetscCall(CxxDataCast(dctx)->clear());
50*0e6b6b59SJacob Faibussowitsch     }
51030f984aSJacob Faibussowitsch     dctx->streamType = PETSC_STREAM_DEFAULT_BLOCKING;
52030f984aSJacob Faibussowitsch     PetscFunctionReturn(0);
53030f984aSJacob Faibussowitsch   }
54030f984aSJacob Faibussowitsch };
55030f984aSJacob Faibussowitsch 
56030f984aSJacob Faibussowitsch static Petsc::ObjectPool<PetscDeviceContext, PetscDeviceContextAllocator> contextPool;
57030f984aSJacob Faibussowitsch 
58030f984aSJacob Faibussowitsch /*@C
59811af0c4SBarry Smith   PetscDeviceContextCreate - Creates a `PetscDeviceContext`
60030f984aSJacob Faibussowitsch 
61*0e6b6b59SJacob Faibussowitsch   Not Collective
62030f984aSJacob Faibussowitsch 
6301d2d390SJose E. Roman   Output Paramemter:
64811af0c4SBarry Smith . dctx - The `PetscDeviceContext`
65030f984aSJacob Faibussowitsch 
66811af0c4SBarry Smith   Note:
67030f984aSJacob Faibussowitsch   Unlike almost every other PETSc class it is advised that most users use
68*0e6b6b59SJacob Faibussowitsch   `PetscDeviceContextDuplicate()` rather than this routine to create new contexts. Contexts of
69*0e6b6b59SJacob Faibussowitsch   different types are incompatible with one another; using `PetscDeviceContextDuplicate()`
70*0e6b6b59SJacob Faibussowitsch   ensures compatible types.
71*0e6b6b59SJacob Faibussowitsch 
72*0e6b6b59SJacob Faibussowitsch   DAG representation:
73*0e6b6b59SJacob Faibussowitsch .vb
74*0e6b6b59SJacob Faibussowitsch   time ->
75*0e6b6b59SJacob Faibussowitsch 
76*0e6b6b59SJacob Faibussowitsch   |= CALL =| - dctx ->
77*0e6b6b59SJacob Faibussowitsch .ve
78030f984aSJacob Faibussowitsch 
79030f984aSJacob Faibussowitsch   Level: beginner
80030f984aSJacob Faibussowitsch 
81*0e6b6b59SJacob Faibussowitsch .N ASYNC_API
82*0e6b6b59SJacob Faibussowitsch 
83db781477SPatrick Sanan .seealso: `PetscDeviceContextDuplicate()`, `PetscDeviceContextSetDevice()`,
84db781477SPatrick Sanan `PetscDeviceContextSetStreamType()`, `PetscDeviceContextSetUp()`,
85*0e6b6b59SJacob Faibussowitsch `PetscDeviceContextSetFromOptions()`, `PetscDeviceContextView()`, `PetscDeviceContextDestroy()`
86030f984aSJacob Faibussowitsch @*/
879371c9d4SSatish Balay PetscErrorCode PetscDeviceContextCreate(PetscDeviceContext *dctx) {
88030f984aSJacob Faibussowitsch   PetscFunctionBegin;
89030f984aSJacob Faibussowitsch   PetscValidPointer(dctx, 1);
909566063dSJacob Faibussowitsch   PetscCall(PetscDeviceInitializePackage());
91*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DCONTEXT_Create, 0, 0, 0, 0));
92*0e6b6b59SJacob Faibussowitsch   PetscCall(contextPool.allocate(dctx));
93*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DCONTEXT_Create, 0, 0, 0, 0));
94030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
95030f984aSJacob Faibussowitsch }
96030f984aSJacob Faibussowitsch 
97030f984aSJacob Faibussowitsch /*@C
98811af0c4SBarry Smith   PetscDeviceContextDestroy - Frees a `PetscDeviceContext`
99030f984aSJacob Faibussowitsch 
100*0e6b6b59SJacob Faibussowitsch   Not Collective
101030f984aSJacob Faibussowitsch 
102030f984aSJacob Faibussowitsch   Input Parameters:
103811af0c4SBarry Smith . dctx - The `PetscDeviceContext`
104030f984aSJacob Faibussowitsch 
105*0e6b6b59SJacob Faibussowitsch   Notes:
106*0e6b6b59SJacob Faibussowitsch   No implicit synchronization occurs due to this routine, all resources are released completely
107*0e6b6b59SJacob Faibussowitsch   asynchronously w.r.t. the host. If one needs to guarantee access to the data produced on
108*0e6b6b59SJacob Faibussowitsch   `dctx`'s stream the user is responsible for calling `PetscDeviceContextSynchronize()` before
109*0e6b6b59SJacob Faibussowitsch   calling this routine.
110030f984aSJacob Faibussowitsch 
111*0e6b6b59SJacob Faibussowitsch   DAG represetation:
112*0e6b6b59SJacob Faibussowitsch .vb
113*0e6b6b59SJacob Faibussowitsch   time ->
114*0e6b6b59SJacob Faibussowitsch 
115*0e6b6b59SJacob Faibussowitsch   -> dctx - |= CALL =|
116*0e6b6b59SJacob Faibussowitsch .ve
117*0e6b6b59SJacob Faibussowitsch 
118*0e6b6b59SJacob Faibussowitsch   Developer Notes:
119*0e6b6b59SJacob Faibussowitsch   `dctx` is never actually "destroyed" in the classical sense. It is returned to an ever
120*0e6b6b59SJacob Faibussowitsch   growing pool of `PetscDeviceContext`s. There are currently no limits on the size of the pool,
121*0e6b6b59SJacob Faibussowitsch   this should perhaps be implemented.
122030f984aSJacob Faibussowitsch 
123030f984aSJacob Faibussowitsch   Level: beginner
124030f984aSJacob Faibussowitsch 
125*0e6b6b59SJacob Faibussowitsch .N ASYNC_API
126*0e6b6b59SJacob Faibussowitsch 
127*0e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextSetDevice()`,
128*0e6b6b59SJacob Faibussowitsch `PetscDeviceContextSetUp()`, `PetscDeviceContextSynchronize()`
129030f984aSJacob Faibussowitsch @*/
1309371c9d4SSatish Balay PetscErrorCode PetscDeviceContextDestroy(PetscDeviceContext *dctx) {
131030f984aSJacob Faibussowitsch   PetscFunctionBegin;
132*0e6b6b59SJacob Faibussowitsch   PetscValidPointer(dctx, 1);
133030f984aSJacob Faibussowitsch   if (!*dctx) PetscFunctionReturn(0);
134*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DCONTEXT_Destroy, 0, 0, 0, 0));
135*0e6b6b59SJacob Faibussowitsch   if (--(PetscObjectCast(*dctx)->refct) <= 0) {
136*0e6b6b59SJacob Faibussowitsch     PetscCall(PetscDeviceContextCheckNotOrphaned_Internal(*dctx));
137*0e6b6b59SJacob Faibussowitsch     // std::move of the expression of the trivially-copyable type 'PetscDeviceContext' (aka
138*0e6b6b59SJacob Faibussowitsch     // '_n_PetscDeviceContext *') has no effect; remove std::move() [performance-move-const-arg]
139*0e6b6b59SJacob Faibussowitsch     // can't remove std::move, since reclaim only takes r-value reference
140*0e6b6b59SJacob Faibussowitsch     PetscCall(contextPool.deallocate(std::move(*dctx))); // NOLINT (performance-move-const-arg)
141*0e6b6b59SJacob Faibussowitsch   }
142*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DCONTEXT_Destroy, 0, 0, 0, 0));
143bf025ffbSJacob Faibussowitsch   *dctx = nullptr;
144030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
145030f984aSJacob Faibussowitsch }
146030f984aSJacob Faibussowitsch 
147030f984aSJacob Faibussowitsch /*@C
148*0e6b6b59SJacob Faibussowitsch   PetscDeviceContextSetStreamType - Set the implementation type of the underlying stream for a
149*0e6b6b59SJacob Faibussowitsch   `PetscDeviceContext`
150030f984aSJacob Faibussowitsch 
151*0e6b6b59SJacob Faibussowitsch   Not Collective
152030f984aSJacob Faibussowitsch 
15301d2d390SJose E. Roman   Input Parameters:
154811af0c4SBarry Smith + dctx - The `PetscDeviceContext`
155811af0c4SBarry Smith - type - The `PetscStreamType`
156030f984aSJacob Faibussowitsch 
157030f984aSJacob Faibussowitsch   Notes:
158811af0c4SBarry Smith   See `PetscStreamType` in `include/petscdevicetypes.h` for more information on the available
159*0e6b6b59SJacob Faibussowitsch   types and their interactions. If the `PetscDeviceContext` was previously set up and stream
160811af0c4SBarry Smith   type was changed, you must call `PetscDeviceContextSetUp()` again after this routine.
161030f984aSJacob Faibussowitsch 
162*0e6b6b59SJacob Faibussowitsch   Level: beginner
163030f984aSJacob Faibussowitsch 
164*0e6b6b59SJacob Faibussowitsch .seealso: `PetscStreamType`, `PetscDeviceContextGetStreamType()`, `PetscDeviceContextCreate()`,
165*0e6b6b59SJacob Faibussowitsch `PetscDeviceContextSetUp()`, `PetscDeviceContextSetFromOptions()`
166030f984aSJacob Faibussowitsch @*/
1679371c9d4SSatish Balay PetscErrorCode PetscDeviceContextSetStreamType(PetscDeviceContext dctx, PetscStreamType type) {
168030f984aSJacob Faibussowitsch   PetscFunctionBegin;
169*0e6b6b59SJacob Faibussowitsch   // do not use getoptionalnullcontext here since we do not want the user to change the stream
170*0e6b6b59SJacob Faibussowitsch   // type
171030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx, 1);
172030f984aSJacob Faibussowitsch   PetscValidStreamType(type, 2);
173*0e6b6b59SJacob Faibussowitsch   // only need to do complex swapping if the object has already been setup
174030f984aSJacob Faibussowitsch   if (dctx->setup && (dctx->streamType != type)) {
175030f984aSJacob Faibussowitsch     dctx->setup = PETSC_FALSE;
176*0e6b6b59SJacob Faibussowitsch     PetscCall(PetscLogEventBegin(DCONTEXT_ChangeStream, dctx, 0, 0, 0));
177*0e6b6b59SJacob Faibussowitsch     PetscUseTypeMethod(dctx, changestreamtype, type);
178*0e6b6b59SJacob Faibussowitsch     PetscCall(PetscLogEventEnd(DCONTEXT_ChangeStream, dctx, 0, 0, 0));
179030f984aSJacob Faibussowitsch   }
180030f984aSJacob Faibussowitsch   dctx->streamType = type;
181030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
182030f984aSJacob Faibussowitsch }
183030f984aSJacob Faibussowitsch 
184030f984aSJacob Faibussowitsch /*@C
185*0e6b6b59SJacob Faibussowitsch   PetscDeviceContextGetStreamType - Get the implementation type of the underlying stream for a
186*0e6b6b59SJacob Faibussowitsch   `PetscDeviceContext`
187030f984aSJacob Faibussowitsch 
188*0e6b6b59SJacob Faibussowitsch   Not Collective
189030f984aSJacob Faibussowitsch 
19001d2d390SJose E. Roman   Input Parameter:
191811af0c4SBarry Smith . dctx - The `PetscDeviceContext`
192030f984aSJacob Faibussowitsch 
193030f984aSJacob Faibussowitsch   Output Parameter:
194811af0c4SBarry Smith . type - The `PetscStreamType`
195030f984aSJacob Faibussowitsch 
196*0e6b6b59SJacob Faibussowitsch   Notes:
197*0e6b6b59SJacob Faibussowitsch   See `PetscStreamType` in `include/petscdevicetypes.h` for more information on the available
198*0e6b6b59SJacob Faibussowitsch   types and their interactions
199030f984aSJacob Faibussowitsch 
200*0e6b6b59SJacob Faibussowitsch   Level: beginner
201030f984aSJacob Faibussowitsch 
202*0e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextSetStreamType()`, `PetscDeviceContextCreate()`,
203*0e6b6b59SJacob Faibussowitsch `PetscDeviceContextSetFromOptions()`
204030f984aSJacob Faibussowitsch @*/
2059371c9d4SSatish Balay PetscErrorCode PetscDeviceContextGetStreamType(PetscDeviceContext dctx, PetscStreamType *type) {
206030f984aSJacob Faibussowitsch   PetscFunctionBegin;
207*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
208030f984aSJacob Faibussowitsch   PetscValidIntPointer(type, 2);
209030f984aSJacob Faibussowitsch   *type = dctx->streamType;
210030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
211030f984aSJacob Faibussowitsch }
212030f984aSJacob Faibussowitsch 
213*0e6b6b59SJacob Faibussowitsch /*
214*0e6b6b59SJacob Faibussowitsch   Actual function to set the device.
215030f984aSJacob Faibussowitsch 
216*0e6b6b59SJacob Faibussowitsch   1. Repeatedly destroying and recreating internal data structures (like streams and events)
217*0e6b6b59SJacob Faibussowitsch      for recycled PetscDeviceContexts is not free. If done often, it does add up.
218*0e6b6b59SJacob Faibussowitsch   2. The vast majority of PetscDeviceContexts are created by PETSc either as children or
219*0e6b6b59SJacob Faibussowitsch      default contexts. The default contexts *never* change type, and the chilren are extremely
220*0e6b6b59SJacob Faibussowitsch      unlikely to (chances are if you fork once, you will fork again very soon).
221*0e6b6b59SJacob Faibussowitsch   3. The only time this calculus changes is if the user themselves sets the device type. In
222*0e6b6b59SJacob Faibussowitsch      this case we do not know what the user has changed, so must always wipe the slate clean.
223*0e6b6b59SJacob Faibussowitsch 
224*0e6b6b59SJacob Faibussowitsch   Thus we need to keep track whether the user explicitly sets the device contexts device.
225*0e6b6b59SJacob Faibussowitsch */
226*0e6b6b59SJacob Faibussowitsch static PetscErrorCode PetscDeviceContextSetDevice_Private(PetscDeviceContext dctx, PetscDevice device, PetscBool user_set) {
227*0e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
228*0e6b6b59SJacob Faibussowitsch   // do not use getoptionalnullcontext here since we do not want the user to change its device
229*0e6b6b59SJacob Faibussowitsch   PetscValidDeviceContext(dctx, 1);
230*0e6b6b59SJacob Faibussowitsch   PetscValidDevice(device, 2);
231*0e6b6b59SJacob Faibussowitsch   if (dctx->device && (dctx->device->id == device->id)) PetscFunctionReturn(0);
232*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DCONTEXT_SetDevice, dctx, 0, 0, 0));
233*0e6b6b59SJacob Faibussowitsch   if (const auto destroy = dctx->ops->destroy) PetscCall((*destroy)(dctx));
234*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceDestroy(&dctx->device));
235*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscMemzero(dctx->ops, sizeof(*dctx->ops)));
236*0e6b6b59SJacob Faibussowitsch   PetscCall((*device->ops->createcontext)(dctx));
237*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DCONTEXT_SetDevice, dctx, 0, 0, 0));
238*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceReference_Internal(device));
239*0e6b6b59SJacob Faibussowitsch   dctx->device        = device;
240*0e6b6b59SJacob Faibussowitsch   dctx->setup         = PETSC_FALSE;
241*0e6b6b59SJacob Faibussowitsch   dctx->usersetdevice = user_set;
242*0e6b6b59SJacob Faibussowitsch   PetscFunctionReturn(0);
243*0e6b6b59SJacob Faibussowitsch }
244*0e6b6b59SJacob Faibussowitsch 
245*0e6b6b59SJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetDefaultDeviceForType_Internal(PetscDeviceContext dctx, PetscDeviceType type) {
246*0e6b6b59SJacob Faibussowitsch   PetscDevice device;
247*0e6b6b59SJacob Faibussowitsch 
248*0e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
249*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceGetDefaultForType_Internal(type, &device));
250*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextSetDevice_Private(dctx, device, PETSC_FALSE));
251*0e6b6b59SJacob Faibussowitsch   PetscFunctionReturn(0);
252*0e6b6b59SJacob Faibussowitsch }
253*0e6b6b59SJacob Faibussowitsch 
254*0e6b6b59SJacob Faibussowitsch /*@C
255*0e6b6b59SJacob Faibussowitsch   PetscDeviceContextSetDevice - Set the underlying `PetscDevice` for a `PetscDeviceContext`
256*0e6b6b59SJacob Faibussowitsch 
257*0e6b6b59SJacob Faibussowitsch   Not Collective
258030f984aSJacob Faibussowitsch 
25901d2d390SJose E. Roman   Input Parameters:
260811af0c4SBarry Smith + dctx   - The `PetscDeviceContext`
261811af0c4SBarry Smith - device - The `PetscDevice`
262030f984aSJacob Faibussowitsch 
263030f984aSJacob Faibussowitsch   Notes:
264*0e6b6b59SJacob Faibussowitsch   This routine is effectively `PetscDeviceContext`'s "set-type" (so every `PetscDeviceContext` must
265*0e6b6b59SJacob Faibussowitsch   also have an attached `PetscDevice`). Unlike the usual set-type semantics, it is not stricly
266*0e6b6b59SJacob Faibussowitsch   necessary to set a contexts device to enable usage, any created `PetscDeviceContext`s will
267*0e6b6b59SJacob Faibussowitsch   always come equipped with the "default" device.
268030f984aSJacob Faibussowitsch 
269*0e6b6b59SJacob Faibussowitsch   This routine is a no-op if `device` is already attached to `dctx`.
270a4af0ceeSJacob Faibussowitsch 
271*0e6b6b59SJacob Faibussowitsch   This routine may (but is very unlikely to) initialize the backend device and may incur
272*0e6b6b59SJacob Faibussowitsch   synchronization.
2735181c4f9SJacob Faibussowitsch 
274030f984aSJacob Faibussowitsch   Level: intermediate
275030f984aSJacob Faibussowitsch 
276*0e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceCreate()`, `PetscDeviceConfigure()`, `PetscDeviceContextGetDevice()`,
277*0e6b6b59SJacob Faibussowitsch `PetscDeviceContextGetDeviceType()`
278030f984aSJacob Faibussowitsch @*/
2799371c9d4SSatish Balay PetscErrorCode PetscDeviceContextSetDevice(PetscDeviceContext dctx, PetscDevice device) {
280030f984aSJacob Faibussowitsch   PetscFunctionBegin;
281*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextSetDevice_Private(dctx, device, PETSC_TRUE));
282030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
283030f984aSJacob Faibussowitsch }
284030f984aSJacob Faibussowitsch 
285030f984aSJacob Faibussowitsch /*@C
286811af0c4SBarry Smith   PetscDeviceContextGetDevice - Get the underlying `PetscDevice` for a `PetscDeviceContext`
287030f984aSJacob Faibussowitsch 
288*0e6b6b59SJacob Faibussowitsch   Not Collective
289030f984aSJacob Faibussowitsch 
290030f984aSJacob Faibussowitsch   Input Parameter:
291811af0c4SBarry Smith . dctx - the `PetscDeviceContext`
292030f984aSJacob Faibussowitsch 
293030f984aSJacob Faibussowitsch   Output Parameter:
294811af0c4SBarry Smith . device - The `PetscDevice`
295030f984aSJacob Faibussowitsch 
296*0e6b6b59SJacob Faibussowitsch   Notes:
297811af0c4SBarry Smith   This is a borrowed reference, the user should not destroy `device`.
298030f984aSJacob Faibussowitsch 
299a375dbeeSPatrick Sanan   Level: intermediate
300a375dbeeSPatrick Sanan 
301*0e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextSetDevice()`, `PetscDevice`, `PetscDeviceContextGetDeviceType()`
302030f984aSJacob Faibussowitsch @*/
3039371c9d4SSatish Balay PetscErrorCode PetscDeviceContextGetDevice(PetscDeviceContext dctx, PetscDevice *device) {
304030f984aSJacob Faibussowitsch   PetscFunctionBegin;
305*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
306030f984aSJacob Faibussowitsch   PetscValidPointer(device, 2);
307*0e6b6b59SJacob Faibussowitsch   PetscAssert(dctx->device, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "PetscDeviceContext %" PetscInt64_FMT " has no attached PetscDevice to get", PetscObjectCast(dctx)->id);
308030f984aSJacob Faibussowitsch   *device = dctx->device;
309030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
310030f984aSJacob Faibussowitsch }
311030f984aSJacob Faibussowitsch 
312030f984aSJacob Faibussowitsch /*@C
313*0e6b6b59SJacob Faibussowitsch   PetscDeviceContextGetDeviceType - Get the `PetscDeviceType` for a `PetscDeviceContext`
314*0e6b6b59SJacob Faibussowitsch 
315*0e6b6b59SJacob Faibussowitsch   Not Collective
316*0e6b6b59SJacob Faibussowitsch 
317*0e6b6b59SJacob Faibussowitsch   Input Parameter:
318*0e6b6b59SJacob Faibussowitsch . dctx - The `PetscDeviceContext`
319*0e6b6b59SJacob Faibussowitsch 
320*0e6b6b59SJacob Faibussowitsch   Output Parameter:
321*0e6b6b59SJacob Faibussowitsch . type - The `PetscDeviceType`
322*0e6b6b59SJacob Faibussowitsch 
323*0e6b6b59SJacob Faibussowitsch   Notes:
324*0e6b6b59SJacob Faibussowitsch   This routine is a convenience shorthand for `PetscDeviceContextGetDevice()` ->
325*0e6b6b59SJacob Faibussowitsch   `PetscDeviceGetType()`.
326*0e6b6b59SJacob Faibussowitsch 
327*0e6b6b59SJacob Faibussowitsch   Level: beginner
328*0e6b6b59SJacob Faibussowitsch 
329*0e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceType`, `PetscDeviceContextGetDevice()`, `PetscDeviceGetType()`, `PetscDevice`
330*0e6b6b59SJacob Faibussowitsch @*/
331*0e6b6b59SJacob Faibussowitsch PetscErrorCode PetscDeviceContextGetDeviceType(PetscDeviceContext dctx, PetscDeviceType *type) {
332*0e6b6b59SJacob Faibussowitsch   PetscDevice device = nullptr;
333*0e6b6b59SJacob Faibussowitsch 
334*0e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
335*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
336*0e6b6b59SJacob Faibussowitsch   PetscValidPointer(type, 2);
337*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetDevice(dctx, &device));
338*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceGetType(device, type));
339*0e6b6b59SJacob Faibussowitsch   PetscFunctionReturn(0);
340*0e6b6b59SJacob Faibussowitsch }
341*0e6b6b59SJacob Faibussowitsch 
342*0e6b6b59SJacob Faibussowitsch /*@C
343811af0c4SBarry Smith   PetscDeviceContextSetUp - Prepares a `PetscDeviceContext` for use
344030f984aSJacob Faibussowitsch 
345*0e6b6b59SJacob Faibussowitsch   Not Collective
346030f984aSJacob Faibussowitsch 
34701d2d390SJose E. Roman   Input Parameter:
348811af0c4SBarry Smith . dctx - The `PetscDeviceContext`
349030f984aSJacob Faibussowitsch 
350*0e6b6b59SJacob Faibussowitsch   Developer Notes:
351*0e6b6b59SJacob Faibussowitsch   This routine is usually the stage where a `PetscDeviceContext` acquires device-side data
352*0e6b6b59SJacob Faibussowitsch   structures such as streams, events, and (possibly) handles.
353030f984aSJacob Faibussowitsch 
354030f984aSJacob Faibussowitsch   Level: beginner
355030f984aSJacob Faibussowitsch 
356*0e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextSetDevice()`,
357*0e6b6b59SJacob Faibussowitsch `PetscDeviceContextDestroy()`, `PetscDeviceContextSetFromOptions()`
358030f984aSJacob Faibussowitsch @*/
3599371c9d4SSatish Balay PetscErrorCode PetscDeviceContextSetUp(PetscDeviceContext dctx) {
360030f984aSJacob Faibussowitsch   PetscFunctionBegin;
361*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
362030f984aSJacob Faibussowitsch   if (dctx->setup) PetscFunctionReturn(0);
363*0e6b6b59SJacob Faibussowitsch   if (!dctx->device) {
364*0e6b6b59SJacob Faibussowitsch     const auto default_dtype = PETSC_DEVICE_DEFAULT();
365*0e6b6b59SJacob Faibussowitsch 
366*0e6b6b59SJacob 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]));
367*0e6b6b59SJacob Faibussowitsch     PetscCall(PetscDeviceContextSetDefaultDeviceForType_Internal(dctx, default_dtype));
368*0e6b6b59SJacob Faibussowitsch   }
369*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DCONTEXT_SetUp, dctx, 0, 0, 0));
370dbbe0bcdSBarry Smith   PetscUseTypeMethod(dctx, setup);
371*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DCONTEXT_SetUp, dctx, 0, 0, 0));
372030f984aSJacob Faibussowitsch   dctx->setup = PETSC_TRUE;
373030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
374030f984aSJacob Faibussowitsch }
375030f984aSJacob Faibussowitsch 
376*0e6b6b59SJacob Faibussowitsch static PetscErrorCode PetscDeviceContextDuplicate_Private(PetscDeviceContext dctx, PetscStreamType stype, PetscDeviceContext *dctxdup) {
377*0e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
378*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DCONTEXT_Duplicate, dctx, 0, 0, 0));
379*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextCreate(dctxdup));
380*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextSetStreamType(*dctxdup, stype));
381*0e6b6b59SJacob Faibussowitsch   if (const auto device = dctx->device) PetscCall(PetscDeviceContextSetDevice_Private(*dctxdup, device, dctx->usersetdevice));
382*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextSetUp(*dctxdup));
383*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DCONTEXT_Duplicate, dctx, 0, 0, 0));
384*0e6b6b59SJacob Faibussowitsch   PetscFunctionReturn(0);
385*0e6b6b59SJacob Faibussowitsch }
386*0e6b6b59SJacob Faibussowitsch 
387030f984aSJacob Faibussowitsch /*@C
388811af0c4SBarry Smith   PetscDeviceContextDuplicate - Duplicates a `PetscDeviceContext` object
389030f984aSJacob Faibussowitsch 
390*0e6b6b59SJacob Faibussowitsch   Not Collective
391030f984aSJacob Faibussowitsch 
392030f984aSJacob Faibussowitsch   Input Parameter:
393811af0c4SBarry Smith . dctx - The `PetscDeviceContext` to duplicate
394030f984aSJacob Faibussowitsch 
3956aad120cSJose E. Roman   Output Parameter:
396811af0c4SBarry Smith . dctxdup - The duplicated `PetscDeviceContext`
397030f984aSJacob Faibussowitsch 
398*0e6b6b59SJacob Faibussowitsch   Notes:
399*0e6b6b59SJacob Faibussowitsch   This is a shorthand method for creating a `PetscDeviceContext` with the exact same settings as
400*0e6b6b59SJacob Faibussowitsch   another. Note however that `dctxdup` does not share any of the underlying data with `dctx`,
401*0e6b6b59SJacob Faibussowitsch   (including its current stream-state) they are completely separate objects.
402*0e6b6b59SJacob Faibussowitsch 
403*0e6b6b59SJacob Faibussowitsch   There is no implied ordering between `dctx` or `dctxdup`.
404*0e6b6b59SJacob Faibussowitsch 
405*0e6b6b59SJacob Faibussowitsch   DAG representation:
406*0e6b6b59SJacob Faibussowitsch .vb
407*0e6b6b59SJacob Faibussowitsch   time ->
408*0e6b6b59SJacob Faibussowitsch 
409*0e6b6b59SJacob Faibussowitsch   -> dctx - |= CALL =| - dctx ---->
410*0e6b6b59SJacob Faibussowitsch                        - dctxdup ->
411*0e6b6b59SJacob Faibussowitsch .ve
412030f984aSJacob Faibussowitsch 
413030f984aSJacob Faibussowitsch   Level: beginner
414030f984aSJacob Faibussowitsch 
415*0e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextSetDevice()`,
416*0e6b6b59SJacob Faibussowitsch `PetscDeviceContextSetStreamType()`
417030f984aSJacob Faibussowitsch @*/
4189371c9d4SSatish Balay PetscErrorCode PetscDeviceContextDuplicate(PetscDeviceContext dctx, PetscDeviceContext *dctxdup) {
419*0e6b6b59SJacob Faibussowitsch   auto stype = PETSC_STREAM_DEFAULT_BLOCKING;
420030f984aSJacob Faibussowitsch 
421030f984aSJacob Faibussowitsch   PetscFunctionBegin;
422*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
423030f984aSJacob Faibussowitsch   PetscValidPointer(dctxdup, 2);
424*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetStreamType(dctx, &stype));
425*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextDuplicate_Private(dctx, stype, dctxdup));
426030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
427030f984aSJacob Faibussowitsch }
428030f984aSJacob Faibussowitsch 
429030f984aSJacob Faibussowitsch /*@C
430811af0c4SBarry Smith   PetscDeviceContextQueryIdle - Returns whether or not a `PetscDeviceContext` is idle
431030f984aSJacob Faibussowitsch 
432*0e6b6b59SJacob Faibussowitsch   Not Collective
433030f984aSJacob Faibussowitsch 
434030f984aSJacob Faibussowitsch   Input Parameter:
435*0e6b6b59SJacob Faibussowitsch . dctx - The `PetscDeviceContext`
436030f984aSJacob Faibussowitsch 
437030f984aSJacob Faibussowitsch   Output Parameter:
438*0e6b6b59SJacob Faibussowitsch . idle - `PETSC_TRUE` if `dctx` has NO work, `PETSC_FALSE` if it has work
439030f984aSJacob Faibussowitsch 
440811af0c4SBarry Smith   Note:
441ef657721SJacob Faibussowitsch   This routine only refers a singular context and does NOT take any of its children into
442*0e6b6b59SJacob Faibussowitsch   account. That is, if `dctx` is idle but has dependents who do have work this routine still
443811af0c4SBarry Smith   returns `PETSC_TRUE`.
444030f984aSJacob Faibussowitsch 
445030f984aSJacob Faibussowitsch   Level: intermediate
446030f984aSJacob Faibussowitsch 
447db781477SPatrick Sanan .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextWaitForContext()`, `PetscDeviceContextFork()`
448030f984aSJacob Faibussowitsch @*/
4499371c9d4SSatish Balay PetscErrorCode PetscDeviceContextQueryIdle(PetscDeviceContext dctx, PetscBool *idle) {
450030f984aSJacob Faibussowitsch   PetscFunctionBegin;
451*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
452030f984aSJacob Faibussowitsch   PetscValidBoolPointer(idle, 2);
453*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DCONTEXT_QueryIdle, dctx, 0, 0, 0));
454dbbe0bcdSBarry Smith   PetscUseTypeMethod(dctx, query, idle);
455*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DCONTEXT_QueryIdle, dctx, 0, 0, 0));
456*0e6b6b59SJacob 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"));
457030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
458030f984aSJacob Faibussowitsch }
459030f984aSJacob Faibussowitsch 
460030f984aSJacob Faibussowitsch /*@C
461030f984aSJacob Faibussowitsch   PetscDeviceContextWaitForContext - Make one context wait for another context to finish
462030f984aSJacob Faibussowitsch 
463*0e6b6b59SJacob Faibussowitsch   Not Collective
464030f984aSJacob Faibussowitsch 
465030f984aSJacob Faibussowitsch   Input Parameters:
466811af0c4SBarry Smith + dctxa - The `PetscDeviceContext` object that is waiting
467811af0c4SBarry Smith - dctxb - The `PetscDeviceContext` object that is being waited on
468030f984aSJacob Faibussowitsch 
469030f984aSJacob Faibussowitsch   Notes:
470*0e6b6b59SJacob Faibussowitsch   Serializes two `PetscDeviceContext`s. Serialization is performed asynchronously; the host
471*0e6b6b59SJacob Faibussowitsch   does not wait for the serialization to actually occur.
472811af0c4SBarry Smith 
473*0e6b6b59SJacob Faibussowitsch   This routine uses only the state of `dctxb` at the moment this routine was called, so any
474*0e6b6b59SJacob Faibussowitsch   future work queued will not affect `dctxa`. It is safe to pass the same context to both
475*0e6b6b59SJacob Faibussowitsch   arguments (in which case this routine does nothing).
476*0e6b6b59SJacob Faibussowitsch 
477*0e6b6b59SJacob Faibussowitsch   DAG representation:
478*0e6b6b59SJacob Faibussowitsch .vb
479*0e6b6b59SJacob Faibussowitsch   time ->
480*0e6b6b59SJacob Faibussowitsch 
481*0e6b6b59SJacob Faibussowitsch   -> dctxa ---/- |= CALL =| - dctxa ->
482*0e6b6b59SJacob Faibussowitsch              /
483*0e6b6b59SJacob Faibussowitsch   -> dctxb -/------------------------>
484*0e6b6b59SJacob Faibussowitsch .ve
485030f984aSJacob Faibussowitsch 
486030f984aSJacob Faibussowitsch   Level: beginner
487030f984aSJacob Faibussowitsch 
488*0e6b6b59SJacob Faibussowitsch .N ASYNC_API
489*0e6b6b59SJacob Faibussowitsch 
490db781477SPatrick Sanan .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextQueryIdle()`, `PetscDeviceContextJoin()`
491030f984aSJacob Faibussowitsch @*/
4929371c9d4SSatish Balay PetscErrorCode PetscDeviceContextWaitForContext(PetscDeviceContext dctxa, PetscDeviceContext dctxb) {
493*0e6b6b59SJacob Faibussowitsch   PetscObject aobj;
494*0e6b6b59SJacob Faibussowitsch 
495030f984aSJacob Faibussowitsch   PetscFunctionBegin;
496*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctxa));
497*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctxb));
498030f984aSJacob Faibussowitsch   PetscCheckCompatibleDeviceContexts(dctxa, 1, dctxb, 2);
499030f984aSJacob Faibussowitsch   if (dctxa == dctxb) PetscFunctionReturn(0);
500*0e6b6b59SJacob Faibussowitsch   aobj = PetscObjectCast(dctxa);
501*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DCONTEXT_WaitForCtx, dctxa, dctxb, 0, 0));
502dbbe0bcdSBarry Smith   PetscUseTypeMethod(dctxa, waitforcontext, dctxb);
503*0e6b6b59SJacob Faibussowitsch   PetscCallCXX(CxxDataCast(dctxa)->upstream[dctxb] = CxxData::parent_type(dctxb));
504*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DCONTEXT_WaitForCtx, dctxa, dctxb, 0, 0));
505*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscInfo(dctxa, "dctx %" PetscInt64_FMT " waiting on dctx %" PetscInt64_FMT "\n", aobj->id, PetscObjectCast(dctxb)->id));
506*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease(aobj));
507030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
508030f984aSJacob Faibussowitsch }
509030f984aSJacob Faibussowitsch 
510*0e6b6b59SJacob Faibussowitsch /*@C
511*0e6b6b59SJacob Faibussowitsch   PetscDeviceContextForkWithStreamType - Create a set of dependent child contexts from a parent
512*0e6b6b59SJacob Faibussowitsch   context with a prescribed `PetscStreamType`
513*0e6b6b59SJacob Faibussowitsch 
514*0e6b6b59SJacob Faibussowitsch   Not Collective, Asynchronous
515*0e6b6b59SJacob Faibussowitsch 
516*0e6b6b59SJacob Faibussowitsch   Input Parameters:
517*0e6b6b59SJacob Faibussowitsch + dctx  - The parent `PetscDeviceContext`
518*0e6b6b59SJacob Faibussowitsch . stype - The prescribed `PetscStreamType`
519*0e6b6b59SJacob Faibussowitsch - n     - The number of children to create
520*0e6b6b59SJacob Faibussowitsch 
521*0e6b6b59SJacob Faibussowitsch   Output Parameter:
522*0e6b6b59SJacob Faibussowitsch . dsub - The created child context(s)
523*0e6b6b59SJacob Faibussowitsch 
524*0e6b6b59SJacob Faibussowitsch   Notes:
525*0e6b6b59SJacob Faibussowitsch   This routine creates `n` edges of a DAG from a source node which are causally dependent on the
526*0e6b6b59SJacob Faibussowitsch   source node. This causal dependency is established as-if by calling
527*0e6b6b59SJacob Faibussowitsch   `PetscDeviceContextWaitForContext()` on every child.
528*0e6b6b59SJacob Faibussowitsch 
529*0e6b6b59SJacob Faibussowitsch   `dsub` is allocated by this routine and has its lifetime bounded by `dctx`. That is, `dctx`
530*0e6b6b59SJacob Faibussowitsch   expects to free `dsub` (via `PetscDeviceContextJoin()`) before it itself is destroyed.
531*0e6b6b59SJacob Faibussowitsch 
532*0e6b6b59SJacob Faibussowitsch   This routine only accounts for work queued on `dctx` up until calling this routine, any
533*0e6b6b59SJacob Faibussowitsch   subsequent work enqueued on `dctx` has no effect on `dsub`.
534*0e6b6b59SJacob Faibussowitsch 
535*0e6b6b59SJacob Faibussowitsch   The `PetscStreamType` of `dctx` does not have to equal `stype`. In fact, it is often the case
536*0e6b6b59SJacob Faibussowitsch   that they are different. This is useful in cases where a routine can locally exploit stream
537*0e6b6b59SJacob Faibussowitsch   parallelism without needing to worry about what stream type the incoming `PetscDeviceContext`
538*0e6b6b59SJacob Faibussowitsch   carries.
539*0e6b6b59SJacob Faibussowitsch 
540*0e6b6b59SJacob Faibussowitsch   DAG representation:
541*0e6b6b59SJacob Faibussowitsch .vb
542*0e6b6b59SJacob Faibussowitsch   time ->
543*0e6b6b59SJacob Faibussowitsch 
544*0e6b6b59SJacob Faibussowitsch   -> dctx - |= CALL =| -\----> dctx ------>
545*0e6b6b59SJacob Faibussowitsch                          \---> dsub[0] --->
546*0e6b6b59SJacob Faibussowitsch                           \--> ... ------->
547*0e6b6b59SJacob Faibussowitsch                            \-> dsub[n-1] ->
548*0e6b6b59SJacob Faibussowitsch .ve
549*0e6b6b59SJacob Faibussowitsch 
550*0e6b6b59SJacob Faibussowitsch   Level: intermediate
551*0e6b6b59SJacob Faibussowitsch 
552*0e6b6b59SJacob Faibussowitsch .N ASYNC_API
553*0e6b6b59SJacob Faibussowitsch 
554*0e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextJoin()`, `PetscDeviceContextSynchronize()`,
555*0e6b6b59SJacob Faibussowitsch `PetscDeviceContextQueryIdle()`, `PetscDeviceContextWaitForContext()`
556*0e6b6b59SJacob Faibussowitsch @*/
557*0e6b6b59SJacob Faibussowitsch PetscErrorCode PetscDeviceContextForkWithStreamType(PetscDeviceContext dctx, PetscStreamType stype, PetscInt n, PetscDeviceContext **dsub) {
558*0e6b6b59SJacob Faibussowitsch   // debugging only
559*0e6b6b59SJacob Faibussowitsch   std::string idList;
560*0e6b6b59SJacob Faibussowitsch   auto        ninput = n;
561*0e6b6b59SJacob Faibussowitsch 
562*0e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
563*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
564*0e6b6b59SJacob Faibussowitsch   PetscAssert(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of contexts requested %" PetscInt_FMT " < 0", n);
565*0e6b6b59SJacob Faibussowitsch   PetscValidPointer(dsub, 4);
566*0e6b6b59SJacob Faibussowitsch   *dsub = nullptr;
567*0e6b6b59SJacob Faibussowitsch   /* reserve 4 chars per id, 2 for number and 2 for ', ' separator */
568*0e6b6b59SJacob Faibussowitsch   if (PetscDefined(USE_DEBUG_AND_INFO)) PetscCallCXX(idList.reserve(4 * n));
569*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DCONTEXT_Fork, dctx, 0, 0, 0));
570*0e6b6b59SJacob Faibussowitsch   /* update child totals */
571*0e6b6b59SJacob Faibussowitsch   dctx->numChildren += n;
572*0e6b6b59SJacob Faibussowitsch   /* now to find out if we have room */
573*0e6b6b59SJacob Faibussowitsch   if (dctx->numChildren > dctx->maxNumChildren) {
574*0e6b6b59SJacob Faibussowitsch     const auto numChildren    = dctx->numChildren;
575*0e6b6b59SJacob Faibussowitsch     auto      &maxNumChildren = dctx->maxNumChildren;
576*0e6b6b59SJacob Faibussowitsch     auto       numAllocated   = numChildren;
577*0e6b6b59SJacob Faibussowitsch 
578*0e6b6b59SJacob Faibussowitsch     /* no room, either from having too many kids or not having any */
579*0e6b6b59SJacob Faibussowitsch     if (auto &childIDs = dctx->childIDs) {
580*0e6b6b59SJacob Faibussowitsch       // the difference is backwards because we have not updated maxNumChildren yet
581*0e6b6b59SJacob Faibussowitsch       numAllocated -= maxNumChildren;
582*0e6b6b59SJacob Faibussowitsch       /* have existing children, must reallocate them */
583*0e6b6b59SJacob Faibussowitsch       PetscCall(PetscRealloc(numChildren * sizeof(*childIDs), &childIDs));
584*0e6b6b59SJacob Faibussowitsch       /* clear the extra memory since realloc doesn't do it for us */
585*0e6b6b59SJacob Faibussowitsch       PetscCall(PetscArrayzero(std::next(childIDs, maxNumChildren), numAllocated));
586*0e6b6b59SJacob Faibussowitsch     } else {
587*0e6b6b59SJacob Faibussowitsch       /* have no children */
588*0e6b6b59SJacob Faibussowitsch       PetscCall(PetscCalloc1(numChildren, &childIDs));
589*0e6b6b59SJacob Faibussowitsch     }
590*0e6b6b59SJacob Faibussowitsch     /* update total number of children */
591*0e6b6b59SJacob Faibussowitsch     maxNumChildren = numChildren;
592*0e6b6b59SJacob Faibussowitsch     PetscCall(PetscLogObjectMemory(PetscObjectCast(dctx), numAllocated * sizeof(*(dctx->childIDs))));
593*0e6b6b59SJacob Faibussowitsch   }
594*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscMalloc1(n, dsub));
595*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscLogObjectMemory(PetscObjectCast(dctx), n * sizeof(*dsub)));
596*0e6b6b59SJacob Faibussowitsch   for (PetscInt i = 0; ninput && (i < dctx->numChildren); ++i) {
597*0e6b6b59SJacob Faibussowitsch     auto &childID = dctx->childIDs[i];
598*0e6b6b59SJacob Faibussowitsch     /* empty child slot */
599*0e6b6b59SJacob Faibussowitsch     if (!childID) {
600*0e6b6b59SJacob Faibussowitsch       auto &childctx = (*dsub)[i];
601*0e6b6b59SJacob Faibussowitsch 
602*0e6b6b59SJacob Faibussowitsch       /* create the child context in the image of its parent */
603*0e6b6b59SJacob Faibussowitsch       PetscCall(PetscDeviceContextDuplicate_Private(dctx, stype, &childctx));
604*0e6b6b59SJacob Faibussowitsch       PetscCall(PetscDeviceContextWaitForContext(childctx, dctx));
605*0e6b6b59SJacob Faibussowitsch       /* register the child with its parent */
606*0e6b6b59SJacob Faibussowitsch       PetscCall(PetscObjectGetId(PetscObjectCast(childctx), &childID));
607*0e6b6b59SJacob Faibussowitsch       if (PetscDefined(USE_DEBUG_AND_INFO)) {
608*0e6b6b59SJacob Faibussowitsch         PetscCallCXX(idList += std::to_string(childID));
609*0e6b6b59SJacob Faibussowitsch         if (ninput != 1) PetscCallCXX(idList += ", ");
610*0e6b6b59SJacob Faibussowitsch       }
611*0e6b6b59SJacob Faibussowitsch       --ninput;
612*0e6b6b59SJacob Faibussowitsch     }
613*0e6b6b59SJacob Faibussowitsch   }
614*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DCONTEXT_Fork, dctx, 0, 0, 0));
615*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscDebugInfo(dctx, "Forked %" PetscInt_FMT " children from parent %" PetscInt64_FMT " with IDs: %s\n", n, PetscObjectCast(dctx)->id, idList.c_str()));
616*0e6b6b59SJacob Faibussowitsch   PetscFunctionReturn(0);
617*0e6b6b59SJacob Faibussowitsch }
618*0e6b6b59SJacob Faibussowitsch 
619030f984aSJacob Faibussowitsch /*@C
620030f984aSJacob Faibussowitsch   PetscDeviceContextFork - Create a set of dependent child contexts from a parent context
621030f984aSJacob Faibussowitsch 
622030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
623030f984aSJacob Faibussowitsch 
624030f984aSJacob Faibussowitsch   Input Parameters:
625811af0c4SBarry Smith + dctx - The parent `PetscDeviceContext`
626030f984aSJacob Faibussowitsch - n    - The number of children to create
627030f984aSJacob Faibussowitsch 
628030f984aSJacob Faibussowitsch   Output Parameter:
629030f984aSJacob Faibussowitsch . dsub - The created child context(s)
630030f984aSJacob Faibussowitsch 
631030f984aSJacob Faibussowitsch   Notes:
632*0e6b6b59SJacob Faibussowitsch   Behaves identically to `PetscDeviceContextForkWithStreamType()` except that the prescribed
633*0e6b6b59SJacob Faibussowitsch   `PetscStreamType` is taken from `dctx`. In effect this routine is shorthand for\:
634030f984aSJacob Faibussowitsch 
635030f984aSJacob Faibussowitsch .vb
636*0e6b6b59SJacob Faibussowitsch   PetscStreamType stype;
637030f984aSJacob Faibussowitsch 
638*0e6b6b59SJacob Faibussowitsch   PetscDeviceContextGetStreamType(dctx, &stype);
639*0e6b6b59SJacob Faibussowitsch   PetscDeviceContextForkWithStreamType(dctx, stype, ...);
640030f984aSJacob Faibussowitsch .ve
641030f984aSJacob Faibussowitsch 
642*0e6b6b59SJacob Faibussowitsch   Level: beginner
643030f984aSJacob Faibussowitsch 
644*0e6b6b59SJacob Faibussowitsch .N ASYNC_API
645*0e6b6b59SJacob Faibussowitsch 
646*0e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextForkWithStreamType()`, `PetscDeviceContextJoin()`,
647*0e6b6b59SJacob Faibussowitsch `PetscDeviceContextSynchronize()`, `PetscDeviceContextQueryIdle()`
648030f984aSJacob Faibussowitsch @*/
6499371c9d4SSatish Balay PetscErrorCode PetscDeviceContextFork(PetscDeviceContext dctx, PetscInt n, PetscDeviceContext **dsub) {
650*0e6b6b59SJacob Faibussowitsch   auto stype = PETSC_STREAM_DEFAULT_BLOCKING;
651030f984aSJacob Faibussowitsch 
652030f984aSJacob Faibussowitsch   PetscFunctionBegin;
653*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
654*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetStreamType(dctx, &stype));
655*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextForkWithStreamType(dctx, stype, n, dsub));
656030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
657030f984aSJacob Faibussowitsch }
658030f984aSJacob Faibussowitsch 
659030f984aSJacob Faibussowitsch /*@C
6605181c4f9SJacob Faibussowitsch   PetscDeviceContextJoin - Converge a set of child contexts
661030f984aSJacob Faibussowitsch 
662030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
663030f984aSJacob Faibussowitsch 
664030f984aSJacob Faibussowitsch   Input Parameters:
665811af0c4SBarry Smith + dctx         - A `PetscDeviceContext` to converge on
666030f984aSJacob Faibussowitsch . n            - The number of sub contexts to converge
667030f984aSJacob Faibussowitsch . joinMode     - The type of join to perform
668030f984aSJacob Faibussowitsch - dsub         - The sub contexts to converge
669030f984aSJacob Faibussowitsch 
670030f984aSJacob Faibussowitsch   Notes:
671*0e6b6b59SJacob Faibussowitsch   If `PetscDeviceContextFork()` creates `n` edges from a source node which all depend on the source
672*0e6b6b59SJacob Faibussowitsch   node, then this routine is the exact mirror. That is, it creates a node (represented in `dctx`)
673*0e6b6b59SJacob Faibussowitsch   which recieves `n` edges (and optionally destroys them) which is dependent on the completion
674*0e6b6b59SJacob Faibussowitsch   of all incoming edges.
675030f984aSJacob Faibussowitsch 
676*0e6b6b59SJacob Faibussowitsch   If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_DESTROY`. All contexts in `dsub` will be
677*0e6b6b59SJacob Faibussowitsch   destroyed by this routine. Thus all sub contexts must have been created with the `dctx`
678*0e6b6b59SJacob Faibussowitsch   passed to this routine.
679030f984aSJacob Faibussowitsch 
680*0e6b6b59SJacob Faibussowitsch   If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_SYNC`. All sub contexts will additionally wait on
681*0e6b6b59SJacob Faibussowitsch   `dctx` after converging. This has the effect of "synchronizing" the outgoing edges. Note the
682*0e6b6b59SJacob Faibussowitsch   sync suffix does NOT refer to the host, i.e. this routine does NOT call
683*0e6b6b59SJacob Faibussowitsch   `PetscDeviceSynchronize()`.
684030f984aSJacob Faibussowitsch 
685*0e6b6b59SJacob Faibussowitsch   If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC`. `dctx` waits for all sub contexts but
686*0e6b6b59SJacob Faibussowitsch   the sub contexts do not wait for one another or `dctx` afterwards.
687030f984aSJacob Faibussowitsch 
688030f984aSJacob Faibussowitsch   DAG representations:
689811af0c4SBarry Smith   If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_DESTROY`
690030f984aSJacob Faibussowitsch .vb
691030f984aSJacob Faibussowitsch   time ->
692030f984aSJacob Faibussowitsch 
693*0e6b6b59SJacob Faibussowitsch   -> dctx ---------/- |= CALL =| - dctx ->
694030f984aSJacob Faibussowitsch   -> dsub[0] -----/
695030f984aSJacob Faibussowitsch   ->  ... -------/
696030f984aSJacob Faibussowitsch   -> dsub[n-1] -/
697030f984aSJacob Faibussowitsch .ve
698811af0c4SBarry Smith   If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_SYNC`
699030f984aSJacob Faibussowitsch .vb
700030f984aSJacob Faibussowitsch   time ->
701030f984aSJacob Faibussowitsch 
702*0e6b6b59SJacob Faibussowitsch   -> dctx ---------/- |= CALL =| -\----> dctx ------>
703030f984aSJacob Faibussowitsch   -> dsub[0] -----/                \---> dsub[0] --->
704030f984aSJacob Faibussowitsch   ->  ... -------/                  \--> ... ------->
705030f984aSJacob Faibussowitsch   -> dsub[n-1] -/                    \-> dsub[n-1] ->
706030f984aSJacob Faibussowitsch .ve
707*0e6b6b59SJacob Faibussowitsch   If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC`
708*0e6b6b59SJacob Faibussowitsch .vb
709*0e6b6b59SJacob Faibussowitsch   time ->
710030f984aSJacob Faibussowitsch 
711*0e6b6b59SJacob Faibussowitsch   -> dctx ----------/- |= CALL =| - dctx ->
712*0e6b6b59SJacob Faibussowitsch   -> dsub[0] ------/----------------------->
713*0e6b6b59SJacob Faibussowitsch   ->  ... --------/------------------------>
714*0e6b6b59SJacob Faibussowitsch   -> dsub[n-1] --/------------------------->
715*0e6b6b59SJacob Faibussowitsch .ve
716030f984aSJacob Faibussowitsch 
717*0e6b6b59SJacob Faibussowitsch   Level: beginner
718*0e6b6b59SJacob Faibussowitsch 
719*0e6b6b59SJacob Faibussowitsch .N ASYNC_API
720*0e6b6b59SJacob Faibussowitsch 
721*0e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextFork()`, `PetscDeviceContextForkWithStreamType()`,
722*0e6b6b59SJacob Faibussowitsch `PetscDeviceContextSynchronize()`, `PetscDeviceContextJoinMode`
723030f984aSJacob Faibussowitsch @*/
7249371c9d4SSatish Balay PetscErrorCode PetscDeviceContextJoin(PetscDeviceContext dctx, PetscInt n, PetscDeviceContextJoinMode joinMode, PetscDeviceContext **dsub) {
725*0e6b6b59SJacob Faibussowitsch   // debugging only
726*0e6b6b59SJacob Faibussowitsch   std::string idList;
727030f984aSJacob Faibussowitsch 
728030f984aSJacob Faibussowitsch   PetscFunctionBegin;
729*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
730030f984aSJacob Faibussowitsch   /* validity of dctx is checked in the wait-for loop */
731030f984aSJacob Faibussowitsch   PetscValidPointer(dsub, 4);
732bf025ffbSJacob Faibussowitsch   PetscAssert(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of contexts merged %" PetscInt_FMT " < 0", n);
733030f984aSJacob Faibussowitsch   /* reserve 4 chars per id, 2 for number and 2 for ', ' separator */
734*0e6b6b59SJacob Faibussowitsch   if (PetscDefined(USE_DEBUG_AND_INFO)) PetscCallCXX(idList.reserve(4 * n));
735030f984aSJacob Faibussowitsch   /* first dctx waits on all the incoming edges */
736*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DCONTEXT_Join, dctx, 0, 0, 0));
737030f984aSJacob Faibussowitsch   for (PetscInt i = 0; i < n; ++i) {
738030f984aSJacob Faibussowitsch     PetscCheckCompatibleDeviceContexts(dctx, 1, (*dsub)[i], 4);
7399566063dSJacob Faibussowitsch     PetscCall(PetscDeviceContextWaitForContext(dctx, (*dsub)[i]));
740*0e6b6b59SJacob Faibussowitsch     if (PetscDefined(USE_DEBUG_AND_INFO)) {
741*0e6b6b59SJacob Faibussowitsch       PetscCallCXX(idList += std::to_string(PetscObjectCast((*dsub)[i])->id));
742*0e6b6b59SJacob Faibussowitsch       if (i + 1 < n) PetscCallCXX(idList += ", ");
743*0e6b6b59SJacob Faibussowitsch     }
744030f984aSJacob Faibussowitsch   }
745030f984aSJacob Faibussowitsch 
746030f984aSJacob Faibussowitsch   /* now we handle the aftermath */
747030f984aSJacob Faibussowitsch   switch (joinMode) {
7489371c9d4SSatish Balay   case PETSC_DEVICE_CONTEXT_JOIN_DESTROY: {
749*0e6b6b59SJacob Faibussowitsch     const auto children = dctx->childIDs;
750*0e6b6b59SJacob Faibussowitsch     const auto maxchild = dctx->maxNumChildren;
751*0e6b6b59SJacob Faibussowitsch     auto      &nchild   = dctx->numChildren;
752030f984aSJacob Faibussowitsch     PetscInt   j        = 0;
753030f984aSJacob Faibussowitsch 
754*0e6b6b59SJacob 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);
755030f984aSJacob Faibussowitsch     /* update child count while it's still fresh in memory */
756*0e6b6b59SJacob Faibussowitsch     nchild -= n;
757*0e6b6b59SJacob Faibussowitsch     for (PetscInt i = 0; i < maxchild; ++i) {
758*0e6b6b59SJacob Faibussowitsch       if (children[i] && (children[i] == PetscObjectCast((*dsub)[j])->id)) {
759030f984aSJacob Faibussowitsch         /* child is one of ours, can destroy it */
7609566063dSJacob Faibussowitsch         PetscCall(PetscDeviceContextDestroy((*dsub) + j));
761030f984aSJacob Faibussowitsch         /* reset the child slot */
762*0e6b6b59SJacob Faibussowitsch         children[i] = 0;
763030f984aSJacob Faibussowitsch         if (++j == n) break;
764030f984aSJacob Faibussowitsch       }
765030f984aSJacob Faibussowitsch     }
766*0e6b6b59SJacob Faibussowitsch     /* gone through the loop but did not find every child */
767*0e6b6b59SJacob 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);
7689566063dSJacob Faibussowitsch     PetscCall(PetscFree(*dsub));
769*0e6b6b59SJacob Faibussowitsch     PetscCall(PetscLogObjectMemory(PetscObjectCast(dctx), -n * sizeof(*dsub)));
7709371c9d4SSatish Balay   } break;
771030f984aSJacob Faibussowitsch   case PETSC_DEVICE_CONTEXT_JOIN_SYNC:
7729566063dSJacob Faibussowitsch     for (PetscInt i = 0; i < n; ++i) PetscCall(PetscDeviceContextWaitForContext((*dsub)[i], dctx));
7739371c9d4SSatish Balay   case PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC: break;
7749371c9d4SSatish Balay   default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown PetscDeviceContextJoinMode given");
775030f984aSJacob Faibussowitsch   }
776*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DCONTEXT_Join, dctx, 0, 0, 0));
777030f984aSJacob Faibussowitsch 
778*0e6b6b59SJacob 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()));
779030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
780030f984aSJacob Faibussowitsch }
781030f984aSJacob Faibussowitsch 
782030f984aSJacob Faibussowitsch /*@C
783*0e6b6b59SJacob Faibussowitsch   PetscDeviceContextSynchronize - Block the host until all work queued on a
784*0e6b6b59SJacob Faibussowitsch   `PetscDeviceContext` has finished
785030f984aSJacob Faibussowitsch 
786*0e6b6b59SJacob Faibussowitsch   Not Collective
787030f984aSJacob Faibussowitsch 
788030f984aSJacob Faibussowitsch   Input Parameters:
789811af0c4SBarry Smith . dctx - The `PetscDeviceContext` to synchronize
790030f984aSJacob Faibussowitsch 
791*0e6b6b59SJacob Faibussowitsch   Notes:
792*0e6b6b59SJacob Faibussowitsch   The host will not return from this routine until `dctx` is idle. Any and all memory
793*0e6b6b59SJacob Faibussowitsch   operations queued on or otherwise associated with (either explicitly or implicitly via
794*0e6b6b59SJacob Faibussowitsch   dependencies) are guaranteed to have finished and be globally visible on return.
795*0e6b6b59SJacob Faibussowitsch 
796*0e6b6b59SJacob Faibussowitsch   In effect, this routine serves as memory and execution barrier.
797*0e6b6b59SJacob Faibussowitsch 
798*0e6b6b59SJacob Faibussowitsch   DAG representation:
799*0e6b6b59SJacob Faibussowitsch .vb
800*0e6b6b59SJacob Faibussowitsch   time ->
801*0e6b6b59SJacob Faibussowitsch 
802*0e6b6b59SJacob Faibussowitsch   -> dctx - |= CALL =| - dctx ->
803*0e6b6b59SJacob Faibussowitsch .ve
804*0e6b6b59SJacob Faibussowitsch 
805030f984aSJacob Faibussowitsch   Level: beginner
806030f984aSJacob Faibussowitsch 
807db781477SPatrick Sanan .seealso: `PetscDeviceContextFork()`, `PetscDeviceContextJoin()`, `PetscDeviceContextQueryIdle()`
808030f984aSJacob Faibussowitsch @*/
8099371c9d4SSatish Balay PetscErrorCode PetscDeviceContextSynchronize(PetscDeviceContext dctx) {
810030f984aSJacob Faibussowitsch   PetscFunctionBegin;
811*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
812*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DCONTEXT_Sync, dctx, 0, 0, 0));
813030f984aSJacob Faibussowitsch   /* if it isn't setup there is nothing to sync on */
814*0e6b6b59SJacob Faibussowitsch   if (dctx->setup) {
815*0e6b6b59SJacob Faibussowitsch     PetscCall((*dctx->ops->synchronize)(dctx));
816*0e6b6b59SJacob Faibussowitsch     PetscCall(PetscDeviceContextSyncClearMap_Internal(dctx));
817*0e6b6b59SJacob Faibussowitsch   }
818*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DCONTEXT_Sync, dctx, 0, 0, 0));
819030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
820030f984aSJacob Faibussowitsch }
821030f984aSJacob Faibussowitsch 
822*0e6b6b59SJacob Faibussowitsch /* every device type has a vector of null PetscDeviceContexts -- one for each device */
823*0e6b6b59SJacob Faibussowitsch static auto nullContexts          = std::array<std::vector<PetscDeviceContext>, PETSC_DEVICE_MAX>{};
824*0e6b6b59SJacob Faibussowitsch static auto nullContextsFinalizer = false;
825030f984aSJacob Faibussowitsch 
826*0e6b6b59SJacob Faibussowitsch static PetscErrorCode PetscDeviceContextGetNullContextForDevice_Private(PetscBool user_set_device, PetscDevice device, PetscDeviceContext *dctx) {
827*0e6b6b59SJacob Faibussowitsch   PetscInt        devid;
828*0e6b6b59SJacob Faibussowitsch   PetscDeviceType dtype;
829a4af0ceeSJacob Faibussowitsch 
830030f984aSJacob Faibussowitsch   PetscFunctionBegin;
831*0e6b6b59SJacob Faibussowitsch   PetscValidDevice(device, 2);
832*0e6b6b59SJacob Faibussowitsch   PetscValidPointer(dctx, 3);
833*0e6b6b59SJacob Faibussowitsch   if (PetscUnlikely(!nullContextsFinalizer)) {
834*0e6b6b59SJacob Faibussowitsch     const auto finalizer = [] {
835*0e6b6b59SJacob Faibussowitsch       PetscFunctionBegin;
836*0e6b6b59SJacob Faibussowitsch       for (auto &&dvec : nullContexts) {
837*0e6b6b59SJacob Faibussowitsch         for (auto &&dctx : dvec) PetscCall(PetscDeviceContextDestroy(&dctx));
838*0e6b6b59SJacob Faibussowitsch         PetscCallCXX(dvec.clear());
839030f984aSJacob Faibussowitsch       }
840*0e6b6b59SJacob Faibussowitsch       nullContextsFinalizer = false;
841a4af0ceeSJacob Faibussowitsch       PetscFunctionReturn(0);
842a4af0ceeSJacob Faibussowitsch     };
843a4af0ceeSJacob Faibussowitsch 
844*0e6b6b59SJacob Faibussowitsch     nullContextsFinalizer = true;
845*0e6b6b59SJacob Faibussowitsch     PetscCall(PetscRegisterFinalize(std::move(finalizer)));
846*0e6b6b59SJacob Faibussowitsch   }
847*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceGetDeviceId(device, &devid));
848*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceGetType(device, &dtype));
849*0e6b6b59SJacob Faibussowitsch   {
850*0e6b6b59SJacob Faibussowitsch     auto &ctxlist = nullContexts[dtype];
851*0e6b6b59SJacob Faibussowitsch 
852*0e6b6b59SJacob Faibussowitsch     PetscCheck(devid >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Device ID (%" PetscInt_FMT ") must be positive", devid);
853*0e6b6b59SJacob Faibussowitsch     // need to resize the container if not big enough because incrementing the iterator in
854*0e6b6b59SJacob Faibussowitsch     // std::next() (if we haven't initialized that ctx yet) may cause it to fall outside the
855*0e6b6b59SJacob Faibussowitsch     // current size of the container.
856*0e6b6b59SJacob Faibussowitsch     if (static_cast<std::size_t>(devid) >= ctxlist.size()) PetscCallCXX(ctxlist.resize(devid + 1));
857*0e6b6b59SJacob Faibussowitsch     if (PetscUnlikely(!ctxlist[devid])) {
858*0e6b6b59SJacob Faibussowitsch       // we have not seen this device before
859*0e6b6b59SJacob Faibussowitsch       PetscCall(PetscDeviceContextCreate(dctx));
860*0e6b6b59SJacob Faibussowitsch       PetscCall(PetscInfo(dctx, "Initializing null PetscDeviceContext (of type %s) for device %" PetscInt_FMT "\n", PetscDeviceTypes[dtype], devid));
861*0e6b6b59SJacob Faibussowitsch       {
862*0e6b6b59SJacob Faibussowitsch         const auto pobj   = PetscObjectCast(*dctx);
863*0e6b6b59SJacob Faibussowitsch         const auto name   = "null context " + std::to_string(devid);
864*0e6b6b59SJacob Faibussowitsch         const auto prefix = "null_context_" + std::to_string(devid) + '_';
865*0e6b6b59SJacob Faibussowitsch 
866*0e6b6b59SJacob Faibussowitsch         PetscCall(PetscObjectSetName(pobj, name.c_str()));
867*0e6b6b59SJacob Faibussowitsch         PetscCall(PetscObjectSetOptionsPrefix(pobj, prefix.c_str()));
868*0e6b6b59SJacob Faibussowitsch       }
869*0e6b6b59SJacob Faibussowitsch       PetscCall(PetscDeviceContextSetStreamType(*dctx, PETSC_STREAM_GLOBAL_BLOCKING));
870*0e6b6b59SJacob Faibussowitsch       PetscCall(PetscDeviceContextSetDevice_Private(*dctx, device, user_set_device));
871*0e6b6b59SJacob Faibussowitsch       PetscCall(PetscDeviceContextSetUp(*dctx));
872*0e6b6b59SJacob Faibussowitsch       // would use ctxlist.cbegin() but GCC 4.8 can't handle const iterator insert!
873*0e6b6b59SJacob Faibussowitsch       PetscCallCXX(ctxlist.insert(std::next(ctxlist.begin(), devid), *dctx));
874*0e6b6b59SJacob Faibussowitsch     } else *dctx = ctxlist[devid];
875*0e6b6b59SJacob Faibussowitsch   }
876030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
877030f984aSJacob Faibussowitsch }
878030f984aSJacob Faibussowitsch 
879*0e6b6b59SJacob Faibussowitsch /*
880*0e6b6b59SJacob Faibussowitsch   Gets the "NULL" context for the current PetscDeviceType and PetscDevice. NULL contexts are
881*0e6b6b59SJacob Faibussowitsch   guaranteed to always be globally blocking.
882*0e6b6b59SJacob Faibussowitsch */
883*0e6b6b59SJacob Faibussowitsch PetscErrorCode PetscDeviceContextGetNullContext_Internal(PetscDeviceContext *dctx) {
884*0e6b6b59SJacob Faibussowitsch   PetscDeviceContext gctx;
885*0e6b6b59SJacob Faibussowitsch   PetscDevice        gdev = nullptr;
886030f984aSJacob Faibussowitsch 
887a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
888a4af0ceeSJacob Faibussowitsch   PetscValidPointer(dctx, 1);
889*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetCurrentContext(&gctx));
890*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetDevice(gctx, &gdev));
891*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetNullContextForDevice_Private(gctx->usersetdevice, gdev, dctx));
892030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
893030f984aSJacob Faibussowitsch }
894030f984aSJacob Faibussowitsch 
895030f984aSJacob Faibussowitsch /*@C
896811af0c4SBarry Smith   PetscDeviceContextSetFromOptions - Configure a `PetscDeviceContext` from the options database
897030f984aSJacob Faibussowitsch 
898*0e6b6b59SJacob Faibussowitsch   Collective on `comm` or `dctx`
899030f984aSJacob Faibussowitsch 
900030f984aSJacob Faibussowitsch   Input Parameters:
901*0e6b6b59SJacob Faibussowitsch + comm - MPI communicator on which to query the options database (optional)
902811af0c4SBarry Smith - dctx - The `PetscDeviceContext` to configure
903030f984aSJacob Faibussowitsch 
904030f984aSJacob Faibussowitsch   Output Parameter:
905811af0c4SBarry Smith . dctx - The `PetscDeviceContext`
906030f984aSJacob Faibussowitsch 
907*0e6b6b59SJacob Faibussowitsch   Options Database:
908*0e6b6b59SJacob Faibussowitsch + -device_context_stream_type - type of stream to create inside the `PetscDeviceContext` -
909*0e6b6b59SJacob Faibussowitsch    `PetscDeviceContextSetStreamType()`
910811af0c4SBarry Smith - -device_context_device_type - the type of `PetscDevice` to attach by default - `PetscDeviceType`
911030f984aSJacob Faibussowitsch 
912*0e6b6b59SJacob Faibussowitsch   Notes:
913*0e6b6b59SJacob Faibussowitsch   The user may pass `MPI_COMM_NULL` for `comm` in which case the communicator of `dctx` is
914*0e6b6b59SJacob Faibussowitsch   used (which is always `PETSC_COMM_SELF`).
915*0e6b6b59SJacob Faibussowitsch 
916030f984aSJacob Faibussowitsch   Level: beginner
917030f984aSJacob Faibussowitsch 
918*0e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextSetStreamType()`, `PetscDeviceContextSetDevice()`,
919*0e6b6b59SJacob Faibussowitsch `PetscDeviceContextView()`
920030f984aSJacob Faibussowitsch @*/
921*0e6b6b59SJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetFromOptions(MPI_Comm comm, PetscDeviceContext dctx) {
922*0e6b6b59SJacob Faibussowitsch   const auto pobj     = PetscObjectCast(dctx);
923*0e6b6b59SJacob Faibussowitsch   auto       dtype    = std::make_pair(PETSC_DEVICE_DEFAULT(), PETSC_FALSE);
924*0e6b6b59SJacob Faibussowitsch   auto       stype    = std::make_pair(PETSC_DEVICE_CONTEXT_DEFAULT_STREAM_TYPE, PETSC_FALSE);
925*0e6b6b59SJacob Faibussowitsch   auto       old_comm = PETSC_COMM_SELF;
926030f984aSJacob Faibussowitsch 
927030f984aSJacob Faibussowitsch   PetscFunctionBegin;
928*0e6b6b59SJacob Faibussowitsch   // do not user getoptionalnullcontext here, the user is not allowed to set it from options!
929*0e6b6b59SJacob Faibussowitsch   PetscValidDeviceContext(dctx, 2);
930*0e6b6b59SJacob Faibussowitsch   /* set the device type first */
931*0e6b6b59SJacob Faibussowitsch   if (const auto device = dctx->device) PetscCall(PetscDeviceGetType(device, &dtype.first));
932*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetStreamType(dctx, &stype.first));
933*0e6b6b59SJacob Faibussowitsch 
934*0e6b6b59SJacob Faibussowitsch   if (comm == MPI_COMM_NULL) {
935*0e6b6b59SJacob Faibussowitsch     PetscCall(PetscObjectGetComm(pobj, &comm));
936*0e6b6b59SJacob Faibussowitsch   } else {
937*0e6b6b59SJacob Faibussowitsch     // briefly set the communicator for dctx (it is always PETSC_COMM_SELF) so
938*0e6b6b59SJacob Faibussowitsch     // PetscObjectOptionsBegin() behaves as if dctx had comm
939*0e6b6b59SJacob Faibussowitsch     old_comm = Petsc::util::exchange(pobj->comm, comm);
940*0e6b6b59SJacob Faibussowitsch   }
941*0e6b6b59SJacob Faibussowitsch 
942*0e6b6b59SJacob Faibussowitsch   PetscObjectOptionsBegin(pobj);
943*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextQueryOptions_Internal(PetscOptionsObject, dtype, stype));
944d0609cedSBarry Smith   PetscOptionsEnd();
945*0e6b6b59SJacob Faibussowitsch   // reset the comm (should be PETSC_COMM_SELF)
946*0e6b6b59SJacob Faibussowitsch   if (comm != MPI_COMM_NULL) pobj->comm = old_comm;
947*0e6b6b59SJacob Faibussowitsch   if (dtype.second) PetscCall(PetscDeviceContextSetDefaultDeviceForType_Internal(dctx, dtype.first));
948*0e6b6b59SJacob Faibussowitsch   if (stype.second) PetscCall(PetscDeviceContextSetStreamType(dctx, stype.first));
949*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextSetUp(dctx));
950*0e6b6b59SJacob Faibussowitsch   PetscFunctionReturn(0);
951*0e6b6b59SJacob Faibussowitsch }
952*0e6b6b59SJacob Faibussowitsch 
953*0e6b6b59SJacob Faibussowitsch /*@C
954*0e6b6b59SJacob Faibussowitsch   PetscDeviceContextView - View a `PetscDeviceContext`
955*0e6b6b59SJacob Faibussowitsch 
956*0e6b6b59SJacob Faibussowitsch   Collective on `viewer`
957*0e6b6b59SJacob Faibussowitsch 
958*0e6b6b59SJacob Faibussowitsch   Input Parameters:
959*0e6b6b59SJacob Faibussowitsch + dctx - The `PetscDeviceContext`
960*0e6b6b59SJacob Faibussowitsch - viewer - The `PetscViewer` to view `dctx` with (may be `NULL`)
961*0e6b6b59SJacob Faibussowitsch 
962*0e6b6b59SJacob Faibussowitsch   Notes:
963*0e6b6b59SJacob Faibussowitsch   If `viewer` is `NULL`, `PETSC_VIEWER_STDOUT_WORLD` is used instead, in which case this
964*0e6b6b59SJacob Faibussowitsch   routine is collective on `PETSC_COMM_WORLD`.
965*0e6b6b59SJacob Faibussowitsch 
966*0e6b6b59SJacob Faibussowitsch   Level: beginner
967*0e6b6b59SJacob Faibussowitsch 
968*0e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextViewFromOptions()`, `PetscDeviceView()`, `PETSC_VIEWER_STDOUT_WORLD`, `PetscDeviceContextCreate()`
969*0e6b6b59SJacob Faibussowitsch @*/
970*0e6b6b59SJacob Faibussowitsch PetscErrorCode PetscDeviceContextView(PetscDeviceContext dctx, PetscViewer viewer) {
971*0e6b6b59SJacob Faibussowitsch   PetscBool iascii;
972*0e6b6b59SJacob Faibussowitsch 
973*0e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
974*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
975*0e6b6b59SJacob Faibussowitsch   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PETSC_COMM_WORLD, &viewer));
976*0e6b6b59SJacob Faibussowitsch   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
977*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare(PetscObjectCast(viewer), PETSCVIEWERASCII, &iascii));
978*0e6b6b59SJacob Faibussowitsch   if (iascii) {
979*0e6b6b59SJacob Faibussowitsch     auto        stype = PETSC_STREAM_DEFAULT_BLOCKING;
980*0e6b6b59SJacob Faibussowitsch     PetscViewer sub;
981*0e6b6b59SJacob Faibussowitsch 
982*0e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sub));
983*0e6b6b59SJacob Faibussowitsch     PetscCall(PetscObjectPrintClassNamePrefixType(PetscObjectCast(dctx), sub));
984*0e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(sub));
985*0e6b6b59SJacob Faibussowitsch     PetscCall(PetscDeviceContextGetStreamType(dctx, &stype));
986*0e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(sub, "stream type: %s\n", PetscStreamTypes[stype]));
987*0e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(sub, "children: %" PetscInt_FMT "\n", dctx->numChildren));
988*0e6b6b59SJacob Faibussowitsch     if (const auto nchild = dctx->numChildren) {
989*0e6b6b59SJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushTab(sub));
990*0e6b6b59SJacob Faibussowitsch       for (PetscInt i = 0; i < nchild; ++i) {
991*0e6b6b59SJacob Faibussowitsch         if (i == nchild - 1) {
992*0e6b6b59SJacob Faibussowitsch           PetscCall(PetscViewerASCIIPrintf(sub, "%" PetscInt64_FMT, dctx->childIDs[i]));
993*0e6b6b59SJacob Faibussowitsch         } else {
994*0e6b6b59SJacob Faibussowitsch           PetscCall(PetscViewerASCIIPrintf(sub, "%" PetscInt64_FMT ", ", dctx->childIDs[i]));
995*0e6b6b59SJacob Faibussowitsch         }
996*0e6b6b59SJacob Faibussowitsch       }
997*0e6b6b59SJacob Faibussowitsch     }
998*0e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(sub));
999*0e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sub));
1000*0e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerFlush(viewer));
1001*0e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(viewer));
1002*0e6b6b59SJacob Faibussowitsch   }
1003*0e6b6b59SJacob Faibussowitsch   if (const auto device = dctx->device) PetscCall(PetscDeviceView(device, viewer));
1004*0e6b6b59SJacob Faibussowitsch   if (iascii) PetscCall(PetscViewerASCIIPopTab(viewer));
1005*0e6b6b59SJacob Faibussowitsch   PetscFunctionReturn(0);
1006*0e6b6b59SJacob Faibussowitsch }
1007*0e6b6b59SJacob Faibussowitsch 
1008*0e6b6b59SJacob Faibussowitsch /*@C
1009*0e6b6b59SJacob Faibussowitsch   PetscDeviceContextViewFromOptions - View a `PetscDeviceContext` from options
1010*0e6b6b59SJacob Faibussowitsch 
1011*0e6b6b59SJacob Faibussowitsch   Input Parameters:
1012*0e6b6b59SJacob Faibussowitsch + dctx - The `PetscDeviceContext` to view
1013*0e6b6b59SJacob Faibussowitsch . obj  - Optional `PetscObject` to associate (may be `NULL`)
1014*0e6b6b59SJacob Faibussowitsch - name - The command line option
1015*0e6b6b59SJacob Faibussowitsch 
1016*0e6b6b59SJacob Faibussowitsch   Level: beginner
1017*0e6b6b59SJacob Faibussowitsch 
1018*0e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextView()`, `PetscObjectViewFromOptions()`, `PetscDeviceContextCreate()`
1019*0e6b6b59SJacob Faibussowitsch @*/
1020*0e6b6b59SJacob Faibussowitsch PetscErrorCode PetscDeviceContextViewFromOptions(PetscDeviceContext dctx, PetscObject obj, const char name[]) {
1021*0e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
1022*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
1023*0e6b6b59SJacob Faibussowitsch   if (obj) PetscValidHeader(obj, 2);
1024*0e6b6b59SJacob Faibussowitsch   PetscValidCharPointer(name, 3);
1025*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscObjectViewFromOptions(PetscObjectCast(dctx), obj, name));
1026030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
1027030f984aSJacob Faibussowitsch }
1028