Actual source code: dcontext.cxx

  1: #include <petsc/private/deviceimpl.h>
  2: #include "objpool.hpp"

  4: const char *const PetscStreamTypes[] = {
  5:   "global_blocking",
  6:   "default_blocking",
  7:   "global_nonblocking",
  8:   "max",
  9:   "PetscStreamType",
 10:   "PETSC_STREAM_",
 11:   nullptr
 12: };

 14: const char *const PetscDeviceContextJoinModes[] = {
 15:   "destroy",
 16:   "sync",
 17:   "no_sync",
 18:   "PetscDeviceContextJoinMode",
 19:   "PETSC_DEVICE_CONTEXT_JOIN_",
 20:   nullptr
 21: };

 23: /* Define the allocator */
 24: struct PetscDeviceContextAllocator : Petsc::AllocatorBase<PetscDeviceContext>
 25: {
 26:   static PetscInt PetscDeviceContextID;

 28:   PETSC_NODISCARD static PetscErrorCode create(PetscDeviceContext *dctx) noexcept
 29:   {
 30:     PetscDeviceContext dc;

 32:     PetscNew(&dc);
 33:     dc->id         = PetscDeviceContextID++;
 34:     dc->streamType = PETSC_STREAM_DEFAULT_BLOCKING;
 35:     *dctx          = dc;
 36:     return 0;
 37:   }

 39:   PETSC_NODISCARD static PetscErrorCode destroy(PetscDeviceContext dctx) noexcept
 40:   {
 41:     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);
 42:     if (dctx->ops->destroy) (*dctx->ops->destroy)(dctx);
 43:     PetscDeviceDestroy(&dctx->device);
 44:     PetscFree(dctx->childIDs);
 45:     PetscFree(dctx);
 46:     return 0;
 47:   }

 49:   PETSC_NODISCARD static PetscErrorCode reset(PetscDeviceContext dctx) noexcept
 50:   {
 51:     /* don't deallocate the child array, rather just zero it out */
 52:     PetscArrayzero(dctx->childIDs,dctx->maxNumChildren);
 53:     dctx->setup       = PETSC_FALSE;
 54:     dctx->numChildren = 0;
 55:     dctx->streamType  = PETSC_STREAM_DEFAULT_BLOCKING;
 56:     return 0;
 57:   }

 59:   PETSC_NODISCARD static constexpr PetscErrorCode finalize() noexcept { return 0; }
 60: };
 61: /* an ID = 0 is invalid */
 62: PetscInt PetscDeviceContextAllocator::PetscDeviceContextID = 1;

 64: static Petsc::ObjectPool<PetscDeviceContext,PetscDeviceContextAllocator> contextPool;

 66: /*@C
 67:   PetscDeviceContextCreate - Creates a PetscDeviceContext

 69:   Not Collective, Asynchronous

 71:   Output Paramemter:
 72: . dctx - The PetscDeviceContext

 74:   Notes:
 75:   Unlike almost every other PETSc class it is advised that most users use
 76:   PetscDeviceContextDuplicate() rather than this routine to create new contexts. Contexts
 77:   of different types are incompatible with one another; using
 78:   PetscDeviceContextDuplicate() ensures compatible types.

 80:   Level: beginner

 82: .seealso: PetscDeviceContextDuplicate(), PetscDeviceContextSetDevice(),
 83: PetscDeviceContextSetStreamType(), PetscDeviceContextSetUp(),
 84: PetscDeviceContextSetFromOptions(), PetscDeviceContextDestroy()
 85: @*/
 86: PetscErrorCode PetscDeviceContextCreate(PetscDeviceContext *dctx)
 87: {
 89:   PetscDeviceInitializePackage();
 90:   contextPool.get(*dctx);
 91:   return 0;
 92: }

 94: /*@C
 95:   PetscDeviceContextDestroy - Frees a PetscDeviceContext

 97:   Not Collective, Asynchronous

 99:   Input Parameters:
100: . dctx - The PetscDeviceContext

102:   Notes:
103:   No implicit synchronization occurs due to this routine, all resources are released completely asynchronously
104:   w.r.t. the host. If one needs to guarantee access to the data produced on this contexts stream one should perform the
105:   appropriate synchronization before calling this routine.

107:   Developer Notes:
108:   The context is never actually "destroyed", only returned to an ever growing pool of
109:   contexts. There are currently no safeguards on the size of the pool, this should perhaps
110:   be implemented.

112:   Level: beginner

114: .seealso: PetscDeviceContextCreate(), PetscDeviceContextSetDevice(), PetscDeviceContextSetUp(), PetscDeviceContextSynchronize()
115: @*/
116: PetscErrorCode PetscDeviceContextDestroy(PetscDeviceContext *dctx)
117: {
118:   if (!*dctx) return 0;
119:   contextPool.reclaim(std::move(*dctx));
120:   *dctx = nullptr;
121:   return 0;
122: }

124: /*@C
125:   PetscDeviceContextSetStreamType - Set the implementation type of the underlying stream for a PetscDeviceContext

127:   Not Collective, Asynchronous

129:   Input Parameters:
130: + dctx - The PetscDeviceContext
131: - type - The PetscStreamType

133:   Notes:
134:   See PetscStreamType in include/petscdevicetypes.h for more information on the available
135:   types and their interactions. If the PetscDeviceContext was previously set up and stream
136:   type was changed, you must call PetscDeviceContextSetUp() again after this routine.

138:   Level: intermediate

140: .seealso: PetscStreamType, PetscDeviceContextGetStreamType(), PetscDeviceContextCreate(), PetscDeviceContextSetUp(), PetscDeviceContextSetFromOptions()
141: @*/
142: PetscErrorCode PetscDeviceContextSetStreamType(PetscDeviceContext dctx, PetscStreamType type)
143: {
146:   /* only need to do complex swapping if the object has already been setup */
147:   if (dctx->setup && (dctx->streamType != type)) {
148:     (*dctx->ops->changestreamtype)(dctx,type);
149:     dctx->setup = PETSC_FALSE;
150:   }
151:   dctx->streamType = type;
152:   return 0;
153: }

155: /*@C
156:   PetscDeviceContextGetStreamType - Get the implementation type of the underlying stream for a PetscDeviceContext

158:   Not Collective, Asynchronous

160:   Input Parameter:
161: . dctx - The PetscDeviceContext

163:   Output Parameter:
164: . type - The PetscStreamType

166:   Notes:
167:   See PetscStreamType in include/petscdevicetypes.h for more information on the available types and their interactions

169:   Level: intermediate

171: .seealso: PetscDeviceContextSetStreamType(), PetscDeviceContextCreate(), PetscDeviceContextSetFromOptions()
172: @*/
173: PetscErrorCode PetscDeviceContextGetStreamType(PetscDeviceContext dctx, PetscStreamType *type)
174: {
177:   *type = dctx->streamType;
178:   return 0;
179: }

181: /*@C
182:   PetscDeviceContextSetDevice - Set the underlying device for the PetscDeviceContext

184:   Not Collective, Possibly Synchronous

186:   Input Parameters:
187: + dctx   - The PetscDeviceContext
188: - device - The PetscDevice

190:   Notes:
191:   This routine is effectively PetscDeviceContext's "set-type" (so every PetscDeviceContext
192:   must also have an attached PetscDevice). Unlike the usual set-type semantics, it is
193:   not stricly necessary to set a contexts device to enable usage, any created device
194:   contexts will always come equipped with the "default" device.

196:   This routine is a no-op if dctx is already attached to device.

198:   This routine may initialize the backend device and incur synchronization.

200:   Level: intermediate

202: .seealso: PetscDeviceCreate(), PetscDeviceConfigure(), PetscDeviceContextGetDevice()
203: @*/
204: PetscErrorCode PetscDeviceContextSetDevice(PetscDeviceContext dctx, PetscDevice device)
205: {
208:   if (dctx->device) {
209:     /* can't do a strict pointer equality check since PetscDevice's are reused */
210:     if (dctx->device->ops->createcontext == device->ops->createcontext) return 0;
211:   }
212:   PetscDeviceDestroy(&dctx->device);
213:   if (dctx->ops->destroy) (*dctx->ops->destroy)(dctx);
214:   PetscMemzero(dctx->ops,sizeof(*dctx->ops));
215:   (*device->ops->createcontext)(dctx);
216:   PetscDeviceReference_Internal(device);
217:   dctx->device = device;
218:   dctx->setup  = PETSC_FALSE;
219:   return 0;
220: }

222: /*@C
223:   PetscDeviceContextGetDevice - Get the underlying PetscDevice for a PetscDeviceContext

225:   Not Collective, Asynchronous

227:   Input Parameter:
228: . dctx - the PetscDeviceContext

230:   Output Parameter:
231: . device - The PetscDevice

233:   Notes:
234:   This is a borrowed reference, the user should not destroy the device.

236:   Level: intermediate

238: .seealso: PetscDeviceContextSetDevice(), PetscDevice
239: @*/
240: PetscErrorCode PetscDeviceContextGetDevice(PetscDeviceContext dctx, PetscDevice *device)
241: {
244:   PetscAssert(dctx->device,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"PetscDeviceContext %" PetscInt_FMT " has no attached PetscDevice to get",dctx->id);
245:   *device = dctx->device;
246:   return 0;
247: }

249: /*@C
250:   PetscDeviceContextSetUp - Prepares a PetscDeviceContext for use

252:   Not Collective, Asynchronous

254:   Input Parameter:
255: . dctx - The PetscDeviceContext

257:   Developer Notes:
258:   This routine is usually the stage where a PetscDeviceContext acquires device-side data structures such as streams,
259:   events, and (possibly) handles.

261:   Level: beginner

263: .seealso: PetscDeviceContextCreate(), PetscDeviceContextSetDevice(), PetscDeviceContextDestroy(), PetscDeviceContextSetFromOptions()
264: @*/
265: PetscErrorCode PetscDeviceContextSetUp(PetscDeviceContext dctx)
266: {
268:   if (!dctx->device) {
269:     PetscInfo(nullptr,"PetscDeviceContext %" PetscInt_FMT " did not have an explicitly attached PetscDevice, using default with type %s\n",dctx->id,PetscDeviceTypes[PETSC_DEVICE_DEFAULT]);
270:     PetscDeviceContextSetDefaultDevice_Internal(dctx);
271:   }
272:   if (dctx->setup) return 0;
273:   (*dctx->ops->setup)(dctx);
274:   dctx->setup = PETSC_TRUE;
275:   return 0;
276: }

278: /*@C
279:   PetscDeviceContextDuplicate - Duplicates a PetscDeviceContext object

281:   Not Collective, Asynchronous

283:   Input Parameter:
284: . dctx - The PetscDeviceContext to duplicate

286:   Output Parameter:
287: . dctxdup - The duplicated PetscDeviceContext

289:   Notes:
290:   This is a shorthand method for creating a PetscDeviceContext with the exact same
291:   settings as another. Note however that the duplicated PetscDeviceContext does not "share"
292:   any of the underlying data with the original, (including its current stream-state) they
293:   are completely separate objects.

295:   Level: beginner

297: .seealso: PetscDeviceContextCreate(), PetscDeviceContextSetDevice(), PetscDeviceContextSetStreamType()
298: @*/
299: PetscErrorCode PetscDeviceContextDuplicate(PetscDeviceContext dctx, PetscDeviceContext *dctxdup)
300: {
301:   PetscDeviceContext dup;

305:   PetscDeviceContextCreate(&dup);
306:   PetscDeviceContextSetStreamType(dup,dctx->streamType);
307:   if (dctx->device) PetscDeviceContextSetDevice(dup,dctx->device);
308:   PetscDeviceContextSetUp(dup);
309:   *dctxdup = dup;
310:   return 0;
311: }

313: /*@C
314:   PetscDeviceContextQueryIdle - Returns whether or not a PetscDeviceContext is idle

316:   Not Collective, Asynchronous

318:   Input Parameter:
319: . dctx - The PetscDeviceContext object

321:   Output Parameter:
322: . idle - PETSC_TRUE if PetscDeviceContext has NO work, PETSC_FALSE if it has work

324:   Notes:
325:   This routine only refers a singular context and does NOT take any of its children into
326:   account. That is, if dctx is idle but has dependents who do have work, this routine still
327:   returns PETSC_TRUE.

329:   Level: intermediate

331: .seealso: PetscDeviceContextCreate(), PetscDeviceContextWaitForContext(), PetscDeviceContextFork()
332: @*/
333: PetscErrorCode PetscDeviceContextQueryIdle(PetscDeviceContext dctx, PetscBool *idle)
334: {
337:   (*dctx->ops->query)(dctx,idle);
338:   PetscInfo(nullptr,"PetscDeviceContext id %" PetscInt_FMT " %s idle\n",dctx->id,*idle ? "was" : "was not");
339:   return 0;
340: }

342: /*@C
343:   PetscDeviceContextWaitForContext - Make one context wait for another context to finish

345:   Not Collective, Asynchronous

347:   Input Parameters:
348: + dctxa - The PetscDeviceContext object that is waiting
349: - dctxb - The PetscDeviceContext object that is being waited on

351:   Notes:
352:   Serializes two PetscDeviceContexts. This routine uses only the state of dctxb at the moment this routine was
353:   called, so any future work queued will not affect dctxa. It is safe to pass the same context to both arguments.

355:   Level: beginner

357: .seealso: PetscDeviceContextCreate(), PetscDeviceContextQueryIdle(), PetscDeviceContextJoin()
358: @*/
359: PetscErrorCode PetscDeviceContextWaitForContext(PetscDeviceContext dctxa, PetscDeviceContext dctxb)
360: {
362:   if (dctxa == dctxb) return 0;
363:   (*dctxa->ops->waitforcontext)(dctxa,dctxb);
364:   return 0;
365: }

367: #define PETSC_USE_DEBUG_AND_INFO (PetscDefined(USE_DEBUG) && PetscDefined(USE_INFO))
368: #if PETSC_USE_DEBUG_AND_INFO
369: #include <string>
370: #endif
371: /*@C
372:   PetscDeviceContextFork - Create a set of dependent child contexts from a parent context

374:   Not Collective, Asynchronous

376:   Input Parameters:
377: + dctx - The parent PetscDeviceContext
378: - n    - The number of children to create

380:   Output Parameter:
381: . dsub - The created child context(s)

383:   Notes:
384:   This routine creates n edges of a DAG from a source node which are causally dependent on the source node, meaning
385:   that work queued on child contexts will not start until the parent context finishes its work. This accounts for work
386:   queued on the parent up until calling this function, any subsequent work enqueued on the parent has no effect on the children.

388:   Any children created with this routine have their lifetimes bounded by the parent. That is, the parent context expects
389:   to free all of it's children (and ONLY its children) before itself is freed.

391:   DAG representation:
392: .vb
393:   time ->

395:   -> dctx \----> dctx ------>
396:            \---> dsub[0] --->
397:             \--> ... ------->
398:              \-> dsub[n-1] ->
399: .ve

401:   Level: intermediate

403: .seealso: PetscDeviceContextJoin(), PetscDeviceContextSynchronize(), PetscDeviceContextQueryIdle()
404: @*/
405: PetscErrorCode PetscDeviceContextFork(PetscDeviceContext dctx, PetscInt n, PetscDeviceContext **dsub)
406: {
407: #if PETSC_USE_DEBUG_AND_INFO
408:   const PetscInt      nBefore = n;
409:   static std::string  idList;
410: #endif
411:   PetscDeviceContext *dsubTmp = nullptr;
412:   PetscInt            i = 0;

416:   PetscAssert(n >= 0,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Number of contexts requested %" PetscInt_FMT " < 0",n);
417: #if PETSC_USE_DEBUG_AND_INFO
418:   /* reserve 4 chars per id, 2 for number and 2 for ', ' separator */
419:   idList.reserve(4*n);
420: #endif
421:   /* update child totals */
422:   dctx->numChildren += n;
423:   /* now to find out if we have room */
424:   if (dctx->numChildren > dctx->maxNumChildren) {
425:     /* no room, either from having too many kids or not having any */
426:     if (dctx->childIDs) {
427:       /* have existing children, must reallocate them */
428:       PetscRealloc(dctx->numChildren*sizeof(*dctx->childIDs),&dctx->childIDs);
429:       /* clear the extra memory since realloc doesn't do it for us */
430:       PetscArrayzero((dctx->childIDs)+(dctx->maxNumChildren),(dctx->numChildren)-(dctx->maxNumChildren));
431:     } else {
432:       /* have no children */
433:       PetscCalloc1(dctx->numChildren,&dctx->childIDs);
434:     }
435:     /* update total number of children */
436:     dctx->maxNumChildren = dctx->numChildren;
437:   }
438:   PetscMalloc1(n,&dsubTmp);
439:   while (n) {
440:     /* empty child slot */
441:     if (!(dctx->childIDs[i])) {
442:       /* create the child context in the image of its parent */
443:       PetscDeviceContextDuplicate(dctx,dsubTmp+i);
444:       PetscDeviceContextWaitForContext(dsubTmp[i],dctx);
445:       /* register the child with its parent */
446:       dctx->childIDs[i] = dsubTmp[i]->id;
447: #if PETSC_USE_DEBUG_AND_INFO
448:       idList += std::to_string(dsubTmp[i]->id);
449:       if (n != 1) idList += ", ";
450: #endif
451:       --n;
452:     }
453:     ++i;
454:   }
455: #if PETSC_USE_DEBUG_AND_INFO
456:   PetscInfo(nullptr,"Forked %" PetscInt_FMT " children from parent %" PetscInt_FMT " with IDs: %s\n",nBefore,dctx->id,idList.c_str());
457:   /* resets the size but doesn't deallocate the memory */
458:   idList.clear();
459: #endif
460:   /* pass the children back to caller */
461:   *dsub = dsubTmp;
462:   return 0;
463: }

465: /*@C
466:   PetscDeviceContextJoin - Converge a set of child contexts

468:   Not Collective, Asynchronous

470:   Input Parameters:
471: + dctx         - A PetscDeviceContext to converge on
472: . n            - The number of sub contexts to converge
473: . joinMode     - The type of join to perform
474: - dsub         - The sub contexts to converge

476:   Notes:
477:   If PetscDeviceContextFork() creates n edges from a source node which all depend on the
478:   source node, then this routine is the exact mirror. That is, it creates a node
479:   (represented in dctx) which recieves n edges (and optionally destroys them) which is
480:   dependent on the completion of all incoming edges.

482:   If joinMode is PETSC_DEVICE_CONTEXT_JOIN_DESTROY all contexts in dsub will be destroyed
483:   by this routine. Thus all sub contexts must have been created with the dctx passed to
484:   this routine.

486:   if joinMode is PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC dctx waits for all sub contexts but the
487:   sub contexts do not wait for one another afterwards.

489:   If joinMode is PETSC_DEVICE_CONTEXT_JOIN_SYNC all sub contexts will additionally
490:   wait on dctx after converging. This has the effect of "synchronizing" the outgoing
491:   edges.

493:   DAG representations:
494:   If joinMode is PETSC_DEVICE_CONTEXT_JOIN_DESTROY
495: .vb
496:   time ->

498:   -> dctx ---------/- dctx ->
499:   -> dsub[0] -----/
500:   ->  ... -------/
501:   -> dsub[n-1] -/
502: .ve
503:   If joinMode is PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC
504: .vb
505:   time ->

507:   -> dctx ---------/- dctx ->
508:   -> dsub[0] -----/--------->
509:   ->  ... -------/---------->
510:   -> dsub[n-1] -/----------->
511: .ve
512:   If joinMode is PETSC_DEVICE_CONTEXT_JOIN_SYNC
513: .vb
514:   time ->

516:   -> dctx ---------/- dctx -\----> dctx ------>
517:   -> dsub[0] -----/          \---> dsub[0] --->
518:   ->  ... -------/            \--> ... ------->
519:   -> dsub[n-1] -/              \-> dsub[n-1] ->
520: .ve

522:   Level: intermediate

524: .seealso: PetscDeviceContextFork(), PetscDeviceContextSynchronize(), PetscDeviceContextJoinMode
525: @*/
526: PetscErrorCode PetscDeviceContextJoin(PetscDeviceContext dctx, PetscInt n, PetscDeviceContextJoinMode joinMode, PetscDeviceContext **dsub)
527: {
528: #if defined(PETSC_USE_DEBUG) && defined(PETSC_USE_INFO)
529:   static std::string idList;
530: #endif

532:   /* validity of dctx is checked in the wait-for loop */
534:   PetscAssert(n >= 0,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Number of contexts merged %" PetscInt_FMT " < 0",n);
535: #if defined(PETSC_USE_DEBUG) && defined(PETSC_USE_INFO)
536:   /* reserve 4 chars per id, 2 for number and 2 for ', ' separator */
537:   idList.reserve(4*n);
538: #endif
539:   /* first dctx waits on all the incoming edges */
540:   for (PetscInt i = 0; i < n; ++i) {
542:     PetscDeviceContextWaitForContext(dctx,(*dsub)[i]);
543: #if defined(PETSC_USE_DEBUG) && defined(PETSC_USE_INFO)
544:     idList += std::to_string((*dsub)[i]->id);
545:     if (i+1 < n) idList += ", ";
546: #endif
547:   }

549:   /* now we handle the aftermath */
550:   switch (joinMode) {
551:   case PETSC_DEVICE_CONTEXT_JOIN_DESTROY:
552:     {
553:       PetscInt j = 0;

555:       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);
556:       /* update child count while it's still fresh in memory */
557:       dctx->numChildren -= n;
558:       for (PetscInt i = 0; i < dctx->maxNumChildren; ++i) {
559:         if (dctx->childIDs[i] && (dctx->childIDs[i] == (*dsub)[j]->id)) {
560:           /* child is one of ours, can destroy it */
561:           PetscDeviceContextDestroy((*dsub)+j);
562:           /* reset the child slot */
563:           dctx->childIDs[i] = 0;
564:           if (++j == n) break;
565:         }
566:       }
567:       /* 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 */
568:       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);
569:       PetscFree(*dsub);
570:     }
571:     break;
572:   case PETSC_DEVICE_CONTEXT_JOIN_SYNC:
573:     for (PetscInt i = 0; i < n; ++i) PetscDeviceContextWaitForContext((*dsub)[i],dctx);
574:   case PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC:
575:     break;
576:   default:
577:     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Unknown PetscDeviceContextJoinMode given");
578:   }

580: #if defined(PETSC_USE_DEBUG) && defined(PETSC_USE_INFO)
581:   PetscInfo(nullptr,"Joined %" PetscInt_FMT " ctxs to ctx %" PetscInt_FMT ", mode %s with IDs: %s\n",n,dctx->id,PetscDeviceContextJoinModes[joinMode],idList.c_str());
582:   idList.clear();
583: #endif
584:   return 0;
585: }

587: /*@C
588:   PetscDeviceContextSynchronize - Block the host until all work queued on or associated with a PetscDeviceContext has finished

590:   Not Collective, Synchronous

592:   Input Parameters:
593: . dctx - The PetscDeviceContext to synchronize

595:   Level: beginner

597: .seealso: PetscDeviceContextFork(), PetscDeviceContextJoin(), PetscDeviceContextQueryIdle()
598: @*/
599: PetscErrorCode PetscDeviceContextSynchronize(PetscDeviceContext dctx)
600: {
602:   /* if it isn't setup there is nothing to sync on */
603:   if (dctx->setup) (*dctx->ops->synchronize)(dctx);
604:   return 0;
605: }

607: #define PETSC_DEVICE_CONTEXT_DEFAULT_DEVICE PETSC_DEVICE_DEFAULT
608: // REMOVE ME (change)
609: #define PETSC_DEVICE_CONTEXT_DEFAULT_STREAM PETSC_STREAM_GLOBAL_BLOCKING

611: static PetscDeviceType    rootDeviceType = PETSC_DEVICE_CONTEXT_DEFAULT_DEVICE;
612: static PetscStreamType    rootStreamType = PETSC_DEVICE_CONTEXT_DEFAULT_STREAM;
613: static PetscDeviceContext globalContext  = nullptr;

615: /* when PetsDevice initializes PetscDeviceContext eagerly the type of device created should
616:  * match whatever device is eagerly intialized */
617: PetscErrorCode PetscDeviceContextSetRootDeviceType_Internal(PetscDeviceType type)
618: {
620:   rootDeviceType = type;
621:   return 0;
622: }

624: #if 0
625: /* currently unused */
626: PetscErrorCode PetscDeviceContextSetRootStreamType_Internal(PetscStreamType type)
627: {
629:   rootStreamType = type;
630:   return 0;
631: }
632: #endif

634: static PetscErrorCode PetscDeviceContextSetupGlobalContext_Private(void)
635: {
636:   static const auto PetscDeviceContextFinalizer = []() -> PetscErrorCode {

638:     PetscDeviceContextDestroy(&globalContext);
639:     rootDeviceType = PETSC_DEVICE_CONTEXT_DEFAULT_DEVICE;
640:     rootStreamType = PETSC_DEVICE_CONTEXT_DEFAULT_STREAM;
641:     return 0;
642:   };

644:   if (globalContext) return 0;
645:   /* this exists purely as a valid device check. */
646:   PetscDeviceInitializePackage();
647:   PetscRegisterFinalize(PetscDeviceContextFinalizer);
648:   PetscInfo(nullptr,"Initializing global PetscDeviceContext\n");
649:   /* we call the allocator directly here since the ObjectPool creates a PetscContainer which
650:    * eventually tries to call logging functions. However, this routine may be purposefully
651:    * called __before__ logging is initialized, so the logging function would PETSCABORT */
652:   contextPool.allocator().create(&globalContext);
653:   PetscDeviceContextSetStreamType(globalContext,rootStreamType);
654:   PetscDeviceContextSetDefaultDeviceForType_Internal(globalContext,rootDeviceType);
655:   PetscDeviceContextSetUp(globalContext);
656:   return 0;
657: }

659: /*@C
660:   PetscDeviceContextGetCurrentContext - Get the current active PetscDeviceContext

662:   Not Collective, Asynchronous

664:   Output Parameter:
665: . dctx - The PetscDeviceContext

667:   Notes:
668:   The user generally should not destroy contexts retrieved with this routine unless they
669:   themselves have created them. There exists no protection against destroying the root
670:   context.

672:   Developer Notes:
673:   Unless the user has set their own, this routine creates the "root" context the first time it
674:   is called, registering its destructor to PetscFinalize().

676:   Level: beginner

678: .seealso: PetscDeviceContextSetCurrentContext(), PetscDeviceContextFork(),
679: PetscDeviceContextJoin(), PetscDeviceContextCreate()
680: @*/
681: PetscErrorCode PetscDeviceContextGetCurrentContext(PetscDeviceContext *dctx)
682: {
684:   PetscDeviceContextSetupGlobalContext_Private();
685:   /* while the static analyzer can find global variables, it will throw a warning about not
686:    * being able to connect this back to the function arguments */
688:   *dctx = globalContext;
689:   return 0;
690: }

692: /*@C
693:   PetscDeviceContextSetCurrentContext - Set the current active PetscDeviceContext

695:   Not Collective, Asynchronous

697:   Input Parameter:
698: . dctx - The PetscDeviceContext

700:   Notes:
701:   This routine can be used to set the defacto "root" PetscDeviceContext to a user-defined
702:   implementation by calling this routine immediately after PetscInitialize() and ensuring that
703:   PetscDevice is not greedily intialized. In this case the user is responsible for destroying
704:   their PetscDeviceContext before PetscFinalize() returns.

706:   The old context is not stored in any way by this routine; if one is overriding a context that
707:   they themselves do not control, one should take care to temporarily store it by calling
708:   PetscDeviceContextGetCurrentContext() before calling this routine.

710:   Level: beginner

712: .seealso: PetscDeviceContextGetCurrentContext(), PetscDeviceContextFork(),
713: PetscDeviceContextJoin(), PetscDeviceContextCreate()
714: @*/
715: PetscErrorCode PetscDeviceContextSetCurrentContext(PetscDeviceContext dctx)
716: {
718:   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);
719:   globalContext = dctx;
720:   PetscInfo(nullptr,"Set global PetscDeviceContext id %" PetscInt_FMT "\n",dctx->id);
721:   return 0;
722: }

724: /*@C
725:   PetscDeviceContextSetFromOptions - Configure a PetscDeviceContext from the options database

727:   Collective on comm, Asynchronous

729:   Input Parameters:
730: + comm   - MPI communicator on which to query the options database
731: . prefix - prefix to prepend to all options database queries, NULL if not needed
732: - dctx   - The PetscDeviceContext to configure

734:   Output Parameter:
735: . dctx - The PetscDeviceContext

737:   Options Database:
738: + -device_context_stream_type - type of stream to create inside the PetscDeviceContext -
739:    PetscDeviceContextSetStreamType()
740: - -device_context_device_type - the type of PetscDevice to attach by default - PetscDeviceType

742:   Level: beginner

744: .seealso: PetscDeviceContextSetStreamType(), PetscDeviceContextSetDevice()
745: @*/
746: PetscErrorCode PetscDeviceContextSetFromOptions(MPI_Comm comm, const char prefix[], PetscDeviceContext dctx)
747: {
748:   PetscBool      flag;
749:   PetscInt       stype,dtype;

754:   PetscOptionsBegin(comm,prefix,"PetscDeviceContext Options","Sys");
755:   PetscOptionsEList("-device_context_stream_type","PetscDeviceContext PetscStreamType","PetscDeviceContextSetStreamType",PetscStreamTypes,PETSC_STREAM_MAX,PetscStreamTypes[dctx->streamType],&stype,&flag);
756:   if (flag) PetscDeviceContextSetStreamType(dctx,static_cast<PetscStreamType>(stype));
757:   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);
758:   if (flag) {
759:     PetscDeviceContextSetDefaultDeviceForType_Internal(dctx,static_cast<PetscDeviceType>(dtype+1));
760:   }
761:   PetscOptionsEnd();
762:   return 0;
763: }