xref: /petsc/src/sys/objects/device/interface/dcontext.cxx (revision 17f48955e3445b92d4f06cdd133e9c1d2d0ea0c8)
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_",
11a4af0ceeSJacob Faibussowitsch   PETSC_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_",
20a4af0ceeSJacob Faibussowitsch   PETSC_NULLPTR
21a4af0ceeSJacob Faibussowitsch };
22a4af0ceeSJacob Faibussowitsch 
23030f984aSJacob Faibussowitsch /* Define the allocator */
24*17f48955SJacob Faibussowitsch struct PetscDeviceContextAllocator : Petsc::AllocatorBase<PetscDeviceContext>
25030f984aSJacob Faibussowitsch {
26030f984aSJacob Faibussowitsch   static PetscInt PetscDeviceContextID;
27030f984aSJacob Faibussowitsch 
28*17f48955SJacob 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->idle       = PETSC_TRUE;
37030f984aSJacob Faibussowitsch     dc->streamType = PETSC_STREAM_DEFAULT_BLOCKING;
38030f984aSJacob Faibussowitsch     *dctx          = dc;
39030f984aSJacob Faibussowitsch     PetscFunctionReturn(0);
40030f984aSJacob Faibussowitsch   }
41030f984aSJacob Faibussowitsch 
42*17f48955SJacob Faibussowitsch   PETSC_NODISCARD static PetscErrorCode destroy(PetscDeviceContext dctx) noexcept
43030f984aSJacob Faibussowitsch   {
44030f984aSJacob Faibussowitsch     PetscErrorCode ierr;
45030f984aSJacob Faibussowitsch 
46030f984aSJacob Faibussowitsch     PetscFunctionBegin;
473ca90d2dSJacob Faibussowitsch     if (PetscUnlikelyDebug(dctx->numChildren)) SETERRQ1(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);
48030f984aSJacob Faibussowitsch     if (dctx->ops->destroy) {ierr = (*dctx->ops->destroy)(dctx);CHKERRQ(ierr);}
49030f984aSJacob Faibussowitsch     ierr = PetscDeviceDestroy(&dctx->device);CHKERRQ(ierr);
50030f984aSJacob Faibussowitsch     ierr = PetscFree(dctx->childIDs);CHKERRQ(ierr);
51030f984aSJacob Faibussowitsch     ierr = PetscFree(dctx);CHKERRQ(ierr);
52030f984aSJacob Faibussowitsch     PetscFunctionReturn(0);
53030f984aSJacob Faibussowitsch   }
54030f984aSJacob Faibussowitsch 
55*17f48955SJacob Faibussowitsch   PETSC_NODISCARD static PetscErrorCode reset(PetscDeviceContext dctx) noexcept
56030f984aSJacob Faibussowitsch   {
57030f984aSJacob Faibussowitsch     PetscErrorCode ierr;
58030f984aSJacob Faibussowitsch 
59030f984aSJacob Faibussowitsch     PetscFunctionBegin;
60030f984aSJacob Faibussowitsch     /* don't deallocate the child array, rather just zero it out */
61030f984aSJacob Faibussowitsch     ierr = PetscArrayzero(dctx->childIDs,dctx->maxNumChildren);CHKERRQ(ierr);
62030f984aSJacob Faibussowitsch     dctx->setup       = PETSC_FALSE;
63030f984aSJacob Faibussowitsch     dctx->numChildren = 0;
64030f984aSJacob Faibussowitsch     dctx->idle        = PETSC_TRUE;
65030f984aSJacob Faibussowitsch     dctx->streamType  = PETSC_STREAM_DEFAULT_BLOCKING;
66030f984aSJacob Faibussowitsch     PetscFunctionReturn(0);
67030f984aSJacob Faibussowitsch   }
68030f984aSJacob Faibussowitsch 
69*17f48955SJacob Faibussowitsch   PETSC_NODISCARD static constexpr PetscErrorCode finalize() noexcept { return 0; }
70030f984aSJacob Faibussowitsch };
71a4af0ceeSJacob Faibussowitsch /* an ID = 0 is invalid */
72a4af0ceeSJacob Faibussowitsch PetscInt PetscDeviceContextAllocator::PetscDeviceContextID = 1;
73030f984aSJacob Faibussowitsch 
74030f984aSJacob Faibussowitsch static Petsc::ObjectPool<PetscDeviceContext,PetscDeviceContextAllocator> contextPool;
75030f984aSJacob Faibussowitsch 
76030f984aSJacob Faibussowitsch /*@C
77030f984aSJacob Faibussowitsch   PetscDeviceContextCreate - Creates a PetscDeviceContext
78030f984aSJacob Faibussowitsch 
79030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
80030f984aSJacob Faibussowitsch 
8101d2d390SJose E. Roman   Output Paramemter:
82030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext
83030f984aSJacob Faibussowitsch 
84030f984aSJacob Faibussowitsch   Notes:
85030f984aSJacob Faibussowitsch   Unlike almost every other PETSc class it is advised that most users use
86030f984aSJacob Faibussowitsch   PetscDeviceContextDuplicate() rather than this routine to create new contexts. Contexts
87030f984aSJacob Faibussowitsch   of different types are incompatible with one another; using
88030f984aSJacob Faibussowitsch   PetscDeviceContextDuplicate() ensures compatible types.
89030f984aSJacob Faibussowitsch 
90030f984aSJacob Faibussowitsch   Level: beginner
91030f984aSJacob Faibussowitsch 
92030f984aSJacob Faibussowitsch .seealso: PetscDeviceContextDuplicate(), PetscDeviceContextSetDevice(),
935181c4f9SJacob Faibussowitsch PetscDeviceContextSetStreamType(), PetscDeviceContextSetUp(),
945181c4f9SJacob Faibussowitsch PetscDeviceContextSetFromOptions(), PetscDeviceContextDestroy()
95030f984aSJacob Faibussowitsch @*/
96030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextCreate(PetscDeviceContext *dctx)
97030f984aSJacob Faibussowitsch {
98030f984aSJacob Faibussowitsch   PetscErrorCode ierr;
99030f984aSJacob Faibussowitsch 
100030f984aSJacob Faibussowitsch   PetscFunctionBegin;
101030f984aSJacob Faibussowitsch   PetscValidPointer(dctx,1);
102030f984aSJacob Faibussowitsch   ierr = PetscDeviceInitializePackage();CHKERRQ(ierr);
103030f984aSJacob Faibussowitsch   ierr = contextPool.get(*dctx);CHKERRQ(ierr);
104030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
105030f984aSJacob Faibussowitsch }
106030f984aSJacob Faibussowitsch 
107030f984aSJacob Faibussowitsch /*@C
108030f984aSJacob Faibussowitsch   PetscDeviceContextDestroy - Frees a PetscDeviceContext
109030f984aSJacob Faibussowitsch 
110030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
111030f984aSJacob Faibussowitsch 
112030f984aSJacob Faibussowitsch   Input Parameters:
113030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext
114030f984aSJacob Faibussowitsch 
115030f984aSJacob Faibussowitsch   Notes:
116030f984aSJacob Faibussowitsch   No implicit synchronization occurs due to this routine, all resources are released completely asynchronously
117030f984aSJacob Faibussowitsch   w.r.t. the host. If one needs to guarantee access to the data produced on this contexts stream one should perform the
118030f984aSJacob Faibussowitsch   appropriate synchronization before calling this routine.
119030f984aSJacob Faibussowitsch 
120030f984aSJacob Faibussowitsch   Developer Notes:
121030f984aSJacob Faibussowitsch   The context is never actually "destroyed", only returned to an ever growing pool of
122030f984aSJacob Faibussowitsch   contexts. There are currently no safeguards on the size of the pool, this should perhaps
123030f984aSJacob Faibussowitsch   be implemented.
124030f984aSJacob Faibussowitsch 
125030f984aSJacob Faibussowitsch   Level: beginner
126030f984aSJacob Faibussowitsch 
127030f984aSJacob Faibussowitsch .seealso: PetscDeviceContextCreate(), PetscDeviceContextSetDevice(), PetscDeviceContextSetUp(), PetscDeviceContextSynchronize()
128030f984aSJacob Faibussowitsch @*/
129030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextDestroy(PetscDeviceContext *dctx)
130030f984aSJacob Faibussowitsch {
131030f984aSJacob Faibussowitsch   PetscErrorCode ierr;
132030f984aSJacob Faibussowitsch 
133030f984aSJacob Faibussowitsch   PetscFunctionBegin;
134030f984aSJacob Faibussowitsch   if (!*dctx) PetscFunctionReturn(0);
135030f984aSJacob Faibussowitsch   ierr  = contextPool.reclaim(std::move(*dctx));CHKERRQ(ierr);
136a4af0ceeSJacob Faibussowitsch   *dctx = PETSC_NULLPTR;
137030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
138030f984aSJacob Faibussowitsch }
139030f984aSJacob Faibussowitsch 
140030f984aSJacob Faibussowitsch /*@C
141030f984aSJacob Faibussowitsch   PetscDeviceContextSetStreamType - Set the implementation type of the underlying stream for a PetscDeviceContext
142030f984aSJacob Faibussowitsch 
143030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
144030f984aSJacob Faibussowitsch 
14501d2d390SJose E. Roman   Input Parameters:
146030f984aSJacob Faibussowitsch + dctx - The PetscDeviceContext
147030f984aSJacob Faibussowitsch - type - The PetscStreamType
148030f984aSJacob Faibussowitsch 
149030f984aSJacob Faibussowitsch   Notes:
150030f984aSJacob Faibussowitsch   See PetscStreamType in include/petscdevicetypes.h for more information on the available
151030f984aSJacob Faibussowitsch   types and their interactions. If the PetscDeviceContext was previously set up and stream
152030f984aSJacob Faibussowitsch   type was changed, you must call PetscDeviceContextSetUp() again after this routine.
153030f984aSJacob Faibussowitsch 
154030f984aSJacob Faibussowitsch   Level: intermediate
155030f984aSJacob Faibussowitsch 
1565181c4f9SJacob Faibussowitsch .seealso: PetscDeviceContextGetStreamType(), PetscDeviceContextCreate(), PetscDeviceContextSetUp(), PetscDeviceContextSetFromOptions()
157030f984aSJacob Faibussowitsch @*/
158030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetStreamType(PetscDeviceContext dctx, PetscStreamType type)
159030f984aSJacob Faibussowitsch {
160030f984aSJacob Faibussowitsch   PetscFunctionBegin;
161030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx,1);
162030f984aSJacob Faibussowitsch   PetscValidStreamType(type,2);
163030f984aSJacob Faibussowitsch   /* only need to do complex swapping if the object has already been setup */
164030f984aSJacob Faibussowitsch   if (dctx->setup && (dctx->streamType != type)) {
165030f984aSJacob Faibussowitsch     PetscErrorCode ierr;
166030f984aSJacob Faibussowitsch 
167030f984aSJacob Faibussowitsch     ierr = (*dctx->ops->changestreamtype)(dctx,type);CHKERRQ(ierr);
168030f984aSJacob Faibussowitsch     dctx->setup = PETSC_FALSE;
169030f984aSJacob Faibussowitsch   }
170030f984aSJacob Faibussowitsch   dctx->streamType = type;
171030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
172030f984aSJacob Faibussowitsch }
173030f984aSJacob Faibussowitsch 
174030f984aSJacob Faibussowitsch /*@C
175030f984aSJacob Faibussowitsch   PetscDeviceContextGetStreamType - Get the implementation type of the underlying stream for a PetscDeviceContext
176030f984aSJacob Faibussowitsch 
177030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
178030f984aSJacob Faibussowitsch 
17901d2d390SJose E. Roman   Input Parameter:
180030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext
181030f984aSJacob Faibussowitsch 
182030f984aSJacob Faibussowitsch   Output Parameter:
183030f984aSJacob Faibussowitsch . type - The PetscStreamType
184030f984aSJacob Faibussowitsch 
185030f984aSJacob Faibussowitsch   Notes:
186030f984aSJacob Faibussowitsch   See PetscStreamType in include/petscdevicetypes.h for more information on the available types and their interactions
187030f984aSJacob Faibussowitsch 
188030f984aSJacob Faibussowitsch   Level: intermediate
189030f984aSJacob Faibussowitsch 
1905181c4f9SJacob Faibussowitsch .seealso: PetscDeviceContextSetStreamType(), PetscDeviceContextCreate(), PetscDeviceContextSetFromOptions()
191030f984aSJacob Faibussowitsch @*/
192030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextGetStreamType(PetscDeviceContext dctx, PetscStreamType *type)
193030f984aSJacob Faibussowitsch {
194030f984aSJacob Faibussowitsch   PetscFunctionBegin;
195030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx,1);
196030f984aSJacob Faibussowitsch   PetscValidIntPointer(type,2);
197030f984aSJacob Faibussowitsch   *type = dctx->streamType;
198030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
199030f984aSJacob Faibussowitsch }
200030f984aSJacob Faibussowitsch 
201030f984aSJacob Faibussowitsch /*@C
202030f984aSJacob Faibussowitsch   PetscDeviceContextSetDevice - Set the underlying device for the PetscDeviceContext
203030f984aSJacob Faibussowitsch 
204030f984aSJacob Faibussowitsch   Not Collective, Possibly Synchronous
205030f984aSJacob Faibussowitsch 
20601d2d390SJose E. Roman   Input Parameters:
207030f984aSJacob Faibussowitsch + dctx   - The PetscDeviceContext
208030f984aSJacob Faibussowitsch - device - The PetscDevice
209030f984aSJacob Faibussowitsch 
210030f984aSJacob Faibussowitsch   Notes:
211030f984aSJacob Faibussowitsch   This routine is effectively PetscDeviceContext's "set-type" (so every PetscDeviceContext
212030f984aSJacob Faibussowitsch   must also have an attached PetscDevice). Unlike the usual set-type semantics, it is
213030f984aSJacob Faibussowitsch   not stricly necessary to set a contexts device to enable usage, any created device
214030f984aSJacob Faibussowitsch   contexts will always come equipped with the "default" device.
215030f984aSJacob Faibussowitsch 
216a4af0ceeSJacob Faibussowitsch   This routine is a no-op if dctx is already attached to device.
217a4af0ceeSJacob Faibussowitsch 
2185181c4f9SJacob Faibussowitsch   This routine may initialize the backend device and incur synchronization.
2195181c4f9SJacob Faibussowitsch 
220030f984aSJacob Faibussowitsch   Level: intermediate
221030f984aSJacob Faibussowitsch 
2225181c4f9SJacob Faibussowitsch .seealso: PetscDeviceCreate(), PetscDeviceConfigure(), PetscDeviceContextGetDevice()
223030f984aSJacob Faibussowitsch @*/
224030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetDevice(PetscDeviceContext dctx, PetscDevice device)
225030f984aSJacob Faibussowitsch {
226030f984aSJacob Faibussowitsch   PetscErrorCode ierr;
227030f984aSJacob Faibussowitsch 
228030f984aSJacob Faibussowitsch   PetscFunctionBegin;
229030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx,1);
230030f984aSJacob Faibussowitsch   PetscValidDevice(device,2);
231a4af0ceeSJacob Faibussowitsch   if (dctx->device) {
232a4af0ceeSJacob Faibussowitsch     /* can't do a strict pointer equality check since PetscDevice's are reused */
233a4af0ceeSJacob Faibussowitsch     if (dctx->device->ops->createcontext == device->ops->createcontext) PetscFunctionReturn(0);
234a4af0ceeSJacob Faibussowitsch   }
235030f984aSJacob Faibussowitsch   ierr = PetscDeviceDestroy(&dctx->device);CHKERRQ(ierr);
236a4af0ceeSJacob Faibussowitsch   if (dctx->ops->destroy) {ierr = (*dctx->ops->destroy)(dctx);CHKERRQ(ierr);}
237030f984aSJacob Faibussowitsch   ierr = PetscMemzero(dctx->ops,sizeof(*dctx->ops));CHKERRQ(ierr);
238030f984aSJacob Faibussowitsch   ierr = (*device->ops->createcontext)(dctx);CHKERRQ(ierr);
239a4af0ceeSJacob Faibussowitsch   ierr = PetscDeviceReference_Internal(device);CHKERRQ(ierr);
240a4af0ceeSJacob Faibussowitsch   dctx->device = device;
241030f984aSJacob Faibussowitsch   dctx->setup  = PETSC_FALSE;
242030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
243030f984aSJacob Faibussowitsch }
244030f984aSJacob Faibussowitsch 
245030f984aSJacob Faibussowitsch /*@C
246030f984aSJacob Faibussowitsch   PetscDeviceContextGetDevice - Get the underlying PetscDevice for a PetscDeviceContext
247030f984aSJacob Faibussowitsch 
248030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
249030f984aSJacob Faibussowitsch 
250030f984aSJacob Faibussowitsch   Input Parameter:
251030f984aSJacob Faibussowitsch . dctx - the PetscDeviceContext
252030f984aSJacob Faibussowitsch 
253030f984aSJacob Faibussowitsch   Output Parameter:
254030f984aSJacob Faibussowitsch . device - The PetscDevice
255030f984aSJacob Faibussowitsch 
256030f984aSJacob Faibussowitsch   Notes:
257030f984aSJacob Faibussowitsch   This is a borrowed reference, the user should not destroy the device.
258030f984aSJacob Faibussowitsch 
259a375dbeeSPatrick Sanan   Level: intermediate
260a375dbeeSPatrick Sanan 
261030f984aSJacob Faibussowitsch .seealso: PetscDeviceContextSetDevice(), PetscDevice
262030f984aSJacob Faibussowitsch @*/
263030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextGetDevice(PetscDeviceContext dctx, PetscDevice *device)
264030f984aSJacob Faibussowitsch {
265030f984aSJacob Faibussowitsch   PetscFunctionBegin;
266030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx,1);
267030f984aSJacob Faibussowitsch   PetscValidPointer(device,2);
2683ca90d2dSJacob Faibussowitsch   if (PetscUnlikelyDebug(!dctx->device)) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"PetscDeviceContext %" PetscInt_FMT " has no attached PetscDevice to get",dctx->id);
269030f984aSJacob Faibussowitsch   *device = dctx->device;
270030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
271030f984aSJacob Faibussowitsch }
272030f984aSJacob Faibussowitsch 
273030f984aSJacob Faibussowitsch /*@C
274030f984aSJacob Faibussowitsch   PetscDeviceContextSetUp - Prepares a PetscDeviceContext for use
275030f984aSJacob Faibussowitsch 
276030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
277030f984aSJacob Faibussowitsch 
27801d2d390SJose E. Roman   Input Parameter:
279030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext
280030f984aSJacob Faibussowitsch 
281030f984aSJacob Faibussowitsch   Developer Notes:
282030f984aSJacob Faibussowitsch   This routine is usually the stage where a PetscDeviceContext acquires device-side data structures such as streams,
283030f984aSJacob Faibussowitsch   events, and (possibly) handles.
284030f984aSJacob Faibussowitsch 
285030f984aSJacob Faibussowitsch   Level: beginner
286030f984aSJacob Faibussowitsch 
2875181c4f9SJacob Faibussowitsch .seealso: PetscDeviceContextCreate(), PetscDeviceContextSetDevice(), PetscDeviceContextDestroy(), PetscDeviceContextSetFromOptions()
288030f984aSJacob Faibussowitsch @*/
289030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetUp(PetscDeviceContext dctx)
290030f984aSJacob Faibussowitsch {
291030f984aSJacob Faibussowitsch   PetscErrorCode ierr;
292030f984aSJacob Faibussowitsch 
293030f984aSJacob Faibussowitsch   PetscFunctionBegin;
294030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx,1);
295030f984aSJacob Faibussowitsch   if (!dctx->device) {
2963ca90d2dSJacob Faibussowitsch     ierr = PetscInfo2(PETSC_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);
297a4af0ceeSJacob Faibussowitsch     ierr = PetscDeviceContextSetDefaultDevice_Internal(dctx);CHKERRQ(ierr);
298030f984aSJacob Faibussowitsch   }
299030f984aSJacob Faibussowitsch   if (dctx->setup) PetscFunctionReturn(0);
300030f984aSJacob Faibussowitsch   ierr = (*dctx->ops->setup)(dctx);CHKERRQ(ierr);
301030f984aSJacob Faibussowitsch   dctx->setup = PETSC_TRUE;
302030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
303030f984aSJacob Faibussowitsch }
304030f984aSJacob Faibussowitsch 
305030f984aSJacob Faibussowitsch /*@C
306030f984aSJacob Faibussowitsch   PetscDeviceContextDuplicate - Duplicates a PetscDeviceContext object
307030f984aSJacob Faibussowitsch 
308030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
309030f984aSJacob Faibussowitsch 
310030f984aSJacob Faibussowitsch   Input Parameter:
311030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext to duplicate
312030f984aSJacob Faibussowitsch 
313030f984aSJacob Faibussowitsch   Output Paramter:
314050c0c3dSJacob Faibussowitsch . dctxdup - The duplicated PetscDeviceContext
315030f984aSJacob Faibussowitsch 
316030f984aSJacob Faibussowitsch   Notes:
317030f984aSJacob Faibussowitsch   This is a shorthand method for creating a PetscDeviceContext with the exact same
318030f984aSJacob Faibussowitsch   settings as another. Note however that the duplicated PetscDeviceContext does not "share"
319030f984aSJacob Faibussowitsch   any of the underlying data with the original, (including its current stream-state) they
320030f984aSJacob Faibussowitsch   are completely separate objects.
321030f984aSJacob Faibussowitsch 
322030f984aSJacob Faibussowitsch   Level: beginner
323030f984aSJacob Faibussowitsch 
324030f984aSJacob Faibussowitsch .seealso: PetscDeviceContextCreate(), PetscDeviceContextSetDevice(), PetscDeviceContextSetStreamType()
325030f984aSJacob Faibussowitsch @*/
326030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextDuplicate(PetscDeviceContext dctx, PetscDeviceContext *dctxdup)
327030f984aSJacob Faibussowitsch {
328a4af0ceeSJacob Faibussowitsch   PetscDeviceContext dup;
329030f984aSJacob Faibussowitsch   PetscErrorCode     ierr;
330030f984aSJacob Faibussowitsch 
331030f984aSJacob Faibussowitsch   PetscFunctionBegin;
332030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx,1);
333030f984aSJacob Faibussowitsch   PetscValidPointer(dctxdup,2);
334a4af0ceeSJacob Faibussowitsch   ierr = PetscDeviceContextCreate(&dup);CHKERRQ(ierr);
335a4af0ceeSJacob Faibussowitsch   ierr = PetscDeviceContextSetStreamType(dup,dctx->streamType);CHKERRQ(ierr);
336a4af0ceeSJacob Faibussowitsch   if (dctx->device) {ierr = PetscDeviceContextSetDevice(dup,dctx->device);CHKERRQ(ierr);}
337a4af0ceeSJacob Faibussowitsch   ierr = PetscDeviceContextSetUp(dup);CHKERRQ(ierr);
338a4af0ceeSJacob Faibussowitsch   *dctxdup = dup;
339030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
340030f984aSJacob Faibussowitsch }
341030f984aSJacob Faibussowitsch 
342030f984aSJacob Faibussowitsch /*@C
343030f984aSJacob Faibussowitsch   PetscDeviceContextQueryIdle - Returns whether or not a PetscDeviceContext is idle
344030f984aSJacob Faibussowitsch 
345030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
346030f984aSJacob Faibussowitsch 
347030f984aSJacob Faibussowitsch   Input Parameter:
348030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext object
349030f984aSJacob Faibussowitsch 
350030f984aSJacob Faibussowitsch   Output Parameter:
351030f984aSJacob Faibussowitsch . idle - PETSC_TRUE if PetscDeviceContext has NO work, PETSC_FALSE if it has work
352030f984aSJacob Faibussowitsch 
353030f984aSJacob Faibussowitsch   Notes:
354030f984aSJacob Faibussowitsch   This routine only refers a singular context and does NOT take any of its children into account. That is, if dctx is
355030f984aSJacob Faibussowitsch   idle but has dependents who do have work, this routine still returns PETSC_TRUE.
356030f984aSJacob Faibussowitsch 
357030f984aSJacob Faibussowitsch   Results of PetscDeviceContextQueryIdle() are cached on return, allowing this function to be called repeatedly in an
358030f984aSJacob Faibussowitsch   efficient manner. When debug mode is enabled this cache is verified on every call to
359030f984aSJacob Faibussowitsch   this routine, but is blindly believed when debugging is disabled.
360030f984aSJacob Faibussowitsch 
361030f984aSJacob Faibussowitsch   Level: intermediate
362030f984aSJacob Faibussowitsch 
363030f984aSJacob Faibussowitsch .seealso: PetscDeviceContextCreate(), PetscDeviceContextWaitForContext(), PetscDeviceContextFork()
364030f984aSJacob Faibussowitsch @*/
365030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextQueryIdle(PetscDeviceContext dctx, PetscBool *idle)
366030f984aSJacob Faibussowitsch {
367030f984aSJacob Faibussowitsch   PetscErrorCode ierr;
368030f984aSJacob Faibussowitsch 
369030f984aSJacob Faibussowitsch   PetscFunctionBegin;
370030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx,1);
371030f984aSJacob Faibussowitsch   PetscValidBoolPointer(idle,2);
372030f984aSJacob Faibussowitsch   if (dctx->idle) {
373030f984aSJacob Faibussowitsch     *idle = PETSC_TRUE;
374030f984aSJacob Faibussowitsch     ierr = PetscDeviceContextValidateIdle_Internal(dctx);CHKERRQ(ierr);
375030f984aSJacob Faibussowitsch   } else {
376030f984aSJacob Faibussowitsch     ierr = (*dctx->ops->query)(dctx,idle);CHKERRQ(ierr);
377030f984aSJacob Faibussowitsch     dctx->idle = *idle;
378030f984aSJacob Faibussowitsch   }
379030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
380030f984aSJacob Faibussowitsch }
381030f984aSJacob Faibussowitsch 
382030f984aSJacob Faibussowitsch /*@C
383030f984aSJacob Faibussowitsch   PetscDeviceContextWaitForContext - Make one context wait for another context to finish
384030f984aSJacob Faibussowitsch 
385030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
386030f984aSJacob Faibussowitsch 
387030f984aSJacob Faibussowitsch   Input Parameters:
388030f984aSJacob Faibussowitsch + dctxa - The PetscDeviceContext object that is waiting
389030f984aSJacob Faibussowitsch - dctxb - The PetscDeviceContext object that is being waited on
390030f984aSJacob Faibussowitsch 
391030f984aSJacob Faibussowitsch   Notes:
392030f984aSJacob Faibussowitsch   Serializes two PetscDeviceContexts. This routine uses only the state of dctxb at the moment this routine was
393030f984aSJacob Faibussowitsch   called, so any future work queued will not affect dctxa. It is safe to pass the same context to both arguments.
394030f984aSJacob Faibussowitsch 
395030f984aSJacob Faibussowitsch   Level: beginner
396030f984aSJacob Faibussowitsch 
397030f984aSJacob Faibussowitsch .seealso: PetscDeviceContextCreate(), PetscDeviceContextQueryIdle(), PetscDeviceContextJoin()
398030f984aSJacob Faibussowitsch @*/
399030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextWaitForContext(PetscDeviceContext dctxa, PetscDeviceContext dctxb)
400030f984aSJacob Faibussowitsch {
401030f984aSJacob Faibussowitsch   PetscErrorCode ierr;
402030f984aSJacob Faibussowitsch 
403030f984aSJacob Faibussowitsch   PetscFunctionBegin;
404030f984aSJacob Faibussowitsch   PetscCheckCompatibleDeviceContexts(dctxa,1,dctxb,2);
405030f984aSJacob Faibussowitsch   if (dctxa == dctxb) PetscFunctionReturn(0);
406030f984aSJacob Faibussowitsch   if (dctxb->idle) {
407030f984aSJacob Faibussowitsch     /* No need to do the extra function lookup and event record if the stream were waiting on isn't doing anything */
408030f984aSJacob Faibussowitsch     ierr = PetscDeviceContextValidateIdle_Internal(dctxb);CHKERRQ(ierr);
409030f984aSJacob Faibussowitsch   } else {
410*17f48955SJacob Faibussowitsch     ierr = (*dctxa->ops->waitforcontext)(dctxa,dctxb);CHKERRQ(ierr);
411030f984aSJacob Faibussowitsch   }
412030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
413030f984aSJacob Faibussowitsch }
414030f984aSJacob Faibussowitsch 
415050c0c3dSJacob Faibussowitsch #define PETSC_USE_DEBUG_AND_INFO (PetscDefined(USE_DEBUG) && PetscDefined(USE_INFO))
416050c0c3dSJacob Faibussowitsch #if PETSC_USE_DEBUG_AND_INFO
417050c0c3dSJacob Faibussowitsch #include <string>
418050c0c3dSJacob Faibussowitsch #endif
419030f984aSJacob Faibussowitsch /*@C
420030f984aSJacob Faibussowitsch   PetscDeviceContextFork - Create a set of dependent child contexts from a parent context
421030f984aSJacob Faibussowitsch 
422030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
423030f984aSJacob Faibussowitsch 
424030f984aSJacob Faibussowitsch   Input Parameters:
425030f984aSJacob Faibussowitsch + dctx - The parent PetscDeviceContext
426030f984aSJacob Faibussowitsch - n    - The number of children to create
427030f984aSJacob Faibussowitsch 
428030f984aSJacob Faibussowitsch   Output Parameter:
429030f984aSJacob Faibussowitsch . dsub - The created child context(s)
430030f984aSJacob Faibussowitsch 
431030f984aSJacob Faibussowitsch   Notes:
432030f984aSJacob Faibussowitsch   This routine creates n edges of a DAG from a source node which are causally dependent on the source node, meaning
433030f984aSJacob Faibussowitsch   that work queued on child contexts will not start until the parent context finishes its work. This accounts for work
434030f984aSJacob Faibussowitsch   queued on the parent up until calling this function, any subsequent work enqueued on the parent has no effect on the children.
435030f984aSJacob Faibussowitsch 
436030f984aSJacob Faibussowitsch   Any children created with this routine have their lifetimes bounded by the parent. That is, the parent context expects
437030f984aSJacob Faibussowitsch   to free all of it's children (and ONLY its children) before itself is freed.
438030f984aSJacob Faibussowitsch 
439030f984aSJacob Faibussowitsch   DAG representation:
440030f984aSJacob Faibussowitsch .vb
441030f984aSJacob Faibussowitsch   time ->
442030f984aSJacob Faibussowitsch 
443030f984aSJacob Faibussowitsch   -> dctx \----> dctx ------>
444030f984aSJacob Faibussowitsch            \---> dsub[0] --->
445030f984aSJacob Faibussowitsch             \--> ... ------->
446030f984aSJacob Faibussowitsch              \-> dsub[n-1] ->
447030f984aSJacob Faibussowitsch .ve
448030f984aSJacob Faibussowitsch 
449030f984aSJacob Faibussowitsch   Level: intermediate
450030f984aSJacob Faibussowitsch 
451030f984aSJacob Faibussowitsch .seealso: PetscDeviceContextJoin(), PetscDeviceContextSynchronize(), PetscDeviceContextQueryIdle()
452030f984aSJacob Faibussowitsch @*/
453030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextFork(PetscDeviceContext dctx, PetscInt n, PetscDeviceContext **dsub)
454030f984aSJacob Faibussowitsch {
455050c0c3dSJacob Faibussowitsch #if PETSC_USE_DEBUG_AND_INFO
456030f984aSJacob Faibussowitsch   const PetscInt      nBefore = n;
457030f984aSJacob Faibussowitsch   static std::string  idList;
458030f984aSJacob Faibussowitsch #endif
459a4af0ceeSJacob Faibussowitsch   PetscDeviceContext *dsubTmp = PETSC_NULLPTR;
460030f984aSJacob Faibussowitsch   PetscInt            i = 0;
461030f984aSJacob Faibussowitsch   PetscErrorCode      ierr;
462030f984aSJacob Faibussowitsch 
463030f984aSJacob Faibussowitsch   PetscFunctionBegin;
464030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx,1);
465030f984aSJacob Faibussowitsch   PetscValidPointer(dsub,3);
4663ca90d2dSJacob Faibussowitsch   if (PetscUnlikelyDebug(n < 0)) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Number of contexts requested %" PetscInt_FMT " < 0",n);
4673ca90d2dSJacob Faibussowitsch #if PETSC_USE_DEBUG_AND_INFO
468030f984aSJacob Faibussowitsch   /* reserve 4 chars per id, 2 for number and 2 for ', ' separator */
469030f984aSJacob Faibussowitsch   idList.reserve(4*n);
470030f984aSJacob Faibussowitsch #endif
471030f984aSJacob Faibussowitsch   /* update child totals */
472030f984aSJacob Faibussowitsch   dctx->numChildren += n;
473030f984aSJacob Faibussowitsch   /* now to find out if we have room */
474030f984aSJacob Faibussowitsch   if (dctx->numChildren > dctx->maxNumChildren) {
475030f984aSJacob Faibussowitsch     /* no room, either from having too many kids or not having any */
476030f984aSJacob Faibussowitsch     if (dctx->childIDs) {
477030f984aSJacob Faibussowitsch       /* have existing children, must reallocate them */
478030f984aSJacob Faibussowitsch       ierr = PetscRealloc(dctx->numChildren*sizeof(*dctx->childIDs),&dctx->childIDs);CHKERRQ(ierr);
479030f984aSJacob Faibussowitsch       /* clear the extra memory since realloc doesn't do it for us */
480030f984aSJacob Faibussowitsch       ierr = PetscArrayzero((dctx->childIDs)+(dctx->maxNumChildren),(dctx->numChildren)-(dctx->maxNumChildren));CHKERRQ(ierr);
481030f984aSJacob Faibussowitsch     } else {
482030f984aSJacob Faibussowitsch       /* have no children */
483030f984aSJacob Faibussowitsch       ierr = PetscCalloc1(dctx->numChildren,&dctx->childIDs);CHKERRQ(ierr);
484030f984aSJacob Faibussowitsch     }
485030f984aSJacob Faibussowitsch     /* update total number of children */
486030f984aSJacob Faibussowitsch     dctx->maxNumChildren = dctx->numChildren;
487030f984aSJacob Faibussowitsch   }
488030f984aSJacob Faibussowitsch   ierr = PetscMalloc1(n,&dsubTmp);CHKERRQ(ierr);
489030f984aSJacob Faibussowitsch   while (n) {
490030f984aSJacob Faibussowitsch     /* empty child slot */
491030f984aSJacob Faibussowitsch     if (!(dctx->childIDs[i])) {
492030f984aSJacob Faibussowitsch       /* create the child context in the image of its parent */
493030f984aSJacob Faibussowitsch       ierr = PetscDeviceContextDuplicate(dctx,dsubTmp+i);CHKERRQ(ierr);
494030f984aSJacob Faibussowitsch       ierr = PetscDeviceContextWaitForContext(dsubTmp[i],dctx);CHKERRQ(ierr);
495030f984aSJacob Faibussowitsch       /* register the child with its parent */
496030f984aSJacob Faibussowitsch       dctx->childIDs[i] = dsubTmp[i]->id;
497050c0c3dSJacob Faibussowitsch #if PETSC_USE_DEBUG_AND_INFO
498030f984aSJacob Faibussowitsch       idList += std::to_string(dsubTmp[i]->id);
499030f984aSJacob Faibussowitsch       if (n != 1) idList += ", ";
500030f984aSJacob Faibussowitsch #endif
501030f984aSJacob Faibussowitsch       --n;
502030f984aSJacob Faibussowitsch     }
503030f984aSJacob Faibussowitsch     ++i;
504030f984aSJacob Faibussowitsch   }
5053ca90d2dSJacob Faibussowitsch #if PETSC_USE_DEBUG_AND_INFO
5063ca90d2dSJacob Faibussowitsch   ierr = PetscInfo3(PETSC_NULLPTR,"Forked %" PetscInt_FMT " children from parent %" PetscInt_FMT " with IDs: %s\n",nBefore,dctx->id,idList.c_str());CHKERRQ(ierr);
507030f984aSJacob Faibussowitsch   /* resets the size but doesn't deallocate the memory */
508030f984aSJacob Faibussowitsch   idList.clear();
509030f984aSJacob Faibussowitsch #endif
510030f984aSJacob Faibussowitsch   /* pass the children back to caller */
511030f984aSJacob Faibussowitsch   *dsub = dsubTmp;
512030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
513030f984aSJacob Faibussowitsch }
514030f984aSJacob Faibussowitsch 
515030f984aSJacob Faibussowitsch /*@C
5165181c4f9SJacob Faibussowitsch   PetscDeviceContextJoin - Converge a set of child contexts
517030f984aSJacob Faibussowitsch 
518030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
519030f984aSJacob Faibussowitsch 
520030f984aSJacob Faibussowitsch   Input Parameters:
521030f984aSJacob Faibussowitsch + dctx         - A PetscDeviceContext to converge on
522030f984aSJacob Faibussowitsch . n            - The number of sub contexts to converge
523030f984aSJacob Faibussowitsch . joinMode     - The type of join to perform
524030f984aSJacob Faibussowitsch - dsub         - The sub contexts to converge
525030f984aSJacob Faibussowitsch 
526030f984aSJacob Faibussowitsch   Notes:
527030f984aSJacob Faibussowitsch   If PetscDeviceContextFork() creates n edges from a source node which all depend on the
528030f984aSJacob Faibussowitsch   source node, then this routine is the exact mirror. That is, it creates a node
529030f984aSJacob Faibussowitsch   (represented in dctx) which recieves n edges (and optionally destroys them) which is
530030f984aSJacob Faibussowitsch   dependent on the completion of all incoming edges.
531030f984aSJacob Faibussowitsch 
532030f984aSJacob Faibussowitsch   If joinMode is PETSC_DEVICE_CONTEXT_JOIN_DESTROY all contexts in dsub will be destroyed
533030f984aSJacob Faibussowitsch   by this routine. Thus all sub contexts must have been created with the dctx passed to
534030f984aSJacob Faibussowitsch   this routine.
535030f984aSJacob Faibussowitsch 
536030f984aSJacob Faibussowitsch   if joinMode is PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC dctx waits for all sub contexts but the
537030f984aSJacob Faibussowitsch   sub contexts do not wait for one another afterwards.
538030f984aSJacob Faibussowitsch 
539030f984aSJacob Faibussowitsch   If joinMode is PETSC_DEVICE_CONTEXT_JOIN_SYNC all sub contexts will additionally
540030f984aSJacob Faibussowitsch   wait on dctx after converging. This has the effect of "synchronizing" the outgoing
541030f984aSJacob Faibussowitsch   edges.
542030f984aSJacob Faibussowitsch 
543030f984aSJacob Faibussowitsch   DAG representations:
544030f984aSJacob Faibussowitsch   If joinMode is PETSC_DEVICE_CONTEXT_JOIN_DESTROY
545030f984aSJacob Faibussowitsch .vb
546030f984aSJacob Faibussowitsch   time ->
547030f984aSJacob Faibussowitsch 
548030f984aSJacob Faibussowitsch   -> dctx ---------/- dctx ->
549030f984aSJacob Faibussowitsch   -> dsub[0] -----/
550030f984aSJacob Faibussowitsch   ->  ... -------/
551030f984aSJacob Faibussowitsch   -> dsub[n-1] -/
552030f984aSJacob Faibussowitsch .ve
553030f984aSJacob Faibussowitsch   If joinMode is PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC
554030f984aSJacob Faibussowitsch .vb
555030f984aSJacob Faibussowitsch   time ->
556030f984aSJacob Faibussowitsch 
557030f984aSJacob Faibussowitsch   -> dctx ---------/- dctx ->
558030f984aSJacob Faibussowitsch   -> dsub[0] -----/--------->
559030f984aSJacob Faibussowitsch   ->  ... -------/---------->
560030f984aSJacob Faibussowitsch   -> dsub[n-1] -/----------->
561030f984aSJacob Faibussowitsch .ve
562030f984aSJacob Faibussowitsch   If joinMode is PETSC_DEVICE_CONTEXT_JOIN_SYNC
563030f984aSJacob Faibussowitsch .vb
564030f984aSJacob Faibussowitsch   time ->
565030f984aSJacob Faibussowitsch 
566030f984aSJacob Faibussowitsch   -> dctx ---------/- dctx -\----> dctx ------>
567030f984aSJacob Faibussowitsch   -> dsub[0] -----/          \---> dsub[0] --->
568030f984aSJacob Faibussowitsch   ->  ... -------/            \--> ... ------->
569030f984aSJacob Faibussowitsch   -> dsub[n-1] -/              \-> dsub[n-1] ->
570030f984aSJacob Faibussowitsch .ve
571030f984aSJacob Faibussowitsch 
572030f984aSJacob Faibussowitsch   Level: intermediate
573030f984aSJacob Faibussowitsch 
574030f984aSJacob Faibussowitsch .seealso: PetscDeviceContextFork(), PetscDeviceContextSynchronize(), PetscDeviceContextJoinMode
575030f984aSJacob Faibussowitsch @*/
576030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextJoin(PetscDeviceContext dctx, PetscInt n, PetscDeviceContextJoinMode joinMode, PetscDeviceContext **dsub)
577030f984aSJacob Faibussowitsch {
578030f984aSJacob Faibussowitsch #if defined(PETSC_USE_DEBUG) && defined(PETSC_USE_INFO)
579030f984aSJacob Faibussowitsch   static std::string idList;
580030f984aSJacob Faibussowitsch #endif
581030f984aSJacob Faibussowitsch   PetscErrorCode     ierr;
582030f984aSJacob Faibussowitsch 
583030f984aSJacob Faibussowitsch   PetscFunctionBegin;
584030f984aSJacob Faibussowitsch   /* validity of dctx is checked in the wait-for loop */
585030f984aSJacob Faibussowitsch   PetscValidPointer(dsub,4);
5863ca90d2dSJacob Faibussowitsch   if (PetscUnlikelyDebug(n < 0)) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Number of contexts merged %" PetscInt_FMT " < 0",n);
587030f984aSJacob Faibussowitsch #if defined(PETSC_USE_DEBUG) && defined(PETSC_USE_INFO)
588030f984aSJacob Faibussowitsch   /* reserve 4 chars per id, 2 for number and 2 for ', ' separator */
589030f984aSJacob Faibussowitsch   idList.reserve(4*n);
590030f984aSJacob Faibussowitsch #endif
591030f984aSJacob Faibussowitsch   /* first dctx waits on all the incoming edges */
592030f984aSJacob Faibussowitsch   for (PetscInt i = 0; i < n; ++i) {
593030f984aSJacob Faibussowitsch     PetscCheckCompatibleDeviceContexts(dctx,1,(*dsub)[i],4);
594030f984aSJacob Faibussowitsch     ierr = PetscDeviceContextWaitForContext(dctx,(*dsub)[i]);CHKERRQ(ierr);
595030f984aSJacob Faibussowitsch #if defined(PETSC_USE_DEBUG) && defined(PETSC_USE_INFO)
596030f984aSJacob Faibussowitsch     idList += std::to_string((*dsub)[i]->id);
597030f984aSJacob Faibussowitsch     if (i+1 < n) idList += ", ";
598030f984aSJacob Faibussowitsch #endif
599030f984aSJacob Faibussowitsch   }
600030f984aSJacob Faibussowitsch 
601030f984aSJacob Faibussowitsch   /* now we handle the aftermath */
602030f984aSJacob Faibussowitsch   switch (joinMode) {
603030f984aSJacob Faibussowitsch   case PETSC_DEVICE_CONTEXT_JOIN_DESTROY:
604030f984aSJacob Faibussowitsch     {
605030f984aSJacob Faibussowitsch       PetscInt j = 0;
606030f984aSJacob Faibussowitsch 
6073ca90d2dSJacob Faibussowitsch       if (PetscUnlikelyDebug(n > dctx->numChildren)) SETERRQ2(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);
608030f984aSJacob Faibussowitsch       /* update child count while it's still fresh in memory */
609030f984aSJacob Faibussowitsch       dctx->numChildren -= n;
610030f984aSJacob Faibussowitsch       for (PetscInt i = 0; i < dctx->maxNumChildren; ++i) {
611030f984aSJacob Faibussowitsch         if (dctx->childIDs[i] && (dctx->childIDs[i] == (*dsub)[j]->id)) {
612030f984aSJacob Faibussowitsch           /* child is one of ours, can destroy it */
613030f984aSJacob Faibussowitsch           ierr = PetscDeviceContextDestroy((*dsub)+j);CHKERRQ(ierr);
614030f984aSJacob Faibussowitsch           /* reset the child slot */
615030f984aSJacob Faibussowitsch           dctx->childIDs[i] = 0;
616030f984aSJacob Faibussowitsch           if (++j == n) break;
617030f984aSJacob Faibussowitsch         }
618030f984aSJacob Faibussowitsch       }
619030f984aSJacob 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 */
6203ca90d2dSJacob Faibussowitsch       if (PetscUnlikelyDebug(j != n)) SETERRQ1(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);
621030f984aSJacob Faibussowitsch       ierr = PetscFree(*dsub);CHKERRQ(ierr);
622030f984aSJacob Faibussowitsch     }
623030f984aSJacob Faibussowitsch     break;
624030f984aSJacob Faibussowitsch   case PETSC_DEVICE_CONTEXT_JOIN_SYNC:
625030f984aSJacob Faibussowitsch     for (PetscInt i = 0; i < n; ++i) {
626030f984aSJacob Faibussowitsch       ierr = PetscDeviceContextWaitForContext((*dsub)[i],dctx);CHKERRQ(ierr);
627030f984aSJacob Faibussowitsch     }
628030f984aSJacob Faibussowitsch   case PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC:
629030f984aSJacob Faibussowitsch     break;
630030f984aSJacob Faibussowitsch   default:
631030f984aSJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Unknown PetscDeviceContextJoinMode given");
632030f984aSJacob Faibussowitsch   }
633030f984aSJacob Faibussowitsch 
634030f984aSJacob Faibussowitsch #if defined(PETSC_USE_DEBUG) && defined(PETSC_USE_INFO)
6353ca90d2dSJacob Faibussowitsch   ierr = PetscInfo4(PETSC_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);
636030f984aSJacob Faibussowitsch   idList.clear();
637030f984aSJacob Faibussowitsch #endif
638030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
639030f984aSJacob Faibussowitsch }
640030f984aSJacob Faibussowitsch 
641030f984aSJacob Faibussowitsch /*@C
6425181c4f9SJacob Faibussowitsch   PetscDeviceContextSynchronize - Block the host until all work queued on or associated with a PetscDeviceContext has finished
643030f984aSJacob Faibussowitsch 
644030f984aSJacob Faibussowitsch   Not Collective, Synchronous
645030f984aSJacob Faibussowitsch 
646030f984aSJacob Faibussowitsch   Input Parameters:
647030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext to synchronize
648030f984aSJacob Faibussowitsch 
649030f984aSJacob Faibussowitsch   Level: beginner
650030f984aSJacob Faibussowitsch 
651030f984aSJacob Faibussowitsch .seealso: PetscDeviceContextFork(), PetscDeviceContextJoin(), PetscDeviceContextQueryIdle()
652030f984aSJacob Faibussowitsch @*/
653030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextSynchronize(PetscDeviceContext dctx)
654030f984aSJacob Faibussowitsch {
655030f984aSJacob Faibussowitsch   PetscErrorCode ierr;
656030f984aSJacob Faibussowitsch 
657030f984aSJacob Faibussowitsch   PetscFunctionBegin;
658030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx,1);
659030f984aSJacob Faibussowitsch   /* if it isn't setup there is nothing to sync on */
660030f984aSJacob Faibussowitsch   if (dctx->setup) {ierr = (*dctx->ops->synchronize)(dctx);CHKERRQ(ierr);}
661030f984aSJacob Faibussowitsch   dctx->idle = PETSC_TRUE;
662030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
663030f984aSJacob Faibussowitsch }
664030f984aSJacob Faibussowitsch 
665a4af0ceeSJacob Faibussowitsch #define PETSC_DEVICE_CONTEXT_DEFAULT_DEVICE PETSC_DEVICE_DEFAULT
666a4af0ceeSJacob Faibussowitsch // REMOVE ME (change)
667a4af0ceeSJacob Faibussowitsch #define PETSC_DEVICE_CONTEXT_DEFAULT_STREAM PETSC_STREAM_GLOBAL_BLOCKING
668030f984aSJacob Faibussowitsch 
669a4af0ceeSJacob Faibussowitsch static PetscDeviceType    rootDeviceType = PETSC_DEVICE_CONTEXT_DEFAULT_DEVICE;
670a4af0ceeSJacob Faibussowitsch static PetscStreamType    rootStreamType = PETSC_DEVICE_CONTEXT_DEFAULT_STREAM;
671a4af0ceeSJacob Faibussowitsch static PetscDeviceContext globalContext  = PETSC_NULLPTR;
672a4af0ceeSJacob Faibussowitsch 
673a4af0ceeSJacob Faibussowitsch /* when PetsDevice initializes PetscDeviceContext eagerly the type of device created should
674a4af0ceeSJacob Faibussowitsch  * match whatever device is eagerly intialized */
675a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetRootDeviceType_Internal(PetscDeviceType type)
676030f984aSJacob Faibussowitsch {
677030f984aSJacob Faibussowitsch   PetscFunctionBegin;
678a4af0ceeSJacob Faibussowitsch   PetscValidDeviceType(type,1);
679a4af0ceeSJacob Faibussowitsch   rootDeviceType = type;
680030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
681030f984aSJacob Faibussowitsch }
682030f984aSJacob Faibussowitsch 
683a4af0ceeSJacob Faibussowitsch #if 0
684a4af0ceeSJacob Faibussowitsch /* currently unused */
685a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetRootStreamType_Internal(PetscStreamType type)
686030f984aSJacob Faibussowitsch {
687a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
688a4af0ceeSJacob Faibussowitsch   PetscValidStreamType(type,1);
689a4af0ceeSJacob Faibussowitsch   rootStreamType = type;
690a4af0ceeSJacob Faibussowitsch   PetscFunctionReturn(0);
691a4af0ceeSJacob Faibussowitsch }
692a4af0ceeSJacob Faibussowitsch #endif
693a4af0ceeSJacob Faibussowitsch 
694a4af0ceeSJacob Faibussowitsch static PetscErrorCode PetscDeviceContextSetupGlobalContext_Private(void)
695a4af0ceeSJacob Faibussowitsch {
696a4af0ceeSJacob Faibussowitsch   PetscErrorCode    ierr;
697a4af0ceeSJacob Faibussowitsch   static const auto PetscDeviceContextFinalizer = []() -> PetscErrorCode {
698030f984aSJacob Faibussowitsch     PetscErrorCode ierr;
699030f984aSJacob Faibussowitsch 
700030f984aSJacob Faibussowitsch     PetscFunctionBegin;
701a4af0ceeSJacob Faibussowitsch     ierr = PetscDeviceContextDestroy(&globalContext);CHKERRQ(ierr);
702a4af0ceeSJacob Faibussowitsch     rootDeviceType = PETSC_DEVICE_CONTEXT_DEFAULT_DEVICE;
703a4af0ceeSJacob Faibussowitsch     rootStreamType = PETSC_DEVICE_CONTEXT_DEFAULT_STREAM;
704a4af0ceeSJacob Faibussowitsch     PetscFunctionReturn(0);
705a4af0ceeSJacob Faibussowitsch   };
706a4af0ceeSJacob Faibussowitsch 
707a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
708a4af0ceeSJacob Faibussowitsch   if (globalContext) PetscFunctionReturn(0);
709a4af0ceeSJacob Faibussowitsch   /* this exists purely as a valid device check. */
710a4af0ceeSJacob Faibussowitsch   ierr = PetscDeviceInitializePackage();CHKERRQ(ierr);
711a4af0ceeSJacob Faibussowitsch   ierr = PetscRegisterFinalize(PetscDeviceContextFinalizer);CHKERRQ(ierr);
712a4af0ceeSJacob Faibussowitsch   ierr = PetscInfo(PETSC_NULLPTR,"Initializing global PetscDeviceContext\n");CHKERRQ(ierr);
713a4af0ceeSJacob Faibussowitsch   /* we call the allocator directly here since the ObjectPool creates a PetscContainer which
714a4af0ceeSJacob Faibussowitsch    * eventually tries to call logging functions. However, this routine may be purposefully
715a4af0ceeSJacob Faibussowitsch    * called __before__ logging is initialized, so the logging function would PETSCABORT */
716*17f48955SJacob Faibussowitsch   ierr = contextPool.allocator().create(&globalContext);CHKERRQ(ierr);
717a4af0ceeSJacob Faibussowitsch   ierr = PetscDeviceContextSetStreamType(globalContext,rootStreamType);CHKERRQ(ierr);
718a4af0ceeSJacob Faibussowitsch   ierr = PetscDeviceContextSetDefaultDeviceForType_Internal(globalContext,rootDeviceType);CHKERRQ(ierr);
719a4af0ceeSJacob Faibussowitsch   ierr = PetscDeviceContextSetUp(globalContext);CHKERRQ(ierr);
720030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
721030f984aSJacob Faibussowitsch }
722030f984aSJacob Faibussowitsch 
723030f984aSJacob Faibussowitsch /*@C
7245181c4f9SJacob Faibussowitsch   PetscDeviceContextGetCurrentContext - Get the current active PetscDeviceContext
725030f984aSJacob Faibussowitsch 
726030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
727030f984aSJacob Faibussowitsch 
728030f984aSJacob Faibussowitsch   Output Parameter:
729030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext
730030f984aSJacob Faibussowitsch 
731030f984aSJacob Faibussowitsch   Notes:
732a4af0ceeSJacob Faibussowitsch   The user generally should not destroy contexts retrieved with this routine unless they
733a4af0ceeSJacob Faibussowitsch   themselves have created them. There exists no protection against destroying the root
734a4af0ceeSJacob Faibussowitsch   context.
735030f984aSJacob Faibussowitsch 
736030f984aSJacob Faibussowitsch   Developer Notes:
737a4af0ceeSJacob Faibussowitsch   Unless the user has set their own, this routine creates the "root" context the first time it
738a4af0ceeSJacob Faibussowitsch   is called, registering its destructor to PetscFinalize().
739030f984aSJacob Faibussowitsch 
740030f984aSJacob Faibussowitsch   Level: beginner
741030f984aSJacob Faibussowitsch 
742030f984aSJacob Faibussowitsch .seealso: PetscDeviceContextSetCurrentContext(), PetscDeviceContextFork(),
743030f984aSJacob Faibussowitsch PetscDeviceContextJoin(), PetscDeviceContextCreate()
744030f984aSJacob Faibussowitsch @*/
745030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextGetCurrentContext(PetscDeviceContext *dctx)
746030f984aSJacob Faibussowitsch {
747030f984aSJacob Faibussowitsch   PetscErrorCode ierr;
748030f984aSJacob Faibussowitsch 
749a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
750a4af0ceeSJacob Faibussowitsch   PetscValidPointer(dctx,1);
751a4af0ceeSJacob Faibussowitsch   ierr = PetscDeviceContextSetupGlobalContext_Private();CHKERRQ(ierr);
752a4af0ceeSJacob Faibussowitsch   /* while the static analyzer can find global variables, it will throw a warning about not
753a4af0ceeSJacob Faibussowitsch    * being able to connect this back to the function arguments */
754a4af0ceeSJacob Faibussowitsch   PetscDisableStaticAnalyzerForExpressionUnderstandingThatThisIsDangerousAndBugprone(PetscValidDeviceContext(globalContext,-1));
755030f984aSJacob Faibussowitsch   *dctx = globalContext;
756030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
757030f984aSJacob Faibussowitsch }
758030f984aSJacob Faibussowitsch 
759030f984aSJacob Faibussowitsch /*@C
7605181c4f9SJacob Faibussowitsch   PetscDeviceContextSetCurrentContext - Set the current active PetscDeviceContext
761030f984aSJacob Faibussowitsch 
762030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
763030f984aSJacob Faibussowitsch 
764030f984aSJacob Faibussowitsch   Input Parameter:
765030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext
766030f984aSJacob Faibussowitsch 
767030f984aSJacob Faibussowitsch   Notes:
768a4af0ceeSJacob Faibussowitsch   This routine can be used to set the defacto "root" PetscDeviceContext to a user-defined
769a4af0ceeSJacob Faibussowitsch   implementation by calling this routine immediately after PetscInitialize() and ensuring that
770a4af0ceeSJacob Faibussowitsch   PetscDevice is not greedily intialized. In this case the user is responsible for destroying
771a4af0ceeSJacob Faibussowitsch   their PetscDeviceContext before PetscFinalize() returns.
772a4af0ceeSJacob Faibussowitsch 
773a4af0ceeSJacob Faibussowitsch   The old context is not stored in any way by this routine; if one is overriding a context that
774a4af0ceeSJacob Faibussowitsch   they themselves do not control, one should take care to temporarily store it by calling
775a4af0ceeSJacob Faibussowitsch   PetscDeviceContextGetCurrentContext() before calling this routine.
776030f984aSJacob Faibussowitsch 
777030f984aSJacob Faibussowitsch   Level: beginner
778030f984aSJacob Faibussowitsch 
779030f984aSJacob Faibussowitsch .seealso: PetscDeviceContextGetCurrentContext(), PetscDeviceContextFork(),
780030f984aSJacob Faibussowitsch PetscDeviceContextJoin(), PetscDeviceContextCreate()
781030f984aSJacob Faibussowitsch @*/
782030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetCurrentContext(PetscDeviceContext dctx)
783030f984aSJacob Faibussowitsch {
784030f984aSJacob Faibussowitsch   PetscErrorCode ierr;
785030f984aSJacob Faibussowitsch 
786030f984aSJacob Faibussowitsch   PetscFunctionBegin;
787030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx,1);
7883ca90d2dSJacob Faibussowitsch   if (PetscUnlikelyDebug(!dctx->setup)) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"PetscDeviceContext %" PetscInt_FMT " must be set up before being set as global context",dctx->id);
789030f984aSJacob Faibussowitsch   globalContext = dctx;
7903ca90d2dSJacob Faibussowitsch   ierr = PetscInfo1(PETSC_NULLPTR,"Set global PetscDeviceContext id %" PetscInt_FMT "\n",dctx->id);CHKERRQ(ierr);
791030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
792030f984aSJacob Faibussowitsch }
793030f984aSJacob Faibussowitsch 
794030f984aSJacob Faibussowitsch /*@C
795030f984aSJacob Faibussowitsch   PetscDeviceContextSetFromOptions - Configure a PetscDeviceContext from the options database
796030f984aSJacob Faibussowitsch 
797030f984aSJacob Faibussowitsch   Collective on comm, Asynchronous
798030f984aSJacob Faibussowitsch 
799030f984aSJacob Faibussowitsch   Input Parameters:
800030f984aSJacob Faibussowitsch + comm   - MPI communicator on which to query the options database
801030f984aSJacob Faibussowitsch . prefix - prefix to prepend to all options database queries, NULL if not needed
802030f984aSJacob Faibussowitsch - dctx   - The PetscDeviceContext to configure
803030f984aSJacob Faibussowitsch 
804030f984aSJacob Faibussowitsch   Output Parameter:
805030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext
806030f984aSJacob Faibussowitsch 
807030f984aSJacob Faibussowitsch   Options Database:
808a4af0ceeSJacob Faibussowitsch + -device_context_stream_type - type of stream to create inside the PetscDeviceContext -
809030f984aSJacob Faibussowitsch    PetscDeviceContextSetStreamType()
810a4af0ceeSJacob Faibussowitsch - -device_context_device_type - the type of PetscDevice to attach by default - PetscDeviceType
811030f984aSJacob Faibussowitsch 
812030f984aSJacob Faibussowitsch   Level: beginner
813030f984aSJacob Faibussowitsch 
8145181c4f9SJacob Faibussowitsch .seealso: PetscDeviceContextSetStreamType(), PetscDeviceContextSetDevice()
815030f984aSJacob Faibussowitsch @*/
816030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetFromOptions(MPI_Comm comm, const char prefix[], PetscDeviceContext dctx)
817030f984aSJacob Faibussowitsch {
818030f984aSJacob Faibussowitsch   PetscBool      flag;
819a4af0ceeSJacob Faibussowitsch   PetscInt       stype,dtype;
820030f984aSJacob Faibussowitsch   PetscErrorCode ierr;
821030f984aSJacob Faibussowitsch 
822030f984aSJacob Faibussowitsch   PetscFunctionBegin;
823a4af0ceeSJacob Faibussowitsch   if (prefix) PetscValidCharPointer(prefix,2);
824030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx,3);
825030f984aSJacob Faibussowitsch   ierr = PetscOptionsBegin(comm,prefix,"PetscDeviceContext Options","Sys");CHKERRQ(ierr);
826a4af0ceeSJacob Faibussowitsch   ierr = PetscOptionsEList("-device_context_stream_type","PetscDeviceContext PetscStreamType","PetscDeviceContextSetStreamType",PetscStreamTypes,PETSC_STREAM_MAX,PetscStreamTypes[dctx->streamType],&stype,&flag);CHKERRQ(ierr);
827030f984aSJacob Faibussowitsch   if (flag) {
828030f984aSJacob Faibussowitsch     ierr = PetscDeviceContextSetStreamType(dctx,static_cast<PetscStreamType>(stype));CHKERRQ(ierr);
829030f984aSJacob Faibussowitsch   }
830a4af0ceeSJacob 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);
831a4af0ceeSJacob Faibussowitsch   if (flag) {
832a4af0ceeSJacob Faibussowitsch     ierr = PetscDeviceContextSetDefaultDeviceForType_Internal(dctx,static_cast<PetscDeviceType>(dtype+1));CHKERRQ(ierr);
833a4af0ceeSJacob Faibussowitsch   }
834030f984aSJacob Faibussowitsch   ierr = PetscOptionsEnd();CHKERRQ(ierr);
835030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
836030f984aSJacob Faibussowitsch }
837