xref: /petsc/src/sys/objects/device/interface/dcontext.cxx (revision 811af0c4b09a35de4306c442f88bd09fdc09897d)
1030f984aSJacob Faibussowitsch #include <petsc/private/deviceimpl.h> /*I "petscdevice.h" I*/
2030f984aSJacob Faibussowitsch #include "objpool.hpp"
3030f984aSJacob Faibussowitsch 
49371c9d4SSatish Balay const char *const PetscStreamTypes[] = {"global_blocking", "default_blocking", "global_nonblocking", "max", "PetscStreamType", "PETSC_STREAM_", nullptr};
5a4af0ceeSJacob Faibussowitsch 
69371c9d4SSatish Balay const char *const PetscDeviceContextJoinModes[] = {"destroy", "sync", "no_sync", "PetscDeviceContextJoinMode", "PETSC_DEVICE_CONTEXT_JOIN_", nullptr};
7a4af0ceeSJacob Faibussowitsch 
8030f984aSJacob Faibussowitsch /* Define the allocator */
99371c9d4SSatish Balay struct PetscDeviceContextAllocator : Petsc::AllocatorBase<PetscDeviceContext> {
10030f984aSJacob Faibussowitsch   static PetscInt PetscDeviceContextID;
11030f984aSJacob Faibussowitsch 
129371c9d4SSatish Balay   PETSC_NODISCARD static PetscErrorCode create(PetscDeviceContext *dctx) noexcept {
13030f984aSJacob Faibussowitsch     PetscDeviceContext dc;
14030f984aSJacob Faibussowitsch 
15030f984aSJacob Faibussowitsch     PetscFunctionBegin;
169566063dSJacob Faibussowitsch     PetscCall(PetscNew(&dc));
17030f984aSJacob Faibussowitsch     dc->id         = PetscDeviceContextID++;
18030f984aSJacob Faibussowitsch     dc->streamType = PETSC_STREAM_DEFAULT_BLOCKING;
19030f984aSJacob Faibussowitsch     *dctx          = dc;
20030f984aSJacob Faibussowitsch     PetscFunctionReturn(0);
21030f984aSJacob Faibussowitsch   }
22030f984aSJacob Faibussowitsch 
239371c9d4SSatish Balay   PETSC_NODISCARD static PetscErrorCode destroy(PetscDeviceContext dctx) noexcept {
24030f984aSJacob Faibussowitsch     PetscFunctionBegin;
25bf025ffbSJacob 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);
26dbbe0bcdSBarry Smith     PetscTryTypeMethod(dctx, destroy);
279566063dSJacob Faibussowitsch     PetscCall(PetscDeviceDestroy(&dctx->device));
289566063dSJacob Faibussowitsch     PetscCall(PetscFree(dctx->childIDs));
299566063dSJacob Faibussowitsch     PetscCall(PetscFree(dctx));
30030f984aSJacob Faibussowitsch     PetscFunctionReturn(0);
31030f984aSJacob Faibussowitsch   }
32030f984aSJacob Faibussowitsch 
339371c9d4SSatish Balay   PETSC_NODISCARD static PetscErrorCode reset(PetscDeviceContext dctx) noexcept {
34030f984aSJacob Faibussowitsch     PetscFunctionBegin;
35030f984aSJacob Faibussowitsch     /* don't deallocate the child array, rather just zero it out */
369566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(dctx->childIDs, dctx->maxNumChildren));
37030f984aSJacob Faibussowitsch     dctx->setup       = PETSC_FALSE;
38030f984aSJacob Faibussowitsch     dctx->numChildren = 0;
39030f984aSJacob Faibussowitsch     dctx->streamType  = PETSC_STREAM_DEFAULT_BLOCKING;
40030f984aSJacob Faibussowitsch     PetscFunctionReturn(0);
41030f984aSJacob Faibussowitsch   }
42030f984aSJacob Faibussowitsch 
4317f48955SJacob Faibussowitsch   PETSC_NODISCARD static constexpr PetscErrorCode finalize() noexcept { return 0; }
44030f984aSJacob Faibussowitsch };
45a4af0ceeSJacob Faibussowitsch /* an ID = 0 is invalid */
46a4af0ceeSJacob Faibussowitsch PetscInt PetscDeviceContextAllocator::PetscDeviceContextID = 1;
47030f984aSJacob Faibussowitsch 
48030f984aSJacob Faibussowitsch static Petsc::ObjectPool<PetscDeviceContext, PetscDeviceContextAllocator> contextPool;
49030f984aSJacob Faibussowitsch 
50030f984aSJacob Faibussowitsch /*@C
51*811af0c4SBarry Smith   PetscDeviceContextCreate - Creates a `PetscDeviceContext`
52030f984aSJacob Faibussowitsch 
53030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
54030f984aSJacob Faibussowitsch 
5501d2d390SJose E. Roman   Output Paramemter:
56*811af0c4SBarry Smith . dctx - The `PetscDeviceContext`
57030f984aSJacob Faibussowitsch 
58*811af0c4SBarry Smith   Note:
59030f984aSJacob Faibussowitsch   Unlike almost every other PETSc class it is advised that most users use
60*811af0c4SBarry Smith   `PetscDeviceContextDuplicate()` rather than this routine to create new contexts. Contexts
61030f984aSJacob Faibussowitsch   of different types are incompatible with one another; using
62*811af0c4SBarry Smith   `PetscDeviceContextDuplicate()` ensures compatible types.
63030f984aSJacob Faibussowitsch 
64030f984aSJacob Faibussowitsch   Level: beginner
65030f984aSJacob Faibussowitsch 
66db781477SPatrick Sanan .seealso: `PetscDeviceContextDuplicate()`, `PetscDeviceContextSetDevice()`,
67db781477SPatrick Sanan           `PetscDeviceContextSetStreamType()`, `PetscDeviceContextSetUp()`,
68db781477SPatrick Sanan           `PetscDeviceContextSetFromOptions()`, `PetscDeviceContextDestroy()`
69030f984aSJacob Faibussowitsch @*/
709371c9d4SSatish Balay PetscErrorCode PetscDeviceContextCreate(PetscDeviceContext *dctx) {
71030f984aSJacob Faibussowitsch   PetscFunctionBegin;
72030f984aSJacob Faibussowitsch   PetscValidPointer(dctx, 1);
739566063dSJacob Faibussowitsch   PetscCall(PetscDeviceInitializePackage());
749566063dSJacob Faibussowitsch   PetscCall(contextPool.get(*dctx));
75030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
76030f984aSJacob Faibussowitsch }
77030f984aSJacob Faibussowitsch 
78030f984aSJacob Faibussowitsch /*@C
79*811af0c4SBarry Smith   PetscDeviceContextDestroy - Frees a `PetscDeviceContext`
80030f984aSJacob Faibussowitsch 
81030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
82030f984aSJacob Faibussowitsch 
83030f984aSJacob Faibussowitsch   Input Parameters:
84*811af0c4SBarry Smith . dctx - The `PetscDeviceContext`
85030f984aSJacob Faibussowitsch 
86*811af0c4SBarry Smith   Note:
87030f984aSJacob Faibussowitsch   No implicit synchronization occurs due to this routine, all resources are released completely asynchronously
88030f984aSJacob Faibussowitsch   w.r.t. the host. If one needs to guarantee access to the data produced on this contexts stream one should perform the
89030f984aSJacob Faibussowitsch   appropriate synchronization before calling this routine.
90030f984aSJacob Faibussowitsch 
91*811af0c4SBarry Smith   Developer Note:
92030f984aSJacob Faibussowitsch   The context is never actually "destroyed", only returned to an ever growing pool of
93030f984aSJacob Faibussowitsch   contexts. There are currently no safeguards on the size of the pool, this should perhaps
94030f984aSJacob Faibussowitsch   be implemented.
95030f984aSJacob Faibussowitsch 
96030f984aSJacob Faibussowitsch   Level: beginner
97030f984aSJacob Faibussowitsch 
98db781477SPatrick Sanan .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextSetDevice()`, `PetscDeviceContextSetUp()`, `PetscDeviceContextSynchronize()`
99030f984aSJacob Faibussowitsch @*/
1009371c9d4SSatish Balay PetscErrorCode PetscDeviceContextDestroy(PetscDeviceContext *dctx) {
101030f984aSJacob Faibussowitsch   PetscFunctionBegin;
102030f984aSJacob Faibussowitsch   if (!*dctx) PetscFunctionReturn(0);
1039566063dSJacob Faibussowitsch   PetscCall(contextPool.reclaim(std::move(*dctx)));
104bf025ffbSJacob Faibussowitsch   *dctx = nullptr;
105030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
106030f984aSJacob Faibussowitsch }
107030f984aSJacob Faibussowitsch 
108030f984aSJacob Faibussowitsch /*@C
109*811af0c4SBarry Smith   PetscDeviceContextSetStreamType - Set the implementation type of the underlying stream for a `PetscDeviceContext`
110030f984aSJacob Faibussowitsch 
111030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
112030f984aSJacob Faibussowitsch 
11301d2d390SJose E. Roman   Input Parameters:
114*811af0c4SBarry Smith + dctx - The `PetscDeviceContext`
115*811af0c4SBarry Smith - type - The `PetscStreamType`
116030f984aSJacob Faibussowitsch 
117030f984aSJacob Faibussowitsch   Notes:
118*811af0c4SBarry Smith   See `PetscStreamType` in `include/petscdevicetypes.h` for more information on the available
119*811af0c4SBarry Smith   types and their interactions.
120*811af0c4SBarry Smith 
121*811af0c4SBarry Smith   If the `PetscDeviceContext` was previously set up and stream
122*811af0c4SBarry Smith   type was changed, you must call `PetscDeviceContextSetUp()` again after this routine.
123030f984aSJacob Faibussowitsch 
124030f984aSJacob Faibussowitsch   Level: intermediate
125030f984aSJacob Faibussowitsch 
126db781477SPatrick Sanan .seealso: `PetscStreamType`, `PetscDeviceContextGetStreamType()`, `PetscDeviceContextCreate()`, `PetscDeviceContextSetUp()`, `PetscDeviceContextSetFromOptions()`
127030f984aSJacob Faibussowitsch @*/
1289371c9d4SSatish Balay PetscErrorCode PetscDeviceContextSetStreamType(PetscDeviceContext dctx, PetscStreamType type) {
129030f984aSJacob Faibussowitsch   PetscFunctionBegin;
130030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx, 1);
131030f984aSJacob Faibussowitsch   PetscValidStreamType(type, 2);
132030f984aSJacob Faibussowitsch   /* only need to do complex swapping if the object has already been setup */
133030f984aSJacob Faibussowitsch   if (dctx->setup && (dctx->streamType != type)) {
134dbbe0bcdSBarry Smith     PetscUseTypeMethod(dctx, changestreamtype, type);
135030f984aSJacob Faibussowitsch     dctx->setup = PETSC_FALSE;
136030f984aSJacob Faibussowitsch   }
137030f984aSJacob Faibussowitsch   dctx->streamType = type;
138030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
139030f984aSJacob Faibussowitsch }
140030f984aSJacob Faibussowitsch 
141030f984aSJacob Faibussowitsch /*@C
142*811af0c4SBarry Smith   PetscDeviceContextGetStreamType - Get the implementation type of the underlying stream for a `PetscDeviceContext`
143030f984aSJacob Faibussowitsch 
144030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
145030f984aSJacob Faibussowitsch 
14601d2d390SJose E. Roman   Input Parameter:
147*811af0c4SBarry Smith . dctx - The `PetscDeviceContext`
148030f984aSJacob Faibussowitsch 
149030f984aSJacob Faibussowitsch   Output Parameter:
150*811af0c4SBarry Smith . type - The `PetscStreamType`
151030f984aSJacob Faibussowitsch 
152*811af0c4SBarry Smith   Note:
153*811af0c4SBarry Smith   See `PetscStreamType` in `include/petscdevicetypes.h` for more information on the available types and their interactions
154030f984aSJacob Faibussowitsch 
155030f984aSJacob Faibussowitsch   Level: intermediate
156030f984aSJacob Faibussowitsch 
157db781477SPatrick Sanan .seealso: `PetscDeviceContextSetStreamType()`, `PetscDeviceContextCreate()`, `PetscDeviceContextSetFromOptions()`
158030f984aSJacob Faibussowitsch @*/
1599371c9d4SSatish Balay PetscErrorCode PetscDeviceContextGetStreamType(PetscDeviceContext dctx, PetscStreamType *type) {
160030f984aSJacob Faibussowitsch   PetscFunctionBegin;
161030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx, 1);
162030f984aSJacob Faibussowitsch   PetscValidIntPointer(type, 2);
163030f984aSJacob Faibussowitsch   *type = dctx->streamType;
164030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
165030f984aSJacob Faibussowitsch }
166030f984aSJacob Faibussowitsch 
167030f984aSJacob Faibussowitsch /*@C
168*811af0c4SBarry Smith   PetscDeviceContextSetDevice - Set the underlying device for the `PetscDeviceContext`
169030f984aSJacob Faibussowitsch 
170030f984aSJacob Faibussowitsch   Not Collective, Possibly Synchronous
171030f984aSJacob Faibussowitsch 
17201d2d390SJose E. Roman   Input Parameters:
173*811af0c4SBarry Smith + dctx   - The `PetscDeviceContext`
174*811af0c4SBarry Smith - device - The `PetscDevice`
175030f984aSJacob Faibussowitsch 
176030f984aSJacob Faibussowitsch   Notes:
177*811af0c4SBarry Smith   This routine is effectively `PetscDeviceContext`'s "set-type" (so every `PetscDeviceContext`
178*811af0c4SBarry Smith   must also have an attached `PetscDevice`). Unlike the usual set-type semantics, it is
179030f984aSJacob Faibussowitsch   not stricly necessary to set a contexts device to enable usage, any created device
180030f984aSJacob Faibussowitsch   contexts will always come equipped with the "default" device.
181030f984aSJacob Faibussowitsch 
182a4af0ceeSJacob Faibussowitsch   This routine is a no-op if dctx is already attached to device.
183a4af0ceeSJacob Faibussowitsch 
1845181c4f9SJacob Faibussowitsch   This routine may initialize the backend device and incur synchronization.
1855181c4f9SJacob Faibussowitsch 
186030f984aSJacob Faibussowitsch   Level: intermediate
187030f984aSJacob Faibussowitsch 
188db781477SPatrick Sanan .seealso: `PetscDeviceCreate()`, `PetscDeviceConfigure()`, `PetscDeviceContextGetDevice()`
189030f984aSJacob Faibussowitsch @*/
1909371c9d4SSatish Balay PetscErrorCode PetscDeviceContextSetDevice(PetscDeviceContext dctx, PetscDevice device) {
191030f984aSJacob Faibussowitsch   PetscFunctionBegin;
192030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx, 1);
193030f984aSJacob Faibussowitsch   PetscValidDevice(device, 2);
194a4af0ceeSJacob Faibussowitsch   if (dctx->device) {
195a4af0ceeSJacob Faibussowitsch     /* can't do a strict pointer equality check since PetscDevice's are reused */
196a4af0ceeSJacob Faibussowitsch     if (dctx->device->ops->createcontext == device->ops->createcontext) PetscFunctionReturn(0);
197a4af0ceeSJacob Faibussowitsch   }
1989566063dSJacob Faibussowitsch   PetscCall(PetscDeviceDestroy(&dctx->device));
199dbbe0bcdSBarry Smith   PetscTryTypeMethod(dctx, destroy);
2009566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(dctx->ops, sizeof(*dctx->ops)));
2019566063dSJacob Faibussowitsch   PetscCall((*device->ops->createcontext)(dctx));
2029566063dSJacob Faibussowitsch   PetscCall(PetscDeviceReference_Internal(device));
203a4af0ceeSJacob Faibussowitsch   dctx->device = device;
204030f984aSJacob Faibussowitsch   dctx->setup  = PETSC_FALSE;
205030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
206030f984aSJacob Faibussowitsch }
207030f984aSJacob Faibussowitsch 
208030f984aSJacob Faibussowitsch /*@C
209*811af0c4SBarry Smith   PetscDeviceContextGetDevice - Get the underlying `PetscDevice` for a `PetscDeviceContext`
210030f984aSJacob Faibussowitsch 
211030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
212030f984aSJacob Faibussowitsch 
213030f984aSJacob Faibussowitsch   Input Parameter:
214*811af0c4SBarry Smith . dctx - the `PetscDeviceContext`
215030f984aSJacob Faibussowitsch 
216030f984aSJacob Faibussowitsch   Output Parameter:
217*811af0c4SBarry Smith . device - The `PetscDevice`
218030f984aSJacob Faibussowitsch 
219*811af0c4SBarry Smith   Note:
220*811af0c4SBarry Smith   This is a borrowed reference, the user should not destroy `device`.
221030f984aSJacob Faibussowitsch 
222a375dbeeSPatrick Sanan   Level: intermediate
223a375dbeeSPatrick Sanan 
224db781477SPatrick Sanan .seealso: `PetscDeviceContextSetDevice()`, `PetscDevice`
225030f984aSJacob Faibussowitsch @*/
2269371c9d4SSatish Balay PetscErrorCode PetscDeviceContextGetDevice(PetscDeviceContext dctx, PetscDevice *device) {
227030f984aSJacob Faibussowitsch   PetscFunctionBegin;
228030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx, 1);
229030f984aSJacob Faibussowitsch   PetscValidPointer(device, 2);
230bf025ffbSJacob Faibussowitsch   PetscAssert(dctx->device, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "PetscDeviceContext %" PetscInt_FMT " has no attached PetscDevice to get", dctx->id);
231030f984aSJacob Faibussowitsch   *device = dctx->device;
232030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
233030f984aSJacob Faibussowitsch }
234030f984aSJacob Faibussowitsch 
235030f984aSJacob Faibussowitsch /*@C
236*811af0c4SBarry Smith   PetscDeviceContextSetUp - Prepares a `PetscDeviceContext` for use
237030f984aSJacob Faibussowitsch 
238030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
239030f984aSJacob Faibussowitsch 
24001d2d390SJose E. Roman   Input Parameter:
241*811af0c4SBarry Smith . dctx - The `PetscDeviceContext`
242030f984aSJacob Faibussowitsch 
243*811af0c4SBarry Smith   Developer Note:
244*811af0c4SBarry Smith   This routine is usually the stage where a `PetscDeviceContext` acquires device-side data structures such as streams,
245030f984aSJacob Faibussowitsch   events, and (possibly) handles.
246030f984aSJacob Faibussowitsch 
247030f984aSJacob Faibussowitsch   Level: beginner
248030f984aSJacob Faibussowitsch 
249db781477SPatrick Sanan .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextSetDevice()`, `PetscDeviceContextDestroy()`, `PetscDeviceContextSetFromOptions()`
250030f984aSJacob Faibussowitsch @*/
2519371c9d4SSatish Balay PetscErrorCode PetscDeviceContextSetUp(PetscDeviceContext dctx) {
252030f984aSJacob Faibussowitsch   PetscFunctionBegin;
253030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx, 1);
254030f984aSJacob Faibussowitsch   if (!dctx->device) {
2559566063dSJacob Faibussowitsch     PetscCall(PetscInfo(nullptr, "PetscDeviceContext %" PetscInt_FMT " did not have an explicitly attached PetscDevice, using default with type %s\n", dctx->id, PetscDeviceTypes[PETSC_DEVICE_DEFAULT]));
2569566063dSJacob Faibussowitsch     PetscCall(PetscDeviceContextSetDefaultDevice_Internal(dctx));
257030f984aSJacob Faibussowitsch   }
258030f984aSJacob Faibussowitsch   if (dctx->setup) PetscFunctionReturn(0);
259dbbe0bcdSBarry Smith   PetscUseTypeMethod(dctx, setup);
260030f984aSJacob Faibussowitsch   dctx->setup = PETSC_TRUE;
261030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
262030f984aSJacob Faibussowitsch }
263030f984aSJacob Faibussowitsch 
264030f984aSJacob Faibussowitsch /*@C
265*811af0c4SBarry Smith   PetscDeviceContextDuplicate - Duplicates a `PetscDeviceContext` object
266030f984aSJacob Faibussowitsch 
267030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
268030f984aSJacob Faibussowitsch 
269030f984aSJacob Faibussowitsch   Input Parameter:
270*811af0c4SBarry Smith . dctx - The `PetscDeviceContext` to duplicate
271030f984aSJacob Faibussowitsch 
2726aad120cSJose E. Roman   Output Parameter:
273*811af0c4SBarry Smith . dctxdup - The duplicated `PetscDeviceContext`
274030f984aSJacob Faibussowitsch 
275*811af0c4SBarry Smith   Note:
276*811af0c4SBarry Smith   This is a shorthand method for creating a `PetscDeviceContext` with the exact same
277*811af0c4SBarry Smith   settings as another. However the `dctxdup` does not "share"
278030f984aSJacob Faibussowitsch   any of the underlying data with the original, (including its current stream-state) they
279030f984aSJacob Faibussowitsch   are completely separate objects.
280030f984aSJacob Faibussowitsch 
281030f984aSJacob Faibussowitsch   Level: beginner
282030f984aSJacob Faibussowitsch 
283db781477SPatrick Sanan .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextSetDevice()`, `PetscDeviceContextSetStreamType()`
284030f984aSJacob Faibussowitsch @*/
2859371c9d4SSatish Balay PetscErrorCode PetscDeviceContextDuplicate(PetscDeviceContext dctx, PetscDeviceContext *dctxdup) {
286a4af0ceeSJacob Faibussowitsch   PetscDeviceContext dup;
287030f984aSJacob Faibussowitsch 
288030f984aSJacob Faibussowitsch   PetscFunctionBegin;
289030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx, 1);
290030f984aSJacob Faibussowitsch   PetscValidPointer(dctxdup, 2);
2919566063dSJacob Faibussowitsch   PetscCall(PetscDeviceContextCreate(&dup));
2929566063dSJacob Faibussowitsch   PetscCall(PetscDeviceContextSetStreamType(dup, dctx->streamType));
2939566063dSJacob Faibussowitsch   if (dctx->device) PetscCall(PetscDeviceContextSetDevice(dup, dctx->device));
2949566063dSJacob Faibussowitsch   PetscCall(PetscDeviceContextSetUp(dup));
295a4af0ceeSJacob Faibussowitsch   *dctxdup = dup;
296030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
297030f984aSJacob Faibussowitsch }
298030f984aSJacob Faibussowitsch 
299030f984aSJacob Faibussowitsch /*@C
300*811af0c4SBarry Smith   PetscDeviceContextQueryIdle - Returns whether or not a `PetscDeviceContext` is idle
301030f984aSJacob Faibussowitsch 
302030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
303030f984aSJacob Faibussowitsch 
304030f984aSJacob Faibussowitsch   Input Parameter:
305*811af0c4SBarry Smith . dctx - The `PetscDeviceContext` object
306030f984aSJacob Faibussowitsch 
307030f984aSJacob Faibussowitsch   Output Parameter:
308*811af0c4SBarry Smith . idle - `PETSC_TRUE` if `PetscDeviceContext` has NO work, `PETSC_FALSE` if it has work
309030f984aSJacob Faibussowitsch 
310*811af0c4SBarry Smith   Note:
311ef657721SJacob Faibussowitsch   This routine only refers a singular context and does NOT take any of its children into
312*811af0c4SBarry Smith   account. That is, if `dctx` is idle but has dependents who do have work, this routine still
313*811af0c4SBarry Smith   returns `PETSC_TRUE`.
314030f984aSJacob Faibussowitsch 
315030f984aSJacob Faibussowitsch   Level: intermediate
316030f984aSJacob Faibussowitsch 
317db781477SPatrick Sanan .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextWaitForContext()`, `PetscDeviceContextFork()`
318030f984aSJacob Faibussowitsch @*/
3199371c9d4SSatish Balay PetscErrorCode PetscDeviceContextQueryIdle(PetscDeviceContext dctx, PetscBool *idle) {
320030f984aSJacob Faibussowitsch   PetscFunctionBegin;
321030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx, 1);
322030f984aSJacob Faibussowitsch   PetscValidBoolPointer(idle, 2);
323dbbe0bcdSBarry Smith   PetscUseTypeMethod(dctx, query, idle);
3249566063dSJacob Faibussowitsch   PetscCall(PetscInfo(nullptr, "PetscDeviceContext id %" PetscInt_FMT " %s idle\n", dctx->id, *idle ? "was" : "was not"));
325030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
326030f984aSJacob Faibussowitsch }
327030f984aSJacob Faibussowitsch 
328030f984aSJacob Faibussowitsch /*@C
329030f984aSJacob Faibussowitsch   PetscDeviceContextWaitForContext - Make one context wait for another context to finish
330030f984aSJacob Faibussowitsch 
331030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
332030f984aSJacob Faibussowitsch 
333030f984aSJacob Faibussowitsch   Input Parameters:
334*811af0c4SBarry Smith + dctxa - The `PetscDeviceContext` object that is waiting
335*811af0c4SBarry Smith - dctxb - The `PetscDeviceContext` object that is being waited on
336030f984aSJacob Faibussowitsch 
337030f984aSJacob Faibussowitsch   Notes:
338*811af0c4SBarry Smith   Serializes two `PetscDeviceContexts`. This routine uses only the state of `dctxb` at the moment this routine was
339*811af0c4SBarry Smith   called, so any future work queued will not affect `dctxa`.
340*811af0c4SBarry Smith 
341*811af0c4SBarry Smith   It is safe to pass the same context to both arguments.
342030f984aSJacob Faibussowitsch 
343030f984aSJacob Faibussowitsch   Level: beginner
344030f984aSJacob Faibussowitsch 
345db781477SPatrick Sanan .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextQueryIdle()`, `PetscDeviceContextJoin()`
346030f984aSJacob Faibussowitsch @*/
3479371c9d4SSatish Balay PetscErrorCode PetscDeviceContextWaitForContext(PetscDeviceContext dctxa, PetscDeviceContext dctxb) {
348030f984aSJacob Faibussowitsch   PetscFunctionBegin;
349030f984aSJacob Faibussowitsch   PetscCheckCompatibleDeviceContexts(dctxa, 1, dctxb, 2);
350030f984aSJacob Faibussowitsch   if (dctxa == dctxb) PetscFunctionReturn(0);
351dbbe0bcdSBarry Smith   PetscUseTypeMethod(dctxa, waitforcontext, dctxb);
352030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
353030f984aSJacob Faibussowitsch }
354030f984aSJacob Faibussowitsch 
355050c0c3dSJacob Faibussowitsch #define PETSC_USE_DEBUG_AND_INFO (PetscDefined(USE_DEBUG) && PetscDefined(USE_INFO))
356050c0c3dSJacob Faibussowitsch #if PETSC_USE_DEBUG_AND_INFO
357050c0c3dSJacob Faibussowitsch #include <string>
358050c0c3dSJacob Faibussowitsch #endif
359030f984aSJacob Faibussowitsch /*@C
360030f984aSJacob Faibussowitsch   PetscDeviceContextFork - Create a set of dependent child contexts from a parent context
361030f984aSJacob Faibussowitsch 
362030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
363030f984aSJacob Faibussowitsch 
364030f984aSJacob Faibussowitsch   Input Parameters:
365*811af0c4SBarry Smith + dctx - The parent `PetscDeviceContext`
366030f984aSJacob Faibussowitsch - n    - The number of children to create
367030f984aSJacob Faibussowitsch 
368030f984aSJacob Faibussowitsch   Output Parameter:
369030f984aSJacob Faibussowitsch . dsub - The created child context(s)
370030f984aSJacob Faibussowitsch 
371030f984aSJacob Faibussowitsch   Notes:
372030f984aSJacob Faibussowitsch   This routine creates n edges of a DAG from a source node which are causally dependent on the source node, meaning
373030f984aSJacob Faibussowitsch   that work queued on child contexts will not start until the parent context finishes its work. This accounts for work
374030f984aSJacob Faibussowitsch   queued on the parent up until calling this function, any subsequent work enqueued on the parent has no effect on the children.
375030f984aSJacob Faibussowitsch 
376030f984aSJacob Faibussowitsch   Any children created with this routine have their lifetimes bounded by the parent. That is, the parent context expects
377030f984aSJacob Faibussowitsch   to free all of it's children (and ONLY its children) before itself is freed.
378030f984aSJacob Faibussowitsch 
379030f984aSJacob Faibussowitsch   DAG representation:
380030f984aSJacob Faibussowitsch .vb
381030f984aSJacob Faibussowitsch   time ->
382030f984aSJacob Faibussowitsch 
383030f984aSJacob Faibussowitsch   -> dctx \----> dctx ------>
384030f984aSJacob Faibussowitsch            \---> dsub[0] --->
385030f984aSJacob Faibussowitsch             \--> ... ------->
386030f984aSJacob Faibussowitsch              \-> dsub[n-1] ->
387030f984aSJacob Faibussowitsch .ve
388030f984aSJacob Faibussowitsch 
389030f984aSJacob Faibussowitsch   Level: intermediate
390030f984aSJacob Faibussowitsch 
391db781477SPatrick Sanan .seealso: `PetscDeviceContextJoin()`, `PetscDeviceContextSynchronize()`, `PetscDeviceContextQueryIdle()`
392030f984aSJacob Faibussowitsch @*/
3939371c9d4SSatish Balay PetscErrorCode PetscDeviceContextFork(PetscDeviceContext dctx, PetscInt n, PetscDeviceContext **dsub) {
394050c0c3dSJacob Faibussowitsch #if PETSC_USE_DEBUG_AND_INFO
395030f984aSJacob Faibussowitsch   const PetscInt     nBefore = n;
396030f984aSJacob Faibussowitsch   static std::string idList;
397030f984aSJacob Faibussowitsch #endif
398bf025ffbSJacob Faibussowitsch   PetscDeviceContext *dsubTmp = nullptr;
399030f984aSJacob Faibussowitsch   PetscInt            i       = 0;
400030f984aSJacob Faibussowitsch 
401030f984aSJacob Faibussowitsch   PetscFunctionBegin;
402030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx, 1);
403030f984aSJacob Faibussowitsch   PetscValidPointer(dsub, 3);
404bf025ffbSJacob Faibussowitsch   PetscAssert(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of contexts requested %" PetscInt_FMT " < 0", n);
4053ca90d2dSJacob Faibussowitsch #if PETSC_USE_DEBUG_AND_INFO
406030f984aSJacob Faibussowitsch   /* reserve 4 chars per id, 2 for number and 2 for ', ' separator */
407030f984aSJacob Faibussowitsch   idList.reserve(4 * n);
408030f984aSJacob Faibussowitsch #endif
409030f984aSJacob Faibussowitsch   /* update child totals */
410030f984aSJacob Faibussowitsch   dctx->numChildren += n;
411030f984aSJacob Faibussowitsch   /* now to find out if we have room */
412030f984aSJacob Faibussowitsch   if (dctx->numChildren > dctx->maxNumChildren) {
413030f984aSJacob Faibussowitsch     /* no room, either from having too many kids or not having any */
414030f984aSJacob Faibussowitsch     if (dctx->childIDs) {
415030f984aSJacob Faibussowitsch       /* have existing children, must reallocate them */
4169566063dSJacob Faibussowitsch       PetscCall(PetscRealloc(dctx->numChildren * sizeof(*dctx->childIDs), &dctx->childIDs));
417030f984aSJacob Faibussowitsch       /* clear the extra memory since realloc doesn't do it for us */
4189566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero((dctx->childIDs) + (dctx->maxNumChildren), (dctx->numChildren) - (dctx->maxNumChildren)));
419030f984aSJacob Faibussowitsch     } else {
420030f984aSJacob Faibussowitsch       /* have no children */
4219566063dSJacob Faibussowitsch       PetscCall(PetscCalloc1(dctx->numChildren, &dctx->childIDs));
422030f984aSJacob Faibussowitsch     }
423030f984aSJacob Faibussowitsch     /* update total number of children */
424030f984aSJacob Faibussowitsch     dctx->maxNumChildren = dctx->numChildren;
425030f984aSJacob Faibussowitsch   }
4269566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &dsubTmp));
427030f984aSJacob Faibussowitsch   while (n) {
428030f984aSJacob Faibussowitsch     /* empty child slot */
429030f984aSJacob Faibussowitsch     if (!(dctx->childIDs[i])) {
430030f984aSJacob Faibussowitsch       /* create the child context in the image of its parent */
4319566063dSJacob Faibussowitsch       PetscCall(PetscDeviceContextDuplicate(dctx, dsubTmp + i));
4329566063dSJacob Faibussowitsch       PetscCall(PetscDeviceContextWaitForContext(dsubTmp[i], dctx));
433030f984aSJacob Faibussowitsch       /* register the child with its parent */
434030f984aSJacob Faibussowitsch       dctx->childIDs[i] = dsubTmp[i]->id;
435050c0c3dSJacob Faibussowitsch #if PETSC_USE_DEBUG_AND_INFO
436030f984aSJacob Faibussowitsch       idList += std::to_string(dsubTmp[i]->id);
437030f984aSJacob Faibussowitsch       if (n != 1) idList += ", ";
438030f984aSJacob Faibussowitsch #endif
439030f984aSJacob Faibussowitsch       --n;
440030f984aSJacob Faibussowitsch     }
441030f984aSJacob Faibussowitsch     ++i;
442030f984aSJacob Faibussowitsch   }
4433ca90d2dSJacob Faibussowitsch #if PETSC_USE_DEBUG_AND_INFO
4449566063dSJacob Faibussowitsch   PetscCall(PetscInfo(nullptr, "Forked %" PetscInt_FMT " children from parent %" PetscInt_FMT " with IDs: %s\n", nBefore, dctx->id, idList.c_str()));
445030f984aSJacob Faibussowitsch   /* resets the size but doesn't deallocate the memory */
446030f984aSJacob Faibussowitsch   idList.clear();
447030f984aSJacob Faibussowitsch #endif
448030f984aSJacob Faibussowitsch   /* pass the children back to caller */
449030f984aSJacob Faibussowitsch   *dsub = dsubTmp;
450030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
451030f984aSJacob Faibussowitsch }
452030f984aSJacob Faibussowitsch 
453030f984aSJacob Faibussowitsch /*@C
4545181c4f9SJacob Faibussowitsch   PetscDeviceContextJoin - Converge a set of child contexts
455030f984aSJacob Faibussowitsch 
456030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
457030f984aSJacob Faibussowitsch 
458030f984aSJacob Faibussowitsch   Input Parameters:
459*811af0c4SBarry Smith + dctx         - A `PetscDeviceContext` to converge on
460030f984aSJacob Faibussowitsch . n            - The number of sub contexts to converge
461030f984aSJacob Faibussowitsch . joinMode     - The type of join to perform
462030f984aSJacob Faibussowitsch - dsub         - The sub contexts to converge
463030f984aSJacob Faibussowitsch 
464030f984aSJacob Faibussowitsch   Notes:
465*811af0c4SBarry Smith   If `PetscDeviceContextFork()` creates `n` edges from a source node which all depend on the
466030f984aSJacob Faibussowitsch   source node, then this routine is the exact mirror. That is, it creates a node
467*811af0c4SBarry Smith   (represented in `dctx`) which receives `n` edges (and optionally destroys them) which is
468030f984aSJacob Faibussowitsch   dependent on the completion of all incoming edges.
469030f984aSJacob Faibussowitsch 
470*811af0c4SBarry Smith   If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_DESTROY` all contexts in `dsub` will be destroyed
471*811af0c4SBarry Smith   by this routine. Thus all sub contexts must have been created with the `dctx` passed to
472030f984aSJacob Faibussowitsch   this routine.
473030f984aSJacob Faibussowitsch 
474*811af0c4SBarry Smith   if `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC` `dctx` waits for all sub contexts but the
475030f984aSJacob Faibussowitsch   sub contexts do not wait for one another afterwards.
476030f984aSJacob Faibussowitsch 
477*811af0c4SBarry Smith   If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_SYNC` all sub contexts will additionally
478*811af0c4SBarry Smith   wait on `dctx` after converging. This has the effect of "synchronizing" the outgoing
479030f984aSJacob Faibussowitsch   edges.
480030f984aSJacob Faibussowitsch 
481030f984aSJacob Faibussowitsch   DAG representations:
482*811af0c4SBarry Smith   If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_DESTROY`
483030f984aSJacob Faibussowitsch .vb
484030f984aSJacob Faibussowitsch   time ->
485030f984aSJacob Faibussowitsch 
486030f984aSJacob Faibussowitsch   -> dctx ---------/- dctx ->
487030f984aSJacob Faibussowitsch   -> dsub[0] -----/
488030f984aSJacob Faibussowitsch   ->  ... -------/
489030f984aSJacob Faibussowitsch   -> dsub[n-1] -/
490030f984aSJacob Faibussowitsch .ve
491*811af0c4SBarry Smith   If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC`
492030f984aSJacob Faibussowitsch .vb
493030f984aSJacob Faibussowitsch   time ->
494030f984aSJacob Faibussowitsch 
495030f984aSJacob Faibussowitsch   -> dctx ---------/- dctx ->
496030f984aSJacob Faibussowitsch   -> dsub[0] -----/--------->
497030f984aSJacob Faibussowitsch   ->  ... -------/---------->
498030f984aSJacob Faibussowitsch   -> dsub[n-1] -/----------->
499030f984aSJacob Faibussowitsch .ve
500*811af0c4SBarry Smith   If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_SYNC`
501030f984aSJacob Faibussowitsch .vb
502030f984aSJacob Faibussowitsch   time ->
503030f984aSJacob Faibussowitsch 
504030f984aSJacob Faibussowitsch   -> dctx ---------/- dctx -\----> dctx ------>
505030f984aSJacob Faibussowitsch   -> dsub[0] -----/          \---> dsub[0] --->
506030f984aSJacob Faibussowitsch   ->  ... -------/            \--> ... ------->
507030f984aSJacob Faibussowitsch   -> dsub[n-1] -/              \-> dsub[n-1] ->
508030f984aSJacob Faibussowitsch .ve
509030f984aSJacob Faibussowitsch 
510030f984aSJacob Faibussowitsch   Level: intermediate
511030f984aSJacob Faibussowitsch 
512db781477SPatrick Sanan .seealso: `PetscDeviceContextFork()`, `PetscDeviceContextSynchronize()`, `PetscDeviceContextJoinMode`
513030f984aSJacob Faibussowitsch @*/
5149371c9d4SSatish Balay PetscErrorCode PetscDeviceContextJoin(PetscDeviceContext dctx, PetscInt n, PetscDeviceContextJoinMode joinMode, PetscDeviceContext **dsub) {
515030f984aSJacob Faibussowitsch #if defined(PETSC_USE_DEBUG) && defined(PETSC_USE_INFO)
516030f984aSJacob Faibussowitsch   static std::string idList;
517030f984aSJacob Faibussowitsch #endif
518030f984aSJacob Faibussowitsch 
519030f984aSJacob Faibussowitsch   PetscFunctionBegin;
520030f984aSJacob Faibussowitsch   /* validity of dctx is checked in the wait-for loop */
521030f984aSJacob Faibussowitsch   PetscValidPointer(dsub, 4);
522bf025ffbSJacob Faibussowitsch   PetscAssert(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of contexts merged %" PetscInt_FMT " < 0", n);
523030f984aSJacob Faibussowitsch #if defined(PETSC_USE_DEBUG) && defined(PETSC_USE_INFO)
524030f984aSJacob Faibussowitsch   /* reserve 4 chars per id, 2 for number and 2 for ', ' separator */
525030f984aSJacob Faibussowitsch   idList.reserve(4 * n);
526030f984aSJacob Faibussowitsch #endif
527030f984aSJacob Faibussowitsch   /* first dctx waits on all the incoming edges */
528030f984aSJacob Faibussowitsch   for (PetscInt i = 0; i < n; ++i) {
529030f984aSJacob Faibussowitsch     PetscCheckCompatibleDeviceContexts(dctx, 1, (*dsub)[i], 4);
5309566063dSJacob Faibussowitsch     PetscCall(PetscDeviceContextWaitForContext(dctx, (*dsub)[i]));
531030f984aSJacob Faibussowitsch #if defined(PETSC_USE_DEBUG) && defined(PETSC_USE_INFO)
532030f984aSJacob Faibussowitsch     idList += std::to_string((*dsub)[i]->id);
533030f984aSJacob Faibussowitsch     if (i + 1 < n) idList += ", ";
534030f984aSJacob Faibussowitsch #endif
535030f984aSJacob Faibussowitsch   }
536030f984aSJacob Faibussowitsch 
537030f984aSJacob Faibussowitsch   /* now we handle the aftermath */
538030f984aSJacob Faibussowitsch   switch (joinMode) {
5399371c9d4SSatish Balay   case PETSC_DEVICE_CONTEXT_JOIN_DESTROY: {
540030f984aSJacob Faibussowitsch     PetscInt j = 0;
541030f984aSJacob Faibussowitsch 
542bf025ffbSJacob Faibussowitsch     PetscAssert(n <= dctx->numChildren, 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, dctx->numChildren);
543030f984aSJacob Faibussowitsch     /* update child count while it's still fresh in memory */
544030f984aSJacob Faibussowitsch     dctx->numChildren -= n;
545030f984aSJacob Faibussowitsch     for (PetscInt i = 0; i < dctx->maxNumChildren; ++i) {
546030f984aSJacob Faibussowitsch       if (dctx->childIDs[i] && (dctx->childIDs[i] == (*dsub)[j]->id)) {
547030f984aSJacob Faibussowitsch         /* child is one of ours, can destroy it */
5489566063dSJacob Faibussowitsch         PetscCall(PetscDeviceContextDestroy((*dsub) + j));
549030f984aSJacob Faibussowitsch         /* reset the child slot */
550030f984aSJacob Faibussowitsch         dctx->childIDs[i] = 0;
551030f984aSJacob Faibussowitsch         if (++j == n) break;
552030f984aSJacob Faibussowitsch       }
553030f984aSJacob Faibussowitsch     }
554030f984aSJacob Faibussowitsch     /* gone through the loop but did not find every child, if this triggers (or well, doesn't) on perf-builds we leak the remaining contexts memory */
555bf025ffbSJacob Faibussowitsch     PetscAssert(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);
5569566063dSJacob Faibussowitsch     PetscCall(PetscFree(*dsub));
5579371c9d4SSatish Balay   } break;
558030f984aSJacob Faibussowitsch   case PETSC_DEVICE_CONTEXT_JOIN_SYNC:
5599566063dSJacob Faibussowitsch     for (PetscInt i = 0; i < n; ++i) PetscCall(PetscDeviceContextWaitForContext((*dsub)[i], dctx));
5609371c9d4SSatish Balay   case PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC: break;
5619371c9d4SSatish Balay   default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown PetscDeviceContextJoinMode given");
562030f984aSJacob Faibussowitsch   }
563030f984aSJacob Faibussowitsch 
564030f984aSJacob Faibussowitsch #if defined(PETSC_USE_DEBUG) && defined(PETSC_USE_INFO)
5659566063dSJacob Faibussowitsch   PetscCall(PetscInfo(nullptr, "Joined %" PetscInt_FMT " ctxs to ctx %" PetscInt_FMT ", mode %s with IDs: %s\n", n, dctx->id, PetscDeviceContextJoinModes[joinMode], idList.c_str()));
566030f984aSJacob Faibussowitsch   idList.clear();
567030f984aSJacob Faibussowitsch #endif
568030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
569030f984aSJacob Faibussowitsch }
570030f984aSJacob Faibussowitsch 
571030f984aSJacob Faibussowitsch /*@C
572*811af0c4SBarry Smith   PetscDeviceContextSynchronize - Block the host until all work queued on or associated with a `PetscDeviceContext` has finished
573030f984aSJacob Faibussowitsch 
574030f984aSJacob Faibussowitsch   Not Collective, Synchronous
575030f984aSJacob Faibussowitsch 
576030f984aSJacob Faibussowitsch   Input Parameters:
577*811af0c4SBarry Smith . dctx - The `PetscDeviceContext` to synchronize
578030f984aSJacob Faibussowitsch 
579030f984aSJacob Faibussowitsch   Level: beginner
580030f984aSJacob Faibussowitsch 
581db781477SPatrick Sanan .seealso: `PetscDeviceContextFork()`, `PetscDeviceContextJoin()`, `PetscDeviceContextQueryIdle()`
582030f984aSJacob Faibussowitsch @*/
5839371c9d4SSatish Balay PetscErrorCode PetscDeviceContextSynchronize(PetscDeviceContext dctx) {
584030f984aSJacob Faibussowitsch   PetscFunctionBegin;
585030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx, 1);
586030f984aSJacob Faibussowitsch   /* if it isn't setup there is nothing to sync on */
587dbbe0bcdSBarry Smith   if (dctx->setup) PetscUseTypeMethod(dctx, synchronize);
588030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
589030f984aSJacob Faibussowitsch }
590030f984aSJacob Faibussowitsch 
591a4af0ceeSJacob Faibussowitsch #define PETSC_DEVICE_CONTEXT_DEFAULT_DEVICE PETSC_DEVICE_DEFAULT
592a4af0ceeSJacob Faibussowitsch // REMOVE ME (change)
593a4af0ceeSJacob Faibussowitsch #define PETSC_DEVICE_CONTEXT_DEFAULT_STREAM PETSC_STREAM_GLOBAL_BLOCKING
594030f984aSJacob Faibussowitsch 
595a4af0ceeSJacob Faibussowitsch static PetscDeviceType    rootDeviceType = PETSC_DEVICE_CONTEXT_DEFAULT_DEVICE;
596a4af0ceeSJacob Faibussowitsch static PetscStreamType    rootStreamType = PETSC_DEVICE_CONTEXT_DEFAULT_STREAM;
597bf025ffbSJacob Faibussowitsch static PetscDeviceContext globalContext  = nullptr;
598a4af0ceeSJacob Faibussowitsch 
599a4af0ceeSJacob Faibussowitsch /* when PetsDevice initializes PetscDeviceContext eagerly the type of device created should
600a4af0ceeSJacob Faibussowitsch  * match whatever device is eagerly intialized */
6019371c9d4SSatish Balay PetscErrorCode PetscDeviceContextSetRootDeviceType_Internal(PetscDeviceType type) {
602030f984aSJacob Faibussowitsch   PetscFunctionBegin;
603a4af0ceeSJacob Faibussowitsch   PetscValidDeviceType(type, 1);
604a4af0ceeSJacob Faibussowitsch   rootDeviceType = type;
605030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
606030f984aSJacob Faibussowitsch }
607030f984aSJacob Faibussowitsch 
608a4af0ceeSJacob Faibussowitsch #if 0
609a4af0ceeSJacob Faibussowitsch /* currently unused */
610a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetRootStreamType_Internal(PetscStreamType type)
611030f984aSJacob Faibussowitsch {
612a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
613a4af0ceeSJacob Faibussowitsch   PetscValidStreamType(type,1);
614a4af0ceeSJacob Faibussowitsch   rootStreamType = type;
615a4af0ceeSJacob Faibussowitsch   PetscFunctionReturn(0);
616a4af0ceeSJacob Faibussowitsch }
617a4af0ceeSJacob Faibussowitsch #endif
618a4af0ceeSJacob Faibussowitsch 
6199371c9d4SSatish Balay static PetscErrorCode PetscDeviceContextSetupGlobalContext_Private(void) {
620a4af0ceeSJacob Faibussowitsch   static const auto PetscDeviceContextFinalizer = []() -> PetscErrorCode {
621030f984aSJacob Faibussowitsch     PetscFunctionBegin;
6229566063dSJacob Faibussowitsch     PetscCall(PetscDeviceContextDestroy(&globalContext));
623a4af0ceeSJacob Faibussowitsch     rootDeviceType = PETSC_DEVICE_CONTEXT_DEFAULT_DEVICE;
624a4af0ceeSJacob Faibussowitsch     rootStreamType = PETSC_DEVICE_CONTEXT_DEFAULT_STREAM;
625a4af0ceeSJacob Faibussowitsch     PetscFunctionReturn(0);
626a4af0ceeSJacob Faibussowitsch   };
627a4af0ceeSJacob Faibussowitsch 
628a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
629a4af0ceeSJacob Faibussowitsch   if (globalContext) PetscFunctionReturn(0);
630a4af0ceeSJacob Faibussowitsch   /* this exists purely as a valid device check. */
6319566063dSJacob Faibussowitsch   PetscCall(PetscDeviceInitializePackage());
6329566063dSJacob Faibussowitsch   PetscCall(PetscRegisterFinalize(PetscDeviceContextFinalizer));
6339566063dSJacob Faibussowitsch   PetscCall(PetscInfo(nullptr, "Initializing global PetscDeviceContext\n"));
634a4af0ceeSJacob Faibussowitsch   /* we call the allocator directly here since the ObjectPool creates a PetscContainer which
635a4af0ceeSJacob Faibussowitsch    * eventually tries to call logging functions. However, this routine may be purposefully
636a4af0ceeSJacob Faibussowitsch    * called __before__ logging is initialized, so the logging function would PETSCABORT */
6379566063dSJacob Faibussowitsch   PetscCall(contextPool.allocator().create(&globalContext));
6389566063dSJacob Faibussowitsch   PetscCall(PetscDeviceContextSetStreamType(globalContext, rootStreamType));
6399566063dSJacob Faibussowitsch   PetscCall(PetscDeviceContextSetDefaultDeviceForType_Internal(globalContext, rootDeviceType));
6409566063dSJacob Faibussowitsch   PetscCall(PetscDeviceContextSetUp(globalContext));
641030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
642030f984aSJacob Faibussowitsch }
643030f984aSJacob Faibussowitsch 
644030f984aSJacob Faibussowitsch /*@C
645*811af0c4SBarry Smith   PetscDeviceContextGetCurrentContext - Get the current active `PetscDeviceContext`
646030f984aSJacob Faibussowitsch 
647030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
648030f984aSJacob Faibussowitsch 
649030f984aSJacob Faibussowitsch   Output Parameter:
650*811af0c4SBarry Smith . dctx - The `PetscDeviceContext`
651030f984aSJacob Faibussowitsch 
652*811af0c4SBarry Smith   Note:
653a4af0ceeSJacob Faibussowitsch   The user generally should not destroy contexts retrieved with this routine unless they
654a4af0ceeSJacob Faibussowitsch   themselves have created them. There exists no protection against destroying the root
655a4af0ceeSJacob Faibussowitsch   context.
656030f984aSJacob Faibussowitsch 
657*811af0c4SBarry Smith   Developer Note:
658a4af0ceeSJacob Faibussowitsch   Unless the user has set their own, this routine creates the "root" context the first time it
659*811af0c4SBarry Smith   is called, registering its destructor to `PetscFinalize()`.
660030f984aSJacob Faibussowitsch 
661030f984aSJacob Faibussowitsch   Level: beginner
662030f984aSJacob Faibussowitsch 
663db781477SPatrick Sanan .seealso: `PetscDeviceContextSetCurrentContext()`, `PetscDeviceContextFork()`,
664db781477SPatrick Sanan           `PetscDeviceContextJoin()`, `PetscDeviceContextCreate()`
665030f984aSJacob Faibussowitsch @*/
6669371c9d4SSatish Balay PetscErrorCode PetscDeviceContextGetCurrentContext(PetscDeviceContext *dctx) {
667a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
668a4af0ceeSJacob Faibussowitsch   PetscValidPointer(dctx, 1);
6699566063dSJacob Faibussowitsch   PetscCall(PetscDeviceContextSetupGlobalContext_Private());
670a4af0ceeSJacob Faibussowitsch   /* while the static analyzer can find global variables, it will throw a warning about not
671a4af0ceeSJacob Faibussowitsch    * being able to connect this back to the function arguments */
672a4af0ceeSJacob Faibussowitsch   PetscDisableStaticAnalyzerForExpressionUnderstandingThatThisIsDangerousAndBugprone(PetscValidDeviceContext(globalContext, -1));
673030f984aSJacob Faibussowitsch   *dctx = globalContext;
674030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
675030f984aSJacob Faibussowitsch }
676030f984aSJacob Faibussowitsch 
677030f984aSJacob Faibussowitsch /*@C
678*811af0c4SBarry Smith   PetscDeviceContextSetCurrentContext - Set the current active `PetscDeviceContext`
679030f984aSJacob Faibussowitsch 
680030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
681030f984aSJacob Faibussowitsch 
682030f984aSJacob Faibussowitsch   Input Parameter:
683*811af0c4SBarry Smith . dctx - The `PetscDeviceContext`
684030f984aSJacob Faibussowitsch 
685030f984aSJacob Faibussowitsch   Notes:
686*811af0c4SBarry Smith   This routine can be used to set the defacto "root" `PetscDeviceContext` to a user-defined
687*811af0c4SBarry Smith   implementation by calling this routine immediately after `PetscInitialize()` and ensuring that
688*811af0c4SBarry Smith   `PetscDevice` is not eagerly initialized. In this case the user is responsible for destroying
689*811af0c4SBarry Smith   their `PetscDeviceContext` before `PetscFinalize()` returns.
690a4af0ceeSJacob Faibussowitsch 
691a4af0ceeSJacob Faibussowitsch   The old context is not stored in any way by this routine; if one is overriding a context that
692a4af0ceeSJacob Faibussowitsch   they themselves do not control, one should take care to temporarily store it by calling
693*811af0c4SBarry Smith   `PetscDeviceContextGetCurrentContext()` before calling this routine.
694030f984aSJacob Faibussowitsch 
695030f984aSJacob Faibussowitsch   Level: beginner
696030f984aSJacob Faibussowitsch 
697db781477SPatrick Sanan .seealso: `PetscDeviceContextGetCurrentContext()`, `PetscDeviceContextFork()`,
698db781477SPatrick Sanan           `PetscDeviceContextJoin()`, `PetscDeviceContextCreate()`
699030f984aSJacob Faibussowitsch @*/
7009371c9d4SSatish Balay PetscErrorCode PetscDeviceContextSetCurrentContext(PetscDeviceContext dctx) {
701030f984aSJacob Faibussowitsch   PetscFunctionBegin;
702030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx, 1);
703bf025ffbSJacob Faibussowitsch   PetscAssert(dctx->setup, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "PetscDeviceContext %" PetscInt_FMT " must be set up before being set as global context", dctx->id);
704030f984aSJacob Faibussowitsch   globalContext = dctx;
7059566063dSJacob Faibussowitsch   PetscCall(PetscInfo(nullptr, "Set global PetscDeviceContext id %" PetscInt_FMT "\n", dctx->id));
706030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
707030f984aSJacob Faibussowitsch }
708030f984aSJacob Faibussowitsch 
709030f984aSJacob Faibussowitsch /*@C
710*811af0c4SBarry Smith   PetscDeviceContextSetFromOptions - Configure a `PetscDeviceContext` from the options database
711030f984aSJacob Faibussowitsch 
712030f984aSJacob Faibussowitsch   Collective on comm, Asynchronous
713030f984aSJacob Faibussowitsch 
714030f984aSJacob Faibussowitsch   Input Parameters:
715030f984aSJacob Faibussowitsch + comm   - MPI communicator on which to query the options database
716030f984aSJacob Faibussowitsch . prefix - prefix to prepend to all options database queries, NULL if not needed
717*811af0c4SBarry Smith - dctx   - The `PetscDeviceContext` to configure
718030f984aSJacob Faibussowitsch 
719030f984aSJacob Faibussowitsch   Output Parameter:
720*811af0c4SBarry Smith . dctx - The `PetscDeviceContext`
721030f984aSJacob Faibussowitsch 
722*811af0c4SBarry Smith   Options Database Keys:
723*811af0c4SBarry Smith + -device_context_stream_type - type of stream to create inside the `PetscDeviceContext` - `PetscDeviceContextSetStreamType()`
724*811af0c4SBarry Smith - -device_context_device_type - the type of `PetscDevice` to attach by default - `PetscDeviceType`
725030f984aSJacob Faibussowitsch 
726030f984aSJacob Faibussowitsch   Level: beginner
727030f984aSJacob Faibussowitsch 
728db781477SPatrick Sanan .seealso: `PetscDeviceContextSetStreamType()`, `PetscDeviceContextSetDevice()`
729030f984aSJacob Faibussowitsch @*/
7309371c9d4SSatish Balay PetscErrorCode PetscDeviceContextSetFromOptions(MPI_Comm comm, const char prefix[], PetscDeviceContext dctx) {
731030f984aSJacob Faibussowitsch   PetscBool flag;
732a4af0ceeSJacob Faibussowitsch   PetscInt  stype, dtype;
733030f984aSJacob Faibussowitsch 
734030f984aSJacob Faibussowitsch   PetscFunctionBegin;
735a4af0ceeSJacob Faibussowitsch   if (prefix) PetscValidCharPointer(prefix, 2);
736030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx, 3);
737d0609cedSBarry Smith   PetscOptionsBegin(comm, prefix, "PetscDeviceContext Options", "Sys");
7389566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEList("-device_context_stream_type", "PetscDeviceContext PetscStreamType", "PetscDeviceContextSetStreamType", PetscStreamTypes, PETSC_STREAM_MAX, PetscStreamTypes[dctx->streamType], &stype, &flag));
7399566063dSJacob Faibussowitsch   if (flag) PetscCall(PetscDeviceContextSetStreamType(dctx, static_cast<PetscStreamType>(stype)));
7409566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEList("-device_context_device_type", "Underlying PetscDevice", "PetscDeviceContextSetDevice", PetscDeviceTypes + 1, PETSC_DEVICE_MAX - 1, dctx->device ? PetscDeviceTypes[dctx->device->type] : PetscDeviceTypes[PETSC_DEVICE_CONTEXT_DEFAULT_DEVICE], &dtype, &flag));
74148a46eb9SPierre Jolivet   if (flag) PetscCall(PetscDeviceContextSetDefaultDeviceForType_Internal(dctx, static_cast<PetscDeviceType>(dtype + 1)));
742d0609cedSBarry Smith   PetscOptionsEnd();
743030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
744030f984aSJacob Faibussowitsch }
745