xref: /petsc/src/sys/objects/device/interface/device.cxx (revision 67b8a455b8687dfb2f87ed52b249206f831b8117)
1 #include "cupmdevice.hpp" /* I "petscdevice.h" */
2 #include <petsc/private/petscadvancedmacros.h>
3 
4 using namespace Petsc::Device;
5 
6 /*
7   note to anyone adding more classes, the name must be ALL_CAPS_SHORT_NAME + Device exactly to
8   be picked up by the switch-case macros below
9 */
10 #if PetscDefined(HAVE_CUDA)
11 static CUPM::Device<CUPM::DeviceType::CUDA> CUDADevice(PetscDeviceContextCreate_CUDA);
12 #endif
13 #if PetscDefined(HAVE_HIP)
14 static CUPM::Device<CUPM::DeviceType::HIP>  HIPDevice(PetscDeviceContextCreate_HIP);
15 #endif
16 #if PetscDefined(HAVE_SYCL)
17 #include "sycldevice.hpp"
18 static SYCL::Device                         SYCLDevice(PetscDeviceContextCreate_SYCL);
19 #endif
20 
21 static_assert(Petsc::util::integral_value(PETSC_DEVICE_INVALID) == 0,"");
22 static_assert(Petsc::util::integral_value(PETSC_DEVICE_CUDA)    == 1,"");
23 static_assert(Petsc::util::integral_value(PETSC_DEVICE_HIP)     == 2,"");
24 static_assert(Petsc::util::integral_value(PETSC_DEVICE_SYCL)    == 3,"");
25 static_assert(Petsc::util::integral_value(PETSC_DEVICE_MAX)     == 4,"");
26 const char *const PetscDeviceTypes[] = {
27   "invalid",
28   "cuda",
29   "hip",
30   "sycl",
31   "max",
32   "PetscDeviceType",
33   "PETSC_DEVICE_",
34   PETSC_NULLPTR
35 };
36 
37 static_assert(Petsc::util::integral_value(PETSC_DEVICE_INIT_NONE)  == 0,"");
38 static_assert(Petsc::util::integral_value(PETSC_DEVICE_INIT_LAZY)  == 1,"");
39 static_assert(Petsc::util::integral_value(PETSC_DEVICE_INIT_EAGER) == 2,"");
40 const char *const PetscDeviceInitTypes[] = {
41   "none",
42   "lazy",
43   "eager",
44   "PetscDeviceInitType",
45   "PETSC_DEVICE_INIT_",
46   PETSC_NULLPTR
47 };
48 static_assert(
49   sizeof(PetscDeviceInitTypes)/sizeof(*PetscDeviceInitTypes) == 6,
50   "Must change CUPMDevice<T>::initialize number of enum values in -device_enable_cupm to match!"
51 );
52 
53 #define PETSC_DEVICE_CASE(IMPLS,func,...)                                     \
54   case PetscConcat_(PETSC_DEVICE_,IMPLS): {                                   \
55     auto ierr_ = PetscConcat_(IMPLS,Device).func(__VA_ARGS__);CHKERRQ(ierr_); \
56   } break
57 
58 /*
59   Suppose you have:
60 
61   CUDADevice.myFunction(arg1,arg2)
62 
63   that you would like to conditionally define and call in a switch-case:
64 
65   switch(PetscDeviceType) {
66   #if PetscDefined(HAVE_CUDA)
67   case PETSC_DEVICE_CUDA: {
68     auto ierr = CUDADevice.myFunction(arg1,arg2);CHKERRQ(ierr);
69   } break;
70   #endif
71   }
72 
73   then calling this macro:
74 
75   PETSC_DEVICE_CASE_IF_PETSC_DEFINED(CUDA,myFunction,arg1,arg2)
76 
77   will expand to the following case statement:
78 
79   case PETSC_DEVICE_CUDA: {
80     auto ierr = CUDADevice.myFunction(arg1,arg2);CHKERRQ(ierr);
81   } break
82 
83   if PetscDefined(HAVE_CUDA) evaluates to 1, and expand to nothing otherwise
84 */
85 #define PETSC_DEVICE_CASE_IF_PETSC_DEFINED(IMPLS,func,...)                                     \
86   PetscIfPetscDefined(PetscConcat_(HAVE_,IMPLS),PETSC_DEVICE_CASE,PetscExpandToNothing)(IMPLS,func,__VA_ARGS__)
87 
88 /*@C
89   PetscDeviceCreate - Get a new handle for a particular device type
90 
91   Not Collective, Possibly Synchronous
92 
93   Input Parameters:
94 + type  - The type of PetscDevice
95 - devid - The numeric ID# of the device (pass PETSC_DECIDE to assign automatically)
96 
97   Output Parameter:
98 . device - The PetscDevice
99 
100   Notes:
101   This routine may initialize PetscDevice. If this is the case, this will most likely cause
102   some sort of device synchronization.
103 
104   devid is what you might pass to cudaSetDevice() for example.
105 
106   Level: beginner
107 
108 .seealso: PetscDevice, PetscDeviceInitType, PetscDeviceInitialize(),
109 PetscDeviceInitialized(), PetscDeviceConfigure(), PetscDeviceView(), PetscDeviceDestroy()
110 @*/
111 PetscErrorCode PetscDeviceCreate(PetscDeviceType type, PetscInt devid, PetscDevice *device)
112 {
113   static PetscInt PetscDeviceCounter = 0;
114   PetscDevice     dev;
115   PetscErrorCode  ierr;
116 
117   PetscFunctionBegin;
118   PetscValidDeviceType(type,1);
119   PetscValidPointer(device,3);
120   ierr = PetscDeviceInitializePackage();CHKERRQ(ierr);
121   ierr = PetscNew(&dev);CHKERRQ(ierr);
122   dev->id     = PetscDeviceCounter++;
123   dev->type   = type;
124   dev->refcnt = 1;
125   /*
126     if you are adding a device, you also need to add it's initialization in
127     PetscDeviceInitializeTypeFromOptions_Private() below
128   */
129   switch (type) {
130     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(CUDA,getDevice,dev,devid);
131     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(HIP,getDevice,dev,devid);
132     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(SYCL,getDevice,dev,devid);
133   default:
134     /* in case the above macros expand to nothing this silences any unused variable warnings */
135     (void)(devid);
136     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"PETSc was seemingly configured for PetscDeviceType %s but we've fallen through all cases in a switch",PetscDeviceTypes[type]);
137   }
138   *device = dev;
139   PetscFunctionReturn(0);
140 }
141 
142 /*@C
143   PetscDeviceDestroy - Free a PetscDevice
144 
145   Not Collective, Asynchronous
146 
147   Input Parameter:
148 . device - The PetscDevice
149 
150   Level: beginner
151 
152 .seealso: PetscDevice, PetscDeviceCreate(), PetscDeviceConfigure(), PetscDeviceView()
153 @*/
154 PetscErrorCode PetscDeviceDestroy(PetscDevice *device)
155 {
156   PetscErrorCode ierr;
157 
158   PetscFunctionBegin;
159   if (!*device) PetscFunctionReturn(0);
160   PetscValidDevice(*device,1);
161   ierr = PetscDeviceDereference_Internal(*device);CHKERRQ(ierr);
162   if ((*device)->refcnt) {
163     *device = PETSC_NULLPTR;
164     PetscFunctionReturn(0);
165   }
166   ierr = PetscFree((*device)->data);CHKERRQ(ierr);
167   ierr = PetscFree(*device);CHKERRQ(ierr);
168   PetscFunctionReturn(0);
169 }
170 
171 /*@C
172   PetscDeviceConfigure - Configure a particular PetscDevice
173 
174   Not Collective, Asynchronous
175 
176   Input Parameter:
177 . device - The PetscDevice to configure
178 
179   Notes:
180   The user should not assume that this is a cheap operation
181 
182   Level: beginner
183 
184 .seealso: PetscDevice, PetscDeviceCreate(), PetscDeviceView(), PetscDeviceDestroy()
185 @*/
186 PetscErrorCode PetscDeviceConfigure(PetscDevice device)
187 {
188   PetscErrorCode ierr;
189 
190   PetscFunctionBegin;
191   PetscValidDevice(device,1);
192   if (PetscDefined(USE_DEBUG)) {
193     /*
194       if no available configuration is available, this cascades all the way down to default
195       and error
196     */
197     switch (device->type) {
198     case PETSC_DEVICE_CUDA: if (PetscDefined(HAVE_CUDA)) break;
199     case PETSC_DEVICE_HIP:  if (PetscDefined(HAVE_HIP))  break;
200     case PETSC_DEVICE_SYCL: if (PetscDefined(HAVE_SYCL)) break;
201     default:
202       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"PETSc was seemingly configured for PetscDeviceType %s but we've fallen through all cases in a switch",PetscDeviceTypes[device->type]);
203     }
204   }
205   ierr = (*device->ops->configure)(device);CHKERRQ(ierr);
206   PetscFunctionReturn(0);
207 }
208 
209 /*@C
210   PetscDeviceView - View a PetscDevice
211 
212   Collective on viewer, Asynchronous
213 
214   Input Parameters:
215 + device - The PetscDevice to view
216 - viewer - The PetscViewer to view the device with (NULL for PETSC_VIEWER_STDOUT_WORLD)
217 
218   Level: beginner
219 
220 .seealso: PetscDevice, PetscDeviceCreate(), PetscDeviceConfigure(), PetscDeviceDestroy()
221 @*/
222 PetscErrorCode PetscDeviceView(PetscDevice device, PetscViewer viewer)
223 {
224   PetscErrorCode ierr;
225 
226   PetscFunctionBegin;
227   PetscValidDevice(device,1);
228   if (!viewer) {ierr = PetscViewerASCIIGetStdout(PETSC_COMM_WORLD,&viewer);CHKERRQ(ierr);}
229   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
230   ierr = (*device->ops->view)(device,viewer);CHKERRQ(ierr);
231   PetscFunctionReturn(0);
232 }
233 
234 /*@C
235   PetscDeviceGetDeviceId - Get the device id
236 
237   Not collective
238 
239   Input Parameter:
240 . device - The PetscDevice
241 
242   Output Parameter:
243 . id - The device id
244 
245   Level: beginner
246 
247 .seealso: PetscDevice, PetscDeviceCreate(), PetscDeviceConfigure(), PetscDeviceDestroy()
248 @*/
249 PetscErrorCode PetscDeviceGetDeviceId(PetscDevice device, PetscInt *id)
250 {
251   PetscFunctionBegin;
252   PetscValidDevice(device,1);
253   PetscValidIntPointer(id,2);
254   *id = device->deviceId;
255   PetscFunctionReturn(0);
256 }
257 
258 static std::array<bool,PETSC_DEVICE_MAX>        initializedDevice = {};
259 static std::array<PetscDevice,PETSC_DEVICE_MAX> defaultDevices    = {};
260 static_assert(initializedDevice.size() == defaultDevices.size(),"");
261 
262 /*@C
263   PetscDeviceInitialize - Initialize PetscDevice
264 
265   Not Collective, Possibly Synchronous
266 
267   Input Parameter:
268 . type - The PetscDeviceType to initialize
269 
270   Notes:
271   Eagerly initializes the corresponding PetscDeviceType if needed.
272 
273   Level: beginner
274 
275 .seealso: PetscDevice, PetscDeviceInitType, PetscDeviceInitialized(), PetscDeviceCreate(), PetscDeviceDestroy()
276 @*/
277 PetscErrorCode PetscDeviceInitialize(PetscDeviceType type)
278 {
279   PetscErrorCode ierr;
280 
281   PetscFunctionBegin;
282   PetscValidDeviceType(type,1);
283   ierr = PetscDeviceInitializeDefaultDevice_Internal(type,PETSC_DECIDE);CHKERRQ(ierr);
284   PetscFunctionReturn(0);
285 }
286 
287 /*@C
288   PetscDeviceInitialized - Determines whether PetscDevice is initialized for a particular
289   PetscDeviceType
290 
291   Not Collective, Asynchronous
292 
293   Input Parameter:
294 . type - The PetscDeviceType to check
295 
296   Output Parameter:
297 . [return value] - PETSC_TRUE if type is initialized, PETSC_FALSE otherwise
298 
299   Notes:
300   If one has not configured PETSc for a particular PetscDeviceType then this routine will
301   return PETSC_FALSE for that PetscDeviceType.
302 
303   Level: beginner
304 
305 .seealso: PetscDevice, PetscDeviceInitType, PetscDeviceInitialize(), PetscDeviceCreate(), PetscDeviceDestroy()
306 @*/
307 PetscBool PetscDeviceInitialized(PetscDeviceType type)
308 {
309   return static_cast<PetscBool>(PetscDeviceConfiguredFor_Internal(type) && initializedDevice[type]);
310 }
311 
312 /*
313   Actual intialization function; any functions claiming to initialize PetscDevice or
314   PetscDeviceContext will have to run through this one
315 */
316 PetscErrorCode PetscDeviceInitializeDefaultDevice_Internal(PetscDeviceType type, PetscInt defaultDeviceId)
317 {
318   PetscErrorCode ierr;
319 
320   PetscFunctionBegin;
321   PetscValidDeviceType(type,1);
322   if (PetscLikely(PetscDeviceInitialized(type))) PetscFunctionReturn(0);
323   PetscAssert(!defaultDevices[type],PETSC_COMM_SELF,PETSC_ERR_MEM,"Trying to overwrite existing default device of type %s",PetscDeviceTypes[type]);
324   ierr = PetscDeviceCreate(type,defaultDeviceId,&defaultDevices[type]);CHKERRQ(ierr);
325   ierr = PetscDeviceConfigure(defaultDevices[type]);CHKERRQ(ierr);
326   initializedDevice[type] = true;
327   PetscFunctionReturn(0);
328 }
329 
330 #if PetscDefined(USE_LOG)
331 PETSC_INTERN PetscErrorCode PetscLogInitialize(void);
332 #else
333 #define PetscLogInitialize() 0
334 #endif
335 
336 static PetscErrorCode PetscDeviceInitializeTypeFromOptions_Private(MPI_Comm comm, PetscDeviceType type, PetscInt defaultDeviceId, PetscBool defaultView, PetscDeviceInitType *defaultInitType)
337 {
338   PetscErrorCode ierr;
339 
340   PetscFunctionBegin;
341   if (!PetscDeviceConfiguredFor_Internal(type)) {
342     ierr = PetscInfo(PETSC_NULLPTR,"PetscDeviceType %s not supported\n",PetscDeviceTypes[type]);CHKERRQ(ierr);
343     defaultDevices[type] = PETSC_NULLPTR;
344     PetscFunctionReturn(0);
345   }
346   ierr = PetscInfo(PETSC_NULLPTR,"PetscDeviceType %s supported, initializing\n",PetscDeviceTypes[type]);CHKERRQ(ierr);
347   /* ugly switch needed to pick the right global variable... could maybe do this as a union? */
348   switch (type) {
349     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(CUDA,initialize,comm,&defaultDeviceId,defaultInitType);
350     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(HIP,initialize,comm,&defaultDeviceId,defaultInitType);
351     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(SYCL,initialize,comm,&defaultDeviceId,defaultInitType);
352   default:
353     SETERRQ(comm,PETSC_ERR_PLIB,"PETSc was seemingly configured for PetscDeviceType %s but we've fallen through all cases in a switch",PetscDeviceTypes[type]);
354   }
355   /*
356     defaultInitType and defaultDeviceId now represent what the individual TYPES have decided to
357     initialize as
358   */
359   if (*defaultInitType == PETSC_DEVICE_INIT_EAGER) {
360     ierr = PetscInfo(PETSC_NULLPTR,"Eagerly initializing %s PetscDevice\n",PetscDeviceTypes[type]);CHKERRQ(ierr);
361     ierr = PetscDeviceInitializeDefaultDevice_Internal(type,defaultDeviceId);CHKERRQ(ierr);
362     if (defaultView) {
363       PetscViewer vwr;
364 
365       ierr = PetscLogInitialize();CHKERRQ(ierr);
366       ierr = PetscViewerASCIIGetStdout(comm,&vwr);CHKERRQ(ierr);
367       ierr = PetscDeviceView(defaultDevices[type],vwr);CHKERRQ(ierr);
368     }
369   }
370   PetscFunctionReturn(0);
371 }
372 
373 /* called from PetscFinalize() do not call yourself! */
374 static PetscErrorCode PetscDeviceFinalize_Private(void)
375 {
376   PetscErrorCode ierr;
377 
378   PetscFunctionBegin;
379   if (PetscDefined(USE_DEBUG)) {
380     const auto PetscDeviceCheckAllDestroyedAfterFinalize = []{
381       PetscFunctionBegin;
382       for (auto&& device : defaultDevices) PetscCheck(!device,PETSC_COMM_WORLD,PETSC_ERR_COR,"Device of type '%s' had reference count %" PetscInt_FMT " and was not fully destroyed during PetscFinalize()",PetscDeviceTypes[device->type],device->refcnt);
383       PetscFunctionReturn(0);
384     };
385     /*
386       you might be thinking, why on earth are you registered yet another finalizer in a
387       function already called during PetscRegisterFinalizeAll()? If this seems stupid it's
388       because it is.
389 
390       The crux of the problem is that the initializer (and therefore the ~finalizer~) of
391       PetscDeviceContext is guaranteed to run after PetscDevice's. So if the global context had
392       a default PetscDevice attached, that PetscDevice will have a reference count >0 and hence
393       won't be destroyed yet. So we need to repeat the check that all devices have been
394       destroyed again ~after~ the global context is destroyed. In summary:
395 
396       1. This finalizer runs and destroys all devices, except it may not because the global
397          context may still hold a reference!
398       2. The global context finalizer runs and does the final reference count decrement
399          required, which actually destroys the held device.
400       3. Our newly added finalizer runs and checks that all is well.
401     */
402     ierr = PetscRegisterFinalize(PetscDeviceCheckAllDestroyedAfterFinalize);CHKERRQ(ierr);
403   }
404   for (auto &&device : defaultDevices) {ierr = PetscDeviceDestroy(&device);CHKERRQ(ierr);}
405   CHKERRCXX(initializedDevice.fill(false));
406   PetscFunctionReturn(0);
407 }
408 
409 /*
410   Begins the init proceeedings for the entire PetscDevice stack. there are 3 stages of
411   initialization types:
412 
413   1. defaultInitType - how does PetscDevice as a whole expect to initialize?
414   2. subTypeDefaultInitType - how does each PetscDevice implementation expect to initialize?
415      e.g. you may want to blanket disable PetscDevice init (and disable say Kokkos init), but
416      have all CUDA devices still initialize.
417 
418   All told the following happens:
419 
420   0. defaultInitType -> LAZY
421   1. Check for log_view/log_summary, if yes defaultInitType -> EAGER
422   2. PetscDevice initializes each sub type with deviceDefaultInitType.
423   2.1 Each enabled PetscDevice sub-type then does the above disable or view check in addition
424       to checking for specific device init. if view or specific device init
425       subTypeDefaultInitType -> EAGER. disabled once again overrides all.
426 */
427 PetscErrorCode PetscDeviceInitializeFromOptions_Internal(MPI_Comm comm)
428 {
429   PetscBool           flg,defaultView = PETSC_FALSE,initializeDeviceContextEagerly = PETSC_FALSE;
430   PetscInt            defaultDevice   = PETSC_DECIDE;
431   PetscDeviceType     deviceContextInitDevice = PETSC_DEVICE_DEFAULT;
432   PetscDeviceInitType defaultInitType;
433   PetscErrorCode      ierr;
434 
435   PetscFunctionBegin;
436   if (PetscDefined(USE_DEBUG)) {
437     int result;
438 
439     ierr = MPI_Comm_compare(comm,PETSC_COMM_WORLD,&result);CHKERRMPI(ierr);
440     /* in order to accurately assign ranks to gpus we need to get the MPI_Comm_rank of the
441      * global space */
442     if (PetscUnlikely(result != MPI_IDENT)) {
443       char name[MPI_MAX_OBJECT_NAME] = {};
444       int  len; /* unused */
445 
446       ierr = MPI_Comm_get_name(comm,name,&len);CHKERRMPI(ierr);
447       SETERRQ(comm,PETSC_ERR_MPI,"Default devices being initialized on MPI_Comm '%s' not PETSC_COMM_WORLD",name);
448     }
449   }
450   comm = PETSC_COMM_WORLD; /* from this point on we assume we're on PETSC_COMM_WORLD */
451   ierr = PetscRegisterFinalize(PetscDeviceFinalize_Private);CHKERRQ(ierr);
452   ierr = PetscOptionsHasName(PETSC_NULLPTR,PETSC_NULLPTR,"-log_view",&flg);CHKERRQ(ierr);
453   if (!flg) {
454     ierr = PetscOptionsHasName(PETSC_NULLPTR,PETSC_NULLPTR,"-log_summary",&flg);CHKERRQ(ierr);
455   }
456   {
457     PetscInt initIdx = flg ? PETSC_DEVICE_INIT_EAGER : PETSC_DEVICE_INIT_LAZY;
458 
459     ierr = PetscOptionsBegin(comm,PETSC_NULLPTR,"PetscDevice Options","Sys");CHKERRQ(ierr);
460     ierr = PetscOptionsEList("-device_enable","How (or whether) to initialize PetscDevices","PetscDeviceInitializeFromOptions_Internal()",PetscDeviceInitTypes,3,PetscDeviceInitTypes[initIdx],&initIdx,PETSC_NULLPTR);CHKERRQ(ierr);
461     ierr = PetscOptionsRangeInt("-device_select","Which device to use. Pass " PetscStringize(PETSC_DECIDE) " to have PETSc decide or (given they exist) [0-NUM_DEVICE) for a specific device","PetscDeviceCreate()",defaultDevice,&defaultDevice,PETSC_NULLPTR,PETSC_DECIDE,std::numeric_limits<int>::max());CHKERRQ(ierr);
462     ierr = PetscOptionsBool("-device_view","Display device information and assignments (forces eager initialization)",PETSC_NULLPTR,defaultView,&defaultView,&flg);CHKERRQ(ierr);
463     ierr = PetscOptionsEnd();CHKERRQ(ierr);
464     if (initIdx == PETSC_DEVICE_INIT_NONE) {
465       /* disabled all device initialization if devices are globally disabled */
466       PetscCheck(defaultDevice == PETSC_DECIDE,comm,PETSC_ERR_USER_INPUT,"You have disabled devices but also specified a particular device to use, these options are mutually exlusive");
467       defaultView = PETSC_FALSE;
468     } else {
469       defaultView = static_cast<decltype(defaultView)>(defaultView && flg);
470       if (defaultView) initIdx = PETSC_DEVICE_INIT_EAGER;
471     }
472     defaultInitType = static_cast<decltype(defaultInitType)>(initIdx);
473   }
474   static_assert((PETSC_DEVICE_INVALID == 0) && (PETSC_DEVICE_MAX < std::numeric_limits<int>::max()),"");
475   for (int i = 1; i < PETSC_DEVICE_MAX; ++i) {
476     const auto deviceType = static_cast<PetscDeviceType>(i);
477     auto initType         = defaultInitType;
478 
479     ierr = PetscDeviceInitializeTypeFromOptions_Private(comm,deviceType,defaultDevice,defaultView,&initType);CHKERRQ(ierr);
480     if (PetscDeviceConfiguredFor_Internal(deviceType) && (initType == PETSC_DEVICE_INIT_EAGER)) {
481       initializeDeviceContextEagerly = PETSC_TRUE;
482       deviceContextInitDevice        = deviceType;
483     }
484   }
485   if (initializeDeviceContextEagerly) {
486     PetscDeviceContext dctx;
487 
488     /*
489       somewhat inefficient here as the device context is potentially fully set up twice (once
490       when retrieved then the second time if setfromoptions makes changes)
491     */
492     ierr = PetscInfo(PETSC_NULLPTR,"Eagerly initializing PetscDeviceContext with %s device\n",PetscDeviceTypes[deviceContextInitDevice]);CHKERRQ(ierr);
493     ierr = PetscDeviceContextSetRootDeviceType_Internal(deviceContextInitDevice);CHKERRQ(ierr);
494     ierr = PetscDeviceContextGetCurrentContext(&dctx);CHKERRQ(ierr);
495     ierr = PetscDeviceContextSetFromOptions(comm,"root_",dctx);CHKERRQ(ierr);
496     ierr = PetscDeviceContextSetUp(dctx);CHKERRQ(ierr);
497   }
498   PetscFunctionReturn(0);
499 }
500 
501 /* Get the default PetscDevice for a particular type and constructs them if lazily initialized. */
502 PetscErrorCode PetscDeviceGetDefaultForType_Internal(PetscDeviceType type, PetscDevice *device)
503 {
504   PetscErrorCode ierr;
505 
506   PetscFunctionBegin;
507   PetscValidPointer(device,2);
508   ierr = PetscDeviceInitialize(type);CHKERRQ(ierr);
509   *device = defaultDevices[type];
510   PetscFunctionReturn(0);
511 }
512