xref: /petsc/src/sys/objects/device/interface/dcontext.cxx (revision 91e63d38360eb9bc922f79d792328cc4769c01ac)
1030f984aSJacob Faibussowitsch #include <petsc/private/deviceimpl.h> /*I "petscdevice.h" I*/
2030f984aSJacob Faibussowitsch #include "objpool.hpp"
3030f984aSJacob Faibussowitsch 
4a4af0ceeSJacob Faibussowitsch const char *const PetscStreamTypes[] = {
5a4af0ceeSJacob Faibussowitsch   "global_blocking",
6a4af0ceeSJacob Faibussowitsch   "default_blocking",
7a4af0ceeSJacob Faibussowitsch   "global_nonblocking",
8a4af0ceeSJacob Faibussowitsch   "max",
9a4af0ceeSJacob Faibussowitsch   "PetscStreamType",
10a4af0ceeSJacob Faibussowitsch   "PETSC_STREAM_",
11bf025ffbSJacob Faibussowitsch   nullptr
12a4af0ceeSJacob Faibussowitsch };
13a4af0ceeSJacob Faibussowitsch 
14a4af0ceeSJacob Faibussowitsch const char *const PetscDeviceContextJoinModes[] = {
15a4af0ceeSJacob Faibussowitsch   "destroy",
16a4af0ceeSJacob Faibussowitsch   "sync",
17a4af0ceeSJacob Faibussowitsch   "no_sync",
18a4af0ceeSJacob Faibussowitsch   "PetscDeviceContextJoinMode",
19a4af0ceeSJacob Faibussowitsch   "PETSC_DEVICE_CONTEXT_JOIN_",
20bf025ffbSJacob Faibussowitsch   nullptr
21a4af0ceeSJacob Faibussowitsch };
22a4af0ceeSJacob Faibussowitsch 
23030f984aSJacob Faibussowitsch /* Define the allocator */
2417f48955SJacob Faibussowitsch struct PetscDeviceContextAllocator : Petsc::AllocatorBase<PetscDeviceContext>
25030f984aSJacob Faibussowitsch {
26030f984aSJacob Faibussowitsch   static PetscInt PetscDeviceContextID;
27030f984aSJacob Faibussowitsch 
2817f48955SJacob Faibussowitsch   PETSC_NODISCARD static PetscErrorCode create(PetscDeviceContext *dctx) noexcept
29030f984aSJacob Faibussowitsch   {
30030f984aSJacob Faibussowitsch     PetscDeviceContext dc;
31030f984aSJacob Faibussowitsch     PetscErrorCode     ierr;
32030f984aSJacob Faibussowitsch 
33030f984aSJacob Faibussowitsch     PetscFunctionBegin;
34030f984aSJacob Faibussowitsch     ierr           = PetscNew(&dc);CHKERRQ(ierr);
35030f984aSJacob Faibussowitsch     dc->id         = PetscDeviceContextID++;
36030f984aSJacob Faibussowitsch     dc->streamType = PETSC_STREAM_DEFAULT_BLOCKING;
37030f984aSJacob Faibussowitsch     *dctx          = dc;
38030f984aSJacob Faibussowitsch     PetscFunctionReturn(0);
39030f984aSJacob Faibussowitsch   }
40030f984aSJacob Faibussowitsch 
4117f48955SJacob Faibussowitsch   PETSC_NODISCARD static PetscErrorCode destroy(PetscDeviceContext dctx) noexcept
42030f984aSJacob Faibussowitsch   {
43030f984aSJacob Faibussowitsch     PetscErrorCode ierr;
44030f984aSJacob Faibussowitsch 
45030f984aSJacob Faibussowitsch     PetscFunctionBegin;
46bf025ffbSJacob 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);
47030f984aSJacob Faibussowitsch     if (dctx->ops->destroy) {ierr = (*dctx->ops->destroy)(dctx);CHKERRQ(ierr);}
48030f984aSJacob Faibussowitsch     ierr = PetscDeviceDestroy(&dctx->device);CHKERRQ(ierr);
49030f984aSJacob Faibussowitsch     ierr = PetscFree(dctx->childIDs);CHKERRQ(ierr);
50030f984aSJacob Faibussowitsch     ierr = PetscFree(dctx);CHKERRQ(ierr);
51030f984aSJacob Faibussowitsch     PetscFunctionReturn(0);
52030f984aSJacob Faibussowitsch   }
53030f984aSJacob Faibussowitsch 
5417f48955SJacob Faibussowitsch   PETSC_NODISCARD static PetscErrorCode reset(PetscDeviceContext dctx) noexcept
55030f984aSJacob Faibussowitsch   {
56030f984aSJacob Faibussowitsch     PetscErrorCode ierr;
57030f984aSJacob Faibussowitsch 
58030f984aSJacob Faibussowitsch     PetscFunctionBegin;
59030f984aSJacob Faibussowitsch     /* don't deallocate the child array, rather just zero it out */
60030f984aSJacob Faibussowitsch     ierr = PetscArrayzero(dctx->childIDs,dctx->maxNumChildren);CHKERRQ(ierr);
61030f984aSJacob Faibussowitsch     dctx->setup       = PETSC_FALSE;
62030f984aSJacob Faibussowitsch     dctx->numChildren = 0;
63030f984aSJacob Faibussowitsch     dctx->streamType  = PETSC_STREAM_DEFAULT_BLOCKING;
64030f984aSJacob Faibussowitsch     PetscFunctionReturn(0);
65030f984aSJacob Faibussowitsch   }
66030f984aSJacob Faibussowitsch 
6717f48955SJacob Faibussowitsch   PETSC_NODISCARD static constexpr PetscErrorCode finalize() noexcept { return 0; }
68030f984aSJacob Faibussowitsch };
69a4af0ceeSJacob Faibussowitsch /* an ID = 0 is invalid */
70a4af0ceeSJacob Faibussowitsch PetscInt PetscDeviceContextAllocator::PetscDeviceContextID = 1;
71030f984aSJacob Faibussowitsch 
72030f984aSJacob Faibussowitsch static Petsc::ObjectPool<PetscDeviceContext,PetscDeviceContextAllocator> contextPool;
73030f984aSJacob Faibussowitsch 
74030f984aSJacob Faibussowitsch /*@C
75030f984aSJacob Faibussowitsch   PetscDeviceContextCreate - Creates a PetscDeviceContext
76030f984aSJacob Faibussowitsch 
77030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
78030f984aSJacob Faibussowitsch 
7901d2d390SJose E. Roman   Output Paramemter:
80030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext
81030f984aSJacob Faibussowitsch 
82030f984aSJacob Faibussowitsch   Notes:
83030f984aSJacob Faibussowitsch   Unlike almost every other PETSc class it is advised that most users use
84030f984aSJacob Faibussowitsch   PetscDeviceContextDuplicate() rather than this routine to create new contexts. Contexts
85030f984aSJacob Faibussowitsch   of different types are incompatible with one another; using
86030f984aSJacob Faibussowitsch   PetscDeviceContextDuplicate() ensures compatible types.
87030f984aSJacob Faibussowitsch 
88030f984aSJacob Faibussowitsch   Level: beginner
89030f984aSJacob Faibussowitsch 
90030f984aSJacob Faibussowitsch .seealso: PetscDeviceContextDuplicate(), PetscDeviceContextSetDevice(),
915181c4f9SJacob Faibussowitsch PetscDeviceContextSetStreamType(), PetscDeviceContextSetUp(),
925181c4f9SJacob Faibussowitsch PetscDeviceContextSetFromOptions(), PetscDeviceContextDestroy()
93030f984aSJacob Faibussowitsch @*/
94030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextCreate(PetscDeviceContext *dctx)
95030f984aSJacob Faibussowitsch {
96030f984aSJacob Faibussowitsch   PetscErrorCode ierr;
97030f984aSJacob Faibussowitsch 
98030f984aSJacob Faibussowitsch   PetscFunctionBegin;
99030f984aSJacob Faibussowitsch   PetscValidPointer(dctx,1);
100030f984aSJacob Faibussowitsch   ierr = PetscDeviceInitializePackage();CHKERRQ(ierr);
101030f984aSJacob Faibussowitsch   ierr = contextPool.get(*dctx);CHKERRQ(ierr);
102030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
103030f984aSJacob Faibussowitsch }
104030f984aSJacob Faibussowitsch 
105030f984aSJacob Faibussowitsch /*@C
106030f984aSJacob Faibussowitsch   PetscDeviceContextDestroy - Frees a PetscDeviceContext
107030f984aSJacob Faibussowitsch 
108030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
109030f984aSJacob Faibussowitsch 
110030f984aSJacob Faibussowitsch   Input Parameters:
111030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext
112030f984aSJacob Faibussowitsch 
113030f984aSJacob Faibussowitsch   Notes:
114030f984aSJacob Faibussowitsch   No implicit synchronization occurs due to this routine, all resources are released completely asynchronously
115030f984aSJacob Faibussowitsch   w.r.t. the host. If one needs to guarantee access to the data produced on this contexts stream one should perform the
116030f984aSJacob Faibussowitsch   appropriate synchronization before calling this routine.
117030f984aSJacob Faibussowitsch 
118030f984aSJacob Faibussowitsch   Developer Notes:
119030f984aSJacob Faibussowitsch   The context is never actually "destroyed", only returned to an ever growing pool of
120030f984aSJacob Faibussowitsch   contexts. There are currently no safeguards on the size of the pool, this should perhaps
121030f984aSJacob Faibussowitsch   be implemented.
122030f984aSJacob Faibussowitsch 
123030f984aSJacob Faibussowitsch   Level: beginner
124030f984aSJacob Faibussowitsch 
125030f984aSJacob Faibussowitsch .seealso: PetscDeviceContextCreate(), PetscDeviceContextSetDevice(), PetscDeviceContextSetUp(), PetscDeviceContextSynchronize()
126030f984aSJacob Faibussowitsch @*/
127030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextDestroy(PetscDeviceContext *dctx)
128030f984aSJacob Faibussowitsch {
129030f984aSJacob Faibussowitsch   PetscErrorCode ierr;
130030f984aSJacob Faibussowitsch 
131030f984aSJacob Faibussowitsch   PetscFunctionBegin;
132030f984aSJacob Faibussowitsch   if (!*dctx) PetscFunctionReturn(0);
133030f984aSJacob Faibussowitsch   ierr  = contextPool.reclaim(std::move(*dctx));CHKERRQ(ierr);
134bf025ffbSJacob Faibussowitsch   *dctx = nullptr;
135030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
136030f984aSJacob Faibussowitsch }
137030f984aSJacob Faibussowitsch 
138030f984aSJacob Faibussowitsch /*@C
139030f984aSJacob Faibussowitsch   PetscDeviceContextSetStreamType - Set the implementation type of the underlying stream for a PetscDeviceContext
140030f984aSJacob Faibussowitsch 
141030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
142030f984aSJacob Faibussowitsch 
14301d2d390SJose E. Roman   Input Parameters:
144030f984aSJacob Faibussowitsch + dctx - The PetscDeviceContext
145030f984aSJacob Faibussowitsch - type - The PetscStreamType
146030f984aSJacob Faibussowitsch 
147030f984aSJacob Faibussowitsch   Notes:
148030f984aSJacob Faibussowitsch   See PetscStreamType in include/petscdevicetypes.h for more information on the available
149030f984aSJacob Faibussowitsch   types and their interactions. If the PetscDeviceContext was previously set up and stream
150030f984aSJacob Faibussowitsch   type was changed, you must call PetscDeviceContextSetUp() again after this routine.
151030f984aSJacob Faibussowitsch 
152030f984aSJacob Faibussowitsch   Level: intermediate
153030f984aSJacob Faibussowitsch 
154*91e63d38SStefano Zampini .seealso: PetscStreamType, PetscDeviceContextGetStreamType(), PetscDeviceContextCreate(), PetscDeviceContextSetUp(), PetscDeviceContextSetFromOptions()
155030f984aSJacob Faibussowitsch @*/
156030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetStreamType(PetscDeviceContext dctx, PetscStreamType type)
157030f984aSJacob Faibussowitsch {
158030f984aSJacob Faibussowitsch   PetscFunctionBegin;
159030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx,1);
160030f984aSJacob Faibussowitsch   PetscValidStreamType(type,2);
161030f984aSJacob Faibussowitsch   /* only need to do complex swapping if the object has already been setup */
162030f984aSJacob Faibussowitsch   if (dctx->setup && (dctx->streamType != type)) {
163030f984aSJacob Faibussowitsch     PetscErrorCode ierr;
164030f984aSJacob Faibussowitsch 
165030f984aSJacob Faibussowitsch     ierr = (*dctx->ops->changestreamtype)(dctx,type);CHKERRQ(ierr);
166030f984aSJacob Faibussowitsch     dctx->setup = PETSC_FALSE;
167030f984aSJacob Faibussowitsch   }
168030f984aSJacob Faibussowitsch   dctx->streamType = type;
169030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
170030f984aSJacob Faibussowitsch }
171030f984aSJacob Faibussowitsch 
172030f984aSJacob Faibussowitsch /*@C
173030f984aSJacob Faibussowitsch   PetscDeviceContextGetStreamType - Get the implementation type of the underlying stream for a PetscDeviceContext
174030f984aSJacob Faibussowitsch 
175030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
176030f984aSJacob Faibussowitsch 
17701d2d390SJose E. Roman   Input Parameter:
178030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext
179030f984aSJacob Faibussowitsch 
180030f984aSJacob Faibussowitsch   Output Parameter:
181030f984aSJacob Faibussowitsch . type - The PetscStreamType
182030f984aSJacob Faibussowitsch 
183030f984aSJacob Faibussowitsch   Notes:
184030f984aSJacob Faibussowitsch   See PetscStreamType in include/petscdevicetypes.h for more information on the available types and their interactions
185030f984aSJacob Faibussowitsch 
186030f984aSJacob Faibussowitsch   Level: intermediate
187030f984aSJacob Faibussowitsch 
1885181c4f9SJacob Faibussowitsch .seealso: PetscDeviceContextSetStreamType(), PetscDeviceContextCreate(), PetscDeviceContextSetFromOptions()
189030f984aSJacob Faibussowitsch @*/
190030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextGetStreamType(PetscDeviceContext dctx, PetscStreamType *type)
191030f984aSJacob Faibussowitsch {
192030f984aSJacob Faibussowitsch   PetscFunctionBegin;
193030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx,1);
194030f984aSJacob Faibussowitsch   PetscValidIntPointer(type,2);
195030f984aSJacob Faibussowitsch   *type = dctx->streamType;
196030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
197030f984aSJacob Faibussowitsch }
198030f984aSJacob Faibussowitsch 
199030f984aSJacob Faibussowitsch /*@C
200030f984aSJacob Faibussowitsch   PetscDeviceContextSetDevice - Set the underlying device for the PetscDeviceContext
201030f984aSJacob Faibussowitsch 
202030f984aSJacob Faibussowitsch   Not Collective, Possibly Synchronous
203030f984aSJacob Faibussowitsch 
20401d2d390SJose E. Roman   Input Parameters:
205030f984aSJacob Faibussowitsch + dctx   - The PetscDeviceContext
206030f984aSJacob Faibussowitsch - device - The PetscDevice
207030f984aSJacob Faibussowitsch 
208030f984aSJacob Faibussowitsch   Notes:
209030f984aSJacob Faibussowitsch   This routine is effectively PetscDeviceContext's "set-type" (so every PetscDeviceContext
210030f984aSJacob Faibussowitsch   must also have an attached PetscDevice). Unlike the usual set-type semantics, it is
211030f984aSJacob Faibussowitsch   not stricly necessary to set a contexts device to enable usage, any created device
212030f984aSJacob Faibussowitsch   contexts will always come equipped with the "default" device.
213030f984aSJacob Faibussowitsch 
214a4af0ceeSJacob Faibussowitsch   This routine is a no-op if dctx is already attached to device.
215a4af0ceeSJacob Faibussowitsch 
2165181c4f9SJacob Faibussowitsch   This routine may initialize the backend device and incur synchronization.
2175181c4f9SJacob Faibussowitsch 
218030f984aSJacob Faibussowitsch   Level: intermediate
219030f984aSJacob Faibussowitsch 
2205181c4f9SJacob Faibussowitsch .seealso: PetscDeviceCreate(), PetscDeviceConfigure(), PetscDeviceContextGetDevice()
221030f984aSJacob Faibussowitsch @*/
222030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetDevice(PetscDeviceContext dctx, PetscDevice device)
223030f984aSJacob Faibussowitsch {
224030f984aSJacob Faibussowitsch   PetscErrorCode ierr;
225030f984aSJacob Faibussowitsch 
226030f984aSJacob Faibussowitsch   PetscFunctionBegin;
227030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx,1);
228030f984aSJacob Faibussowitsch   PetscValidDevice(device,2);
229a4af0ceeSJacob Faibussowitsch   if (dctx->device) {
230a4af0ceeSJacob Faibussowitsch     /* can't do a strict pointer equality check since PetscDevice's are reused */
231a4af0ceeSJacob Faibussowitsch     if (dctx->device->ops->createcontext == device->ops->createcontext) PetscFunctionReturn(0);
232a4af0ceeSJacob Faibussowitsch   }
233030f984aSJacob Faibussowitsch   ierr = PetscDeviceDestroy(&dctx->device);CHKERRQ(ierr);
234a4af0ceeSJacob Faibussowitsch   if (dctx->ops->destroy) {ierr = (*dctx->ops->destroy)(dctx);CHKERRQ(ierr);}
235030f984aSJacob Faibussowitsch   ierr = PetscMemzero(dctx->ops,sizeof(*dctx->ops));CHKERRQ(ierr);
236030f984aSJacob Faibussowitsch   ierr = (*device->ops->createcontext)(dctx);CHKERRQ(ierr);
237a4af0ceeSJacob Faibussowitsch   ierr = PetscDeviceReference_Internal(device);CHKERRQ(ierr);
238a4af0ceeSJacob Faibussowitsch   dctx->device = device;
239030f984aSJacob Faibussowitsch   dctx->setup  = PETSC_FALSE;
240030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
241030f984aSJacob Faibussowitsch }
242030f984aSJacob Faibussowitsch 
243030f984aSJacob Faibussowitsch /*@C
244030f984aSJacob Faibussowitsch   PetscDeviceContextGetDevice - Get the underlying PetscDevice for a PetscDeviceContext
245030f984aSJacob Faibussowitsch 
246030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
247030f984aSJacob Faibussowitsch 
248030f984aSJacob Faibussowitsch   Input Parameter:
249030f984aSJacob Faibussowitsch . dctx - the PetscDeviceContext
250030f984aSJacob Faibussowitsch 
251030f984aSJacob Faibussowitsch   Output Parameter:
252030f984aSJacob Faibussowitsch . device - The PetscDevice
253030f984aSJacob Faibussowitsch 
254030f984aSJacob Faibussowitsch   Notes:
255030f984aSJacob Faibussowitsch   This is a borrowed reference, the user should not destroy the device.
256030f984aSJacob Faibussowitsch 
257a375dbeeSPatrick Sanan   Level: intermediate
258a375dbeeSPatrick Sanan 
259030f984aSJacob Faibussowitsch .seealso: PetscDeviceContextSetDevice(), PetscDevice
260030f984aSJacob Faibussowitsch @*/
261030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextGetDevice(PetscDeviceContext dctx, PetscDevice *device)
262030f984aSJacob Faibussowitsch {
263030f984aSJacob Faibussowitsch   PetscFunctionBegin;
264030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx,1);
265030f984aSJacob Faibussowitsch   PetscValidPointer(device,2);
266bf025ffbSJacob Faibussowitsch   PetscAssert(dctx->device,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"PetscDeviceContext %" PetscInt_FMT " has no attached PetscDevice to get",dctx->id);
267030f984aSJacob Faibussowitsch   *device = dctx->device;
268030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
269030f984aSJacob Faibussowitsch }
270030f984aSJacob Faibussowitsch 
271030f984aSJacob Faibussowitsch /*@C
272030f984aSJacob Faibussowitsch   PetscDeviceContextSetUp - Prepares a PetscDeviceContext for use
273030f984aSJacob Faibussowitsch 
274030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
275030f984aSJacob Faibussowitsch 
27601d2d390SJose E. Roman   Input Parameter:
277030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext
278030f984aSJacob Faibussowitsch 
279030f984aSJacob Faibussowitsch   Developer Notes:
280030f984aSJacob Faibussowitsch   This routine is usually the stage where a PetscDeviceContext acquires device-side data structures such as streams,
281030f984aSJacob Faibussowitsch   events, and (possibly) handles.
282030f984aSJacob Faibussowitsch 
283030f984aSJacob Faibussowitsch   Level: beginner
284030f984aSJacob Faibussowitsch 
2855181c4f9SJacob Faibussowitsch .seealso: PetscDeviceContextCreate(), PetscDeviceContextSetDevice(), PetscDeviceContextDestroy(), PetscDeviceContextSetFromOptions()
286030f984aSJacob Faibussowitsch @*/
287030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetUp(PetscDeviceContext dctx)
288030f984aSJacob Faibussowitsch {
289030f984aSJacob Faibussowitsch   PetscErrorCode ierr;
290030f984aSJacob Faibussowitsch 
291030f984aSJacob Faibussowitsch   PetscFunctionBegin;
292030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx,1);
293030f984aSJacob Faibussowitsch   if (!dctx->device) {
294bf025ffbSJacob Faibussowitsch     ierr = PetscInfo(nullptr,"PetscDeviceContext %" PetscInt_FMT " did not have an explicitly attached PetscDevice, using default with type %s\n",dctx->id,PetscDeviceTypes[PETSC_DEVICE_DEFAULT]);CHKERRQ(ierr);
295a4af0ceeSJacob Faibussowitsch     ierr = PetscDeviceContextSetDefaultDevice_Internal(dctx);CHKERRQ(ierr);
296030f984aSJacob Faibussowitsch   }
297030f984aSJacob Faibussowitsch   if (dctx->setup) PetscFunctionReturn(0);
298030f984aSJacob Faibussowitsch   ierr = (*dctx->ops->setup)(dctx);CHKERRQ(ierr);
299030f984aSJacob Faibussowitsch   dctx->setup = PETSC_TRUE;
300030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
301030f984aSJacob Faibussowitsch }
302030f984aSJacob Faibussowitsch 
303030f984aSJacob Faibussowitsch /*@C
304030f984aSJacob Faibussowitsch   PetscDeviceContextDuplicate - Duplicates a PetscDeviceContext object
305030f984aSJacob Faibussowitsch 
306030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
307030f984aSJacob Faibussowitsch 
308030f984aSJacob Faibussowitsch   Input Parameter:
309030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext to duplicate
310030f984aSJacob Faibussowitsch 
311030f984aSJacob Faibussowitsch   Output Paramter:
312050c0c3dSJacob Faibussowitsch . dctxdup - The duplicated PetscDeviceContext
313030f984aSJacob Faibussowitsch 
314030f984aSJacob Faibussowitsch   Notes:
315030f984aSJacob Faibussowitsch   This is a shorthand method for creating a PetscDeviceContext with the exact same
316030f984aSJacob Faibussowitsch   settings as another. Note however that the duplicated PetscDeviceContext does not "share"
317030f984aSJacob Faibussowitsch   any of the underlying data with the original, (including its current stream-state) they
318030f984aSJacob Faibussowitsch   are completely separate objects.
319030f984aSJacob Faibussowitsch 
320030f984aSJacob Faibussowitsch   Level: beginner
321030f984aSJacob Faibussowitsch 
322030f984aSJacob Faibussowitsch .seealso: PetscDeviceContextCreate(), PetscDeviceContextSetDevice(), PetscDeviceContextSetStreamType()
323030f984aSJacob Faibussowitsch @*/
324030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextDuplicate(PetscDeviceContext dctx, PetscDeviceContext *dctxdup)
325030f984aSJacob Faibussowitsch {
326a4af0ceeSJacob Faibussowitsch   PetscDeviceContext dup;
327030f984aSJacob Faibussowitsch   PetscErrorCode     ierr;
328030f984aSJacob Faibussowitsch 
329030f984aSJacob Faibussowitsch   PetscFunctionBegin;
330030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx,1);
331030f984aSJacob Faibussowitsch   PetscValidPointer(dctxdup,2);
332a4af0ceeSJacob Faibussowitsch   ierr = PetscDeviceContextCreate(&dup);CHKERRQ(ierr);
333a4af0ceeSJacob Faibussowitsch   ierr = PetscDeviceContextSetStreamType(dup,dctx->streamType);CHKERRQ(ierr);
334a4af0ceeSJacob Faibussowitsch   if (dctx->device) {ierr = PetscDeviceContextSetDevice(dup,dctx->device);CHKERRQ(ierr);}
335a4af0ceeSJacob Faibussowitsch   ierr = PetscDeviceContextSetUp(dup);CHKERRQ(ierr);
336a4af0ceeSJacob Faibussowitsch   *dctxdup = dup;
337030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
338030f984aSJacob Faibussowitsch }
339030f984aSJacob Faibussowitsch 
340030f984aSJacob Faibussowitsch /*@C
341030f984aSJacob Faibussowitsch   PetscDeviceContextQueryIdle - Returns whether or not a PetscDeviceContext is idle
342030f984aSJacob Faibussowitsch 
343030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
344030f984aSJacob Faibussowitsch 
345030f984aSJacob Faibussowitsch   Input Parameter:
346030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext object
347030f984aSJacob Faibussowitsch 
348030f984aSJacob Faibussowitsch   Output Parameter:
349030f984aSJacob Faibussowitsch . idle - PETSC_TRUE if PetscDeviceContext has NO work, PETSC_FALSE if it has work
350030f984aSJacob Faibussowitsch 
351030f984aSJacob Faibussowitsch   Notes:
352ef657721SJacob Faibussowitsch   This routine only refers a singular context and does NOT take any of its children into
353ef657721SJacob Faibussowitsch   account. That is, if dctx is idle but has dependents who do have work, this routine still
354ef657721SJacob Faibussowitsch   returns PETSC_TRUE.
355030f984aSJacob Faibussowitsch 
356030f984aSJacob Faibussowitsch   Level: intermediate
357030f984aSJacob Faibussowitsch 
358030f984aSJacob Faibussowitsch .seealso: PetscDeviceContextCreate(), PetscDeviceContextWaitForContext(), PetscDeviceContextFork()
359030f984aSJacob Faibussowitsch @*/
360030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextQueryIdle(PetscDeviceContext dctx, PetscBool *idle)
361030f984aSJacob Faibussowitsch {
362030f984aSJacob Faibussowitsch   PetscErrorCode ierr;
363030f984aSJacob Faibussowitsch 
364030f984aSJacob Faibussowitsch   PetscFunctionBegin;
365030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx,1);
366030f984aSJacob Faibussowitsch   PetscValidBoolPointer(idle,2);
367030f984aSJacob Faibussowitsch   ierr = (*dctx->ops->query)(dctx,idle);CHKERRQ(ierr);
368ef657721SJacob Faibussowitsch   ierr = PetscInfo(nullptr,"PetscDeviceContext id %" PetscInt_FMT " %s idle\n",dctx->id,*idle ? "was" : "was not");CHKERRQ(ierr);
369030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
370030f984aSJacob Faibussowitsch }
371030f984aSJacob Faibussowitsch 
372030f984aSJacob Faibussowitsch /*@C
373030f984aSJacob Faibussowitsch   PetscDeviceContextWaitForContext - Make one context wait for another context to finish
374030f984aSJacob Faibussowitsch 
375030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
376030f984aSJacob Faibussowitsch 
377030f984aSJacob Faibussowitsch   Input Parameters:
378030f984aSJacob Faibussowitsch + dctxa - The PetscDeviceContext object that is waiting
379030f984aSJacob Faibussowitsch - dctxb - The PetscDeviceContext object that is being waited on
380030f984aSJacob Faibussowitsch 
381030f984aSJacob Faibussowitsch   Notes:
382030f984aSJacob Faibussowitsch   Serializes two PetscDeviceContexts. This routine uses only the state of dctxb at the moment this routine was
383030f984aSJacob Faibussowitsch   called, so any future work queued will not affect dctxa. It is safe to pass the same context to both arguments.
384030f984aSJacob Faibussowitsch 
385030f984aSJacob Faibussowitsch   Level: beginner
386030f984aSJacob Faibussowitsch 
387030f984aSJacob Faibussowitsch .seealso: PetscDeviceContextCreate(), PetscDeviceContextQueryIdle(), PetscDeviceContextJoin()
388030f984aSJacob Faibussowitsch @*/
389030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextWaitForContext(PetscDeviceContext dctxa, PetscDeviceContext dctxb)
390030f984aSJacob Faibussowitsch {
391030f984aSJacob Faibussowitsch   PetscErrorCode ierr;
392030f984aSJacob Faibussowitsch 
393030f984aSJacob Faibussowitsch   PetscFunctionBegin;
394030f984aSJacob Faibussowitsch   PetscCheckCompatibleDeviceContexts(dctxa,1,dctxb,2);
395030f984aSJacob Faibussowitsch   if (dctxa == dctxb) PetscFunctionReturn(0);
39617f48955SJacob Faibussowitsch   ierr = (*dctxa->ops->waitforcontext)(dctxa,dctxb);CHKERRQ(ierr);
397030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
398030f984aSJacob Faibussowitsch }
399030f984aSJacob Faibussowitsch 
400050c0c3dSJacob Faibussowitsch #define PETSC_USE_DEBUG_AND_INFO (PetscDefined(USE_DEBUG) && PetscDefined(USE_INFO))
401050c0c3dSJacob Faibussowitsch #if PETSC_USE_DEBUG_AND_INFO
402050c0c3dSJacob Faibussowitsch #include <string>
403050c0c3dSJacob Faibussowitsch #endif
404030f984aSJacob Faibussowitsch /*@C
405030f984aSJacob Faibussowitsch   PetscDeviceContextFork - Create a set of dependent child contexts from a parent context
406030f984aSJacob Faibussowitsch 
407030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
408030f984aSJacob Faibussowitsch 
409030f984aSJacob Faibussowitsch   Input Parameters:
410030f984aSJacob Faibussowitsch + dctx - The parent PetscDeviceContext
411030f984aSJacob Faibussowitsch - n    - The number of children to create
412030f984aSJacob Faibussowitsch 
413030f984aSJacob Faibussowitsch   Output Parameter:
414030f984aSJacob Faibussowitsch . dsub - The created child context(s)
415030f984aSJacob Faibussowitsch 
416030f984aSJacob Faibussowitsch   Notes:
417030f984aSJacob Faibussowitsch   This routine creates n edges of a DAG from a source node which are causally dependent on the source node, meaning
418030f984aSJacob Faibussowitsch   that work queued on child contexts will not start until the parent context finishes its work. This accounts for work
419030f984aSJacob Faibussowitsch   queued on the parent up until calling this function, any subsequent work enqueued on the parent has no effect on the children.
420030f984aSJacob Faibussowitsch 
421030f984aSJacob Faibussowitsch   Any children created with this routine have their lifetimes bounded by the parent. That is, the parent context expects
422030f984aSJacob Faibussowitsch   to free all of it's children (and ONLY its children) before itself is freed.
423030f984aSJacob Faibussowitsch 
424030f984aSJacob Faibussowitsch   DAG representation:
425030f984aSJacob Faibussowitsch .vb
426030f984aSJacob Faibussowitsch   time ->
427030f984aSJacob Faibussowitsch 
428030f984aSJacob Faibussowitsch   -> dctx \----> dctx ------>
429030f984aSJacob Faibussowitsch            \---> dsub[0] --->
430030f984aSJacob Faibussowitsch             \--> ... ------->
431030f984aSJacob Faibussowitsch              \-> dsub[n-1] ->
432030f984aSJacob Faibussowitsch .ve
433030f984aSJacob Faibussowitsch 
434030f984aSJacob Faibussowitsch   Level: intermediate
435030f984aSJacob Faibussowitsch 
436030f984aSJacob Faibussowitsch .seealso: PetscDeviceContextJoin(), PetscDeviceContextSynchronize(), PetscDeviceContextQueryIdle()
437030f984aSJacob Faibussowitsch @*/
438030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextFork(PetscDeviceContext dctx, PetscInt n, PetscDeviceContext **dsub)
439030f984aSJacob Faibussowitsch {
440050c0c3dSJacob Faibussowitsch #if PETSC_USE_DEBUG_AND_INFO
441030f984aSJacob Faibussowitsch   const PetscInt      nBefore = n;
442030f984aSJacob Faibussowitsch   static std::string  idList;
443030f984aSJacob Faibussowitsch #endif
444bf025ffbSJacob Faibussowitsch   PetscDeviceContext *dsubTmp = nullptr;
445030f984aSJacob Faibussowitsch   PetscInt            i = 0;
446030f984aSJacob Faibussowitsch   PetscErrorCode      ierr;
447030f984aSJacob Faibussowitsch 
448030f984aSJacob Faibussowitsch   PetscFunctionBegin;
449030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx,1);
450030f984aSJacob Faibussowitsch   PetscValidPointer(dsub,3);
451bf025ffbSJacob Faibussowitsch   PetscAssert(n >= 0,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Number of contexts requested %" PetscInt_FMT " < 0",n);
4523ca90d2dSJacob Faibussowitsch #if PETSC_USE_DEBUG_AND_INFO
453030f984aSJacob Faibussowitsch   /* reserve 4 chars per id, 2 for number and 2 for ', ' separator */
454030f984aSJacob Faibussowitsch   idList.reserve(4*n);
455030f984aSJacob Faibussowitsch #endif
456030f984aSJacob Faibussowitsch   /* update child totals */
457030f984aSJacob Faibussowitsch   dctx->numChildren += n;
458030f984aSJacob Faibussowitsch   /* now to find out if we have room */
459030f984aSJacob Faibussowitsch   if (dctx->numChildren > dctx->maxNumChildren) {
460030f984aSJacob Faibussowitsch     /* no room, either from having too many kids or not having any */
461030f984aSJacob Faibussowitsch     if (dctx->childIDs) {
462030f984aSJacob Faibussowitsch       /* have existing children, must reallocate them */
463030f984aSJacob Faibussowitsch       ierr = PetscRealloc(dctx->numChildren*sizeof(*dctx->childIDs),&dctx->childIDs);CHKERRQ(ierr);
464030f984aSJacob Faibussowitsch       /* clear the extra memory since realloc doesn't do it for us */
465030f984aSJacob Faibussowitsch       ierr = PetscArrayzero((dctx->childIDs)+(dctx->maxNumChildren),(dctx->numChildren)-(dctx->maxNumChildren));CHKERRQ(ierr);
466030f984aSJacob Faibussowitsch     } else {
467030f984aSJacob Faibussowitsch       /* have no children */
468030f984aSJacob Faibussowitsch       ierr = PetscCalloc1(dctx->numChildren,&dctx->childIDs);CHKERRQ(ierr);
469030f984aSJacob Faibussowitsch     }
470030f984aSJacob Faibussowitsch     /* update total number of children */
471030f984aSJacob Faibussowitsch     dctx->maxNumChildren = dctx->numChildren;
472030f984aSJacob Faibussowitsch   }
473030f984aSJacob Faibussowitsch   ierr = PetscMalloc1(n,&dsubTmp);CHKERRQ(ierr);
474030f984aSJacob Faibussowitsch   while (n) {
475030f984aSJacob Faibussowitsch     /* empty child slot */
476030f984aSJacob Faibussowitsch     if (!(dctx->childIDs[i])) {
477030f984aSJacob Faibussowitsch       /* create the child context in the image of its parent */
478030f984aSJacob Faibussowitsch       ierr = PetscDeviceContextDuplicate(dctx,dsubTmp+i);CHKERRQ(ierr);
479030f984aSJacob Faibussowitsch       ierr = PetscDeviceContextWaitForContext(dsubTmp[i],dctx);CHKERRQ(ierr);
480030f984aSJacob Faibussowitsch       /* register the child with its parent */
481030f984aSJacob Faibussowitsch       dctx->childIDs[i] = dsubTmp[i]->id;
482050c0c3dSJacob Faibussowitsch #if PETSC_USE_DEBUG_AND_INFO
483030f984aSJacob Faibussowitsch       idList += std::to_string(dsubTmp[i]->id);
484030f984aSJacob Faibussowitsch       if (n != 1) idList += ", ";
485030f984aSJacob Faibussowitsch #endif
486030f984aSJacob Faibussowitsch       --n;
487030f984aSJacob Faibussowitsch     }
488030f984aSJacob Faibussowitsch     ++i;
489030f984aSJacob Faibussowitsch   }
4903ca90d2dSJacob Faibussowitsch #if PETSC_USE_DEBUG_AND_INFO
491bf025ffbSJacob Faibussowitsch   ierr = PetscInfo(nullptr,"Forked %" PetscInt_FMT " children from parent %" PetscInt_FMT " with IDs: %s\n",nBefore,dctx->id,idList.c_str());CHKERRQ(ierr);
492030f984aSJacob Faibussowitsch   /* resets the size but doesn't deallocate the memory */
493030f984aSJacob Faibussowitsch   idList.clear();
494030f984aSJacob Faibussowitsch #endif
495030f984aSJacob Faibussowitsch   /* pass the children back to caller */
496030f984aSJacob Faibussowitsch   *dsub = dsubTmp;
497030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
498030f984aSJacob Faibussowitsch }
499030f984aSJacob Faibussowitsch 
500030f984aSJacob Faibussowitsch /*@C
5015181c4f9SJacob Faibussowitsch   PetscDeviceContextJoin - Converge a set of child contexts
502030f984aSJacob Faibussowitsch 
503030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
504030f984aSJacob Faibussowitsch 
505030f984aSJacob Faibussowitsch   Input Parameters:
506030f984aSJacob Faibussowitsch + dctx         - A PetscDeviceContext to converge on
507030f984aSJacob Faibussowitsch . n            - The number of sub contexts to converge
508030f984aSJacob Faibussowitsch . joinMode     - The type of join to perform
509030f984aSJacob Faibussowitsch - dsub         - The sub contexts to converge
510030f984aSJacob Faibussowitsch 
511030f984aSJacob Faibussowitsch   Notes:
512030f984aSJacob Faibussowitsch   If PetscDeviceContextFork() creates n edges from a source node which all depend on the
513030f984aSJacob Faibussowitsch   source node, then this routine is the exact mirror. That is, it creates a node
514030f984aSJacob Faibussowitsch   (represented in dctx) which recieves n edges (and optionally destroys them) which is
515030f984aSJacob Faibussowitsch   dependent on the completion of all incoming edges.
516030f984aSJacob Faibussowitsch 
517030f984aSJacob Faibussowitsch   If joinMode is PETSC_DEVICE_CONTEXT_JOIN_DESTROY all contexts in dsub will be destroyed
518030f984aSJacob Faibussowitsch   by this routine. Thus all sub contexts must have been created with the dctx passed to
519030f984aSJacob Faibussowitsch   this routine.
520030f984aSJacob Faibussowitsch 
521030f984aSJacob Faibussowitsch   if joinMode is PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC dctx waits for all sub contexts but the
522030f984aSJacob Faibussowitsch   sub contexts do not wait for one another afterwards.
523030f984aSJacob Faibussowitsch 
524030f984aSJacob Faibussowitsch   If joinMode is PETSC_DEVICE_CONTEXT_JOIN_SYNC all sub contexts will additionally
525030f984aSJacob Faibussowitsch   wait on dctx after converging. This has the effect of "synchronizing" the outgoing
526030f984aSJacob Faibussowitsch   edges.
527030f984aSJacob Faibussowitsch 
528030f984aSJacob Faibussowitsch   DAG representations:
529030f984aSJacob Faibussowitsch   If joinMode is PETSC_DEVICE_CONTEXT_JOIN_DESTROY
530030f984aSJacob Faibussowitsch .vb
531030f984aSJacob Faibussowitsch   time ->
532030f984aSJacob Faibussowitsch 
533030f984aSJacob Faibussowitsch   -> dctx ---------/- dctx ->
534030f984aSJacob Faibussowitsch   -> dsub[0] -----/
535030f984aSJacob Faibussowitsch   ->  ... -------/
536030f984aSJacob Faibussowitsch   -> dsub[n-1] -/
537030f984aSJacob Faibussowitsch .ve
538030f984aSJacob Faibussowitsch   If joinMode is PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC
539030f984aSJacob Faibussowitsch .vb
540030f984aSJacob Faibussowitsch   time ->
541030f984aSJacob Faibussowitsch 
542030f984aSJacob Faibussowitsch   -> dctx ---------/- dctx ->
543030f984aSJacob Faibussowitsch   -> dsub[0] -----/--------->
544030f984aSJacob Faibussowitsch   ->  ... -------/---------->
545030f984aSJacob Faibussowitsch   -> dsub[n-1] -/----------->
546030f984aSJacob Faibussowitsch .ve
547030f984aSJacob Faibussowitsch   If joinMode is PETSC_DEVICE_CONTEXT_JOIN_SYNC
548030f984aSJacob Faibussowitsch .vb
549030f984aSJacob Faibussowitsch   time ->
550030f984aSJacob Faibussowitsch 
551030f984aSJacob Faibussowitsch   -> dctx ---------/- dctx -\----> dctx ------>
552030f984aSJacob Faibussowitsch   -> dsub[0] -----/          \---> dsub[0] --->
553030f984aSJacob Faibussowitsch   ->  ... -------/            \--> ... ------->
554030f984aSJacob Faibussowitsch   -> dsub[n-1] -/              \-> dsub[n-1] ->
555030f984aSJacob Faibussowitsch .ve
556030f984aSJacob Faibussowitsch 
557030f984aSJacob Faibussowitsch   Level: intermediate
558030f984aSJacob Faibussowitsch 
559030f984aSJacob Faibussowitsch .seealso: PetscDeviceContextFork(), PetscDeviceContextSynchronize(), PetscDeviceContextJoinMode
560030f984aSJacob Faibussowitsch @*/
561030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextJoin(PetscDeviceContext dctx, PetscInt n, PetscDeviceContextJoinMode joinMode, PetscDeviceContext **dsub)
562030f984aSJacob Faibussowitsch {
563030f984aSJacob Faibussowitsch #if defined(PETSC_USE_DEBUG) && defined(PETSC_USE_INFO)
564030f984aSJacob Faibussowitsch   static std::string idList;
565030f984aSJacob Faibussowitsch #endif
566030f984aSJacob Faibussowitsch   PetscErrorCode     ierr;
567030f984aSJacob Faibussowitsch 
568030f984aSJacob Faibussowitsch   PetscFunctionBegin;
569030f984aSJacob Faibussowitsch   /* validity of dctx is checked in the wait-for loop */
570030f984aSJacob Faibussowitsch   PetscValidPointer(dsub,4);
571bf025ffbSJacob Faibussowitsch   PetscAssert(n >= 0,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Number of contexts merged %" PetscInt_FMT " < 0",n);
572030f984aSJacob Faibussowitsch #if defined(PETSC_USE_DEBUG) && defined(PETSC_USE_INFO)
573030f984aSJacob Faibussowitsch   /* reserve 4 chars per id, 2 for number and 2 for ', ' separator */
574030f984aSJacob Faibussowitsch   idList.reserve(4*n);
575030f984aSJacob Faibussowitsch #endif
576030f984aSJacob Faibussowitsch   /* first dctx waits on all the incoming edges */
577030f984aSJacob Faibussowitsch   for (PetscInt i = 0; i < n; ++i) {
578030f984aSJacob Faibussowitsch     PetscCheckCompatibleDeviceContexts(dctx,1,(*dsub)[i],4);
579030f984aSJacob Faibussowitsch     ierr = PetscDeviceContextWaitForContext(dctx,(*dsub)[i]);CHKERRQ(ierr);
580030f984aSJacob Faibussowitsch #if defined(PETSC_USE_DEBUG) && defined(PETSC_USE_INFO)
581030f984aSJacob Faibussowitsch     idList += std::to_string((*dsub)[i]->id);
582030f984aSJacob Faibussowitsch     if (i+1 < n) idList += ", ";
583030f984aSJacob Faibussowitsch #endif
584030f984aSJacob Faibussowitsch   }
585030f984aSJacob Faibussowitsch 
586030f984aSJacob Faibussowitsch   /* now we handle the aftermath */
587030f984aSJacob Faibussowitsch   switch (joinMode) {
588030f984aSJacob Faibussowitsch   case PETSC_DEVICE_CONTEXT_JOIN_DESTROY:
589030f984aSJacob Faibussowitsch     {
590030f984aSJacob Faibussowitsch       PetscInt j = 0;
591030f984aSJacob Faibussowitsch 
592bf025ffbSJacob 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);
593030f984aSJacob Faibussowitsch       /* update child count while it's still fresh in memory */
594030f984aSJacob Faibussowitsch       dctx->numChildren -= n;
595030f984aSJacob Faibussowitsch       for (PetscInt i = 0; i < dctx->maxNumChildren; ++i) {
596030f984aSJacob Faibussowitsch         if (dctx->childIDs[i] && (dctx->childIDs[i] == (*dsub)[j]->id)) {
597030f984aSJacob Faibussowitsch           /* child is one of ours, can destroy it */
598030f984aSJacob Faibussowitsch           ierr = PetscDeviceContextDestroy((*dsub)+j);CHKERRQ(ierr);
599030f984aSJacob Faibussowitsch           /* reset the child slot */
600030f984aSJacob Faibussowitsch           dctx->childIDs[i] = 0;
601030f984aSJacob Faibussowitsch           if (++j == n) break;
602030f984aSJacob Faibussowitsch         }
603030f984aSJacob Faibussowitsch       }
604030f984aSJacob 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 */
605bf025ffbSJacob 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);
606030f984aSJacob Faibussowitsch       ierr = PetscFree(*dsub);CHKERRQ(ierr);
607030f984aSJacob Faibussowitsch     }
608030f984aSJacob Faibussowitsch     break;
609030f984aSJacob Faibussowitsch   case PETSC_DEVICE_CONTEXT_JOIN_SYNC:
610030f984aSJacob Faibussowitsch     for (PetscInt i = 0; i < n; ++i) {
611030f984aSJacob Faibussowitsch       ierr = PetscDeviceContextWaitForContext((*dsub)[i],dctx);CHKERRQ(ierr);
612030f984aSJacob Faibussowitsch     }
613030f984aSJacob Faibussowitsch   case PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC:
614030f984aSJacob Faibussowitsch     break;
615030f984aSJacob Faibussowitsch   default:
616030f984aSJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Unknown PetscDeviceContextJoinMode given");
617030f984aSJacob Faibussowitsch   }
618030f984aSJacob Faibussowitsch 
619030f984aSJacob Faibussowitsch #if defined(PETSC_USE_DEBUG) && defined(PETSC_USE_INFO)
620bf025ffbSJacob Faibussowitsch   ierr = PetscInfo(nullptr,"Joined %" PetscInt_FMT " ctxs to ctx %" PetscInt_FMT ", mode %s with IDs: %s\n",n,dctx->id,PetscDeviceContextJoinModes[joinMode],idList.c_str());CHKERRQ(ierr);
621030f984aSJacob Faibussowitsch   idList.clear();
622030f984aSJacob Faibussowitsch #endif
623030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
624030f984aSJacob Faibussowitsch }
625030f984aSJacob Faibussowitsch 
626030f984aSJacob Faibussowitsch /*@C
6275181c4f9SJacob Faibussowitsch   PetscDeviceContextSynchronize - Block the host until all work queued on or associated with a PetscDeviceContext has finished
628030f984aSJacob Faibussowitsch 
629030f984aSJacob Faibussowitsch   Not Collective, Synchronous
630030f984aSJacob Faibussowitsch 
631030f984aSJacob Faibussowitsch   Input Parameters:
632030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext to synchronize
633030f984aSJacob Faibussowitsch 
634030f984aSJacob Faibussowitsch   Level: beginner
635030f984aSJacob Faibussowitsch 
636030f984aSJacob Faibussowitsch .seealso: PetscDeviceContextFork(), PetscDeviceContextJoin(), PetscDeviceContextQueryIdle()
637030f984aSJacob Faibussowitsch @*/
638030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextSynchronize(PetscDeviceContext dctx)
639030f984aSJacob Faibussowitsch {
640030f984aSJacob Faibussowitsch   PetscFunctionBegin;
641030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx,1);
642030f984aSJacob Faibussowitsch   /* if it isn't setup there is nothing to sync on */
643ef657721SJacob Faibussowitsch   if (dctx->setup) {auto ierr = (*dctx->ops->synchronize)(dctx);CHKERRQ(ierr);}
644030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
645030f984aSJacob Faibussowitsch }
646030f984aSJacob Faibussowitsch 
647a4af0ceeSJacob Faibussowitsch #define PETSC_DEVICE_CONTEXT_DEFAULT_DEVICE PETSC_DEVICE_DEFAULT
648a4af0ceeSJacob Faibussowitsch // REMOVE ME (change)
649a4af0ceeSJacob Faibussowitsch #define PETSC_DEVICE_CONTEXT_DEFAULT_STREAM PETSC_STREAM_GLOBAL_BLOCKING
650030f984aSJacob Faibussowitsch 
651a4af0ceeSJacob Faibussowitsch static PetscDeviceType    rootDeviceType = PETSC_DEVICE_CONTEXT_DEFAULT_DEVICE;
652a4af0ceeSJacob Faibussowitsch static PetscStreamType    rootStreamType = PETSC_DEVICE_CONTEXT_DEFAULT_STREAM;
653bf025ffbSJacob Faibussowitsch static PetscDeviceContext globalContext  = nullptr;
654a4af0ceeSJacob Faibussowitsch 
655a4af0ceeSJacob Faibussowitsch /* when PetsDevice initializes PetscDeviceContext eagerly the type of device created should
656a4af0ceeSJacob Faibussowitsch  * match whatever device is eagerly intialized */
657a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetRootDeviceType_Internal(PetscDeviceType type)
658030f984aSJacob Faibussowitsch {
659030f984aSJacob Faibussowitsch   PetscFunctionBegin;
660a4af0ceeSJacob Faibussowitsch   PetscValidDeviceType(type,1);
661a4af0ceeSJacob Faibussowitsch   rootDeviceType = type;
662030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
663030f984aSJacob Faibussowitsch }
664030f984aSJacob Faibussowitsch 
665a4af0ceeSJacob Faibussowitsch #if 0
666a4af0ceeSJacob Faibussowitsch /* currently unused */
667a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetRootStreamType_Internal(PetscStreamType type)
668030f984aSJacob Faibussowitsch {
669a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
670a4af0ceeSJacob Faibussowitsch   PetscValidStreamType(type,1);
671a4af0ceeSJacob Faibussowitsch   rootStreamType = type;
672a4af0ceeSJacob Faibussowitsch   PetscFunctionReturn(0);
673a4af0ceeSJacob Faibussowitsch }
674a4af0ceeSJacob Faibussowitsch #endif
675a4af0ceeSJacob Faibussowitsch 
676a4af0ceeSJacob Faibussowitsch static PetscErrorCode PetscDeviceContextSetupGlobalContext_Private(void)
677a4af0ceeSJacob Faibussowitsch {
678a4af0ceeSJacob Faibussowitsch   PetscErrorCode    ierr;
679a4af0ceeSJacob Faibussowitsch   static const auto PetscDeviceContextFinalizer = []() -> PetscErrorCode {
680030f984aSJacob Faibussowitsch     PetscErrorCode ierr;
681030f984aSJacob Faibussowitsch 
682030f984aSJacob Faibussowitsch     PetscFunctionBegin;
683a4af0ceeSJacob Faibussowitsch     ierr = PetscDeviceContextDestroy(&globalContext);CHKERRQ(ierr);
684a4af0ceeSJacob Faibussowitsch     rootDeviceType = PETSC_DEVICE_CONTEXT_DEFAULT_DEVICE;
685a4af0ceeSJacob Faibussowitsch     rootStreamType = PETSC_DEVICE_CONTEXT_DEFAULT_STREAM;
686a4af0ceeSJacob Faibussowitsch     PetscFunctionReturn(0);
687a4af0ceeSJacob Faibussowitsch   };
688a4af0ceeSJacob Faibussowitsch 
689a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
690a4af0ceeSJacob Faibussowitsch   if (globalContext) PetscFunctionReturn(0);
691a4af0ceeSJacob Faibussowitsch   /* this exists purely as a valid device check. */
692a4af0ceeSJacob Faibussowitsch   ierr = PetscDeviceInitializePackage();CHKERRQ(ierr);
693a4af0ceeSJacob Faibussowitsch   ierr = PetscRegisterFinalize(PetscDeviceContextFinalizer);CHKERRQ(ierr);
694bf025ffbSJacob Faibussowitsch   ierr = PetscInfo(nullptr,"Initializing global PetscDeviceContext\n");CHKERRQ(ierr);
695a4af0ceeSJacob Faibussowitsch   /* we call the allocator directly here since the ObjectPool creates a PetscContainer which
696a4af0ceeSJacob Faibussowitsch    * eventually tries to call logging functions. However, this routine may be purposefully
697a4af0ceeSJacob Faibussowitsch    * called __before__ logging is initialized, so the logging function would PETSCABORT */
69817f48955SJacob Faibussowitsch   ierr = contextPool.allocator().create(&globalContext);CHKERRQ(ierr);
699a4af0ceeSJacob Faibussowitsch   ierr = PetscDeviceContextSetStreamType(globalContext,rootStreamType);CHKERRQ(ierr);
700a4af0ceeSJacob Faibussowitsch   ierr = PetscDeviceContextSetDefaultDeviceForType_Internal(globalContext,rootDeviceType);CHKERRQ(ierr);
701a4af0ceeSJacob Faibussowitsch   ierr = PetscDeviceContextSetUp(globalContext);CHKERRQ(ierr);
702030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
703030f984aSJacob Faibussowitsch }
704030f984aSJacob Faibussowitsch 
705030f984aSJacob Faibussowitsch /*@C
7065181c4f9SJacob Faibussowitsch   PetscDeviceContextGetCurrentContext - Get the current active PetscDeviceContext
707030f984aSJacob Faibussowitsch 
708030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
709030f984aSJacob Faibussowitsch 
710030f984aSJacob Faibussowitsch   Output Parameter:
711030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext
712030f984aSJacob Faibussowitsch 
713030f984aSJacob Faibussowitsch   Notes:
714a4af0ceeSJacob Faibussowitsch   The user generally should not destroy contexts retrieved with this routine unless they
715a4af0ceeSJacob Faibussowitsch   themselves have created them. There exists no protection against destroying the root
716a4af0ceeSJacob Faibussowitsch   context.
717030f984aSJacob Faibussowitsch 
718030f984aSJacob Faibussowitsch   Developer Notes:
719a4af0ceeSJacob Faibussowitsch   Unless the user has set their own, this routine creates the "root" context the first time it
720a4af0ceeSJacob Faibussowitsch   is called, registering its destructor to PetscFinalize().
721030f984aSJacob Faibussowitsch 
722030f984aSJacob Faibussowitsch   Level: beginner
723030f984aSJacob Faibussowitsch 
724030f984aSJacob Faibussowitsch .seealso: PetscDeviceContextSetCurrentContext(), PetscDeviceContextFork(),
725030f984aSJacob Faibussowitsch PetscDeviceContextJoin(), PetscDeviceContextCreate()
726030f984aSJacob Faibussowitsch @*/
727030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextGetCurrentContext(PetscDeviceContext *dctx)
728030f984aSJacob Faibussowitsch {
729030f984aSJacob Faibussowitsch   PetscErrorCode ierr;
730030f984aSJacob Faibussowitsch 
731a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
732a4af0ceeSJacob Faibussowitsch   PetscValidPointer(dctx,1);
733a4af0ceeSJacob Faibussowitsch   ierr = PetscDeviceContextSetupGlobalContext_Private();CHKERRQ(ierr);
734a4af0ceeSJacob Faibussowitsch   /* while the static analyzer can find global variables, it will throw a warning about not
735a4af0ceeSJacob Faibussowitsch    * being able to connect this back to the function arguments */
736a4af0ceeSJacob Faibussowitsch   PetscDisableStaticAnalyzerForExpressionUnderstandingThatThisIsDangerousAndBugprone(PetscValidDeviceContext(globalContext,-1));
737030f984aSJacob Faibussowitsch   *dctx = globalContext;
738030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
739030f984aSJacob Faibussowitsch }
740030f984aSJacob Faibussowitsch 
741030f984aSJacob Faibussowitsch /*@C
7425181c4f9SJacob Faibussowitsch   PetscDeviceContextSetCurrentContext - Set the current active PetscDeviceContext
743030f984aSJacob Faibussowitsch 
744030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
745030f984aSJacob Faibussowitsch 
746030f984aSJacob Faibussowitsch   Input Parameter:
747030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext
748030f984aSJacob Faibussowitsch 
749030f984aSJacob Faibussowitsch   Notes:
750a4af0ceeSJacob Faibussowitsch   This routine can be used to set the defacto "root" PetscDeviceContext to a user-defined
751a4af0ceeSJacob Faibussowitsch   implementation by calling this routine immediately after PetscInitialize() and ensuring that
752a4af0ceeSJacob Faibussowitsch   PetscDevice is not greedily intialized. In this case the user is responsible for destroying
753a4af0ceeSJacob Faibussowitsch   their PetscDeviceContext before PetscFinalize() returns.
754a4af0ceeSJacob Faibussowitsch 
755a4af0ceeSJacob Faibussowitsch   The old context is not stored in any way by this routine; if one is overriding a context that
756a4af0ceeSJacob Faibussowitsch   they themselves do not control, one should take care to temporarily store it by calling
757a4af0ceeSJacob Faibussowitsch   PetscDeviceContextGetCurrentContext() before calling this routine.
758030f984aSJacob Faibussowitsch 
759030f984aSJacob Faibussowitsch   Level: beginner
760030f984aSJacob Faibussowitsch 
761030f984aSJacob Faibussowitsch .seealso: PetscDeviceContextGetCurrentContext(), PetscDeviceContextFork(),
762030f984aSJacob Faibussowitsch PetscDeviceContextJoin(), PetscDeviceContextCreate()
763030f984aSJacob Faibussowitsch @*/
764030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetCurrentContext(PetscDeviceContext dctx)
765030f984aSJacob Faibussowitsch {
766030f984aSJacob Faibussowitsch   PetscErrorCode ierr;
767030f984aSJacob Faibussowitsch 
768030f984aSJacob Faibussowitsch   PetscFunctionBegin;
769030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx,1);
770bf025ffbSJacob 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);
771030f984aSJacob Faibussowitsch   globalContext = dctx;
772bf025ffbSJacob Faibussowitsch   ierr = PetscInfo(nullptr,"Set global PetscDeviceContext id %" PetscInt_FMT "\n",dctx->id);CHKERRQ(ierr);
773030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
774030f984aSJacob Faibussowitsch }
775030f984aSJacob Faibussowitsch 
776030f984aSJacob Faibussowitsch /*@C
777030f984aSJacob Faibussowitsch   PetscDeviceContextSetFromOptions - Configure a PetscDeviceContext from the options database
778030f984aSJacob Faibussowitsch 
779030f984aSJacob Faibussowitsch   Collective on comm, Asynchronous
780030f984aSJacob Faibussowitsch 
781030f984aSJacob Faibussowitsch   Input Parameters:
782030f984aSJacob Faibussowitsch + comm   - MPI communicator on which to query the options database
783030f984aSJacob Faibussowitsch . prefix - prefix to prepend to all options database queries, NULL if not needed
784030f984aSJacob Faibussowitsch - dctx   - The PetscDeviceContext to configure
785030f984aSJacob Faibussowitsch 
786030f984aSJacob Faibussowitsch   Output Parameter:
787030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext
788030f984aSJacob Faibussowitsch 
789030f984aSJacob Faibussowitsch   Options Database:
790a4af0ceeSJacob Faibussowitsch + -device_context_stream_type - type of stream to create inside the PetscDeviceContext -
791030f984aSJacob Faibussowitsch    PetscDeviceContextSetStreamType()
792a4af0ceeSJacob Faibussowitsch - -device_context_device_type - the type of PetscDevice to attach by default - PetscDeviceType
793030f984aSJacob Faibussowitsch 
794030f984aSJacob Faibussowitsch   Level: beginner
795030f984aSJacob Faibussowitsch 
7965181c4f9SJacob Faibussowitsch .seealso: PetscDeviceContextSetStreamType(), PetscDeviceContextSetDevice()
797030f984aSJacob Faibussowitsch @*/
798030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetFromOptions(MPI_Comm comm, const char prefix[], PetscDeviceContext dctx)
799030f984aSJacob Faibussowitsch {
800030f984aSJacob Faibussowitsch   PetscBool      flag;
801a4af0ceeSJacob Faibussowitsch   PetscInt       stype,dtype;
802030f984aSJacob Faibussowitsch   PetscErrorCode ierr;
803030f984aSJacob Faibussowitsch 
804030f984aSJacob Faibussowitsch   PetscFunctionBegin;
805a4af0ceeSJacob Faibussowitsch   if (prefix) PetscValidCharPointer(prefix,2);
806030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx,3);
807030f984aSJacob Faibussowitsch   ierr = PetscOptionsBegin(comm,prefix,"PetscDeviceContext Options","Sys");CHKERRQ(ierr);
808a4af0ceeSJacob Faibussowitsch   ierr = PetscOptionsEList("-device_context_stream_type","PetscDeviceContext PetscStreamType","PetscDeviceContextSetStreamType",PetscStreamTypes,PETSC_STREAM_MAX,PetscStreamTypes[dctx->streamType],&stype,&flag);CHKERRQ(ierr);
809030f984aSJacob Faibussowitsch   if (flag) {
810030f984aSJacob Faibussowitsch     ierr = PetscDeviceContextSetStreamType(dctx,static_cast<PetscStreamType>(stype));CHKERRQ(ierr);
811030f984aSJacob Faibussowitsch   }
812a4af0ceeSJacob Faibussowitsch   ierr = 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);CHKERRQ(ierr);
813a4af0ceeSJacob Faibussowitsch   if (flag) {
814a4af0ceeSJacob Faibussowitsch     ierr = PetscDeviceContextSetDefaultDeviceForType_Internal(dctx,static_cast<PetscDeviceType>(dtype+1));CHKERRQ(ierr);
815a4af0ceeSJacob Faibussowitsch   }
816030f984aSJacob Faibussowitsch   ierr = PetscOptionsEnd();CHKERRQ(ierr);
817030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
818030f984aSJacob Faibussowitsch }
819