xref: /petsc/src/sys/objects/device/interface/dcontext.cxx (revision 030f984af8d8bb4c203755d35bded3c05b3d83ce)
1*030f984aSJacob Faibussowitsch #include <petsc/private/deviceimpl.h> /*I "petscdevice.h" I*/
2*030f984aSJacob Faibussowitsch #include "objpool.hpp"
3*030f984aSJacob Faibussowitsch 
4*030f984aSJacob Faibussowitsch /* Define the allocator */
5*030f984aSJacob Faibussowitsch struct PetscDeviceContextAllocator : Petsc::Allocator<PetscDeviceContext>
6*030f984aSJacob Faibussowitsch {
7*030f984aSJacob Faibussowitsch   static PetscInt PetscDeviceContextID;
8*030f984aSJacob Faibussowitsch 
9*030f984aSJacob Faibussowitsch   PETSC_NODISCARD PetscErrorCode create(PetscDeviceContext *dctx) noexcept
10*030f984aSJacob Faibussowitsch   {
11*030f984aSJacob Faibussowitsch     PetscDeviceContext dc;
12*030f984aSJacob Faibussowitsch     PetscErrorCode     ierr;
13*030f984aSJacob Faibussowitsch 
14*030f984aSJacob Faibussowitsch     PetscFunctionBegin;
15*030f984aSJacob Faibussowitsch     ierr           = PetscNew(&dc);CHKERRQ(ierr);
16*030f984aSJacob Faibussowitsch     dc->id         = PetscDeviceContextID++;
17*030f984aSJacob Faibussowitsch     dc->idle       = PETSC_TRUE;
18*030f984aSJacob Faibussowitsch     dc->streamType = PETSC_STREAM_DEFAULT_BLOCKING;
19*030f984aSJacob Faibussowitsch     *dctx          = dc;
20*030f984aSJacob Faibussowitsch     PetscFunctionReturn(0);
21*030f984aSJacob Faibussowitsch   }
22*030f984aSJacob Faibussowitsch 
23*030f984aSJacob Faibussowitsch   PETSC_NODISCARD PetscErrorCode destroy(PetscDeviceContext &dctx) const noexcept
24*030f984aSJacob Faibussowitsch   {
25*030f984aSJacob Faibussowitsch     PetscErrorCode ierr;
26*030f984aSJacob Faibussowitsch 
27*030f984aSJacob Faibussowitsch     PetscFunctionBegin;
28*030f984aSJacob Faibussowitsch     if (PetscUnlikelyDebug(dctx->numChildren)) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Device context still has %D un-restored children, must call PetscDeviceContextRestore() on all children before destroying",dctx->numChildren);
29*030f984aSJacob Faibussowitsch     if (dctx->ops->destroy) {ierr = (*dctx->ops->destroy)(dctx);CHKERRQ(ierr);}
30*030f984aSJacob Faibussowitsch     ierr = PetscDeviceDestroy(&dctx->device);CHKERRQ(ierr);
31*030f984aSJacob Faibussowitsch     ierr = PetscFree(dctx->childIDs);CHKERRQ(ierr);
32*030f984aSJacob Faibussowitsch     ierr = PetscFree(dctx);CHKERRQ(ierr);
33*030f984aSJacob Faibussowitsch     PetscFunctionReturn(0);
34*030f984aSJacob Faibussowitsch   }
35*030f984aSJacob Faibussowitsch 
36*030f984aSJacob Faibussowitsch   PETSC_NODISCARD PetscErrorCode reset(PetscDeviceContext &dctx) const noexcept
37*030f984aSJacob Faibussowitsch   {
38*030f984aSJacob Faibussowitsch     PetscErrorCode ierr;
39*030f984aSJacob Faibussowitsch 
40*030f984aSJacob Faibussowitsch     PetscFunctionBegin;
41*030f984aSJacob Faibussowitsch     /* don't deallocate the child array, rather just zero it out */
42*030f984aSJacob Faibussowitsch     ierr = PetscArrayzero(dctx->childIDs,dctx->maxNumChildren);CHKERRQ(ierr);
43*030f984aSJacob Faibussowitsch     dctx->setup       = PETSC_FALSE;
44*030f984aSJacob Faibussowitsch     dctx->numChildren = 0;
45*030f984aSJacob Faibussowitsch     dctx->idle        = PETSC_TRUE;
46*030f984aSJacob Faibussowitsch     dctx->streamType  = PETSC_STREAM_DEFAULT_BLOCKING;
47*030f984aSJacob Faibussowitsch     PetscFunctionReturn(0);
48*030f984aSJacob Faibussowitsch   }
49*030f984aSJacob Faibussowitsch 
50*030f984aSJacob Faibussowitsch   PETSC_NODISCARD PetscErrorCode finalize(void) noexcept
51*030f984aSJacob Faibussowitsch   {
52*030f984aSJacob Faibussowitsch     PetscFunctionBegin;
53*030f984aSJacob Faibussowitsch     PetscDeviceContextID = 0;
54*030f984aSJacob Faibussowitsch     PetscFunctionReturn(0);
55*030f984aSJacob Faibussowitsch   }
56*030f984aSJacob Faibussowitsch };
57*030f984aSJacob Faibussowitsch PetscInt PetscDeviceContextAllocator::PetscDeviceContextID = 0;
58*030f984aSJacob Faibussowitsch 
59*030f984aSJacob Faibussowitsch static Petsc::ObjectPool<PetscDeviceContext,PetscDeviceContextAllocator> contextPool;
60*030f984aSJacob Faibussowitsch 
61*030f984aSJacob Faibussowitsch /*@C
62*030f984aSJacob Faibussowitsch   PetscDeviceContextCreate - Creates a PetscDeviceContext
63*030f984aSJacob Faibussowitsch 
64*030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
65*030f984aSJacob Faibussowitsch 
66*030f984aSJacob Faibussowitsch   Ouput Paramemters:
67*030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext
68*030f984aSJacob Faibussowitsch 
69*030f984aSJacob Faibussowitsch   Notes:
70*030f984aSJacob Faibussowitsch   Unlike almost every other PETSc class it is advised that most users use
71*030f984aSJacob Faibussowitsch   PetscDeviceContextDuplicate() rather than this routine to create new contexts. Contexts
72*030f984aSJacob Faibussowitsch   of different types are incompatible with one another; using
73*030f984aSJacob Faibussowitsch   PetscDeviceContextDuplicate() ensures compatible types.
74*030f984aSJacob Faibussowitsch 
75*030f984aSJacob Faibussowitsch   Level: beginner
76*030f984aSJacob Faibussowitsch 
77*030f984aSJacob Faibussowitsch .seealso: PetscDeviceContextDuplicate(), PetscDeviceContextSetDevice(),
78*030f984aSJacob Faibussowitsch PetscDeviceContextSetStreamType(), PetscDeviceContextSetUp(), PetscDeviceContextDestroy(),
79*030f984aSJacob Faibussowitsch PetscDeviceContextSetFromOptions()
80*030f984aSJacob Faibussowitsch @*/
81*030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextCreate(PetscDeviceContext *dctx)
82*030f984aSJacob Faibussowitsch {
83*030f984aSJacob Faibussowitsch   PetscErrorCode ierr;
84*030f984aSJacob Faibussowitsch 
85*030f984aSJacob Faibussowitsch   PetscFunctionBegin;
86*030f984aSJacob Faibussowitsch   PetscValidPointer(dctx,1);
87*030f984aSJacob Faibussowitsch   ierr = PetscDeviceInitializePackage();CHKERRQ(ierr);
88*030f984aSJacob Faibussowitsch   ierr = contextPool.get(*dctx);CHKERRQ(ierr);
89*030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
90*030f984aSJacob Faibussowitsch }
91*030f984aSJacob Faibussowitsch 
92*030f984aSJacob Faibussowitsch /*@C
93*030f984aSJacob Faibussowitsch   PetscDeviceContextDestroy - Frees a PetscDeviceContext
94*030f984aSJacob Faibussowitsch 
95*030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
96*030f984aSJacob Faibussowitsch 
97*030f984aSJacob Faibussowitsch   Input Parameters:
98*030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext
99*030f984aSJacob Faibussowitsch 
100*030f984aSJacob Faibussowitsch   Notes:
101*030f984aSJacob Faibussowitsch   No implicit synchronization occurs due to this routine, all resources are released completely asynchronously
102*030f984aSJacob Faibussowitsch   w.r.t. the host. If one needs to guarantee access to the data produced on this contexts stream one should perform the
103*030f984aSJacob Faibussowitsch   appropriate synchronization before calling this routine.
104*030f984aSJacob Faibussowitsch 
105*030f984aSJacob Faibussowitsch   Developer Notes:
106*030f984aSJacob Faibussowitsch   The context is never actually "destroyed", only returned to an ever growing pool of
107*030f984aSJacob Faibussowitsch   contexts. There are currently no safeguards on the size of the pool, this should perhaps
108*030f984aSJacob Faibussowitsch   be implemented.
109*030f984aSJacob Faibussowitsch 
110*030f984aSJacob Faibussowitsch   Level: beginner
111*030f984aSJacob Faibussowitsch 
112*030f984aSJacob Faibussowitsch .seealso: PetscDeviceContextCreate(), PetscDeviceContextSetDevice(), PetscDeviceContextSetUp(), PetscDeviceContextSynchronize()
113*030f984aSJacob Faibussowitsch @*/
114*030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextDestroy(PetscDeviceContext *dctx)
115*030f984aSJacob Faibussowitsch {
116*030f984aSJacob Faibussowitsch   PetscErrorCode ierr;
117*030f984aSJacob Faibussowitsch 
118*030f984aSJacob Faibussowitsch   PetscFunctionBegin;
119*030f984aSJacob Faibussowitsch   if (!*dctx) PetscFunctionReturn(0);
120*030f984aSJacob Faibussowitsch   /* use move assignment whenever possible */
121*030f984aSJacob Faibussowitsch   ierr = contextPool.reclaim(std::move(*dctx));CHKERRQ(ierr);
122*030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
123*030f984aSJacob Faibussowitsch }
124*030f984aSJacob Faibussowitsch 
125*030f984aSJacob Faibussowitsch /*@C
126*030f984aSJacob Faibussowitsch   PetscDeviceContextSetStreamType - Set the implementation type of the underlying stream for a PetscDeviceContext
127*030f984aSJacob Faibussowitsch 
128*030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
129*030f984aSJacob Faibussowitsch 
130*030f984aSJacob Faibussowitsch   Input Paramaters:
131*030f984aSJacob Faibussowitsch + dctx - The PetscDeviceContext
132*030f984aSJacob Faibussowitsch - type - The PetscStreamType
133*030f984aSJacob Faibussowitsch 
134*030f984aSJacob Faibussowitsch   Notes:
135*030f984aSJacob Faibussowitsch   See PetscStreamType in include/petscdevicetypes.h for more information on the available
136*030f984aSJacob Faibussowitsch   types and their interactions. If the PetscDeviceContext was previously set up and stream
137*030f984aSJacob Faibussowitsch   type was changed, you must call PetscDeviceContextSetUp() again after this routine.
138*030f984aSJacob Faibussowitsch 
139*030f984aSJacob Faibussowitsch   Level: intermediate
140*030f984aSJacob Faibussowitsch 
141*030f984aSJacob Faibussowitsch .seealso: PetscDeviceContextCreate(), PetscDeviceContextSetDevice(),
142*030f984aSJacob Faibussowitsch PetscDeviceContextGetStreamType(), PetscDeviceContextSetUp(), PetscDeviceContextSetFromOptions()
143*030f984aSJacob Faibussowitsch @*/
144*030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetStreamType(PetscDeviceContext dctx, PetscStreamType type)
145*030f984aSJacob Faibussowitsch {
146*030f984aSJacob Faibussowitsch   PetscFunctionBegin;
147*030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx,1);
148*030f984aSJacob Faibussowitsch   PetscValidStreamType(type,2);
149*030f984aSJacob Faibussowitsch   /* only need to do complex swapping if the object has already been setup */
150*030f984aSJacob Faibussowitsch   if (dctx->setup && (dctx->streamType != type)) {
151*030f984aSJacob Faibussowitsch     PetscErrorCode ierr;
152*030f984aSJacob Faibussowitsch 
153*030f984aSJacob Faibussowitsch     ierr = (*dctx->ops->changestreamtype)(dctx,type);CHKERRQ(ierr);
154*030f984aSJacob Faibussowitsch     dctx->setup = PETSC_FALSE;
155*030f984aSJacob Faibussowitsch   }
156*030f984aSJacob Faibussowitsch   dctx->streamType = type;
157*030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
158*030f984aSJacob Faibussowitsch }
159*030f984aSJacob Faibussowitsch 
160*030f984aSJacob Faibussowitsch /*@C
161*030f984aSJacob Faibussowitsch   PetscDeviceContextGetStreamType - Get the implementation type of the underlying stream for a PetscDeviceContext
162*030f984aSJacob Faibussowitsch 
163*030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
164*030f984aSJacob Faibussowitsch 
165*030f984aSJacob Faibussowitsch   Input Paramater:
166*030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext
167*030f984aSJacob Faibussowitsch 
168*030f984aSJacob Faibussowitsch   Output Parameter:
169*030f984aSJacob Faibussowitsch . type - The PetscStreamType
170*030f984aSJacob Faibussowitsch 
171*030f984aSJacob Faibussowitsch   Notes:
172*030f984aSJacob Faibussowitsch   See PetscStreamType in include/petscdevicetypes.h for more information on the available types and their interactions
173*030f984aSJacob Faibussowitsch 
174*030f984aSJacob Faibussowitsch   Level: intermediate
175*030f984aSJacob Faibussowitsch 
176*030f984aSJacob Faibussowitsch .seealso: PetscDeviceContextCreate(), PetscDeviceContextSetDevice(),
177*030f984aSJacob Faibussowitsch PetscDeviceContextSetStreamType(), PetscDeviceContextSetFromOptions()
178*030f984aSJacob Faibussowitsch @*/
179*030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextGetStreamType(PetscDeviceContext dctx, PetscStreamType *type)
180*030f984aSJacob Faibussowitsch {
181*030f984aSJacob Faibussowitsch   PetscFunctionBegin;
182*030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx,1);
183*030f984aSJacob Faibussowitsch   PetscValidIntPointer(type,2);
184*030f984aSJacob Faibussowitsch   *type = dctx->streamType;
185*030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
186*030f984aSJacob Faibussowitsch }
187*030f984aSJacob Faibussowitsch 
188*030f984aSJacob Faibussowitsch /*@C
189*030f984aSJacob Faibussowitsch   PetscDeviceContextSetDevice - Set the underlying device for the PetscDeviceContext
190*030f984aSJacob Faibussowitsch 
191*030f984aSJacob Faibussowitsch   Not Collective, Possibly Synchronous
192*030f984aSJacob Faibussowitsch 
193*030f984aSJacob Faibussowitsch   Input Paramaters:
194*030f984aSJacob Faibussowitsch + dctx   - The PetscDeviceContext
195*030f984aSJacob Faibussowitsch - device - The PetscDevice
196*030f984aSJacob Faibussowitsch 
197*030f984aSJacob Faibussowitsch   Notes:
198*030f984aSJacob Faibussowitsch   This routine is effectively PetscDeviceContext's "set-type" (so every PetscDeviceContext
199*030f984aSJacob Faibussowitsch   must also have an attached PetscDevice). Unlike the usual set-type semantics, it is
200*030f984aSJacob Faibussowitsch   not stricly necessary to set a contexts device to enable usage, any created device
201*030f984aSJacob Faibussowitsch   contexts will always come equipped with the "default" device.
202*030f984aSJacob Faibussowitsch 
203*030f984aSJacob Faibussowitsch   Level: intermediate
204*030f984aSJacob Faibussowitsch 
205*030f984aSJacob Faibussowitsch .seealso: PetscDeviceCreate(), PetscDeviceContextGetDevice()
206*030f984aSJacob Faibussowitsch @*/
207*030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetDevice(PetscDeviceContext dctx, PetscDevice device)
208*030f984aSJacob Faibussowitsch {
209*030f984aSJacob Faibussowitsch   PetscErrorCode ierr;
210*030f984aSJacob Faibussowitsch 
211*030f984aSJacob Faibussowitsch   PetscFunctionBegin;
212*030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx,1);
213*030f984aSJacob Faibussowitsch   PetscValidDevice(device,2);
214*030f984aSJacob Faibussowitsch   if (dctx->device == device) PetscFunctionReturn(0);
215*030f984aSJacob Faibussowitsch   ierr = PetscDeviceDestroy(&dctx->device);CHKERRQ(ierr);
216*030f984aSJacob Faibussowitsch   ierr = PetscMemzero(dctx->ops,sizeof(*dctx->ops));CHKERRQ(ierr);
217*030f984aSJacob Faibussowitsch   ierr = (*device->ops->createcontext)(dctx);CHKERRQ(ierr);
218*030f984aSJacob Faibussowitsch   dctx->device = PetscDeviceReference(device);
219*030f984aSJacob Faibussowitsch   dctx->setup  = PETSC_FALSE;
220*030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
221*030f984aSJacob Faibussowitsch }
222*030f984aSJacob Faibussowitsch 
223*030f984aSJacob Faibussowitsch /*@C
224*030f984aSJacob Faibussowitsch   PetscDeviceContextGetDevice - Get the underlying PetscDevice for a PetscDeviceContext
225*030f984aSJacob Faibussowitsch 
226*030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
227*030f984aSJacob Faibussowitsch 
228*030f984aSJacob Faibussowitsch   Input Parameter:
229*030f984aSJacob Faibussowitsch . dctx - the PetscDeviceContext
230*030f984aSJacob Faibussowitsch 
231*030f984aSJacob Faibussowitsch   Output Parameter:
232*030f984aSJacob Faibussowitsch . device - The PetscDevice
233*030f984aSJacob Faibussowitsch 
234*030f984aSJacob Faibussowitsch   Notes:
235*030f984aSJacob Faibussowitsch   This is a borrowed reference, the user should not destroy the device.
236*030f984aSJacob Faibussowitsch 
237*030f984aSJacob Faibussowitsch .seealso: PetscDeviceContextSetDevice(), PetscDevice
238*030f984aSJacob Faibussowitsch @*/
239*030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextGetDevice(PetscDeviceContext dctx, PetscDevice *device)
240*030f984aSJacob Faibussowitsch {
241*030f984aSJacob Faibussowitsch   PetscFunctionBegin;
242*030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx,1);
243*030f984aSJacob Faibussowitsch   PetscValidPointer(device,2);
244*030f984aSJacob Faibussowitsch   *device = dctx->device;
245*030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
246*030f984aSJacob Faibussowitsch }
247*030f984aSJacob Faibussowitsch 
248*030f984aSJacob Faibussowitsch /*@C
249*030f984aSJacob Faibussowitsch   PetscDeviceContextSetUp - Prepares a PetscDeviceContext for use
250*030f984aSJacob Faibussowitsch 
251*030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
252*030f984aSJacob Faibussowitsch 
253*030f984aSJacob Faibussowitsch   Intput Parameter:
254*030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext
255*030f984aSJacob Faibussowitsch 
256*030f984aSJacob Faibussowitsch   Developer Notes:
257*030f984aSJacob Faibussowitsch   This routine is usually the stage where a PetscDeviceContext acquires device-side data structures such as streams,
258*030f984aSJacob Faibussowitsch   events, and (possibly) handles.
259*030f984aSJacob Faibussowitsch 
260*030f984aSJacob Faibussowitsch   Level: beginner
261*030f984aSJacob Faibussowitsch 
262*030f984aSJacob Faibussowitsch .seealso: PetscDeviceContextTypes, PetscDeviceContextCreate(),
263*030f984aSJacob Faibussowitsch PetscDeviceContextSetDevice(), PetscDeviceContextDestroy(), PetscDeviceContextSetFromOptions()
264*030f984aSJacob Faibussowitsch @*/
265*030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetUp(PetscDeviceContext dctx)
266*030f984aSJacob Faibussowitsch {
267*030f984aSJacob Faibussowitsch   PetscErrorCode ierr;
268*030f984aSJacob Faibussowitsch 
269*030f984aSJacob Faibussowitsch   PetscFunctionBegin;
270*030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx,1);
271*030f984aSJacob Faibussowitsch   if (!dctx->device) {
272*030f984aSJacob Faibussowitsch     ierr = PetscInfo2(NULL,"PetscDeviceContext %d did not have an explicitly attached PetscDevice, using default with type %s\n",dctx->id,PetscDeviceKinds[PETSC_DEVICE_DEFAULT]);CHKERRQ(ierr);
273*030f984aSJacob Faibussowitsch     ierr = PetscDeviceContextSetDevice(dctx,PetscDeviceDefault_Internal());CHKERRQ(ierr);
274*030f984aSJacob Faibussowitsch   }
275*030f984aSJacob Faibussowitsch   if (dctx->setup) PetscFunctionReturn(0);
276*030f984aSJacob Faibussowitsch   ierr = (*dctx->ops->setup)(dctx);CHKERRQ(ierr);
277*030f984aSJacob Faibussowitsch   dctx->setup = PETSC_TRUE;
278*030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
279*030f984aSJacob Faibussowitsch }
280*030f984aSJacob Faibussowitsch 
281*030f984aSJacob Faibussowitsch /*@C
282*030f984aSJacob Faibussowitsch   PetscDeviceContextDuplicate - Duplicates a PetscDeviceContext object
283*030f984aSJacob Faibussowitsch 
284*030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
285*030f984aSJacob Faibussowitsch 
286*030f984aSJacob Faibussowitsch   Input Parameter:
287*030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext to duplicate
288*030f984aSJacob Faibussowitsch 
289*030f984aSJacob Faibussowitsch   Output Paramter:
290*030f984aSJacob Faibussowitsch . strmdup - The duplicated PetscDeviceContext
291*030f984aSJacob Faibussowitsch 
292*030f984aSJacob Faibussowitsch   Notes:
293*030f984aSJacob Faibussowitsch   This is a shorthand method for creating a PetscDeviceContext with the exact same
294*030f984aSJacob Faibussowitsch   settings as another. Note however that the duplicated PetscDeviceContext does not "share"
295*030f984aSJacob Faibussowitsch   any of the underlying data with the original, (including its current stream-state) they
296*030f984aSJacob Faibussowitsch   are completely separate objects.
297*030f984aSJacob Faibussowitsch 
298*030f984aSJacob Faibussowitsch   Level: beginner
299*030f984aSJacob Faibussowitsch 
300*030f984aSJacob Faibussowitsch .seealso: PetscDeviceContextCreate(), PetscDeviceContextSetDevice(), PetscDeviceContextSetStreamType()
301*030f984aSJacob Faibussowitsch @*/
302*030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextDuplicate(PetscDeviceContext dctx, PetscDeviceContext *dctxdup)
303*030f984aSJacob Faibussowitsch {
304*030f984aSJacob Faibussowitsch   PetscErrorCode ierr;
305*030f984aSJacob Faibussowitsch 
306*030f984aSJacob Faibussowitsch   PetscFunctionBegin;
307*030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx,1);
308*030f984aSJacob Faibussowitsch   PetscValidPointer(dctxdup,2);
309*030f984aSJacob Faibussowitsch   ierr = PetscDeviceContextCreate(dctxdup);CHKERRQ(ierr);
310*030f984aSJacob Faibussowitsch   ierr = PetscDeviceContextSetDevice(*dctxdup,dctx->device);CHKERRQ(ierr);
311*030f984aSJacob Faibussowitsch   ierr = PetscDeviceContextSetStreamType(*dctxdup,dctx->streamType);CHKERRQ(ierr);
312*030f984aSJacob Faibussowitsch   ierr = PetscDeviceContextSetUp(*dctxdup);CHKERRQ(ierr);
313*030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
314*030f984aSJacob Faibussowitsch }
315*030f984aSJacob Faibussowitsch 
316*030f984aSJacob Faibussowitsch /*@C
317*030f984aSJacob Faibussowitsch   PetscDeviceContextQueryIdle - Returns whether or not a PetscDeviceContext is idle
318*030f984aSJacob Faibussowitsch 
319*030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
320*030f984aSJacob Faibussowitsch 
321*030f984aSJacob Faibussowitsch   Input Parameter:
322*030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext object
323*030f984aSJacob Faibussowitsch 
324*030f984aSJacob Faibussowitsch   Output Parameter:
325*030f984aSJacob Faibussowitsch . idle - PETSC_TRUE if PetscDeviceContext has NO work, PETSC_FALSE if it has work
326*030f984aSJacob Faibussowitsch 
327*030f984aSJacob Faibussowitsch   Notes:
328*030f984aSJacob Faibussowitsch   This routine only refers a singular context and does NOT take any of its children into account. That is, if dctx is
329*030f984aSJacob Faibussowitsch   idle but has dependents who do have work, this routine still returns PETSC_TRUE.
330*030f984aSJacob Faibussowitsch 
331*030f984aSJacob Faibussowitsch   Results of PetscDeviceContextQueryIdle() are cached on return, allowing this function to be called repeatedly in an
332*030f984aSJacob Faibussowitsch   efficient manner. When debug mode is enabled this cache is verified on every call to
333*030f984aSJacob Faibussowitsch   this routine, but is blindly believed when debugging is disabled.
334*030f984aSJacob Faibussowitsch 
335*030f984aSJacob Faibussowitsch   Level: intermediate
336*030f984aSJacob Faibussowitsch 
337*030f984aSJacob Faibussowitsch .seealso: PetscDeviceContextCreate(), PetscDeviceContextWaitForContext(), PetscDeviceContextFork()
338*030f984aSJacob Faibussowitsch @*/
339*030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextQueryIdle(PetscDeviceContext dctx, PetscBool *idle)
340*030f984aSJacob Faibussowitsch {
341*030f984aSJacob Faibussowitsch   PetscErrorCode ierr;
342*030f984aSJacob Faibussowitsch 
343*030f984aSJacob Faibussowitsch   PetscFunctionBegin;
344*030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx,1);
345*030f984aSJacob Faibussowitsch   PetscValidBoolPointer(idle,2);
346*030f984aSJacob Faibussowitsch   if (dctx->idle) {
347*030f984aSJacob Faibussowitsch     *idle = PETSC_TRUE;
348*030f984aSJacob Faibussowitsch     ierr = PetscDeviceContextValidateIdle_Internal(dctx);CHKERRQ(ierr);
349*030f984aSJacob Faibussowitsch   } else {
350*030f984aSJacob Faibussowitsch     ierr = (*dctx->ops->query)(dctx,idle);CHKERRQ(ierr);
351*030f984aSJacob Faibussowitsch     dctx->idle = *idle;
352*030f984aSJacob Faibussowitsch   }
353*030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
354*030f984aSJacob Faibussowitsch }
355*030f984aSJacob Faibussowitsch 
356*030f984aSJacob Faibussowitsch /*@C
357*030f984aSJacob Faibussowitsch   PetscDeviceContextWaitForContext - Make one context wait for another context to finish
358*030f984aSJacob Faibussowitsch 
359*030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
360*030f984aSJacob Faibussowitsch 
361*030f984aSJacob Faibussowitsch   Input Parameters:
362*030f984aSJacob Faibussowitsch + dctxa - The PetscDeviceContext object that is waiting
363*030f984aSJacob Faibussowitsch - dctxb - The PetscDeviceContext object that is being waited on
364*030f984aSJacob Faibussowitsch 
365*030f984aSJacob Faibussowitsch   Notes:
366*030f984aSJacob Faibussowitsch   Serializes two PetscDeviceContexts. This routine uses only the state of dctxb at the moment this routine was
367*030f984aSJacob Faibussowitsch   called, so any future work queued will not affect dctxa. It is safe to pass the same context to both arguments.
368*030f984aSJacob Faibussowitsch 
369*030f984aSJacob Faibussowitsch   Level: beginner
370*030f984aSJacob Faibussowitsch 
371*030f984aSJacob Faibussowitsch .seealso: PetscDeviceContextCreate(), PetscDeviceContextQueryIdle(), PetscDeviceContextJoin()
372*030f984aSJacob Faibussowitsch @*/
373*030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextWaitForContext(PetscDeviceContext dctxa, PetscDeviceContext dctxb)
374*030f984aSJacob Faibussowitsch {
375*030f984aSJacob Faibussowitsch   PetscErrorCode ierr;
376*030f984aSJacob Faibussowitsch 
377*030f984aSJacob Faibussowitsch   PetscFunctionBegin;
378*030f984aSJacob Faibussowitsch   PetscCheckCompatibleDeviceContexts(dctxa,1,dctxb,2);
379*030f984aSJacob Faibussowitsch   if (dctxa == dctxb) PetscFunctionReturn(0);
380*030f984aSJacob Faibussowitsch   if (dctxb->idle) {
381*030f984aSJacob Faibussowitsch     /* No need to do the extra function lookup and event record if the stream were waiting on isn't doing anything */
382*030f984aSJacob Faibussowitsch     ierr = PetscDeviceContextValidateIdle_Internal(dctxb);CHKERRQ(ierr);
383*030f984aSJacob Faibussowitsch   } else {
384*030f984aSJacob Faibussowitsch     ierr = (*dctxa->ops->waitforctx)(dctxa,dctxb);CHKERRQ(ierr);
385*030f984aSJacob Faibussowitsch   }
386*030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
387*030f984aSJacob Faibussowitsch }
388*030f984aSJacob Faibussowitsch 
389*030f984aSJacob Faibussowitsch /*@C
390*030f984aSJacob Faibussowitsch   PetscDeviceContextFork - Create a set of dependent child contexts from a parent context
391*030f984aSJacob Faibussowitsch 
392*030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
393*030f984aSJacob Faibussowitsch 
394*030f984aSJacob Faibussowitsch   Input Parameters:
395*030f984aSJacob Faibussowitsch + dctx - The parent PetscDeviceContext
396*030f984aSJacob Faibussowitsch - n    - The number of children to create
397*030f984aSJacob Faibussowitsch 
398*030f984aSJacob Faibussowitsch   Output Parameter:
399*030f984aSJacob Faibussowitsch . dsub - The created child context(s)
400*030f984aSJacob Faibussowitsch 
401*030f984aSJacob Faibussowitsch   Notes:
402*030f984aSJacob Faibussowitsch   This routine creates n edges of a DAG from a source node which are causally dependent on the source node, meaning
403*030f984aSJacob Faibussowitsch   that work queued on child contexts will not start until the parent context finishes its work. This accounts for work
404*030f984aSJacob Faibussowitsch   queued on the parent up until calling this function, any subsequent work enqueued on the parent has no effect on the children.
405*030f984aSJacob Faibussowitsch 
406*030f984aSJacob Faibussowitsch   Any children created with this routine have their lifetimes bounded by the parent. That is, the parent context expects
407*030f984aSJacob Faibussowitsch   to free all of it's children (and ONLY its children) before itself is freed.
408*030f984aSJacob Faibussowitsch 
409*030f984aSJacob Faibussowitsch   DAG representation:
410*030f984aSJacob Faibussowitsch .vb
411*030f984aSJacob Faibussowitsch   time ->
412*030f984aSJacob Faibussowitsch 
413*030f984aSJacob Faibussowitsch   -> dctx \----> dctx ------>
414*030f984aSJacob Faibussowitsch            \---> dsub[0] --->
415*030f984aSJacob Faibussowitsch             \--> ... ------->
416*030f984aSJacob Faibussowitsch              \-> dsub[n-1] ->
417*030f984aSJacob Faibussowitsch .ve
418*030f984aSJacob Faibussowitsch 
419*030f984aSJacob Faibussowitsch   Level: intermediate
420*030f984aSJacob Faibussowitsch 
421*030f984aSJacob Faibussowitsch .seealso: PetscDeviceContextJoin(), PetscDeviceContextSynchronize(), PetscDeviceContextQueryIdle()
422*030f984aSJacob Faibussowitsch @*/
423*030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextFork(PetscDeviceContext dctx, PetscInt n, PetscDeviceContext **dsub)
424*030f984aSJacob Faibussowitsch {
425*030f984aSJacob Faibussowitsch #if defined(PETSC_USE_DEBUG) && defined(PETSC_USE_INFO)
426*030f984aSJacob Faibussowitsch   const PetscInt      nBefore = n;
427*030f984aSJacob Faibussowitsch   static std::string  idList;
428*030f984aSJacob Faibussowitsch #endif
429*030f984aSJacob Faibussowitsch   PetscDeviceContext *dsubTmp = nullptr;
430*030f984aSJacob Faibussowitsch   PetscInt            i = 0;
431*030f984aSJacob Faibussowitsch   PetscErrorCode      ierr;
432*030f984aSJacob Faibussowitsch 
433*030f984aSJacob Faibussowitsch   PetscFunctionBegin;
434*030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx,1);
435*030f984aSJacob Faibussowitsch   PetscValidPointer(dsub,3);
436*030f984aSJacob Faibussowitsch   if (PetscUnlikelyDebug(n < 0)) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Number of contexts requested %D < 0",n);
437*030f984aSJacob Faibussowitsch #if defined(PETSC_USE_DEBUG) && defined(PETSC_USE_INFO)
438*030f984aSJacob Faibussowitsch   /* reserve 4 chars per id, 2 for number and 2 for ', ' separator */
439*030f984aSJacob Faibussowitsch   idList.reserve(4*n);
440*030f984aSJacob Faibussowitsch #endif
441*030f984aSJacob Faibussowitsch   /* update child totals */
442*030f984aSJacob Faibussowitsch   dctx->numChildren += n;
443*030f984aSJacob Faibussowitsch   /* now to find out if we have room */
444*030f984aSJacob Faibussowitsch   if (dctx->numChildren > dctx->maxNumChildren) {
445*030f984aSJacob Faibussowitsch     /* no room, either from having too many kids or not having any */
446*030f984aSJacob Faibussowitsch     if (dctx->childIDs) {
447*030f984aSJacob Faibussowitsch       /* have existing children, must reallocate them */
448*030f984aSJacob Faibussowitsch       ierr = PetscRealloc(dctx->numChildren*sizeof(*dctx->childIDs),&dctx->childIDs);CHKERRQ(ierr);
449*030f984aSJacob Faibussowitsch       /* clear the extra memory since realloc doesn't do it for us */
450*030f984aSJacob Faibussowitsch       ierr = PetscArrayzero((dctx->childIDs)+(dctx->maxNumChildren),(dctx->numChildren)-(dctx->maxNumChildren));CHKERRQ(ierr);
451*030f984aSJacob Faibussowitsch     } else {
452*030f984aSJacob Faibussowitsch       /* have no children */
453*030f984aSJacob Faibussowitsch       ierr = PetscCalloc1(dctx->numChildren,&dctx->childIDs);CHKERRQ(ierr);
454*030f984aSJacob Faibussowitsch     }
455*030f984aSJacob Faibussowitsch     /* update total number of children */
456*030f984aSJacob Faibussowitsch     dctx->maxNumChildren = dctx->numChildren;
457*030f984aSJacob Faibussowitsch   }
458*030f984aSJacob Faibussowitsch   ierr = PetscMalloc1(n,&dsubTmp);CHKERRQ(ierr);
459*030f984aSJacob Faibussowitsch   while (n) {
460*030f984aSJacob Faibussowitsch     /* empty child slot */
461*030f984aSJacob Faibussowitsch     if (!(dctx->childIDs[i])) {
462*030f984aSJacob Faibussowitsch       /* create the child context in the image of its parent */
463*030f984aSJacob Faibussowitsch       ierr = PetscDeviceContextDuplicate(dctx,dsubTmp+i);CHKERRQ(ierr);
464*030f984aSJacob Faibussowitsch       ierr = PetscDeviceContextWaitForContext(dsubTmp[i],dctx);CHKERRQ(ierr);
465*030f984aSJacob Faibussowitsch       /* register the child with its parent */
466*030f984aSJacob Faibussowitsch       dctx->childIDs[i] = dsubTmp[i]->id;
467*030f984aSJacob Faibussowitsch #if defined(PETSC_USE_DEBUG) && defined(PETSC_USE_INFO)
468*030f984aSJacob Faibussowitsch       idList += std::to_string(dsubTmp[i]->id);
469*030f984aSJacob Faibussowitsch       if (n != 1) idList += ", ";
470*030f984aSJacob Faibussowitsch #endif
471*030f984aSJacob Faibussowitsch       --n;
472*030f984aSJacob Faibussowitsch     }
473*030f984aSJacob Faibussowitsch     ++i;
474*030f984aSJacob Faibussowitsch   }
475*030f984aSJacob Faibussowitsch #if defined(PETSC_USE_DEBUG) && defined(PETSC_USE_INFO)
476*030f984aSJacob Faibussowitsch   ierr = PetscInfo3(NULL,"Forked %D children from parent %D with IDs: %s\n",nBefore,dctx->id,idList.c_str());CHKERRQ(ierr);
477*030f984aSJacob Faibussowitsch   /* resets the size but doesn't deallocate the memory */
478*030f984aSJacob Faibussowitsch   idList.clear();
479*030f984aSJacob Faibussowitsch #endif
480*030f984aSJacob Faibussowitsch   /* pass the children back to caller */
481*030f984aSJacob Faibussowitsch   *dsub = dsubTmp;
482*030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
483*030f984aSJacob Faibussowitsch }
484*030f984aSJacob Faibussowitsch 
485*030f984aSJacob Faibussowitsch /*@C
486*030f984aSJacob Faibussowitsch   PetscDeviceContextJoin() - Converge a set of child contexts
487*030f984aSJacob Faibussowitsch 
488*030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
489*030f984aSJacob Faibussowitsch 
490*030f984aSJacob Faibussowitsch   Input Parameters:
491*030f984aSJacob Faibussowitsch + dctx         - A PetscDeviceContext to converge on
492*030f984aSJacob Faibussowitsch . n            - The number of sub contexts to converge
493*030f984aSJacob Faibussowitsch . joinMode     - The type of join to perform
494*030f984aSJacob Faibussowitsch - dsub         - The sub contexts to converge
495*030f984aSJacob Faibussowitsch 
496*030f984aSJacob Faibussowitsch   Notes:
497*030f984aSJacob Faibussowitsch   If PetscDeviceContextFork() creates n edges from a source node which all depend on the
498*030f984aSJacob Faibussowitsch   source node, then this routine is the exact mirror. That is, it creates a node
499*030f984aSJacob Faibussowitsch   (represented in dctx) which recieves n edges (and optionally destroys them) which is
500*030f984aSJacob Faibussowitsch   dependent on the completion of all incoming edges.
501*030f984aSJacob Faibussowitsch 
502*030f984aSJacob Faibussowitsch   If joinMode is PETSC_DEVICE_CONTEXT_JOIN_DESTROY all contexts in dsub will be destroyed
503*030f984aSJacob Faibussowitsch   by this routine. Thus all sub contexts must have been created with the dctx passed to
504*030f984aSJacob Faibussowitsch   this routine.
505*030f984aSJacob Faibussowitsch 
506*030f984aSJacob Faibussowitsch   if joinMode is PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC dctx waits for all sub contexts but the
507*030f984aSJacob Faibussowitsch   sub contexts do not wait for one another afterwards.
508*030f984aSJacob Faibussowitsch 
509*030f984aSJacob Faibussowitsch   If joinMode is PETSC_DEVICE_CONTEXT_JOIN_SYNC all sub contexts will additionally
510*030f984aSJacob Faibussowitsch   wait on dctx after converging. This has the effect of "synchronizing" the outgoing
511*030f984aSJacob Faibussowitsch   edges.
512*030f984aSJacob Faibussowitsch 
513*030f984aSJacob Faibussowitsch   DAG representations:
514*030f984aSJacob Faibussowitsch   If joinMode is PETSC_DEVICE_CONTEXT_JOIN_DESTROY
515*030f984aSJacob Faibussowitsch .vb
516*030f984aSJacob Faibussowitsch   time ->
517*030f984aSJacob Faibussowitsch 
518*030f984aSJacob Faibussowitsch   -> dctx ---------/- dctx ->
519*030f984aSJacob Faibussowitsch   -> dsub[0] -----/
520*030f984aSJacob Faibussowitsch   ->  ... -------/
521*030f984aSJacob Faibussowitsch   -> dsub[n-1] -/
522*030f984aSJacob Faibussowitsch .ve
523*030f984aSJacob Faibussowitsch   If joinMode is PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC
524*030f984aSJacob Faibussowitsch .vb
525*030f984aSJacob Faibussowitsch   time ->
526*030f984aSJacob Faibussowitsch 
527*030f984aSJacob Faibussowitsch   -> dctx ---------/- dctx ->
528*030f984aSJacob Faibussowitsch   -> dsub[0] -----/--------->
529*030f984aSJacob Faibussowitsch   ->  ... -------/---------->
530*030f984aSJacob Faibussowitsch   -> dsub[n-1] -/----------->
531*030f984aSJacob Faibussowitsch .ve
532*030f984aSJacob Faibussowitsch   If joinMode is PETSC_DEVICE_CONTEXT_JOIN_SYNC
533*030f984aSJacob Faibussowitsch .vb
534*030f984aSJacob Faibussowitsch   time ->
535*030f984aSJacob Faibussowitsch 
536*030f984aSJacob Faibussowitsch   -> dctx ---------/- dctx -\----> dctx ------>
537*030f984aSJacob Faibussowitsch   -> dsub[0] -----/          \---> dsub[0] --->
538*030f984aSJacob Faibussowitsch   ->  ... -------/            \--> ... ------->
539*030f984aSJacob Faibussowitsch   -> dsub[n-1] -/              \-> dsub[n-1] ->
540*030f984aSJacob Faibussowitsch .ve
541*030f984aSJacob Faibussowitsch 
542*030f984aSJacob Faibussowitsch   Level: intermediate
543*030f984aSJacob Faibussowitsch 
544*030f984aSJacob Faibussowitsch .seealso: PetscDeviceContextFork(), PetscDeviceContextSynchronize(), PetscDeviceContextJoinMode
545*030f984aSJacob Faibussowitsch @*/
546*030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextJoin(PetscDeviceContext dctx, PetscInt n, PetscDeviceContextJoinMode joinMode, PetscDeviceContext **dsub)
547*030f984aSJacob Faibussowitsch {
548*030f984aSJacob Faibussowitsch #if defined(PETSC_USE_DEBUG) && defined(PETSC_USE_INFO)
549*030f984aSJacob Faibussowitsch   static std::string idList;
550*030f984aSJacob Faibussowitsch #endif
551*030f984aSJacob Faibussowitsch   PetscErrorCode     ierr;
552*030f984aSJacob Faibussowitsch 
553*030f984aSJacob Faibussowitsch   PetscFunctionBegin;
554*030f984aSJacob Faibussowitsch   /* validity of dctx is checked in the wait-for loop */
555*030f984aSJacob Faibussowitsch   PetscValidPointer(dsub,4);
556*030f984aSJacob Faibussowitsch   if (PetscUnlikelyDebug(n < 0)) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Number of contexts merged %D < 0",n);
557*030f984aSJacob Faibussowitsch #if defined(PETSC_USE_DEBUG) && defined(PETSC_USE_INFO)
558*030f984aSJacob Faibussowitsch   /* reserve 4 chars per id, 2 for number and 2 for ', ' separator */
559*030f984aSJacob Faibussowitsch   idList.reserve(4*n);
560*030f984aSJacob Faibussowitsch #endif
561*030f984aSJacob Faibussowitsch   /* first dctx waits on all the incoming edges */
562*030f984aSJacob Faibussowitsch   for (PetscInt i = 0; i < n; ++i) {
563*030f984aSJacob Faibussowitsch     PetscCheckCompatibleDeviceContexts(dctx,1,(*dsub)[i],4);
564*030f984aSJacob Faibussowitsch     ierr = PetscDeviceContextWaitForContext(dctx,(*dsub)[i]);CHKERRQ(ierr);
565*030f984aSJacob Faibussowitsch #if defined(PETSC_USE_DEBUG) && defined(PETSC_USE_INFO)
566*030f984aSJacob Faibussowitsch     idList += std::to_string((*dsub)[i]->id);
567*030f984aSJacob Faibussowitsch     if (i+1 < n) idList += ", ";
568*030f984aSJacob Faibussowitsch #endif
569*030f984aSJacob Faibussowitsch   }
570*030f984aSJacob Faibussowitsch 
571*030f984aSJacob Faibussowitsch   /* now we handle the aftermath */
572*030f984aSJacob Faibussowitsch   switch (joinMode) {
573*030f984aSJacob Faibussowitsch   case PETSC_DEVICE_CONTEXT_JOIN_DESTROY:
574*030f984aSJacob Faibussowitsch     {
575*030f984aSJacob Faibussowitsch       PetscInt j = 0;
576*030f984aSJacob Faibussowitsch 
577*030f984aSJacob Faibussowitsch       if (PetscUnlikelyDebug(n > dctx->numChildren)) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Trying to destroy %D children of a parent context that only has %D children, likely trying to restore to wrong parent",n,dctx->numChildren);
578*030f984aSJacob Faibussowitsch       /* update child count while it's still fresh in memory */
579*030f984aSJacob Faibussowitsch       dctx->numChildren -= n;
580*030f984aSJacob Faibussowitsch       for (PetscInt i = 0; i < dctx->maxNumChildren; ++i) {
581*030f984aSJacob Faibussowitsch         if (dctx->childIDs[i] && (dctx->childIDs[i] == (*dsub)[j]->id)) {
582*030f984aSJacob Faibussowitsch           /* child is one of ours, can destroy it */
583*030f984aSJacob Faibussowitsch           ierr = PetscDeviceContextDestroy((*dsub)+j);CHKERRQ(ierr);
584*030f984aSJacob Faibussowitsch           /* reset the child slot */
585*030f984aSJacob Faibussowitsch           dctx->childIDs[i] = 0;
586*030f984aSJacob Faibussowitsch           if (++j == n) break;
587*030f984aSJacob Faibussowitsch         }
588*030f984aSJacob Faibussowitsch       }
589*030f984aSJacob 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 */
590*030f984aSJacob Faibussowitsch       if (PetscUnlikelyDebug(j != n)) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"%D 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);
591*030f984aSJacob Faibussowitsch       ierr = PetscFree(*dsub);CHKERRQ(ierr);
592*030f984aSJacob Faibussowitsch     }
593*030f984aSJacob Faibussowitsch     break;
594*030f984aSJacob Faibussowitsch   case PETSC_DEVICE_CONTEXT_JOIN_SYNC:
595*030f984aSJacob Faibussowitsch     for (PetscInt i = 0; i < n; ++i) {
596*030f984aSJacob Faibussowitsch       ierr = PetscDeviceContextWaitForContext((*dsub)[i],dctx);CHKERRQ(ierr);
597*030f984aSJacob Faibussowitsch     }
598*030f984aSJacob Faibussowitsch   case PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC:
599*030f984aSJacob Faibussowitsch     break;
600*030f984aSJacob Faibussowitsch   default:
601*030f984aSJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Unknown PetscDeviceContextJoinMode given");
602*030f984aSJacob Faibussowitsch     break;
603*030f984aSJacob Faibussowitsch   }
604*030f984aSJacob Faibussowitsch 
605*030f984aSJacob Faibussowitsch #if defined(PETSC_USE_DEBUG) && defined(PETSC_USE_INFO)
606*030f984aSJacob Faibussowitsch   ierr = PetscInfo4(NULL,"Joined %D ctxs to ctx %D, mode %s with IDs: %s\n",n,dctx->id,PetscDeviceContextJoinModes[joinMode],idList.c_str());CHKERRQ(ierr);
607*030f984aSJacob Faibussowitsch   idList.clear();
608*030f984aSJacob Faibussowitsch #endif
609*030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
610*030f984aSJacob Faibussowitsch }
611*030f984aSJacob Faibussowitsch 
612*030f984aSJacob Faibussowitsch /*@C
613*030f984aSJacob Faibussowitsch   PetscDeviceContextSynchronize() - Block the host until all work queued on or associated with a PetscDeviceContext has finished
614*030f984aSJacob Faibussowitsch 
615*030f984aSJacob Faibussowitsch   Not Collective, Synchronous
616*030f984aSJacob Faibussowitsch 
617*030f984aSJacob Faibussowitsch   Input Parameters:
618*030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext to synchronize
619*030f984aSJacob Faibussowitsch 
620*030f984aSJacob Faibussowitsch   Level: beginner
621*030f984aSJacob Faibussowitsch 
622*030f984aSJacob Faibussowitsch .seealso: PetscDeviceContextFork(), PetscDeviceContextJoin(), PetscDeviceContextQueryIdle()
623*030f984aSJacob Faibussowitsch @*/
624*030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextSynchronize(PetscDeviceContext dctx)
625*030f984aSJacob Faibussowitsch {
626*030f984aSJacob Faibussowitsch   PetscErrorCode ierr;
627*030f984aSJacob Faibussowitsch 
628*030f984aSJacob Faibussowitsch   PetscFunctionBegin;
629*030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx,1);
630*030f984aSJacob Faibussowitsch   /* if it isn't setup there is nothing to sync on */
631*030f984aSJacob Faibussowitsch   if (dctx->setup) {ierr = (*dctx->ops->synchronize)(dctx);CHKERRQ(ierr);}
632*030f984aSJacob Faibussowitsch   dctx->idle = PETSC_TRUE;
633*030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
634*030f984aSJacob Faibussowitsch }
635*030f984aSJacob Faibussowitsch 
636*030f984aSJacob Faibussowitsch static PetscDeviceContext globalContext      = nullptr;
637*030f984aSJacob Faibussowitsch static PetscBool          globalContextSetup = PETSC_FALSE;
638*030f984aSJacob Faibussowitsch static PetscStreamType    defaultStreamType  = PETSC_STREAM_DEFAULT_BLOCKING;
639*030f984aSJacob Faibussowitsch 
640*030f984aSJacob Faibussowitsch /* automatically registered to PetscFinalize() when first context is instantiated, do not
641*030f984aSJacob Faibussowitsch    call */
642*030f984aSJacob Faibussowitsch static PetscErrorCode PetscDeviceContextDestroyGlobalContext_Private(void)
643*030f984aSJacob Faibussowitsch {
644*030f984aSJacob Faibussowitsch   PetscErrorCode ierr;
645*030f984aSJacob Faibussowitsch 
646*030f984aSJacob Faibussowitsch   PetscFunctionBegin;
647*030f984aSJacob Faibussowitsch   ierr = PetscDeviceContextSynchronize(globalContext);CHKERRQ(ierr);
648*030f984aSJacob Faibussowitsch   ierr = PetscDeviceContextDestroy(&globalContext);CHKERRQ(ierr);
649*030f984aSJacob Faibussowitsch   /* reset everything to defaults */
650*030f984aSJacob Faibussowitsch   defaultStreamType  = PETSC_STREAM_DEFAULT_BLOCKING;
651*030f984aSJacob Faibussowitsch   globalContextSetup = PETSC_FALSE;
652*030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
653*030f984aSJacob Faibussowitsch }
654*030f984aSJacob Faibussowitsch 
655*030f984aSJacob Faibussowitsch /* creates and initializes the root context in PetscInitialize() but does not call
656*030f984aSJacob Faibussowitsch    SetUp() as the user may wish to change types after PetscInitialize() */
657*030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextInitializeRootContext_Internal(MPI_Comm comm, const char prefix[])
658*030f984aSJacob Faibussowitsch {
659*030f984aSJacob Faibussowitsch   PetscErrorCode ierr;
660*030f984aSJacob Faibussowitsch 
661*030f984aSJacob Faibussowitsch   PetscFunctionBegin;
662*030f984aSJacob Faibussowitsch   ierr = PetscInfo1(NULL,"Initializing root PetscDeviceContext with PetscDeviceKind %s\n",PetscDeviceKinds[PETSC_DEVICE_DEFAULT]);CHKERRQ(ierr);
663*030f984aSJacob Faibussowitsch   ierr = PetscDeviceContextCreate(&globalContext);CHKERRQ(ierr);
664*030f984aSJacob Faibussowitsch   if (PetscUnlikelyDebug(globalContext->id != 0)) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"The root current PetscDeviceContext should have id = 0, however it has id = %D",globalContext->id);
665*030f984aSJacob Faibussowitsch   ierr = PetscDeviceContextSetDevice(globalContext,PetscDeviceDefault_Internal());CHKERRQ(ierr);
666*030f984aSJacob Faibussowitsch   ierr = PetscDeviceContextSetStreamType(globalContext,defaultStreamType);CHKERRQ(ierr);
667*030f984aSJacob Faibussowitsch   ierr = PetscDeviceContextSetFromOptions(comm,prefix,globalContext);CHKERRQ(ierr);
668*030f984aSJacob Faibussowitsch   ierr = PetscRegisterFinalize(PetscDeviceContextDestroyGlobalContext_Private);CHKERRQ(ierr);
669*030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
670*030f984aSJacob Faibussowitsch }
671*030f984aSJacob Faibussowitsch 
672*030f984aSJacob Faibussowitsch /*@C
673*030f984aSJacob Faibussowitsch   PetscDeviceContextGetCurrentContext() - Get the current active PetscDeviceContext
674*030f984aSJacob Faibussowitsch 
675*030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
676*030f984aSJacob Faibussowitsch 
677*030f984aSJacob Faibussowitsch   Output Parameter:
678*030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext
679*030f984aSJacob Faibussowitsch 
680*030f984aSJacob Faibussowitsch   Notes:
681*030f984aSJacob Faibussowitsch   The user generally should not destroy contexts retrieved with this routine unless they themselves have created
682*030f984aSJacob Faibussowitsch   them. There exists no protection against destroying the root context.
683*030f984aSJacob Faibussowitsch 
684*030f984aSJacob Faibussowitsch   Developer Notes:
685*030f984aSJacob Faibussowitsch   This routine creates the "root" context the first time it is called, registering its
686*030f984aSJacob Faibussowitsch   destructor to PetscFinalize(). The root context is synchronized before being destroyed.
687*030f984aSJacob Faibussowitsch 
688*030f984aSJacob Faibussowitsch   Level: beginner
689*030f984aSJacob Faibussowitsch 
690*030f984aSJacob Faibussowitsch .seealso: PetscDeviceContextSetCurrentContext(), PetscDeviceContextFork(),
691*030f984aSJacob Faibussowitsch PetscDeviceContextJoin(), PetscDeviceContextCreate()
692*030f984aSJacob Faibussowitsch @*/
693*030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextGetCurrentContext(PetscDeviceContext *dctx)
694*030f984aSJacob Faibussowitsch {
695*030f984aSJacob Faibussowitsch   PetscFunctionBegin;
696*030f984aSJacob Faibussowitsch   PetscValidPointer(dctx,1);
697*030f984aSJacob Faibussowitsch   if (PetscUnlikely(!globalContextSetup)) {
698*030f984aSJacob Faibussowitsch     PetscErrorCode ierr;
699*030f984aSJacob Faibussowitsch 
700*030f984aSJacob Faibussowitsch     /* if there is no available device backend, PetscDeviceInitializePackage() will fire a
701*030f984aSJacob Faibussowitsch        PETSC_ERR_SUP_SYS error. */
702*030f984aSJacob Faibussowitsch     ierr = PetscDeviceInitializePackage();CHKERRQ(ierr);
703*030f984aSJacob Faibussowitsch     ierr = PetscDeviceContextSetUp(globalContext);CHKERRQ(ierr);
704*030f984aSJacob Faibussowitsch     globalContextSetup = PETSC_TRUE;
705*030f984aSJacob Faibussowitsch   }
706*030f984aSJacob Faibussowitsch   *dctx = globalContext;
707*030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
708*030f984aSJacob Faibussowitsch }
709*030f984aSJacob Faibussowitsch 
710*030f984aSJacob Faibussowitsch /*@C
711*030f984aSJacob Faibussowitsch   PetscDeviceContextSetCurrentContext() - Set the current active PetscDeviceContext
712*030f984aSJacob Faibussowitsch 
713*030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
714*030f984aSJacob Faibussowitsch 
715*030f984aSJacob Faibussowitsch   Input Parameter:
716*030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext
717*030f984aSJacob Faibussowitsch 
718*030f984aSJacob Faibussowitsch   Notes:
719*030f984aSJacob Faibussowitsch   The old context is not stored in any way by this routine; if one is overriding a context that they themselves do not
720*030f984aSJacob Faibussowitsch   control, one should take care to temporarily store it by calling PetscDeviceContextGetCurrentContext() before calling
721*030f984aSJacob Faibussowitsch   this routine.
722*030f984aSJacob Faibussowitsch 
723*030f984aSJacob Faibussowitsch   Level: beginner
724*030f984aSJacob Faibussowitsch 
725*030f984aSJacob Faibussowitsch .seealso: PetscDeviceContextGetCurrentContext(), PetscDeviceContextFork(),
726*030f984aSJacob Faibussowitsch PetscDeviceContextJoin(), PetscDeviceContextCreate()
727*030f984aSJacob Faibussowitsch @*/
728*030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetCurrentContext(PetscDeviceContext dctx)
729*030f984aSJacob Faibussowitsch {
730*030f984aSJacob Faibussowitsch   PetscErrorCode ierr;
731*030f984aSJacob Faibussowitsch 
732*030f984aSJacob Faibussowitsch   PetscFunctionBegin;
733*030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx,1);
734*030f984aSJacob Faibussowitsch   globalContext = dctx;
735*030f984aSJacob Faibussowitsch   ierr = PetscInfo1(NULL,"Set global device context id %D\n",dctx->id);CHKERRQ(ierr);
736*030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
737*030f984aSJacob Faibussowitsch }
738*030f984aSJacob Faibussowitsch 
739*030f984aSJacob Faibussowitsch /*@C
740*030f984aSJacob Faibussowitsch   PetscDeviceContextSetFromOptions - Configure a PetscDeviceContext from the options database
741*030f984aSJacob Faibussowitsch 
742*030f984aSJacob Faibussowitsch   Collective on comm, Asynchronous
743*030f984aSJacob Faibussowitsch 
744*030f984aSJacob Faibussowitsch   Input Parameters:
745*030f984aSJacob Faibussowitsch + comm   - MPI communicator on which to query the options database
746*030f984aSJacob Faibussowitsch . prefix - prefix to prepend to all options database queries, NULL if not needed
747*030f984aSJacob Faibussowitsch - dctx   - The PetscDeviceContext to configure
748*030f984aSJacob Faibussowitsch 
749*030f984aSJacob Faibussowitsch   Output Parameter:
750*030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext
751*030f984aSJacob Faibussowitsch 
752*030f984aSJacob Faibussowitsch   Options Database:
753*030f984aSJacob Faibussowitsch . -device_context_device_kind - the kind of PetscDevice to attach by default
754*030f984aSJacob Faibussowitsch . -device_context_stream_type - type of stream to create inside the PetscDeviceContext -
755*030f984aSJacob Faibussowitsch   PetscDeviceContextSetStreamType()
756*030f984aSJacob Faibussowitsch 
757*030f984aSJacob Faibussowitsch   Level: beginner
758*030f984aSJacob Faibussowitsch 
759*030f984aSJacob Faibussowitsch .seealso: PetscDeviceContextSetStreamType()
760*030f984aSJacob Faibussowitsch @*/
761*030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetFromOptions(MPI_Comm comm, const char prefix[], PetscDeviceContext dctx)
762*030f984aSJacob Faibussowitsch {
763*030f984aSJacob Faibussowitsch   PetscBool      flag;
764*030f984aSJacob Faibussowitsch   PetscInt       stype,dkind;
765*030f984aSJacob Faibussowitsch   PetscErrorCode ierr;
766*030f984aSJacob Faibussowitsch 
767*030f984aSJacob Faibussowitsch   PetscFunctionBegin;
768*030f984aSJacob Faibussowitsch   if (prefix) {PetscValidCharPointer(prefix,2);}
769*030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx,3);
770*030f984aSJacob Faibussowitsch   ierr = PetscOptionsBegin(comm,prefix,"PetscDeviceContext Options","Sys");CHKERRQ(ierr);
771*030f984aSJacob Faibussowitsch   ierr = PetscOptionsEList("-device_context_device_kind","Underlying PetscDevice","PetscDeviceContextSetDevice",PetscDeviceKinds+1,PETSC_DEVICE_MAX-1,dctx->device ? PetscDeviceKinds[dctx->device->kind] : PetscDeviceKinds[PETSC_DEVICE_DEFAULT],&dkind,&flag);CHKERRQ(ierr);
772*030f984aSJacob Faibussowitsch   if (flag) {
773*030f984aSJacob Faibussowitsch     ierr = PetscDeviceContextSetDevice(dctx,PetscDeviceDefaultKind_Internal(static_cast<PetscDeviceKind>(dkind+1)));CHKERRQ(ierr);
774*030f984aSJacob Faibussowitsch   }
775*030f984aSJacob Faibussowitsch   ierr = PetscOptionsEList("-device_context_stream_type","PetscDeviceContext PetscStreamType","PetscDeviceContextSetStreamType",PetscStreamTypes,3,PetscStreamTypes[dctx->streamType],&stype,&flag);CHKERRQ(ierr);
776*030f984aSJacob Faibussowitsch   if (flag) {
777*030f984aSJacob Faibussowitsch     ierr = PetscDeviceContextSetStreamType(dctx,static_cast<PetscStreamType>(stype));CHKERRQ(ierr);
778*030f984aSJacob Faibussowitsch   }
779*030f984aSJacob Faibussowitsch   ierr = PetscOptionsEnd();CHKERRQ(ierr);
780*030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
781*030f984aSJacob Faibussowitsch }
782