xref: /petsc/src/sys/objects/device/interface/dcontext.cxx (revision 48a46eb9bd028bec07ec0f396b1a3abb43f14558)
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
51030f984aSJacob Faibussowitsch   PetscDeviceContextCreate - Creates a PetscDeviceContext
52030f984aSJacob Faibussowitsch 
53030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
54030f984aSJacob Faibussowitsch 
5501d2d390SJose E. Roman   Output Paramemter:
56030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext
57030f984aSJacob Faibussowitsch 
58030f984aSJacob Faibussowitsch   Notes:
59030f984aSJacob Faibussowitsch   Unlike almost every other PETSc class it is advised that most users use
60030f984aSJacob Faibussowitsch   PetscDeviceContextDuplicate() rather than this routine to create new contexts. Contexts
61030f984aSJacob Faibussowitsch   of different types are incompatible with one another; using
62030f984aSJacob Faibussowitsch   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
79030f984aSJacob Faibussowitsch   PetscDeviceContextDestroy - Frees a PetscDeviceContext
80030f984aSJacob Faibussowitsch 
81030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
82030f984aSJacob Faibussowitsch 
83030f984aSJacob Faibussowitsch   Input Parameters:
84030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext
85030f984aSJacob Faibussowitsch 
86030f984aSJacob Faibussowitsch   Notes:
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 
91030f984aSJacob Faibussowitsch   Developer Notes:
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
109030f984aSJacob Faibussowitsch   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:
114030f984aSJacob Faibussowitsch + dctx - The PetscDeviceContext
115030f984aSJacob Faibussowitsch - type - The PetscStreamType
116030f984aSJacob Faibussowitsch 
117030f984aSJacob Faibussowitsch   Notes:
118030f984aSJacob Faibussowitsch   See PetscStreamType in include/petscdevicetypes.h for more information on the available
119030f984aSJacob Faibussowitsch   types and their interactions. If the PetscDeviceContext was previously set up and stream
120030f984aSJacob Faibussowitsch   type was changed, you must call PetscDeviceContextSetUp() again after this routine.
121030f984aSJacob Faibussowitsch 
122030f984aSJacob Faibussowitsch   Level: intermediate
123030f984aSJacob Faibussowitsch 
124db781477SPatrick Sanan .seealso: `PetscStreamType`, `PetscDeviceContextGetStreamType()`, `PetscDeviceContextCreate()`, `PetscDeviceContextSetUp()`, `PetscDeviceContextSetFromOptions()`
125030f984aSJacob Faibussowitsch @*/
1269371c9d4SSatish Balay PetscErrorCode PetscDeviceContextSetStreamType(PetscDeviceContext dctx, PetscStreamType type) {
127030f984aSJacob Faibussowitsch   PetscFunctionBegin;
128030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx, 1);
129030f984aSJacob Faibussowitsch   PetscValidStreamType(type, 2);
130030f984aSJacob Faibussowitsch   /* only need to do complex swapping if the object has already been setup */
131030f984aSJacob Faibussowitsch   if (dctx->setup && (dctx->streamType != type)) {
132dbbe0bcdSBarry Smith     PetscUseTypeMethod(dctx, changestreamtype, type);
133030f984aSJacob Faibussowitsch     dctx->setup = PETSC_FALSE;
134030f984aSJacob Faibussowitsch   }
135030f984aSJacob Faibussowitsch   dctx->streamType = type;
136030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
137030f984aSJacob Faibussowitsch }
138030f984aSJacob Faibussowitsch 
139030f984aSJacob Faibussowitsch /*@C
140030f984aSJacob Faibussowitsch   PetscDeviceContextGetStreamType - Get the implementation type of the underlying stream for a PetscDeviceContext
141030f984aSJacob Faibussowitsch 
142030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
143030f984aSJacob Faibussowitsch 
14401d2d390SJose E. Roman   Input Parameter:
145030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext
146030f984aSJacob Faibussowitsch 
147030f984aSJacob Faibussowitsch   Output Parameter:
148030f984aSJacob Faibussowitsch . type - The PetscStreamType
149030f984aSJacob Faibussowitsch 
150030f984aSJacob Faibussowitsch   Notes:
151030f984aSJacob Faibussowitsch   See PetscStreamType in include/petscdevicetypes.h for more information on the available types and their interactions
152030f984aSJacob Faibussowitsch 
153030f984aSJacob Faibussowitsch   Level: intermediate
154030f984aSJacob Faibussowitsch 
155db781477SPatrick Sanan .seealso: `PetscDeviceContextSetStreamType()`, `PetscDeviceContextCreate()`, `PetscDeviceContextSetFromOptions()`
156030f984aSJacob Faibussowitsch @*/
1579371c9d4SSatish Balay PetscErrorCode PetscDeviceContextGetStreamType(PetscDeviceContext dctx, PetscStreamType *type) {
158030f984aSJacob Faibussowitsch   PetscFunctionBegin;
159030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx, 1);
160030f984aSJacob Faibussowitsch   PetscValidIntPointer(type, 2);
161030f984aSJacob Faibussowitsch   *type = dctx->streamType;
162030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
163030f984aSJacob Faibussowitsch }
164030f984aSJacob Faibussowitsch 
165030f984aSJacob Faibussowitsch /*@C
166030f984aSJacob Faibussowitsch   PetscDeviceContextSetDevice - Set the underlying device for the PetscDeviceContext
167030f984aSJacob Faibussowitsch 
168030f984aSJacob Faibussowitsch   Not Collective, Possibly Synchronous
169030f984aSJacob Faibussowitsch 
17001d2d390SJose E. Roman   Input Parameters:
171030f984aSJacob Faibussowitsch + dctx   - The PetscDeviceContext
172030f984aSJacob Faibussowitsch - device - The PetscDevice
173030f984aSJacob Faibussowitsch 
174030f984aSJacob Faibussowitsch   Notes:
175030f984aSJacob Faibussowitsch   This routine is effectively PetscDeviceContext's "set-type" (so every PetscDeviceContext
176030f984aSJacob Faibussowitsch   must also have an attached PetscDevice). Unlike the usual set-type semantics, it is
177030f984aSJacob Faibussowitsch   not stricly necessary to set a contexts device to enable usage, any created device
178030f984aSJacob Faibussowitsch   contexts will always come equipped with the "default" device.
179030f984aSJacob Faibussowitsch 
180a4af0ceeSJacob Faibussowitsch   This routine is a no-op if dctx is already attached to device.
181a4af0ceeSJacob Faibussowitsch 
1825181c4f9SJacob Faibussowitsch   This routine may initialize the backend device and incur synchronization.
1835181c4f9SJacob Faibussowitsch 
184030f984aSJacob Faibussowitsch   Level: intermediate
185030f984aSJacob Faibussowitsch 
186db781477SPatrick Sanan .seealso: `PetscDeviceCreate()`, `PetscDeviceConfigure()`, `PetscDeviceContextGetDevice()`
187030f984aSJacob Faibussowitsch @*/
1889371c9d4SSatish Balay PetscErrorCode PetscDeviceContextSetDevice(PetscDeviceContext dctx, PetscDevice device) {
189030f984aSJacob Faibussowitsch   PetscFunctionBegin;
190030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx, 1);
191030f984aSJacob Faibussowitsch   PetscValidDevice(device, 2);
192a4af0ceeSJacob Faibussowitsch   if (dctx->device) {
193a4af0ceeSJacob Faibussowitsch     /* can't do a strict pointer equality check since PetscDevice's are reused */
194a4af0ceeSJacob Faibussowitsch     if (dctx->device->ops->createcontext == device->ops->createcontext) PetscFunctionReturn(0);
195a4af0ceeSJacob Faibussowitsch   }
1969566063dSJacob Faibussowitsch   PetscCall(PetscDeviceDestroy(&dctx->device));
197dbbe0bcdSBarry Smith   PetscTryTypeMethod(dctx, destroy);
1989566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(dctx->ops, sizeof(*dctx->ops)));
1999566063dSJacob Faibussowitsch   PetscCall((*device->ops->createcontext)(dctx));
2009566063dSJacob Faibussowitsch   PetscCall(PetscDeviceReference_Internal(device));
201a4af0ceeSJacob Faibussowitsch   dctx->device = device;
202030f984aSJacob Faibussowitsch   dctx->setup  = PETSC_FALSE;
203030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
204030f984aSJacob Faibussowitsch }
205030f984aSJacob Faibussowitsch 
206030f984aSJacob Faibussowitsch /*@C
207030f984aSJacob Faibussowitsch   PetscDeviceContextGetDevice - Get the underlying PetscDevice for a PetscDeviceContext
208030f984aSJacob Faibussowitsch 
209030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
210030f984aSJacob Faibussowitsch 
211030f984aSJacob Faibussowitsch   Input Parameter:
212030f984aSJacob Faibussowitsch . dctx - the PetscDeviceContext
213030f984aSJacob Faibussowitsch 
214030f984aSJacob Faibussowitsch   Output Parameter:
215030f984aSJacob Faibussowitsch . device - The PetscDevice
216030f984aSJacob Faibussowitsch 
217030f984aSJacob Faibussowitsch   Notes:
218030f984aSJacob Faibussowitsch   This is a borrowed reference, the user should not destroy the device.
219030f984aSJacob Faibussowitsch 
220a375dbeeSPatrick Sanan   Level: intermediate
221a375dbeeSPatrick Sanan 
222db781477SPatrick Sanan .seealso: `PetscDeviceContextSetDevice()`, `PetscDevice`
223030f984aSJacob Faibussowitsch @*/
2249371c9d4SSatish Balay PetscErrorCode PetscDeviceContextGetDevice(PetscDeviceContext dctx, PetscDevice *device) {
225030f984aSJacob Faibussowitsch   PetscFunctionBegin;
226030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx, 1);
227030f984aSJacob Faibussowitsch   PetscValidPointer(device, 2);
228bf025ffbSJacob Faibussowitsch   PetscAssert(dctx->device, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "PetscDeviceContext %" PetscInt_FMT " has no attached PetscDevice to get", dctx->id);
229030f984aSJacob Faibussowitsch   *device = dctx->device;
230030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
231030f984aSJacob Faibussowitsch }
232030f984aSJacob Faibussowitsch 
233030f984aSJacob Faibussowitsch /*@C
234030f984aSJacob Faibussowitsch   PetscDeviceContextSetUp - Prepares a PetscDeviceContext for use
235030f984aSJacob Faibussowitsch 
236030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
237030f984aSJacob Faibussowitsch 
23801d2d390SJose E. Roman   Input Parameter:
239030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext
240030f984aSJacob Faibussowitsch 
241030f984aSJacob Faibussowitsch   Developer Notes:
242030f984aSJacob Faibussowitsch   This routine is usually the stage where a PetscDeviceContext acquires device-side data structures such as streams,
243030f984aSJacob Faibussowitsch   events, and (possibly) handles.
244030f984aSJacob Faibussowitsch 
245030f984aSJacob Faibussowitsch   Level: beginner
246030f984aSJacob Faibussowitsch 
247db781477SPatrick Sanan .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextSetDevice()`, `PetscDeviceContextDestroy()`, `PetscDeviceContextSetFromOptions()`
248030f984aSJacob Faibussowitsch @*/
2499371c9d4SSatish Balay PetscErrorCode PetscDeviceContextSetUp(PetscDeviceContext dctx) {
250030f984aSJacob Faibussowitsch   PetscFunctionBegin;
251030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx, 1);
252030f984aSJacob Faibussowitsch   if (!dctx->device) {
2539566063dSJacob 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]));
2549566063dSJacob Faibussowitsch     PetscCall(PetscDeviceContextSetDefaultDevice_Internal(dctx));
255030f984aSJacob Faibussowitsch   }
256030f984aSJacob Faibussowitsch   if (dctx->setup) PetscFunctionReturn(0);
257dbbe0bcdSBarry Smith   PetscUseTypeMethod(dctx, setup);
258030f984aSJacob Faibussowitsch   dctx->setup = PETSC_TRUE;
259030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
260030f984aSJacob Faibussowitsch }
261030f984aSJacob Faibussowitsch 
262030f984aSJacob Faibussowitsch /*@C
263030f984aSJacob Faibussowitsch   PetscDeviceContextDuplicate - Duplicates a PetscDeviceContext object
264030f984aSJacob Faibussowitsch 
265030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
266030f984aSJacob Faibussowitsch 
267030f984aSJacob Faibussowitsch   Input Parameter:
268030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext to duplicate
269030f984aSJacob Faibussowitsch 
2706aad120cSJose E. Roman   Output Parameter:
271050c0c3dSJacob Faibussowitsch . dctxdup - The duplicated PetscDeviceContext
272030f984aSJacob Faibussowitsch 
273030f984aSJacob Faibussowitsch   Notes:
274030f984aSJacob Faibussowitsch   This is a shorthand method for creating a PetscDeviceContext with the exact same
275030f984aSJacob Faibussowitsch   settings as another. Note however that the duplicated PetscDeviceContext does not "share"
276030f984aSJacob Faibussowitsch   any of the underlying data with the original, (including its current stream-state) they
277030f984aSJacob Faibussowitsch   are completely separate objects.
278030f984aSJacob Faibussowitsch 
279030f984aSJacob Faibussowitsch   Level: beginner
280030f984aSJacob Faibussowitsch 
281db781477SPatrick Sanan .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextSetDevice()`, `PetscDeviceContextSetStreamType()`
282030f984aSJacob Faibussowitsch @*/
2839371c9d4SSatish Balay PetscErrorCode PetscDeviceContextDuplicate(PetscDeviceContext dctx, PetscDeviceContext *dctxdup) {
284a4af0ceeSJacob Faibussowitsch   PetscDeviceContext dup;
285030f984aSJacob Faibussowitsch 
286030f984aSJacob Faibussowitsch   PetscFunctionBegin;
287030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx, 1);
288030f984aSJacob Faibussowitsch   PetscValidPointer(dctxdup, 2);
2899566063dSJacob Faibussowitsch   PetscCall(PetscDeviceContextCreate(&dup));
2909566063dSJacob Faibussowitsch   PetscCall(PetscDeviceContextSetStreamType(dup, dctx->streamType));
2919566063dSJacob Faibussowitsch   if (dctx->device) PetscCall(PetscDeviceContextSetDevice(dup, dctx->device));
2929566063dSJacob Faibussowitsch   PetscCall(PetscDeviceContextSetUp(dup));
293a4af0ceeSJacob Faibussowitsch   *dctxdup = dup;
294030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
295030f984aSJacob Faibussowitsch }
296030f984aSJacob Faibussowitsch 
297030f984aSJacob Faibussowitsch /*@C
298030f984aSJacob Faibussowitsch   PetscDeviceContextQueryIdle - Returns whether or not a PetscDeviceContext is idle
299030f984aSJacob Faibussowitsch 
300030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
301030f984aSJacob Faibussowitsch 
302030f984aSJacob Faibussowitsch   Input Parameter:
303030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext object
304030f984aSJacob Faibussowitsch 
305030f984aSJacob Faibussowitsch   Output Parameter:
306030f984aSJacob Faibussowitsch . idle - PETSC_TRUE if PetscDeviceContext has NO work, PETSC_FALSE if it has work
307030f984aSJacob Faibussowitsch 
308030f984aSJacob Faibussowitsch   Notes:
309ef657721SJacob Faibussowitsch   This routine only refers a singular context and does NOT take any of its children into
310ef657721SJacob Faibussowitsch   account. That is, if dctx is idle but has dependents who do have work, this routine still
311ef657721SJacob Faibussowitsch   returns PETSC_TRUE.
312030f984aSJacob Faibussowitsch 
313030f984aSJacob Faibussowitsch   Level: intermediate
314030f984aSJacob Faibussowitsch 
315db781477SPatrick Sanan .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextWaitForContext()`, `PetscDeviceContextFork()`
316030f984aSJacob Faibussowitsch @*/
3179371c9d4SSatish Balay PetscErrorCode PetscDeviceContextQueryIdle(PetscDeviceContext dctx, PetscBool *idle) {
318030f984aSJacob Faibussowitsch   PetscFunctionBegin;
319030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx, 1);
320030f984aSJacob Faibussowitsch   PetscValidBoolPointer(idle, 2);
321dbbe0bcdSBarry Smith   PetscUseTypeMethod(dctx, query, idle);
3229566063dSJacob Faibussowitsch   PetscCall(PetscInfo(nullptr, "PetscDeviceContext id %" PetscInt_FMT " %s idle\n", dctx->id, *idle ? "was" : "was not"));
323030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
324030f984aSJacob Faibussowitsch }
325030f984aSJacob Faibussowitsch 
326030f984aSJacob Faibussowitsch /*@C
327030f984aSJacob Faibussowitsch   PetscDeviceContextWaitForContext - Make one context wait for another context to finish
328030f984aSJacob Faibussowitsch 
329030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
330030f984aSJacob Faibussowitsch 
331030f984aSJacob Faibussowitsch   Input Parameters:
332030f984aSJacob Faibussowitsch + dctxa - The PetscDeviceContext object that is waiting
333030f984aSJacob Faibussowitsch - dctxb - The PetscDeviceContext object that is being waited on
334030f984aSJacob Faibussowitsch 
335030f984aSJacob Faibussowitsch   Notes:
336030f984aSJacob Faibussowitsch   Serializes two PetscDeviceContexts. This routine uses only the state of dctxb at the moment this routine was
337030f984aSJacob Faibussowitsch   called, so any future work queued will not affect dctxa. It is safe to pass the same context to both arguments.
338030f984aSJacob Faibussowitsch 
339030f984aSJacob Faibussowitsch   Level: beginner
340030f984aSJacob Faibussowitsch 
341db781477SPatrick Sanan .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextQueryIdle()`, `PetscDeviceContextJoin()`
342030f984aSJacob Faibussowitsch @*/
3439371c9d4SSatish Balay PetscErrorCode PetscDeviceContextWaitForContext(PetscDeviceContext dctxa, PetscDeviceContext dctxb) {
344030f984aSJacob Faibussowitsch   PetscFunctionBegin;
345030f984aSJacob Faibussowitsch   PetscCheckCompatibleDeviceContexts(dctxa, 1, dctxb, 2);
346030f984aSJacob Faibussowitsch   if (dctxa == dctxb) PetscFunctionReturn(0);
347dbbe0bcdSBarry Smith   PetscUseTypeMethod(dctxa, waitforcontext, dctxb);
348030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
349030f984aSJacob Faibussowitsch }
350030f984aSJacob Faibussowitsch 
351050c0c3dSJacob Faibussowitsch #define PETSC_USE_DEBUG_AND_INFO (PetscDefined(USE_DEBUG) && PetscDefined(USE_INFO))
352050c0c3dSJacob Faibussowitsch #if PETSC_USE_DEBUG_AND_INFO
353050c0c3dSJacob Faibussowitsch #include <string>
354050c0c3dSJacob Faibussowitsch #endif
355030f984aSJacob Faibussowitsch /*@C
356030f984aSJacob Faibussowitsch   PetscDeviceContextFork - Create a set of dependent child contexts from a parent context
357030f984aSJacob Faibussowitsch 
358030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
359030f984aSJacob Faibussowitsch 
360030f984aSJacob Faibussowitsch   Input Parameters:
361030f984aSJacob Faibussowitsch + dctx - The parent PetscDeviceContext
362030f984aSJacob Faibussowitsch - n    - The number of children to create
363030f984aSJacob Faibussowitsch 
364030f984aSJacob Faibussowitsch   Output Parameter:
365030f984aSJacob Faibussowitsch . dsub - The created child context(s)
366030f984aSJacob Faibussowitsch 
367030f984aSJacob Faibussowitsch   Notes:
368030f984aSJacob Faibussowitsch   This routine creates n edges of a DAG from a source node which are causally dependent on the source node, meaning
369030f984aSJacob Faibussowitsch   that work queued on child contexts will not start until the parent context finishes its work. This accounts for work
370030f984aSJacob Faibussowitsch   queued on the parent up until calling this function, any subsequent work enqueued on the parent has no effect on the children.
371030f984aSJacob Faibussowitsch 
372030f984aSJacob Faibussowitsch   Any children created with this routine have their lifetimes bounded by the parent. That is, the parent context expects
373030f984aSJacob Faibussowitsch   to free all of it's children (and ONLY its children) before itself is freed.
374030f984aSJacob Faibussowitsch 
375030f984aSJacob Faibussowitsch   DAG representation:
376030f984aSJacob Faibussowitsch .vb
377030f984aSJacob Faibussowitsch   time ->
378030f984aSJacob Faibussowitsch 
379030f984aSJacob Faibussowitsch   -> dctx \----> dctx ------>
380030f984aSJacob Faibussowitsch            \---> dsub[0] --->
381030f984aSJacob Faibussowitsch             \--> ... ------->
382030f984aSJacob Faibussowitsch              \-> dsub[n-1] ->
383030f984aSJacob Faibussowitsch .ve
384030f984aSJacob Faibussowitsch 
385030f984aSJacob Faibussowitsch   Level: intermediate
386030f984aSJacob Faibussowitsch 
387db781477SPatrick Sanan .seealso: `PetscDeviceContextJoin()`, `PetscDeviceContextSynchronize()`, `PetscDeviceContextQueryIdle()`
388030f984aSJacob Faibussowitsch @*/
3899371c9d4SSatish Balay PetscErrorCode PetscDeviceContextFork(PetscDeviceContext dctx, PetscInt n, PetscDeviceContext **dsub) {
390050c0c3dSJacob Faibussowitsch #if PETSC_USE_DEBUG_AND_INFO
391030f984aSJacob Faibussowitsch   const PetscInt     nBefore = n;
392030f984aSJacob Faibussowitsch   static std::string idList;
393030f984aSJacob Faibussowitsch #endif
394bf025ffbSJacob Faibussowitsch   PetscDeviceContext *dsubTmp = nullptr;
395030f984aSJacob Faibussowitsch   PetscInt            i       = 0;
396030f984aSJacob Faibussowitsch 
397030f984aSJacob Faibussowitsch   PetscFunctionBegin;
398030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx, 1);
399030f984aSJacob Faibussowitsch   PetscValidPointer(dsub, 3);
400bf025ffbSJacob Faibussowitsch   PetscAssert(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of contexts requested %" PetscInt_FMT " < 0", n);
4013ca90d2dSJacob Faibussowitsch #if PETSC_USE_DEBUG_AND_INFO
402030f984aSJacob Faibussowitsch   /* reserve 4 chars per id, 2 for number and 2 for ', ' separator */
403030f984aSJacob Faibussowitsch   idList.reserve(4 * n);
404030f984aSJacob Faibussowitsch #endif
405030f984aSJacob Faibussowitsch   /* update child totals */
406030f984aSJacob Faibussowitsch   dctx->numChildren += n;
407030f984aSJacob Faibussowitsch   /* now to find out if we have room */
408030f984aSJacob Faibussowitsch   if (dctx->numChildren > dctx->maxNumChildren) {
409030f984aSJacob Faibussowitsch     /* no room, either from having too many kids or not having any */
410030f984aSJacob Faibussowitsch     if (dctx->childIDs) {
411030f984aSJacob Faibussowitsch       /* have existing children, must reallocate them */
4129566063dSJacob Faibussowitsch       PetscCall(PetscRealloc(dctx->numChildren * sizeof(*dctx->childIDs), &dctx->childIDs));
413030f984aSJacob Faibussowitsch       /* clear the extra memory since realloc doesn't do it for us */
4149566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero((dctx->childIDs) + (dctx->maxNumChildren), (dctx->numChildren) - (dctx->maxNumChildren)));
415030f984aSJacob Faibussowitsch     } else {
416030f984aSJacob Faibussowitsch       /* have no children */
4179566063dSJacob Faibussowitsch       PetscCall(PetscCalloc1(dctx->numChildren, &dctx->childIDs));
418030f984aSJacob Faibussowitsch     }
419030f984aSJacob Faibussowitsch     /* update total number of children */
420030f984aSJacob Faibussowitsch     dctx->maxNumChildren = dctx->numChildren;
421030f984aSJacob Faibussowitsch   }
4229566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &dsubTmp));
423030f984aSJacob Faibussowitsch   while (n) {
424030f984aSJacob Faibussowitsch     /* empty child slot */
425030f984aSJacob Faibussowitsch     if (!(dctx->childIDs[i])) {
426030f984aSJacob Faibussowitsch       /* create the child context in the image of its parent */
4279566063dSJacob Faibussowitsch       PetscCall(PetscDeviceContextDuplicate(dctx, dsubTmp + i));
4289566063dSJacob Faibussowitsch       PetscCall(PetscDeviceContextWaitForContext(dsubTmp[i], dctx));
429030f984aSJacob Faibussowitsch       /* register the child with its parent */
430030f984aSJacob Faibussowitsch       dctx->childIDs[i] = dsubTmp[i]->id;
431050c0c3dSJacob Faibussowitsch #if PETSC_USE_DEBUG_AND_INFO
432030f984aSJacob Faibussowitsch       idList += std::to_string(dsubTmp[i]->id);
433030f984aSJacob Faibussowitsch       if (n != 1) idList += ", ";
434030f984aSJacob Faibussowitsch #endif
435030f984aSJacob Faibussowitsch       --n;
436030f984aSJacob Faibussowitsch     }
437030f984aSJacob Faibussowitsch     ++i;
438030f984aSJacob Faibussowitsch   }
4393ca90d2dSJacob Faibussowitsch #if PETSC_USE_DEBUG_AND_INFO
4409566063dSJacob Faibussowitsch   PetscCall(PetscInfo(nullptr, "Forked %" PetscInt_FMT " children from parent %" PetscInt_FMT " with IDs: %s\n", nBefore, dctx->id, idList.c_str()));
441030f984aSJacob Faibussowitsch   /* resets the size but doesn't deallocate the memory */
442030f984aSJacob Faibussowitsch   idList.clear();
443030f984aSJacob Faibussowitsch #endif
444030f984aSJacob Faibussowitsch   /* pass the children back to caller */
445030f984aSJacob Faibussowitsch   *dsub = dsubTmp;
446030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
447030f984aSJacob Faibussowitsch }
448030f984aSJacob Faibussowitsch 
449030f984aSJacob Faibussowitsch /*@C
4505181c4f9SJacob Faibussowitsch   PetscDeviceContextJoin - Converge a set of child contexts
451030f984aSJacob Faibussowitsch 
452030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
453030f984aSJacob Faibussowitsch 
454030f984aSJacob Faibussowitsch   Input Parameters:
455030f984aSJacob Faibussowitsch + dctx         - A PetscDeviceContext to converge on
456030f984aSJacob Faibussowitsch . n            - The number of sub contexts to converge
457030f984aSJacob Faibussowitsch . joinMode     - The type of join to perform
458030f984aSJacob Faibussowitsch - dsub         - The sub contexts to converge
459030f984aSJacob Faibussowitsch 
460030f984aSJacob Faibussowitsch   Notes:
461030f984aSJacob Faibussowitsch   If PetscDeviceContextFork() creates n edges from a source node which all depend on the
462030f984aSJacob Faibussowitsch   source node, then this routine is the exact mirror. That is, it creates a node
463030f984aSJacob Faibussowitsch   (represented in dctx) which recieves n edges (and optionally destroys them) which is
464030f984aSJacob Faibussowitsch   dependent on the completion of all incoming edges.
465030f984aSJacob Faibussowitsch 
466030f984aSJacob Faibussowitsch   If joinMode is PETSC_DEVICE_CONTEXT_JOIN_DESTROY all contexts in dsub will be destroyed
467030f984aSJacob Faibussowitsch   by this routine. Thus all sub contexts must have been created with the dctx passed to
468030f984aSJacob Faibussowitsch   this routine.
469030f984aSJacob Faibussowitsch 
470030f984aSJacob Faibussowitsch   if joinMode is PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC dctx waits for all sub contexts but the
471030f984aSJacob Faibussowitsch   sub contexts do not wait for one another afterwards.
472030f984aSJacob Faibussowitsch 
473030f984aSJacob Faibussowitsch   If joinMode is PETSC_DEVICE_CONTEXT_JOIN_SYNC all sub contexts will additionally
474030f984aSJacob Faibussowitsch   wait on dctx after converging. This has the effect of "synchronizing" the outgoing
475030f984aSJacob Faibussowitsch   edges.
476030f984aSJacob Faibussowitsch 
477030f984aSJacob Faibussowitsch   DAG representations:
478030f984aSJacob Faibussowitsch   If joinMode is PETSC_DEVICE_CONTEXT_JOIN_DESTROY
479030f984aSJacob Faibussowitsch .vb
480030f984aSJacob Faibussowitsch   time ->
481030f984aSJacob Faibussowitsch 
482030f984aSJacob Faibussowitsch   -> dctx ---------/- dctx ->
483030f984aSJacob Faibussowitsch   -> dsub[0] -----/
484030f984aSJacob Faibussowitsch   ->  ... -------/
485030f984aSJacob Faibussowitsch   -> dsub[n-1] -/
486030f984aSJacob Faibussowitsch .ve
487030f984aSJacob Faibussowitsch   If joinMode is PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC
488030f984aSJacob Faibussowitsch .vb
489030f984aSJacob Faibussowitsch   time ->
490030f984aSJacob Faibussowitsch 
491030f984aSJacob Faibussowitsch   -> dctx ---------/- dctx ->
492030f984aSJacob Faibussowitsch   -> dsub[0] -----/--------->
493030f984aSJacob Faibussowitsch   ->  ... -------/---------->
494030f984aSJacob Faibussowitsch   -> dsub[n-1] -/----------->
495030f984aSJacob Faibussowitsch .ve
496030f984aSJacob Faibussowitsch   If joinMode is PETSC_DEVICE_CONTEXT_JOIN_SYNC
497030f984aSJacob Faibussowitsch .vb
498030f984aSJacob Faibussowitsch   time ->
499030f984aSJacob Faibussowitsch 
500030f984aSJacob Faibussowitsch   -> dctx ---------/- dctx -\----> dctx ------>
501030f984aSJacob Faibussowitsch   -> dsub[0] -----/          \---> dsub[0] --->
502030f984aSJacob Faibussowitsch   ->  ... -------/            \--> ... ------->
503030f984aSJacob Faibussowitsch   -> dsub[n-1] -/              \-> dsub[n-1] ->
504030f984aSJacob Faibussowitsch .ve
505030f984aSJacob Faibussowitsch 
506030f984aSJacob Faibussowitsch   Level: intermediate
507030f984aSJacob Faibussowitsch 
508db781477SPatrick Sanan .seealso: `PetscDeviceContextFork()`, `PetscDeviceContextSynchronize()`, `PetscDeviceContextJoinMode`
509030f984aSJacob Faibussowitsch @*/
5109371c9d4SSatish Balay PetscErrorCode PetscDeviceContextJoin(PetscDeviceContext dctx, PetscInt n, PetscDeviceContextJoinMode joinMode, PetscDeviceContext **dsub) {
511030f984aSJacob Faibussowitsch #if defined(PETSC_USE_DEBUG) && defined(PETSC_USE_INFO)
512030f984aSJacob Faibussowitsch   static std::string idList;
513030f984aSJacob Faibussowitsch #endif
514030f984aSJacob Faibussowitsch 
515030f984aSJacob Faibussowitsch   PetscFunctionBegin;
516030f984aSJacob Faibussowitsch   /* validity of dctx is checked in the wait-for loop */
517030f984aSJacob Faibussowitsch   PetscValidPointer(dsub, 4);
518bf025ffbSJacob Faibussowitsch   PetscAssert(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of contexts merged %" PetscInt_FMT " < 0", n);
519030f984aSJacob Faibussowitsch #if defined(PETSC_USE_DEBUG) && defined(PETSC_USE_INFO)
520030f984aSJacob Faibussowitsch   /* reserve 4 chars per id, 2 for number and 2 for ', ' separator */
521030f984aSJacob Faibussowitsch   idList.reserve(4 * n);
522030f984aSJacob Faibussowitsch #endif
523030f984aSJacob Faibussowitsch   /* first dctx waits on all the incoming edges */
524030f984aSJacob Faibussowitsch   for (PetscInt i = 0; i < n; ++i) {
525030f984aSJacob Faibussowitsch     PetscCheckCompatibleDeviceContexts(dctx, 1, (*dsub)[i], 4);
5269566063dSJacob Faibussowitsch     PetscCall(PetscDeviceContextWaitForContext(dctx, (*dsub)[i]));
527030f984aSJacob Faibussowitsch #if defined(PETSC_USE_DEBUG) && defined(PETSC_USE_INFO)
528030f984aSJacob Faibussowitsch     idList += std::to_string((*dsub)[i]->id);
529030f984aSJacob Faibussowitsch     if (i + 1 < n) idList += ", ";
530030f984aSJacob Faibussowitsch #endif
531030f984aSJacob Faibussowitsch   }
532030f984aSJacob Faibussowitsch 
533030f984aSJacob Faibussowitsch   /* now we handle the aftermath */
534030f984aSJacob Faibussowitsch   switch (joinMode) {
5359371c9d4SSatish Balay   case PETSC_DEVICE_CONTEXT_JOIN_DESTROY: {
536030f984aSJacob Faibussowitsch     PetscInt j = 0;
537030f984aSJacob Faibussowitsch 
538bf025ffbSJacob 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);
539030f984aSJacob Faibussowitsch     /* update child count while it's still fresh in memory */
540030f984aSJacob Faibussowitsch     dctx->numChildren -= n;
541030f984aSJacob Faibussowitsch     for (PetscInt i = 0; i < dctx->maxNumChildren; ++i) {
542030f984aSJacob Faibussowitsch       if (dctx->childIDs[i] && (dctx->childIDs[i] == (*dsub)[j]->id)) {
543030f984aSJacob Faibussowitsch         /* child is one of ours, can destroy it */
5449566063dSJacob Faibussowitsch         PetscCall(PetscDeviceContextDestroy((*dsub) + j));
545030f984aSJacob Faibussowitsch         /* reset the child slot */
546030f984aSJacob Faibussowitsch         dctx->childIDs[i] = 0;
547030f984aSJacob Faibussowitsch         if (++j == n) break;
548030f984aSJacob Faibussowitsch       }
549030f984aSJacob Faibussowitsch     }
550030f984aSJacob 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 */
551bf025ffbSJacob 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);
5529566063dSJacob Faibussowitsch     PetscCall(PetscFree(*dsub));
5539371c9d4SSatish Balay   } break;
554030f984aSJacob Faibussowitsch   case PETSC_DEVICE_CONTEXT_JOIN_SYNC:
5559566063dSJacob Faibussowitsch     for (PetscInt i = 0; i < n; ++i) PetscCall(PetscDeviceContextWaitForContext((*dsub)[i], dctx));
5569371c9d4SSatish Balay   case PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC: break;
5579371c9d4SSatish Balay   default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown PetscDeviceContextJoinMode given");
558030f984aSJacob Faibussowitsch   }
559030f984aSJacob Faibussowitsch 
560030f984aSJacob Faibussowitsch #if defined(PETSC_USE_DEBUG) && defined(PETSC_USE_INFO)
5619566063dSJacob 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()));
562030f984aSJacob Faibussowitsch   idList.clear();
563030f984aSJacob Faibussowitsch #endif
564030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
565030f984aSJacob Faibussowitsch }
566030f984aSJacob Faibussowitsch 
567030f984aSJacob Faibussowitsch /*@C
5685181c4f9SJacob Faibussowitsch   PetscDeviceContextSynchronize - Block the host until all work queued on or associated with a PetscDeviceContext has finished
569030f984aSJacob Faibussowitsch 
570030f984aSJacob Faibussowitsch   Not Collective, Synchronous
571030f984aSJacob Faibussowitsch 
572030f984aSJacob Faibussowitsch   Input Parameters:
573030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext to synchronize
574030f984aSJacob Faibussowitsch 
575030f984aSJacob Faibussowitsch   Level: beginner
576030f984aSJacob Faibussowitsch 
577db781477SPatrick Sanan .seealso: `PetscDeviceContextFork()`, `PetscDeviceContextJoin()`, `PetscDeviceContextQueryIdle()`
578030f984aSJacob Faibussowitsch @*/
5799371c9d4SSatish Balay PetscErrorCode PetscDeviceContextSynchronize(PetscDeviceContext dctx) {
580030f984aSJacob Faibussowitsch   PetscFunctionBegin;
581030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx, 1);
582030f984aSJacob Faibussowitsch   /* if it isn't setup there is nothing to sync on */
583dbbe0bcdSBarry Smith   if (dctx->setup) PetscUseTypeMethod(dctx, synchronize);
584030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
585030f984aSJacob Faibussowitsch }
586030f984aSJacob Faibussowitsch 
587a4af0ceeSJacob Faibussowitsch #define PETSC_DEVICE_CONTEXT_DEFAULT_DEVICE PETSC_DEVICE_DEFAULT
588a4af0ceeSJacob Faibussowitsch // REMOVE ME (change)
589a4af0ceeSJacob Faibussowitsch #define PETSC_DEVICE_CONTEXT_DEFAULT_STREAM PETSC_STREAM_GLOBAL_BLOCKING
590030f984aSJacob Faibussowitsch 
591a4af0ceeSJacob Faibussowitsch static PetscDeviceType    rootDeviceType = PETSC_DEVICE_CONTEXT_DEFAULT_DEVICE;
592a4af0ceeSJacob Faibussowitsch static PetscStreamType    rootStreamType = PETSC_DEVICE_CONTEXT_DEFAULT_STREAM;
593bf025ffbSJacob Faibussowitsch static PetscDeviceContext globalContext  = nullptr;
594a4af0ceeSJacob Faibussowitsch 
595a4af0ceeSJacob Faibussowitsch /* when PetsDevice initializes PetscDeviceContext eagerly the type of device created should
596a4af0ceeSJacob Faibussowitsch  * match whatever device is eagerly intialized */
5979371c9d4SSatish Balay PetscErrorCode PetscDeviceContextSetRootDeviceType_Internal(PetscDeviceType type) {
598030f984aSJacob Faibussowitsch   PetscFunctionBegin;
599a4af0ceeSJacob Faibussowitsch   PetscValidDeviceType(type, 1);
600a4af0ceeSJacob Faibussowitsch   rootDeviceType = type;
601030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
602030f984aSJacob Faibussowitsch }
603030f984aSJacob Faibussowitsch 
604a4af0ceeSJacob Faibussowitsch #if 0
605a4af0ceeSJacob Faibussowitsch /* currently unused */
606a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetRootStreamType_Internal(PetscStreamType type)
607030f984aSJacob Faibussowitsch {
608a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
609a4af0ceeSJacob Faibussowitsch   PetscValidStreamType(type,1);
610a4af0ceeSJacob Faibussowitsch   rootStreamType = type;
611a4af0ceeSJacob Faibussowitsch   PetscFunctionReturn(0);
612a4af0ceeSJacob Faibussowitsch }
613a4af0ceeSJacob Faibussowitsch #endif
614a4af0ceeSJacob Faibussowitsch 
6159371c9d4SSatish Balay static PetscErrorCode PetscDeviceContextSetupGlobalContext_Private(void) {
616a4af0ceeSJacob Faibussowitsch   static const auto PetscDeviceContextFinalizer = []() -> PetscErrorCode {
617030f984aSJacob Faibussowitsch     PetscFunctionBegin;
6189566063dSJacob Faibussowitsch     PetscCall(PetscDeviceContextDestroy(&globalContext));
619a4af0ceeSJacob Faibussowitsch     rootDeviceType = PETSC_DEVICE_CONTEXT_DEFAULT_DEVICE;
620a4af0ceeSJacob Faibussowitsch     rootStreamType = PETSC_DEVICE_CONTEXT_DEFAULT_STREAM;
621a4af0ceeSJacob Faibussowitsch     PetscFunctionReturn(0);
622a4af0ceeSJacob Faibussowitsch   };
623a4af0ceeSJacob Faibussowitsch 
624a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
625a4af0ceeSJacob Faibussowitsch   if (globalContext) PetscFunctionReturn(0);
626a4af0ceeSJacob Faibussowitsch   /* this exists purely as a valid device check. */
6279566063dSJacob Faibussowitsch   PetscCall(PetscDeviceInitializePackage());
6289566063dSJacob Faibussowitsch   PetscCall(PetscRegisterFinalize(PetscDeviceContextFinalizer));
6299566063dSJacob Faibussowitsch   PetscCall(PetscInfo(nullptr, "Initializing global PetscDeviceContext\n"));
630a4af0ceeSJacob Faibussowitsch   /* we call the allocator directly here since the ObjectPool creates a PetscContainer which
631a4af0ceeSJacob Faibussowitsch    * eventually tries to call logging functions. However, this routine may be purposefully
632a4af0ceeSJacob Faibussowitsch    * called __before__ logging is initialized, so the logging function would PETSCABORT */
6339566063dSJacob Faibussowitsch   PetscCall(contextPool.allocator().create(&globalContext));
6349566063dSJacob Faibussowitsch   PetscCall(PetscDeviceContextSetStreamType(globalContext, rootStreamType));
6359566063dSJacob Faibussowitsch   PetscCall(PetscDeviceContextSetDefaultDeviceForType_Internal(globalContext, rootDeviceType));
6369566063dSJacob Faibussowitsch   PetscCall(PetscDeviceContextSetUp(globalContext));
637030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
638030f984aSJacob Faibussowitsch }
639030f984aSJacob Faibussowitsch 
640030f984aSJacob Faibussowitsch /*@C
6415181c4f9SJacob Faibussowitsch   PetscDeviceContextGetCurrentContext - Get the current active PetscDeviceContext
642030f984aSJacob Faibussowitsch 
643030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
644030f984aSJacob Faibussowitsch 
645030f984aSJacob Faibussowitsch   Output Parameter:
646030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext
647030f984aSJacob Faibussowitsch 
648030f984aSJacob Faibussowitsch   Notes:
649a4af0ceeSJacob Faibussowitsch   The user generally should not destroy contexts retrieved with this routine unless they
650a4af0ceeSJacob Faibussowitsch   themselves have created them. There exists no protection against destroying the root
651a4af0ceeSJacob Faibussowitsch   context.
652030f984aSJacob Faibussowitsch 
653030f984aSJacob Faibussowitsch   Developer Notes:
654a4af0ceeSJacob Faibussowitsch   Unless the user has set their own, this routine creates the "root" context the first time it
655a4af0ceeSJacob Faibussowitsch   is called, registering its destructor to PetscFinalize().
656030f984aSJacob Faibussowitsch 
657030f984aSJacob Faibussowitsch   Level: beginner
658030f984aSJacob Faibussowitsch 
659db781477SPatrick Sanan .seealso: `PetscDeviceContextSetCurrentContext()`, `PetscDeviceContextFork()`,
660db781477SPatrick Sanan           `PetscDeviceContextJoin()`, `PetscDeviceContextCreate()`
661030f984aSJacob Faibussowitsch @*/
6629371c9d4SSatish Balay PetscErrorCode PetscDeviceContextGetCurrentContext(PetscDeviceContext *dctx) {
663a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
664a4af0ceeSJacob Faibussowitsch   PetscValidPointer(dctx, 1);
6659566063dSJacob Faibussowitsch   PetscCall(PetscDeviceContextSetupGlobalContext_Private());
666a4af0ceeSJacob Faibussowitsch   /* while the static analyzer can find global variables, it will throw a warning about not
667a4af0ceeSJacob Faibussowitsch    * being able to connect this back to the function arguments */
668a4af0ceeSJacob Faibussowitsch   PetscDisableStaticAnalyzerForExpressionUnderstandingThatThisIsDangerousAndBugprone(PetscValidDeviceContext(globalContext, -1));
669030f984aSJacob Faibussowitsch   *dctx = globalContext;
670030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
671030f984aSJacob Faibussowitsch }
672030f984aSJacob Faibussowitsch 
673030f984aSJacob Faibussowitsch /*@C
6745181c4f9SJacob Faibussowitsch   PetscDeviceContextSetCurrentContext - Set the current active PetscDeviceContext
675030f984aSJacob Faibussowitsch 
676030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
677030f984aSJacob Faibussowitsch 
678030f984aSJacob Faibussowitsch   Input Parameter:
679030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext
680030f984aSJacob Faibussowitsch 
681030f984aSJacob Faibussowitsch   Notes:
682a4af0ceeSJacob Faibussowitsch   This routine can be used to set the defacto "root" PetscDeviceContext to a user-defined
683a4af0ceeSJacob Faibussowitsch   implementation by calling this routine immediately after PetscInitialize() and ensuring that
684a4af0ceeSJacob Faibussowitsch   PetscDevice is not greedily intialized. In this case the user is responsible for destroying
685a4af0ceeSJacob Faibussowitsch   their PetscDeviceContext before PetscFinalize() returns.
686a4af0ceeSJacob Faibussowitsch 
687a4af0ceeSJacob Faibussowitsch   The old context is not stored in any way by this routine; if one is overriding a context that
688a4af0ceeSJacob Faibussowitsch   they themselves do not control, one should take care to temporarily store it by calling
689a4af0ceeSJacob Faibussowitsch   PetscDeviceContextGetCurrentContext() before calling this routine.
690030f984aSJacob Faibussowitsch 
691030f984aSJacob Faibussowitsch   Level: beginner
692030f984aSJacob Faibussowitsch 
693db781477SPatrick Sanan .seealso: `PetscDeviceContextGetCurrentContext()`, `PetscDeviceContextFork()`,
694db781477SPatrick Sanan           `PetscDeviceContextJoin()`, `PetscDeviceContextCreate()`
695030f984aSJacob Faibussowitsch @*/
6969371c9d4SSatish Balay PetscErrorCode PetscDeviceContextSetCurrentContext(PetscDeviceContext dctx) {
697030f984aSJacob Faibussowitsch   PetscFunctionBegin;
698030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx, 1);
699bf025ffbSJacob 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);
700030f984aSJacob Faibussowitsch   globalContext = dctx;
7019566063dSJacob Faibussowitsch   PetscCall(PetscInfo(nullptr, "Set global PetscDeviceContext id %" PetscInt_FMT "\n", dctx->id));
702030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
703030f984aSJacob Faibussowitsch }
704030f984aSJacob Faibussowitsch 
705030f984aSJacob Faibussowitsch /*@C
706030f984aSJacob Faibussowitsch   PetscDeviceContextSetFromOptions - Configure a PetscDeviceContext from the options database
707030f984aSJacob Faibussowitsch 
708030f984aSJacob Faibussowitsch   Collective on comm, Asynchronous
709030f984aSJacob Faibussowitsch 
710030f984aSJacob Faibussowitsch   Input Parameters:
711030f984aSJacob Faibussowitsch + comm   - MPI communicator on which to query the options database
712030f984aSJacob Faibussowitsch . prefix - prefix to prepend to all options database queries, NULL if not needed
713030f984aSJacob Faibussowitsch - dctx   - The PetscDeviceContext to configure
714030f984aSJacob Faibussowitsch 
715030f984aSJacob Faibussowitsch   Output Parameter:
716030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext
717030f984aSJacob Faibussowitsch 
718030f984aSJacob Faibussowitsch   Options Database:
719a4af0ceeSJacob Faibussowitsch + -device_context_stream_type - type of stream to create inside the PetscDeviceContext -
720030f984aSJacob Faibussowitsch    PetscDeviceContextSetStreamType()
721a4af0ceeSJacob Faibussowitsch - -device_context_device_type - the type of PetscDevice to attach by default - PetscDeviceType
722030f984aSJacob Faibussowitsch 
723030f984aSJacob Faibussowitsch   Level: beginner
724030f984aSJacob Faibussowitsch 
725db781477SPatrick Sanan .seealso: `PetscDeviceContextSetStreamType()`, `PetscDeviceContextSetDevice()`
726030f984aSJacob Faibussowitsch @*/
7279371c9d4SSatish Balay PetscErrorCode PetscDeviceContextSetFromOptions(MPI_Comm comm, const char prefix[], PetscDeviceContext dctx) {
728030f984aSJacob Faibussowitsch   PetscBool flag;
729a4af0ceeSJacob Faibussowitsch   PetscInt  stype, dtype;
730030f984aSJacob Faibussowitsch 
731030f984aSJacob Faibussowitsch   PetscFunctionBegin;
732a4af0ceeSJacob Faibussowitsch   if (prefix) PetscValidCharPointer(prefix, 2);
733030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx, 3);
734d0609cedSBarry Smith   PetscOptionsBegin(comm, prefix, "PetscDeviceContext Options", "Sys");
7359566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEList("-device_context_stream_type", "PetscDeviceContext PetscStreamType", "PetscDeviceContextSetStreamType", PetscStreamTypes, PETSC_STREAM_MAX, PetscStreamTypes[dctx->streamType], &stype, &flag));
7369566063dSJacob Faibussowitsch   if (flag) PetscCall(PetscDeviceContextSetStreamType(dctx, static_cast<PetscStreamType>(stype)));
7379566063dSJacob 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));
738*48a46eb9SPierre Jolivet   if (flag) PetscCall(PetscDeviceContextSetDefaultDeviceForType_Internal(dctx, static_cast<PetscDeviceType>(dtype + 1)));
739d0609cedSBarry Smith   PetscOptionsEnd();
740030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
741030f984aSJacob Faibussowitsch }
742