xref: /petsc/src/sys/objects/device/interface/dcontext.cxx (revision dbbe0bcd3f3a8fbab5a45420dc06f8387e5764c6)
1030f984aSJacob Faibussowitsch #include <petsc/private/deviceimpl.h> /*I "petscdevice.h" I*/
2030f984aSJacob Faibussowitsch #include "objpool.hpp"
3030f984aSJacob Faibussowitsch 
4a4af0ceeSJacob Faibussowitsch const char *const PetscStreamTypes[] = {
5a4af0ceeSJacob Faibussowitsch   "global_blocking",
6a4af0ceeSJacob Faibussowitsch   "default_blocking",
7a4af0ceeSJacob Faibussowitsch   "global_nonblocking",
8a4af0ceeSJacob Faibussowitsch   "max",
9a4af0ceeSJacob Faibussowitsch   "PetscStreamType",
10a4af0ceeSJacob Faibussowitsch   "PETSC_STREAM_",
11bf025ffbSJacob Faibussowitsch   nullptr
12a4af0ceeSJacob Faibussowitsch };
13a4af0ceeSJacob Faibussowitsch 
14a4af0ceeSJacob Faibussowitsch const char *const PetscDeviceContextJoinModes[] = {
15a4af0ceeSJacob Faibussowitsch   "destroy",
16a4af0ceeSJacob Faibussowitsch   "sync",
17a4af0ceeSJacob Faibussowitsch   "no_sync",
18a4af0ceeSJacob Faibussowitsch   "PetscDeviceContextJoinMode",
19a4af0ceeSJacob Faibussowitsch   "PETSC_DEVICE_CONTEXT_JOIN_",
20bf025ffbSJacob Faibussowitsch   nullptr
21a4af0ceeSJacob Faibussowitsch };
22a4af0ceeSJacob Faibussowitsch 
23030f984aSJacob Faibussowitsch /* Define the allocator */
2417f48955SJacob Faibussowitsch struct PetscDeviceContextAllocator : Petsc::AllocatorBase<PetscDeviceContext>
25030f984aSJacob Faibussowitsch {
26030f984aSJacob Faibussowitsch   static PetscInt PetscDeviceContextID;
27030f984aSJacob Faibussowitsch 
2817f48955SJacob Faibussowitsch   PETSC_NODISCARD static PetscErrorCode create(PetscDeviceContext *dctx) noexcept
29030f984aSJacob Faibussowitsch   {
30030f984aSJacob Faibussowitsch     PetscDeviceContext dc;
31030f984aSJacob Faibussowitsch 
32030f984aSJacob Faibussowitsch     PetscFunctionBegin;
339566063dSJacob Faibussowitsch     PetscCall(PetscNew(&dc));
34030f984aSJacob Faibussowitsch     dc->id         = PetscDeviceContextID++;
35030f984aSJacob Faibussowitsch     dc->streamType = PETSC_STREAM_DEFAULT_BLOCKING;
36030f984aSJacob Faibussowitsch     *dctx          = dc;
37030f984aSJacob Faibussowitsch     PetscFunctionReturn(0);
38030f984aSJacob Faibussowitsch   }
39030f984aSJacob Faibussowitsch 
4017f48955SJacob Faibussowitsch   PETSC_NODISCARD static PetscErrorCode destroy(PetscDeviceContext dctx) noexcept
41030f984aSJacob Faibussowitsch   {
42030f984aSJacob Faibussowitsch     PetscFunctionBegin;
43bf025ffbSJacob Faibussowitsch     PetscAssert(!dctx->numChildren,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Device context still has %" PetscInt_FMT " un-joined children, must call PetscDeviceContextJoin() with all children before destroying",dctx->numChildren);
44*dbbe0bcdSBarry Smith     PetscTryTypeMethod(dctx,destroy);
459566063dSJacob Faibussowitsch     PetscCall(PetscDeviceDestroy(&dctx->device));
469566063dSJacob Faibussowitsch     PetscCall(PetscFree(dctx->childIDs));
479566063dSJacob Faibussowitsch     PetscCall(PetscFree(dctx));
48030f984aSJacob Faibussowitsch     PetscFunctionReturn(0);
49030f984aSJacob Faibussowitsch   }
50030f984aSJacob Faibussowitsch 
5117f48955SJacob Faibussowitsch   PETSC_NODISCARD static PetscErrorCode reset(PetscDeviceContext dctx) noexcept
52030f984aSJacob Faibussowitsch   {
53030f984aSJacob Faibussowitsch     PetscFunctionBegin;
54030f984aSJacob Faibussowitsch     /* don't deallocate the child array, rather just zero it out */
559566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(dctx->childIDs,dctx->maxNumChildren));
56030f984aSJacob Faibussowitsch     dctx->setup       = PETSC_FALSE;
57030f984aSJacob Faibussowitsch     dctx->numChildren = 0;
58030f984aSJacob Faibussowitsch     dctx->streamType  = PETSC_STREAM_DEFAULT_BLOCKING;
59030f984aSJacob Faibussowitsch     PetscFunctionReturn(0);
60030f984aSJacob Faibussowitsch   }
61030f984aSJacob Faibussowitsch 
6217f48955SJacob Faibussowitsch   PETSC_NODISCARD static constexpr PetscErrorCode finalize() noexcept { return 0; }
63030f984aSJacob Faibussowitsch };
64a4af0ceeSJacob Faibussowitsch /* an ID = 0 is invalid */
65a4af0ceeSJacob Faibussowitsch PetscInt PetscDeviceContextAllocator::PetscDeviceContextID = 1;
66030f984aSJacob Faibussowitsch 
67030f984aSJacob Faibussowitsch static Petsc::ObjectPool<PetscDeviceContext,PetscDeviceContextAllocator> contextPool;
68030f984aSJacob Faibussowitsch 
69030f984aSJacob Faibussowitsch /*@C
70030f984aSJacob Faibussowitsch   PetscDeviceContextCreate - Creates a PetscDeviceContext
71030f984aSJacob Faibussowitsch 
72030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
73030f984aSJacob Faibussowitsch 
7401d2d390SJose E. Roman   Output Paramemter:
75030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext
76030f984aSJacob Faibussowitsch 
77030f984aSJacob Faibussowitsch   Notes:
78030f984aSJacob Faibussowitsch   Unlike almost every other PETSc class it is advised that most users use
79030f984aSJacob Faibussowitsch   PetscDeviceContextDuplicate() rather than this routine to create new contexts. Contexts
80030f984aSJacob Faibussowitsch   of different types are incompatible with one another; using
81030f984aSJacob Faibussowitsch   PetscDeviceContextDuplicate() ensures compatible types.
82030f984aSJacob Faibussowitsch 
83030f984aSJacob Faibussowitsch   Level: beginner
84030f984aSJacob Faibussowitsch 
85db781477SPatrick Sanan .seealso: `PetscDeviceContextDuplicate()`, `PetscDeviceContextSetDevice()`,
86db781477SPatrick Sanan           `PetscDeviceContextSetStreamType()`, `PetscDeviceContextSetUp()`,
87db781477SPatrick Sanan           `PetscDeviceContextSetFromOptions()`, `PetscDeviceContextDestroy()`
88030f984aSJacob Faibussowitsch @*/
89030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextCreate(PetscDeviceContext *dctx)
90030f984aSJacob Faibussowitsch {
91030f984aSJacob Faibussowitsch   PetscFunctionBegin;
92030f984aSJacob Faibussowitsch   PetscValidPointer(dctx,1);
939566063dSJacob Faibussowitsch   PetscCall(PetscDeviceInitializePackage());
949566063dSJacob Faibussowitsch   PetscCall(contextPool.get(*dctx));
95030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
96030f984aSJacob Faibussowitsch }
97030f984aSJacob Faibussowitsch 
98030f984aSJacob Faibussowitsch /*@C
99030f984aSJacob Faibussowitsch   PetscDeviceContextDestroy - Frees a PetscDeviceContext
100030f984aSJacob Faibussowitsch 
101030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
102030f984aSJacob Faibussowitsch 
103030f984aSJacob Faibussowitsch   Input Parameters:
104030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext
105030f984aSJacob Faibussowitsch 
106030f984aSJacob Faibussowitsch   Notes:
107030f984aSJacob Faibussowitsch   No implicit synchronization occurs due to this routine, all resources are released completely asynchronously
108030f984aSJacob Faibussowitsch   w.r.t. the host. If one needs to guarantee access to the data produced on this contexts stream one should perform the
109030f984aSJacob Faibussowitsch   appropriate synchronization before calling this routine.
110030f984aSJacob Faibussowitsch 
111030f984aSJacob Faibussowitsch   Developer Notes:
112030f984aSJacob Faibussowitsch   The context is never actually "destroyed", only returned to an ever growing pool of
113030f984aSJacob Faibussowitsch   contexts. There are currently no safeguards on the size of the pool, this should perhaps
114030f984aSJacob Faibussowitsch   be implemented.
115030f984aSJacob Faibussowitsch 
116030f984aSJacob Faibussowitsch   Level: beginner
117030f984aSJacob Faibussowitsch 
118db781477SPatrick Sanan .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextSetDevice()`, `PetscDeviceContextSetUp()`, `PetscDeviceContextSynchronize()`
119030f984aSJacob Faibussowitsch @*/
120030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextDestroy(PetscDeviceContext *dctx)
121030f984aSJacob Faibussowitsch {
122030f984aSJacob Faibussowitsch   PetscFunctionBegin;
123030f984aSJacob Faibussowitsch   if (!*dctx) PetscFunctionReturn(0);
1249566063dSJacob Faibussowitsch   PetscCall(contextPool.reclaim(std::move(*dctx)));
125bf025ffbSJacob Faibussowitsch   *dctx = nullptr;
126030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
127030f984aSJacob Faibussowitsch }
128030f984aSJacob Faibussowitsch 
129030f984aSJacob Faibussowitsch /*@C
130030f984aSJacob Faibussowitsch   PetscDeviceContextSetStreamType - Set the implementation type of the underlying stream for a PetscDeviceContext
131030f984aSJacob Faibussowitsch 
132030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
133030f984aSJacob Faibussowitsch 
13401d2d390SJose E. Roman   Input Parameters:
135030f984aSJacob Faibussowitsch + dctx - The PetscDeviceContext
136030f984aSJacob Faibussowitsch - type - The PetscStreamType
137030f984aSJacob Faibussowitsch 
138030f984aSJacob Faibussowitsch   Notes:
139030f984aSJacob Faibussowitsch   See PetscStreamType in include/petscdevicetypes.h for more information on the available
140030f984aSJacob Faibussowitsch   types and their interactions. If the PetscDeviceContext was previously set up and stream
141030f984aSJacob Faibussowitsch   type was changed, you must call PetscDeviceContextSetUp() again after this routine.
142030f984aSJacob Faibussowitsch 
143030f984aSJacob Faibussowitsch   Level: intermediate
144030f984aSJacob Faibussowitsch 
145db781477SPatrick Sanan .seealso: `PetscStreamType`, `PetscDeviceContextGetStreamType()`, `PetscDeviceContextCreate()`, `PetscDeviceContextSetUp()`, `PetscDeviceContextSetFromOptions()`
146030f984aSJacob Faibussowitsch @*/
147030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetStreamType(PetscDeviceContext dctx, PetscStreamType type)
148030f984aSJacob Faibussowitsch {
149030f984aSJacob Faibussowitsch   PetscFunctionBegin;
150030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx,1);
151030f984aSJacob Faibussowitsch   PetscValidStreamType(type,2);
152030f984aSJacob Faibussowitsch   /* only need to do complex swapping if the object has already been setup */
153030f984aSJacob Faibussowitsch   if (dctx->setup && (dctx->streamType != type)) {
154*dbbe0bcdSBarry Smith     PetscUseTypeMethod(dctx,changestreamtype ,type);
155030f984aSJacob Faibussowitsch     dctx->setup = PETSC_FALSE;
156030f984aSJacob Faibussowitsch   }
157030f984aSJacob Faibussowitsch   dctx->streamType = type;
158030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
159030f984aSJacob Faibussowitsch }
160030f984aSJacob Faibussowitsch 
161030f984aSJacob Faibussowitsch /*@C
162030f984aSJacob Faibussowitsch   PetscDeviceContextGetStreamType - Get the implementation type of the underlying stream for a PetscDeviceContext
163030f984aSJacob Faibussowitsch 
164030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
165030f984aSJacob Faibussowitsch 
16601d2d390SJose E. Roman   Input Parameter:
167030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext
168030f984aSJacob Faibussowitsch 
169030f984aSJacob Faibussowitsch   Output Parameter:
170030f984aSJacob Faibussowitsch . type - The PetscStreamType
171030f984aSJacob Faibussowitsch 
172030f984aSJacob Faibussowitsch   Notes:
173030f984aSJacob Faibussowitsch   See PetscStreamType in include/petscdevicetypes.h for more information on the available types and their interactions
174030f984aSJacob Faibussowitsch 
175030f984aSJacob Faibussowitsch   Level: intermediate
176030f984aSJacob Faibussowitsch 
177db781477SPatrick Sanan .seealso: `PetscDeviceContextSetStreamType()`, `PetscDeviceContextCreate()`, `PetscDeviceContextSetFromOptions()`
178030f984aSJacob Faibussowitsch @*/
179030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextGetStreamType(PetscDeviceContext dctx, PetscStreamType *type)
180030f984aSJacob Faibussowitsch {
181030f984aSJacob Faibussowitsch   PetscFunctionBegin;
182030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx,1);
183030f984aSJacob Faibussowitsch   PetscValidIntPointer(type,2);
184030f984aSJacob Faibussowitsch   *type = dctx->streamType;
185030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
186030f984aSJacob Faibussowitsch }
187030f984aSJacob Faibussowitsch 
188030f984aSJacob Faibussowitsch /*@C
189030f984aSJacob Faibussowitsch   PetscDeviceContextSetDevice - Set the underlying device for the PetscDeviceContext
190030f984aSJacob Faibussowitsch 
191030f984aSJacob Faibussowitsch   Not Collective, Possibly Synchronous
192030f984aSJacob Faibussowitsch 
19301d2d390SJose E. Roman   Input Parameters:
194030f984aSJacob Faibussowitsch + dctx   - The PetscDeviceContext
195030f984aSJacob Faibussowitsch - device - The PetscDevice
196030f984aSJacob Faibussowitsch 
197030f984aSJacob Faibussowitsch   Notes:
198030f984aSJacob Faibussowitsch   This routine is effectively PetscDeviceContext's "set-type" (so every PetscDeviceContext
199030f984aSJacob Faibussowitsch   must also have an attached PetscDevice). Unlike the usual set-type semantics, it is
200030f984aSJacob Faibussowitsch   not stricly necessary to set a contexts device to enable usage, any created device
201030f984aSJacob Faibussowitsch   contexts will always come equipped with the "default" device.
202030f984aSJacob Faibussowitsch 
203a4af0ceeSJacob Faibussowitsch   This routine is a no-op if dctx is already attached to device.
204a4af0ceeSJacob Faibussowitsch 
2055181c4f9SJacob Faibussowitsch   This routine may initialize the backend device and incur synchronization.
2065181c4f9SJacob Faibussowitsch 
207030f984aSJacob Faibussowitsch   Level: intermediate
208030f984aSJacob Faibussowitsch 
209db781477SPatrick Sanan .seealso: `PetscDeviceCreate()`, `PetscDeviceConfigure()`, `PetscDeviceContextGetDevice()`
210030f984aSJacob Faibussowitsch @*/
211030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetDevice(PetscDeviceContext dctx, PetscDevice device)
212030f984aSJacob Faibussowitsch {
213030f984aSJacob Faibussowitsch   PetscFunctionBegin;
214030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx,1);
215030f984aSJacob Faibussowitsch   PetscValidDevice(device,2);
216a4af0ceeSJacob Faibussowitsch   if (dctx->device) {
217a4af0ceeSJacob Faibussowitsch     /* can't do a strict pointer equality check since PetscDevice's are reused */
218a4af0ceeSJacob Faibussowitsch     if (dctx->device->ops->createcontext == device->ops->createcontext) PetscFunctionReturn(0);
219a4af0ceeSJacob Faibussowitsch   }
2209566063dSJacob Faibussowitsch   PetscCall(PetscDeviceDestroy(&dctx->device));
221*dbbe0bcdSBarry Smith   PetscTryTypeMethod(dctx,destroy);
2229566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(dctx->ops,sizeof(*dctx->ops)));
2239566063dSJacob Faibussowitsch   PetscCall((*device->ops->createcontext)(dctx));
2249566063dSJacob Faibussowitsch   PetscCall(PetscDeviceReference_Internal(device));
225a4af0ceeSJacob Faibussowitsch   dctx->device = device;
226030f984aSJacob Faibussowitsch   dctx->setup  = PETSC_FALSE;
227030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
228030f984aSJacob Faibussowitsch }
229030f984aSJacob Faibussowitsch 
230030f984aSJacob Faibussowitsch /*@C
231030f984aSJacob Faibussowitsch   PetscDeviceContextGetDevice - Get the underlying PetscDevice for a PetscDeviceContext
232030f984aSJacob Faibussowitsch 
233030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
234030f984aSJacob Faibussowitsch 
235030f984aSJacob Faibussowitsch   Input Parameter:
236030f984aSJacob Faibussowitsch . dctx - the PetscDeviceContext
237030f984aSJacob Faibussowitsch 
238030f984aSJacob Faibussowitsch   Output Parameter:
239030f984aSJacob Faibussowitsch . device - The PetscDevice
240030f984aSJacob Faibussowitsch 
241030f984aSJacob Faibussowitsch   Notes:
242030f984aSJacob Faibussowitsch   This is a borrowed reference, the user should not destroy the device.
243030f984aSJacob Faibussowitsch 
244a375dbeeSPatrick Sanan   Level: intermediate
245a375dbeeSPatrick Sanan 
246db781477SPatrick Sanan .seealso: `PetscDeviceContextSetDevice()`, `PetscDevice`
247030f984aSJacob Faibussowitsch @*/
248030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextGetDevice(PetscDeviceContext dctx, PetscDevice *device)
249030f984aSJacob Faibussowitsch {
250030f984aSJacob Faibussowitsch   PetscFunctionBegin;
251030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx,1);
252030f984aSJacob Faibussowitsch   PetscValidPointer(device,2);
253bf025ffbSJacob Faibussowitsch   PetscAssert(dctx->device,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"PetscDeviceContext %" PetscInt_FMT " has no attached PetscDevice to get",dctx->id);
254030f984aSJacob Faibussowitsch   *device = dctx->device;
255030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
256030f984aSJacob Faibussowitsch }
257030f984aSJacob Faibussowitsch 
258030f984aSJacob Faibussowitsch /*@C
259030f984aSJacob Faibussowitsch   PetscDeviceContextSetUp - Prepares a PetscDeviceContext for use
260030f984aSJacob Faibussowitsch 
261030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
262030f984aSJacob Faibussowitsch 
26301d2d390SJose E. Roman   Input Parameter:
264030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext
265030f984aSJacob Faibussowitsch 
266030f984aSJacob Faibussowitsch   Developer Notes:
267030f984aSJacob Faibussowitsch   This routine is usually the stage where a PetscDeviceContext acquires device-side data structures such as streams,
268030f984aSJacob Faibussowitsch   events, and (possibly) handles.
269030f984aSJacob Faibussowitsch 
270030f984aSJacob Faibussowitsch   Level: beginner
271030f984aSJacob Faibussowitsch 
272db781477SPatrick Sanan .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextSetDevice()`, `PetscDeviceContextDestroy()`, `PetscDeviceContextSetFromOptions()`
273030f984aSJacob Faibussowitsch @*/
274030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetUp(PetscDeviceContext dctx)
275030f984aSJacob Faibussowitsch {
276030f984aSJacob Faibussowitsch   PetscFunctionBegin;
277030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx,1);
278030f984aSJacob Faibussowitsch   if (!dctx->device) {
2799566063dSJacob Faibussowitsch     PetscCall(PetscInfo(nullptr,"PetscDeviceContext %" PetscInt_FMT " did not have an explicitly attached PetscDevice, using default with type %s\n",dctx->id,PetscDeviceTypes[PETSC_DEVICE_DEFAULT]));
2809566063dSJacob Faibussowitsch     PetscCall(PetscDeviceContextSetDefaultDevice_Internal(dctx));
281030f984aSJacob Faibussowitsch   }
282030f984aSJacob Faibussowitsch   if (dctx->setup) PetscFunctionReturn(0);
283*dbbe0bcdSBarry Smith   PetscUseTypeMethod(dctx,setup);
284030f984aSJacob Faibussowitsch   dctx->setup = PETSC_TRUE;
285030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
286030f984aSJacob Faibussowitsch }
287030f984aSJacob Faibussowitsch 
288030f984aSJacob Faibussowitsch /*@C
289030f984aSJacob Faibussowitsch   PetscDeviceContextDuplicate - Duplicates a PetscDeviceContext object
290030f984aSJacob Faibussowitsch 
291030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
292030f984aSJacob Faibussowitsch 
293030f984aSJacob Faibussowitsch   Input Parameter:
294030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext to duplicate
295030f984aSJacob Faibussowitsch 
2966aad120cSJose E. Roman   Output Parameter:
297050c0c3dSJacob Faibussowitsch . dctxdup - The duplicated PetscDeviceContext
298030f984aSJacob Faibussowitsch 
299030f984aSJacob Faibussowitsch   Notes:
300030f984aSJacob Faibussowitsch   This is a shorthand method for creating a PetscDeviceContext with the exact same
301030f984aSJacob Faibussowitsch   settings as another. Note however that the duplicated PetscDeviceContext does not "share"
302030f984aSJacob Faibussowitsch   any of the underlying data with the original, (including its current stream-state) they
303030f984aSJacob Faibussowitsch   are completely separate objects.
304030f984aSJacob Faibussowitsch 
305030f984aSJacob Faibussowitsch   Level: beginner
306030f984aSJacob Faibussowitsch 
307db781477SPatrick Sanan .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextSetDevice()`, `PetscDeviceContextSetStreamType()`
308030f984aSJacob Faibussowitsch @*/
309030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextDuplicate(PetscDeviceContext dctx, PetscDeviceContext *dctxdup)
310030f984aSJacob Faibussowitsch {
311a4af0ceeSJacob Faibussowitsch   PetscDeviceContext dup;
312030f984aSJacob Faibussowitsch 
313030f984aSJacob Faibussowitsch   PetscFunctionBegin;
314030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx,1);
315030f984aSJacob Faibussowitsch   PetscValidPointer(dctxdup,2);
3169566063dSJacob Faibussowitsch   PetscCall(PetscDeviceContextCreate(&dup));
3179566063dSJacob Faibussowitsch   PetscCall(PetscDeviceContextSetStreamType(dup,dctx->streamType));
3189566063dSJacob Faibussowitsch   if (dctx->device) PetscCall(PetscDeviceContextSetDevice(dup,dctx->device));
3199566063dSJacob Faibussowitsch   PetscCall(PetscDeviceContextSetUp(dup));
320a4af0ceeSJacob Faibussowitsch   *dctxdup = dup;
321030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
322030f984aSJacob Faibussowitsch }
323030f984aSJacob Faibussowitsch 
324030f984aSJacob Faibussowitsch /*@C
325030f984aSJacob Faibussowitsch   PetscDeviceContextQueryIdle - Returns whether or not a PetscDeviceContext is idle
326030f984aSJacob Faibussowitsch 
327030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
328030f984aSJacob Faibussowitsch 
329030f984aSJacob Faibussowitsch   Input Parameter:
330030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext object
331030f984aSJacob Faibussowitsch 
332030f984aSJacob Faibussowitsch   Output Parameter:
333030f984aSJacob Faibussowitsch . idle - PETSC_TRUE if PetscDeviceContext has NO work, PETSC_FALSE if it has work
334030f984aSJacob Faibussowitsch 
335030f984aSJacob Faibussowitsch   Notes:
336ef657721SJacob Faibussowitsch   This routine only refers a singular context and does NOT take any of its children into
337ef657721SJacob Faibussowitsch   account. That is, if dctx is idle but has dependents who do have work, this routine still
338ef657721SJacob Faibussowitsch   returns PETSC_TRUE.
339030f984aSJacob Faibussowitsch 
340030f984aSJacob Faibussowitsch   Level: intermediate
341030f984aSJacob Faibussowitsch 
342db781477SPatrick Sanan .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextWaitForContext()`, `PetscDeviceContextFork()`
343030f984aSJacob Faibussowitsch @*/
344030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextQueryIdle(PetscDeviceContext dctx, PetscBool *idle)
345030f984aSJacob Faibussowitsch {
346030f984aSJacob Faibussowitsch   PetscFunctionBegin;
347030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx,1);
348030f984aSJacob Faibussowitsch   PetscValidBoolPointer(idle,2);
349*dbbe0bcdSBarry Smith   PetscUseTypeMethod(dctx,query ,idle);
3509566063dSJacob Faibussowitsch   PetscCall(PetscInfo(nullptr,"PetscDeviceContext id %" PetscInt_FMT " %s idle\n",dctx->id,*idle ? "was" : "was not"));
351030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
352030f984aSJacob Faibussowitsch }
353030f984aSJacob Faibussowitsch 
354030f984aSJacob Faibussowitsch /*@C
355030f984aSJacob Faibussowitsch   PetscDeviceContextWaitForContext - Make one context wait for another context to finish
356030f984aSJacob Faibussowitsch 
357030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
358030f984aSJacob Faibussowitsch 
359030f984aSJacob Faibussowitsch   Input Parameters:
360030f984aSJacob Faibussowitsch + dctxa - The PetscDeviceContext object that is waiting
361030f984aSJacob Faibussowitsch - dctxb - The PetscDeviceContext object that is being waited on
362030f984aSJacob Faibussowitsch 
363030f984aSJacob Faibussowitsch   Notes:
364030f984aSJacob Faibussowitsch   Serializes two PetscDeviceContexts. This routine uses only the state of dctxb at the moment this routine was
365030f984aSJacob Faibussowitsch   called, so any future work queued will not affect dctxa. It is safe to pass the same context to both arguments.
366030f984aSJacob Faibussowitsch 
367030f984aSJacob Faibussowitsch   Level: beginner
368030f984aSJacob Faibussowitsch 
369db781477SPatrick Sanan .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextQueryIdle()`, `PetscDeviceContextJoin()`
370030f984aSJacob Faibussowitsch @*/
371030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextWaitForContext(PetscDeviceContext dctxa, PetscDeviceContext dctxb)
372030f984aSJacob Faibussowitsch {
373030f984aSJacob Faibussowitsch   PetscFunctionBegin;
374030f984aSJacob Faibussowitsch   PetscCheckCompatibleDeviceContexts(dctxa,1,dctxb,2);
375030f984aSJacob Faibussowitsch   if (dctxa == dctxb) PetscFunctionReturn(0);
376*dbbe0bcdSBarry Smith   PetscUseTypeMethod(dctxa,waitforcontext ,dctxb);
377030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
378030f984aSJacob Faibussowitsch }
379030f984aSJacob Faibussowitsch 
380050c0c3dSJacob Faibussowitsch #define PETSC_USE_DEBUG_AND_INFO (PetscDefined(USE_DEBUG) && PetscDefined(USE_INFO))
381050c0c3dSJacob Faibussowitsch #if PETSC_USE_DEBUG_AND_INFO
382050c0c3dSJacob Faibussowitsch #include <string>
383050c0c3dSJacob Faibussowitsch #endif
384030f984aSJacob Faibussowitsch /*@C
385030f984aSJacob Faibussowitsch   PetscDeviceContextFork - Create a set of dependent child contexts from a parent context
386030f984aSJacob Faibussowitsch 
387030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
388030f984aSJacob Faibussowitsch 
389030f984aSJacob Faibussowitsch   Input Parameters:
390030f984aSJacob Faibussowitsch + dctx - The parent PetscDeviceContext
391030f984aSJacob Faibussowitsch - n    - The number of children to create
392030f984aSJacob Faibussowitsch 
393030f984aSJacob Faibussowitsch   Output Parameter:
394030f984aSJacob Faibussowitsch . dsub - The created child context(s)
395030f984aSJacob Faibussowitsch 
396030f984aSJacob Faibussowitsch   Notes:
397030f984aSJacob Faibussowitsch   This routine creates n edges of a DAG from a source node which are causally dependent on the source node, meaning
398030f984aSJacob Faibussowitsch   that work queued on child contexts will not start until the parent context finishes its work. This accounts for work
399030f984aSJacob Faibussowitsch   queued on the parent up until calling this function, any subsequent work enqueued on the parent has no effect on the children.
400030f984aSJacob Faibussowitsch 
401030f984aSJacob Faibussowitsch   Any children created with this routine have their lifetimes bounded by the parent. That is, the parent context expects
402030f984aSJacob Faibussowitsch   to free all of it's children (and ONLY its children) before itself is freed.
403030f984aSJacob Faibussowitsch 
404030f984aSJacob Faibussowitsch   DAG representation:
405030f984aSJacob Faibussowitsch .vb
406030f984aSJacob Faibussowitsch   time ->
407030f984aSJacob Faibussowitsch 
408030f984aSJacob Faibussowitsch   -> dctx \----> dctx ------>
409030f984aSJacob Faibussowitsch            \---> dsub[0] --->
410030f984aSJacob Faibussowitsch             \--> ... ------->
411030f984aSJacob Faibussowitsch              \-> dsub[n-1] ->
412030f984aSJacob Faibussowitsch .ve
413030f984aSJacob Faibussowitsch 
414030f984aSJacob Faibussowitsch   Level: intermediate
415030f984aSJacob Faibussowitsch 
416db781477SPatrick Sanan .seealso: `PetscDeviceContextJoin()`, `PetscDeviceContextSynchronize()`, `PetscDeviceContextQueryIdle()`
417030f984aSJacob Faibussowitsch @*/
418030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextFork(PetscDeviceContext dctx, PetscInt n, PetscDeviceContext **dsub)
419030f984aSJacob Faibussowitsch {
420050c0c3dSJacob Faibussowitsch #if PETSC_USE_DEBUG_AND_INFO
421030f984aSJacob Faibussowitsch   const PetscInt      nBefore = n;
422030f984aSJacob Faibussowitsch   static std::string  idList;
423030f984aSJacob Faibussowitsch #endif
424bf025ffbSJacob Faibussowitsch   PetscDeviceContext *dsubTmp = nullptr;
425030f984aSJacob Faibussowitsch   PetscInt            i = 0;
426030f984aSJacob Faibussowitsch 
427030f984aSJacob Faibussowitsch   PetscFunctionBegin;
428030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx,1);
429030f984aSJacob Faibussowitsch   PetscValidPointer(dsub,3);
430bf025ffbSJacob Faibussowitsch   PetscAssert(n >= 0,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Number of contexts requested %" PetscInt_FMT " < 0",n);
4313ca90d2dSJacob Faibussowitsch #if PETSC_USE_DEBUG_AND_INFO
432030f984aSJacob Faibussowitsch   /* reserve 4 chars per id, 2 for number and 2 for ', ' separator */
433030f984aSJacob Faibussowitsch   idList.reserve(4*n);
434030f984aSJacob Faibussowitsch #endif
435030f984aSJacob Faibussowitsch   /* update child totals */
436030f984aSJacob Faibussowitsch   dctx->numChildren += n;
437030f984aSJacob Faibussowitsch   /* now to find out if we have room */
438030f984aSJacob Faibussowitsch   if (dctx->numChildren > dctx->maxNumChildren) {
439030f984aSJacob Faibussowitsch     /* no room, either from having too many kids or not having any */
440030f984aSJacob Faibussowitsch     if (dctx->childIDs) {
441030f984aSJacob Faibussowitsch       /* have existing children, must reallocate them */
4429566063dSJacob Faibussowitsch       PetscCall(PetscRealloc(dctx->numChildren*sizeof(*dctx->childIDs),&dctx->childIDs));
443030f984aSJacob Faibussowitsch       /* clear the extra memory since realloc doesn't do it for us */
4449566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero((dctx->childIDs)+(dctx->maxNumChildren),(dctx->numChildren)-(dctx->maxNumChildren)));
445030f984aSJacob Faibussowitsch     } else {
446030f984aSJacob Faibussowitsch       /* have no children */
4479566063dSJacob Faibussowitsch       PetscCall(PetscCalloc1(dctx->numChildren,&dctx->childIDs));
448030f984aSJacob Faibussowitsch     }
449030f984aSJacob Faibussowitsch     /* update total number of children */
450030f984aSJacob Faibussowitsch     dctx->maxNumChildren = dctx->numChildren;
451030f984aSJacob Faibussowitsch   }
4529566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n,&dsubTmp));
453030f984aSJacob Faibussowitsch   while (n) {
454030f984aSJacob Faibussowitsch     /* empty child slot */
455030f984aSJacob Faibussowitsch     if (!(dctx->childIDs[i])) {
456030f984aSJacob Faibussowitsch       /* create the child context in the image of its parent */
4579566063dSJacob Faibussowitsch       PetscCall(PetscDeviceContextDuplicate(dctx,dsubTmp+i));
4589566063dSJacob Faibussowitsch       PetscCall(PetscDeviceContextWaitForContext(dsubTmp[i],dctx));
459030f984aSJacob Faibussowitsch       /* register the child with its parent */
460030f984aSJacob Faibussowitsch       dctx->childIDs[i] = dsubTmp[i]->id;
461050c0c3dSJacob Faibussowitsch #if PETSC_USE_DEBUG_AND_INFO
462030f984aSJacob Faibussowitsch       idList += std::to_string(dsubTmp[i]->id);
463030f984aSJacob Faibussowitsch       if (n != 1) idList += ", ";
464030f984aSJacob Faibussowitsch #endif
465030f984aSJacob Faibussowitsch       --n;
466030f984aSJacob Faibussowitsch     }
467030f984aSJacob Faibussowitsch     ++i;
468030f984aSJacob Faibussowitsch   }
4693ca90d2dSJacob Faibussowitsch #if PETSC_USE_DEBUG_AND_INFO
4709566063dSJacob Faibussowitsch   PetscCall(PetscInfo(nullptr,"Forked %" PetscInt_FMT " children from parent %" PetscInt_FMT " with IDs: %s\n",nBefore,dctx->id,idList.c_str()));
471030f984aSJacob Faibussowitsch   /* resets the size but doesn't deallocate the memory */
472030f984aSJacob Faibussowitsch   idList.clear();
473030f984aSJacob Faibussowitsch #endif
474030f984aSJacob Faibussowitsch   /* pass the children back to caller */
475030f984aSJacob Faibussowitsch   *dsub = dsubTmp;
476030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
477030f984aSJacob Faibussowitsch }
478030f984aSJacob Faibussowitsch 
479030f984aSJacob Faibussowitsch /*@C
4805181c4f9SJacob Faibussowitsch   PetscDeviceContextJoin - Converge a set of child contexts
481030f984aSJacob Faibussowitsch 
482030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
483030f984aSJacob Faibussowitsch 
484030f984aSJacob Faibussowitsch   Input Parameters:
485030f984aSJacob Faibussowitsch + dctx         - A PetscDeviceContext to converge on
486030f984aSJacob Faibussowitsch . n            - The number of sub contexts to converge
487030f984aSJacob Faibussowitsch . joinMode     - The type of join to perform
488030f984aSJacob Faibussowitsch - dsub         - The sub contexts to converge
489030f984aSJacob Faibussowitsch 
490030f984aSJacob Faibussowitsch   Notes:
491030f984aSJacob Faibussowitsch   If PetscDeviceContextFork() creates n edges from a source node which all depend on the
492030f984aSJacob Faibussowitsch   source node, then this routine is the exact mirror. That is, it creates a node
493030f984aSJacob Faibussowitsch   (represented in dctx) which recieves n edges (and optionally destroys them) which is
494030f984aSJacob Faibussowitsch   dependent on the completion of all incoming edges.
495030f984aSJacob Faibussowitsch 
496030f984aSJacob Faibussowitsch   If joinMode is PETSC_DEVICE_CONTEXT_JOIN_DESTROY all contexts in dsub will be destroyed
497030f984aSJacob Faibussowitsch   by this routine. Thus all sub contexts must have been created with the dctx passed to
498030f984aSJacob Faibussowitsch   this routine.
499030f984aSJacob Faibussowitsch 
500030f984aSJacob Faibussowitsch   if joinMode is PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC dctx waits for all sub contexts but the
501030f984aSJacob Faibussowitsch   sub contexts do not wait for one another afterwards.
502030f984aSJacob Faibussowitsch 
503030f984aSJacob Faibussowitsch   If joinMode is PETSC_DEVICE_CONTEXT_JOIN_SYNC all sub contexts will additionally
504030f984aSJacob Faibussowitsch   wait on dctx after converging. This has the effect of "synchronizing" the outgoing
505030f984aSJacob Faibussowitsch   edges.
506030f984aSJacob Faibussowitsch 
507030f984aSJacob Faibussowitsch   DAG representations:
508030f984aSJacob Faibussowitsch   If joinMode is PETSC_DEVICE_CONTEXT_JOIN_DESTROY
509030f984aSJacob Faibussowitsch .vb
510030f984aSJacob Faibussowitsch   time ->
511030f984aSJacob Faibussowitsch 
512030f984aSJacob Faibussowitsch   -> dctx ---------/- dctx ->
513030f984aSJacob Faibussowitsch   -> dsub[0] -----/
514030f984aSJacob Faibussowitsch   ->  ... -------/
515030f984aSJacob Faibussowitsch   -> dsub[n-1] -/
516030f984aSJacob Faibussowitsch .ve
517030f984aSJacob Faibussowitsch   If joinMode is PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC
518030f984aSJacob Faibussowitsch .vb
519030f984aSJacob Faibussowitsch   time ->
520030f984aSJacob Faibussowitsch 
521030f984aSJacob Faibussowitsch   -> dctx ---------/- dctx ->
522030f984aSJacob Faibussowitsch   -> dsub[0] -----/--------->
523030f984aSJacob Faibussowitsch   ->  ... -------/---------->
524030f984aSJacob Faibussowitsch   -> dsub[n-1] -/----------->
525030f984aSJacob Faibussowitsch .ve
526030f984aSJacob Faibussowitsch   If joinMode is PETSC_DEVICE_CONTEXT_JOIN_SYNC
527030f984aSJacob Faibussowitsch .vb
528030f984aSJacob Faibussowitsch   time ->
529030f984aSJacob Faibussowitsch 
530030f984aSJacob Faibussowitsch   -> dctx ---------/- dctx -\----> dctx ------>
531030f984aSJacob Faibussowitsch   -> dsub[0] -----/          \---> dsub[0] --->
532030f984aSJacob Faibussowitsch   ->  ... -------/            \--> ... ------->
533030f984aSJacob Faibussowitsch   -> dsub[n-1] -/              \-> dsub[n-1] ->
534030f984aSJacob Faibussowitsch .ve
535030f984aSJacob Faibussowitsch 
536030f984aSJacob Faibussowitsch   Level: intermediate
537030f984aSJacob Faibussowitsch 
538db781477SPatrick Sanan .seealso: `PetscDeviceContextFork()`, `PetscDeviceContextSynchronize()`, `PetscDeviceContextJoinMode`
539030f984aSJacob Faibussowitsch @*/
540030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextJoin(PetscDeviceContext dctx, PetscInt n, PetscDeviceContextJoinMode joinMode, PetscDeviceContext **dsub)
541030f984aSJacob Faibussowitsch {
542030f984aSJacob Faibussowitsch #if defined(PETSC_USE_DEBUG) && defined(PETSC_USE_INFO)
543030f984aSJacob Faibussowitsch   static std::string idList;
544030f984aSJacob Faibussowitsch #endif
545030f984aSJacob Faibussowitsch 
546030f984aSJacob Faibussowitsch   PetscFunctionBegin;
547030f984aSJacob Faibussowitsch   /* validity of dctx is checked in the wait-for loop */
548030f984aSJacob Faibussowitsch   PetscValidPointer(dsub,4);
549bf025ffbSJacob Faibussowitsch   PetscAssert(n >= 0,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Number of contexts merged %" PetscInt_FMT " < 0",n);
550030f984aSJacob Faibussowitsch #if defined(PETSC_USE_DEBUG) && defined(PETSC_USE_INFO)
551030f984aSJacob Faibussowitsch   /* reserve 4 chars per id, 2 for number and 2 for ', ' separator */
552030f984aSJacob Faibussowitsch   idList.reserve(4*n);
553030f984aSJacob Faibussowitsch #endif
554030f984aSJacob Faibussowitsch   /* first dctx waits on all the incoming edges */
555030f984aSJacob Faibussowitsch   for (PetscInt i = 0; i < n; ++i) {
556030f984aSJacob Faibussowitsch     PetscCheckCompatibleDeviceContexts(dctx,1,(*dsub)[i],4);
5579566063dSJacob Faibussowitsch     PetscCall(PetscDeviceContextWaitForContext(dctx,(*dsub)[i]));
558030f984aSJacob Faibussowitsch #if defined(PETSC_USE_DEBUG) && defined(PETSC_USE_INFO)
559030f984aSJacob Faibussowitsch     idList += std::to_string((*dsub)[i]->id);
560030f984aSJacob Faibussowitsch     if (i+1 < n) idList += ", ";
561030f984aSJacob Faibussowitsch #endif
562030f984aSJacob Faibussowitsch   }
563030f984aSJacob Faibussowitsch 
564030f984aSJacob Faibussowitsch   /* now we handle the aftermath */
565030f984aSJacob Faibussowitsch   switch (joinMode) {
566030f984aSJacob Faibussowitsch   case PETSC_DEVICE_CONTEXT_JOIN_DESTROY:
567030f984aSJacob Faibussowitsch     {
568030f984aSJacob Faibussowitsch       PetscInt j = 0;
569030f984aSJacob Faibussowitsch 
570bf025ffbSJacob Faibussowitsch       PetscAssert(n <= dctx->numChildren,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Trying to destroy %" PetscInt_FMT " children of a parent context that only has %" PetscInt_FMT " children, likely trying to restore to wrong parent",n,dctx->numChildren);
571030f984aSJacob Faibussowitsch       /* update child count while it's still fresh in memory */
572030f984aSJacob Faibussowitsch       dctx->numChildren -= n;
573030f984aSJacob Faibussowitsch       for (PetscInt i = 0; i < dctx->maxNumChildren; ++i) {
574030f984aSJacob Faibussowitsch         if (dctx->childIDs[i] && (dctx->childIDs[i] == (*dsub)[j]->id)) {
575030f984aSJacob Faibussowitsch           /* child is one of ours, can destroy it */
5769566063dSJacob Faibussowitsch           PetscCall(PetscDeviceContextDestroy((*dsub)+j));
577030f984aSJacob Faibussowitsch           /* reset the child slot */
578030f984aSJacob Faibussowitsch           dctx->childIDs[i] = 0;
579030f984aSJacob Faibussowitsch           if (++j == n) break;
580030f984aSJacob Faibussowitsch         }
581030f984aSJacob Faibussowitsch       }
582030f984aSJacob 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 */
583bf025ffbSJacob Faibussowitsch       PetscAssert(j == n,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"%" PetscInt_FMT " contexts still remain after destroy, this may be because you are trying to restore to the wrong parent context, or the device contexts are not in the same order as they were checked out out in.",n-j);
5849566063dSJacob Faibussowitsch       PetscCall(PetscFree(*dsub));
585030f984aSJacob Faibussowitsch     }
586030f984aSJacob Faibussowitsch     break;
587030f984aSJacob Faibussowitsch   case PETSC_DEVICE_CONTEXT_JOIN_SYNC:
5889566063dSJacob Faibussowitsch     for (PetscInt i = 0; i < n; ++i) PetscCall(PetscDeviceContextWaitForContext((*dsub)[i],dctx));
589030f984aSJacob Faibussowitsch   case PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC:
590030f984aSJacob Faibussowitsch     break;
591030f984aSJacob Faibussowitsch   default:
592030f984aSJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Unknown PetscDeviceContextJoinMode given");
593030f984aSJacob Faibussowitsch   }
594030f984aSJacob Faibussowitsch 
595030f984aSJacob Faibussowitsch #if defined(PETSC_USE_DEBUG) && defined(PETSC_USE_INFO)
5969566063dSJacob Faibussowitsch   PetscCall(PetscInfo(nullptr,"Joined %" PetscInt_FMT " ctxs to ctx %" PetscInt_FMT ", mode %s with IDs: %s\n",n,dctx->id,PetscDeviceContextJoinModes[joinMode],idList.c_str()));
597030f984aSJacob Faibussowitsch   idList.clear();
598030f984aSJacob Faibussowitsch #endif
599030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
600030f984aSJacob Faibussowitsch }
601030f984aSJacob Faibussowitsch 
602030f984aSJacob Faibussowitsch /*@C
6035181c4f9SJacob Faibussowitsch   PetscDeviceContextSynchronize - Block the host until all work queued on or associated with a PetscDeviceContext has finished
604030f984aSJacob Faibussowitsch 
605030f984aSJacob Faibussowitsch   Not Collective, Synchronous
606030f984aSJacob Faibussowitsch 
607030f984aSJacob Faibussowitsch   Input Parameters:
608030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext to synchronize
609030f984aSJacob Faibussowitsch 
610030f984aSJacob Faibussowitsch   Level: beginner
611030f984aSJacob Faibussowitsch 
612db781477SPatrick Sanan .seealso: `PetscDeviceContextFork()`, `PetscDeviceContextJoin()`, `PetscDeviceContextQueryIdle()`
613030f984aSJacob Faibussowitsch @*/
614030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextSynchronize(PetscDeviceContext dctx)
615030f984aSJacob Faibussowitsch {
616030f984aSJacob Faibussowitsch   PetscFunctionBegin;
617030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx,1);
618030f984aSJacob Faibussowitsch   /* if it isn't setup there is nothing to sync on */
619*dbbe0bcdSBarry Smith   if (dctx->setup) PetscUseTypeMethod(dctx,synchronize);
620030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
621030f984aSJacob Faibussowitsch }
622030f984aSJacob Faibussowitsch 
623a4af0ceeSJacob Faibussowitsch #define PETSC_DEVICE_CONTEXT_DEFAULT_DEVICE PETSC_DEVICE_DEFAULT
624a4af0ceeSJacob Faibussowitsch // REMOVE ME (change)
625a4af0ceeSJacob Faibussowitsch #define PETSC_DEVICE_CONTEXT_DEFAULT_STREAM PETSC_STREAM_GLOBAL_BLOCKING
626030f984aSJacob Faibussowitsch 
627a4af0ceeSJacob Faibussowitsch static PetscDeviceType    rootDeviceType = PETSC_DEVICE_CONTEXT_DEFAULT_DEVICE;
628a4af0ceeSJacob Faibussowitsch static PetscStreamType    rootStreamType = PETSC_DEVICE_CONTEXT_DEFAULT_STREAM;
629bf025ffbSJacob Faibussowitsch static PetscDeviceContext globalContext  = nullptr;
630a4af0ceeSJacob Faibussowitsch 
631a4af0ceeSJacob Faibussowitsch /* when PetsDevice initializes PetscDeviceContext eagerly the type of device created should
632a4af0ceeSJacob Faibussowitsch  * match whatever device is eagerly intialized */
633a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetRootDeviceType_Internal(PetscDeviceType type)
634030f984aSJacob Faibussowitsch {
635030f984aSJacob Faibussowitsch   PetscFunctionBegin;
636a4af0ceeSJacob Faibussowitsch   PetscValidDeviceType(type,1);
637a4af0ceeSJacob Faibussowitsch   rootDeviceType = type;
638030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
639030f984aSJacob Faibussowitsch }
640030f984aSJacob Faibussowitsch 
641a4af0ceeSJacob Faibussowitsch #if 0
642a4af0ceeSJacob Faibussowitsch /* currently unused */
643a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetRootStreamType_Internal(PetscStreamType type)
644030f984aSJacob Faibussowitsch {
645a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
646a4af0ceeSJacob Faibussowitsch   PetscValidStreamType(type,1);
647a4af0ceeSJacob Faibussowitsch   rootStreamType = type;
648a4af0ceeSJacob Faibussowitsch   PetscFunctionReturn(0);
649a4af0ceeSJacob Faibussowitsch }
650a4af0ceeSJacob Faibussowitsch #endif
651a4af0ceeSJacob Faibussowitsch 
652a4af0ceeSJacob Faibussowitsch static PetscErrorCode PetscDeviceContextSetupGlobalContext_Private(void)
653a4af0ceeSJacob Faibussowitsch {
654a4af0ceeSJacob Faibussowitsch   static const auto PetscDeviceContextFinalizer = []() -> PetscErrorCode {
655030f984aSJacob Faibussowitsch 
656030f984aSJacob Faibussowitsch     PetscFunctionBegin;
6579566063dSJacob Faibussowitsch     PetscCall(PetscDeviceContextDestroy(&globalContext));
658a4af0ceeSJacob Faibussowitsch     rootDeviceType = PETSC_DEVICE_CONTEXT_DEFAULT_DEVICE;
659a4af0ceeSJacob Faibussowitsch     rootStreamType = PETSC_DEVICE_CONTEXT_DEFAULT_STREAM;
660a4af0ceeSJacob Faibussowitsch     PetscFunctionReturn(0);
661a4af0ceeSJacob Faibussowitsch   };
662a4af0ceeSJacob Faibussowitsch 
663a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
664a4af0ceeSJacob Faibussowitsch   if (globalContext) PetscFunctionReturn(0);
665a4af0ceeSJacob Faibussowitsch   /* this exists purely as a valid device check. */
6669566063dSJacob Faibussowitsch   PetscCall(PetscDeviceInitializePackage());
6679566063dSJacob Faibussowitsch   PetscCall(PetscRegisterFinalize(PetscDeviceContextFinalizer));
6689566063dSJacob Faibussowitsch   PetscCall(PetscInfo(nullptr,"Initializing global PetscDeviceContext\n"));
669a4af0ceeSJacob Faibussowitsch   /* we call the allocator directly here since the ObjectPool creates a PetscContainer which
670a4af0ceeSJacob Faibussowitsch    * eventually tries to call logging functions. However, this routine may be purposefully
671a4af0ceeSJacob Faibussowitsch    * called __before__ logging is initialized, so the logging function would PETSCABORT */
6729566063dSJacob Faibussowitsch   PetscCall(contextPool.allocator().create(&globalContext));
6739566063dSJacob Faibussowitsch   PetscCall(PetscDeviceContextSetStreamType(globalContext,rootStreamType));
6749566063dSJacob Faibussowitsch   PetscCall(PetscDeviceContextSetDefaultDeviceForType_Internal(globalContext,rootDeviceType));
6759566063dSJacob Faibussowitsch   PetscCall(PetscDeviceContextSetUp(globalContext));
676030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
677030f984aSJacob Faibussowitsch }
678030f984aSJacob Faibussowitsch 
679030f984aSJacob Faibussowitsch /*@C
6805181c4f9SJacob Faibussowitsch   PetscDeviceContextGetCurrentContext - Get the current active PetscDeviceContext
681030f984aSJacob Faibussowitsch 
682030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
683030f984aSJacob Faibussowitsch 
684030f984aSJacob Faibussowitsch   Output Parameter:
685030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext
686030f984aSJacob Faibussowitsch 
687030f984aSJacob Faibussowitsch   Notes:
688a4af0ceeSJacob Faibussowitsch   The user generally should not destroy contexts retrieved with this routine unless they
689a4af0ceeSJacob Faibussowitsch   themselves have created them. There exists no protection against destroying the root
690a4af0ceeSJacob Faibussowitsch   context.
691030f984aSJacob Faibussowitsch 
692030f984aSJacob Faibussowitsch   Developer Notes:
693a4af0ceeSJacob Faibussowitsch   Unless the user has set their own, this routine creates the "root" context the first time it
694a4af0ceeSJacob Faibussowitsch   is called, registering its destructor to PetscFinalize().
695030f984aSJacob Faibussowitsch 
696030f984aSJacob Faibussowitsch   Level: beginner
697030f984aSJacob Faibussowitsch 
698db781477SPatrick Sanan .seealso: `PetscDeviceContextSetCurrentContext()`, `PetscDeviceContextFork()`,
699db781477SPatrick Sanan           `PetscDeviceContextJoin()`, `PetscDeviceContextCreate()`
700030f984aSJacob Faibussowitsch @*/
701030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextGetCurrentContext(PetscDeviceContext *dctx)
702030f984aSJacob Faibussowitsch {
703a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
704a4af0ceeSJacob Faibussowitsch   PetscValidPointer(dctx,1);
7059566063dSJacob Faibussowitsch   PetscCall(PetscDeviceContextSetupGlobalContext_Private());
706a4af0ceeSJacob Faibussowitsch   /* while the static analyzer can find global variables, it will throw a warning about not
707a4af0ceeSJacob Faibussowitsch    * being able to connect this back to the function arguments */
708a4af0ceeSJacob Faibussowitsch   PetscDisableStaticAnalyzerForExpressionUnderstandingThatThisIsDangerousAndBugprone(PetscValidDeviceContext(globalContext,-1));
709030f984aSJacob Faibussowitsch   *dctx = globalContext;
710030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
711030f984aSJacob Faibussowitsch }
712030f984aSJacob Faibussowitsch 
713030f984aSJacob Faibussowitsch /*@C
7145181c4f9SJacob Faibussowitsch   PetscDeviceContextSetCurrentContext - Set the current active PetscDeviceContext
715030f984aSJacob Faibussowitsch 
716030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
717030f984aSJacob Faibussowitsch 
718030f984aSJacob Faibussowitsch   Input Parameter:
719030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext
720030f984aSJacob Faibussowitsch 
721030f984aSJacob Faibussowitsch   Notes:
722a4af0ceeSJacob Faibussowitsch   This routine can be used to set the defacto "root" PetscDeviceContext to a user-defined
723a4af0ceeSJacob Faibussowitsch   implementation by calling this routine immediately after PetscInitialize() and ensuring that
724a4af0ceeSJacob Faibussowitsch   PetscDevice is not greedily intialized. In this case the user is responsible for destroying
725a4af0ceeSJacob Faibussowitsch   their PetscDeviceContext before PetscFinalize() returns.
726a4af0ceeSJacob Faibussowitsch 
727a4af0ceeSJacob Faibussowitsch   The old context is not stored in any way by this routine; if one is overriding a context that
728a4af0ceeSJacob Faibussowitsch   they themselves do not control, one should take care to temporarily store it by calling
729a4af0ceeSJacob Faibussowitsch   PetscDeviceContextGetCurrentContext() before calling this routine.
730030f984aSJacob Faibussowitsch 
731030f984aSJacob Faibussowitsch   Level: beginner
732030f984aSJacob Faibussowitsch 
733db781477SPatrick Sanan .seealso: `PetscDeviceContextGetCurrentContext()`, `PetscDeviceContextFork()`,
734db781477SPatrick Sanan           `PetscDeviceContextJoin()`, `PetscDeviceContextCreate()`
735030f984aSJacob Faibussowitsch @*/
736030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetCurrentContext(PetscDeviceContext dctx)
737030f984aSJacob Faibussowitsch {
738030f984aSJacob Faibussowitsch   PetscFunctionBegin;
739030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx,1);
740bf025ffbSJacob Faibussowitsch   PetscAssert(dctx->setup,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"PetscDeviceContext %" PetscInt_FMT " must be set up before being set as global context",dctx->id);
741030f984aSJacob Faibussowitsch   globalContext = dctx;
7429566063dSJacob Faibussowitsch   PetscCall(PetscInfo(nullptr,"Set global PetscDeviceContext id %" PetscInt_FMT "\n",dctx->id));
743030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
744030f984aSJacob Faibussowitsch }
745030f984aSJacob Faibussowitsch 
746030f984aSJacob Faibussowitsch /*@C
747030f984aSJacob Faibussowitsch   PetscDeviceContextSetFromOptions - Configure a PetscDeviceContext from the options database
748030f984aSJacob Faibussowitsch 
749030f984aSJacob Faibussowitsch   Collective on comm, Asynchronous
750030f984aSJacob Faibussowitsch 
751030f984aSJacob Faibussowitsch   Input Parameters:
752030f984aSJacob Faibussowitsch + comm   - MPI communicator on which to query the options database
753030f984aSJacob Faibussowitsch . prefix - prefix to prepend to all options database queries, NULL if not needed
754030f984aSJacob Faibussowitsch - dctx   - The PetscDeviceContext to configure
755030f984aSJacob Faibussowitsch 
756030f984aSJacob Faibussowitsch   Output Parameter:
757030f984aSJacob Faibussowitsch . dctx - The PetscDeviceContext
758030f984aSJacob Faibussowitsch 
759030f984aSJacob Faibussowitsch   Options Database:
760a4af0ceeSJacob Faibussowitsch + -device_context_stream_type - type of stream to create inside the PetscDeviceContext -
761030f984aSJacob Faibussowitsch    PetscDeviceContextSetStreamType()
762a4af0ceeSJacob Faibussowitsch - -device_context_device_type - the type of PetscDevice to attach by default - PetscDeviceType
763030f984aSJacob Faibussowitsch 
764030f984aSJacob Faibussowitsch   Level: beginner
765030f984aSJacob Faibussowitsch 
766db781477SPatrick Sanan .seealso: `PetscDeviceContextSetStreamType()`, `PetscDeviceContextSetDevice()`
767030f984aSJacob Faibussowitsch @*/
768030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetFromOptions(MPI_Comm comm, const char prefix[], PetscDeviceContext dctx)
769030f984aSJacob Faibussowitsch {
770030f984aSJacob Faibussowitsch   PetscBool      flag;
771a4af0ceeSJacob Faibussowitsch   PetscInt       stype,dtype;
772030f984aSJacob Faibussowitsch 
773030f984aSJacob Faibussowitsch   PetscFunctionBegin;
774a4af0ceeSJacob Faibussowitsch   if (prefix) PetscValidCharPointer(prefix,2);
775030f984aSJacob Faibussowitsch   PetscValidDeviceContext(dctx,3);
776d0609cedSBarry Smith   PetscOptionsBegin(comm,prefix,"PetscDeviceContext Options","Sys");
7779566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEList("-device_context_stream_type","PetscDeviceContext PetscStreamType","PetscDeviceContextSetStreamType",PetscStreamTypes,PETSC_STREAM_MAX,PetscStreamTypes[dctx->streamType],&stype,&flag));
7789566063dSJacob Faibussowitsch   if (flag) PetscCall(PetscDeviceContextSetStreamType(dctx,static_cast<PetscStreamType>(stype)));
7799566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEList("-device_context_device_type","Underlying PetscDevice","PetscDeviceContextSetDevice",PetscDeviceTypes+1,PETSC_DEVICE_MAX-1,dctx->device ? PetscDeviceTypes[dctx->device->type] : PetscDeviceTypes[PETSC_DEVICE_CONTEXT_DEFAULT_DEVICE],&dtype,&flag));
780030f984aSJacob Faibussowitsch   if (flag) {
7819566063dSJacob Faibussowitsch     PetscCall(PetscDeviceContextSetDefaultDeviceForType_Internal(dctx,static_cast<PetscDeviceType>(dtype+1)));
782a4af0ceeSJacob Faibussowitsch   }
783d0609cedSBarry Smith   PetscOptionsEnd();
784030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
785030f984aSJacob Faibussowitsch }
786