xref: /petsc/src/sys/objects/device/interface/device.cxx (revision dbbe0bcd3f3a8fbab5a45420dc06f8387e5764c6)
1030f984aSJacob Faibussowitsch #include "cupmdevice.hpp" /* I "petscdevice.h" */
217f48955SJacob Faibussowitsch #include <petsc/private/petscadvancedmacros.h>
3030f984aSJacob Faibussowitsch 
417f48955SJacob Faibussowitsch using namespace Petsc::Device;
5030f984aSJacob Faibussowitsch 
6cf3a2253SJacob Faibussowitsch /*
7cf3a2253SJacob Faibussowitsch   note to anyone adding more classes, the name must be ALL_CAPS_SHORT_NAME + Device exactly to
8cf3a2253SJacob Faibussowitsch   be picked up by the switch-case macros below
9cf3a2253SJacob Faibussowitsch */
10030f984aSJacob Faibussowitsch #if PetscDefined(HAVE_CUDA)
1117f48955SJacob Faibussowitsch static CUPM::Device<CUPM::DeviceType::CUDA> CUDADevice(PetscDeviceContextCreate_CUDA);
12030f984aSJacob Faibussowitsch #endif
13030f984aSJacob Faibussowitsch #if PetscDefined(HAVE_HIP)
1417f48955SJacob Faibussowitsch static CUPM::Device<CUPM::DeviceType::HIP>  HIPDevice(PetscDeviceContextCreate_HIP);
15030f984aSJacob Faibussowitsch #endif
16a2158755SJunchao Zhang #if PetscDefined(HAVE_SYCL)
17a2158755SJunchao Zhang #include "sycldevice.hpp"
1817f48955SJacob Faibussowitsch static SYCL::Device                         SYCLDevice(PetscDeviceContextCreate_SYCL);
19a2158755SJunchao Zhang #endif
20030f984aSJacob Faibussowitsch 
2117f48955SJacob Faibussowitsch static_assert(Petsc::util::integral_value(PETSC_DEVICE_INVALID) == 0,"");
2217f48955SJacob Faibussowitsch static_assert(Petsc::util::integral_value(PETSC_DEVICE_CUDA)    == 1,"");
2317f48955SJacob Faibussowitsch static_assert(Petsc::util::integral_value(PETSC_DEVICE_HIP)     == 2,"");
2417f48955SJacob Faibussowitsch static_assert(Petsc::util::integral_value(PETSC_DEVICE_SYCL)    == 3,"");
2517f48955SJacob Faibussowitsch static_assert(Petsc::util::integral_value(PETSC_DEVICE_MAX)     == 4,"");
26a4af0ceeSJacob Faibussowitsch const char *const PetscDeviceTypes[] = {
27a4af0ceeSJacob Faibussowitsch   "invalid",
28a4af0ceeSJacob Faibussowitsch   "cuda",
29a4af0ceeSJacob Faibussowitsch   "hip",
30a2158755SJunchao Zhang   "sycl",
31a4af0ceeSJacob Faibussowitsch   "max",
32a4af0ceeSJacob Faibussowitsch   "PetscDeviceType",
33a4af0ceeSJacob Faibussowitsch   "PETSC_DEVICE_",
34a4af0ceeSJacob Faibussowitsch   PETSC_NULLPTR
35a4af0ceeSJacob Faibussowitsch };
36a4af0ceeSJacob Faibussowitsch 
3717f48955SJacob Faibussowitsch static_assert(Petsc::util::integral_value(PETSC_DEVICE_INIT_NONE)  == 0,"");
3817f48955SJacob Faibussowitsch static_assert(Petsc::util::integral_value(PETSC_DEVICE_INIT_LAZY)  == 1,"");
3917f48955SJacob Faibussowitsch static_assert(Petsc::util::integral_value(PETSC_DEVICE_INIT_EAGER) == 2,"");
40a4af0ceeSJacob Faibussowitsch const char *const PetscDeviceInitTypes[] = {
41a4af0ceeSJacob Faibussowitsch   "none",
42a4af0ceeSJacob Faibussowitsch   "lazy",
43a4af0ceeSJacob Faibussowitsch   "eager",
44a4af0ceeSJacob Faibussowitsch   "PetscDeviceInitType",
45a4af0ceeSJacob Faibussowitsch   "PETSC_DEVICE_INIT_",
46a4af0ceeSJacob Faibussowitsch   PETSC_NULLPTR
47a4af0ceeSJacob Faibussowitsch };
48a4af0ceeSJacob Faibussowitsch static_assert(
49a4af0ceeSJacob Faibussowitsch   sizeof(PetscDeviceInitTypes)/sizeof(*PetscDeviceInitTypes) == 6,
50a4af0ceeSJacob Faibussowitsch   "Must change CUPMDevice<T>::initialize number of enum values in -device_enable_cupm to match!"
51a4af0ceeSJacob Faibussowitsch );
52a4af0ceeSJacob Faibussowitsch 
5317f48955SJacob Faibussowitsch #define PETSC_DEVICE_CASE(IMPLS,func,...)                                     \
5417f48955SJacob Faibussowitsch   case PetscConcat_(PETSC_DEVICE_,IMPLS): {                                   \
559566063dSJacob Faibussowitsch     PetscCall(PetscConcat_(IMPLS,Device).func(__VA_ARGS__));                    \
5617f48955SJacob Faibussowitsch   } break
57a4af0ceeSJacob Faibussowitsch 
58cf3a2253SJacob Faibussowitsch /*
59cf3a2253SJacob Faibussowitsch   Suppose you have:
60cf3a2253SJacob Faibussowitsch 
61cf3a2253SJacob Faibussowitsch   CUDADevice.myFunction(arg1,arg2)
62cf3a2253SJacob Faibussowitsch 
63cf3a2253SJacob Faibussowitsch   that you would like to conditionally define and call in a switch-case:
64cf3a2253SJacob Faibussowitsch 
65cf3a2253SJacob Faibussowitsch   switch(PetscDeviceType) {
66cf3a2253SJacob Faibussowitsch   #if PetscDefined(HAVE_CUDA)
67cf3a2253SJacob Faibussowitsch   case PETSC_DEVICE_CUDA: {
689566063dSJacob Faibussowitsch     PetscCall(CUDADevice.myFunction(arg1,arg2));
69cf3a2253SJacob Faibussowitsch   } break;
70cf3a2253SJacob Faibussowitsch   #endif
71cf3a2253SJacob Faibussowitsch   }
72cf3a2253SJacob Faibussowitsch 
73cf3a2253SJacob Faibussowitsch   then calling this macro:
74cf3a2253SJacob Faibussowitsch 
75cf3a2253SJacob Faibussowitsch   PETSC_DEVICE_CASE_IF_PETSC_DEFINED(CUDA,myFunction,arg1,arg2)
76cf3a2253SJacob Faibussowitsch 
77cf3a2253SJacob Faibussowitsch   will expand to the following case statement:
78cf3a2253SJacob Faibussowitsch 
79cf3a2253SJacob Faibussowitsch   case PETSC_DEVICE_CUDA: {
809566063dSJacob Faibussowitsch     PetscCall(CUDADevice.myFunction(arg1,arg2));
81cf3a2253SJacob Faibussowitsch   } break
82cf3a2253SJacob Faibussowitsch 
83cf3a2253SJacob Faibussowitsch   if PetscDefined(HAVE_CUDA) evaluates to 1, and expand to nothing otherwise
8417f48955SJacob Faibussowitsch */
8517f48955SJacob Faibussowitsch #define PETSC_DEVICE_CASE_IF_PETSC_DEFINED(IMPLS,func,...)                                     \
8617f48955SJacob Faibussowitsch   PetscIfPetscDefined(PetscConcat_(HAVE_,IMPLS),PETSC_DEVICE_CASE,PetscExpandToNothing)(IMPLS,func,__VA_ARGS__)
87030f984aSJacob Faibussowitsch 
88030f984aSJacob Faibussowitsch /*@C
89a4af0ceeSJacob Faibussowitsch   PetscDeviceCreate - Get a new handle for a particular device type
90030f984aSJacob Faibussowitsch 
91030f984aSJacob Faibussowitsch   Not Collective, Possibly Synchronous
92030f984aSJacob Faibussowitsch 
93f1a722f8SMatthew G. Knepley   Input Parameters:
94f1a722f8SMatthew G. Knepley + type  - The type of PetscDevice
95f1a722f8SMatthew G. Knepley - devid - The numeric ID# of the device (pass PETSC_DECIDE to assign automatically)
96030f984aSJacob Faibussowitsch 
97030f984aSJacob Faibussowitsch   Output Parameter:
98030f984aSJacob Faibussowitsch . device - The PetscDevice
99030f984aSJacob Faibussowitsch 
100030f984aSJacob Faibussowitsch   Notes:
101a4af0ceeSJacob Faibussowitsch   This routine may initialize PetscDevice. If this is the case, this will most likely cause
102a4af0ceeSJacob Faibussowitsch   some sort of device synchronization.
103a4af0ceeSJacob Faibussowitsch 
104a4af0ceeSJacob Faibussowitsch   devid is what you might pass to cudaSetDevice() for example.
105030f984aSJacob Faibussowitsch 
106030f984aSJacob Faibussowitsch   Level: beginner
107030f984aSJacob Faibussowitsch 
108db781477SPatrick Sanan .seealso: `PetscDevice`, `PetscDeviceInitType`, `PetscDeviceInitialize()`,
109db781477SPatrick Sanan           `PetscDeviceInitialized()`, `PetscDeviceConfigure()`, `PetscDeviceView()`, `PetscDeviceDestroy()`
110030f984aSJacob Faibussowitsch @*/
111a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceCreate(PetscDeviceType type, PetscInt devid, PetscDevice *device)
112030f984aSJacob Faibussowitsch {
113030f984aSJacob Faibussowitsch   static PetscInt PetscDeviceCounter = 0;
114030f984aSJacob Faibussowitsch   PetscDevice     dev;
115030f984aSJacob Faibussowitsch 
116030f984aSJacob Faibussowitsch   PetscFunctionBegin;
117a4af0ceeSJacob Faibussowitsch   PetscValidDeviceType(type,1);
118a4af0ceeSJacob Faibussowitsch   PetscValidPointer(device,3);
1199566063dSJacob Faibussowitsch   PetscCall(PetscDeviceInitializePackage());
1209566063dSJacob Faibussowitsch   PetscCall(PetscNew(&dev));
121030f984aSJacob Faibussowitsch   dev->id     = PetscDeviceCounter++;
122a4af0ceeSJacob Faibussowitsch   dev->type   = type;
123a4af0ceeSJacob Faibussowitsch   dev->refcnt = 1;
124cf3a2253SJacob Faibussowitsch   /*
125cf3a2253SJacob Faibussowitsch     if you are adding a device, you also need to add it's initialization in
126cf3a2253SJacob Faibussowitsch     PetscDeviceInitializeTypeFromOptions_Private() below
127cf3a2253SJacob Faibussowitsch   */
128a4af0ceeSJacob Faibussowitsch   switch (type) {
129a4af0ceeSJacob Faibussowitsch     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(CUDA,getDevice,dev,devid);
130a4af0ceeSJacob Faibussowitsch     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(HIP,getDevice,dev,devid);
131a2158755SJunchao Zhang     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(SYCL,getDevice,dev,devid);
132030f984aSJacob Faibussowitsch   default:
13317f48955SJacob Faibussowitsch     /* in case the above macros expand to nothing this silences any unused variable warnings */
13417f48955SJacob Faibussowitsch     (void)(devid);
13598921bdaSJacob Faibussowitsch     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]);
136030f984aSJacob Faibussowitsch   }
137030f984aSJacob Faibussowitsch   *device = dev;
138030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
139030f984aSJacob Faibussowitsch }
140030f984aSJacob Faibussowitsch 
141030f984aSJacob Faibussowitsch /*@C
142030f984aSJacob Faibussowitsch   PetscDeviceDestroy - Free a PetscDevice
143030f984aSJacob Faibussowitsch 
144030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
145030f984aSJacob Faibussowitsch 
146030f984aSJacob Faibussowitsch   Input Parameter:
147030f984aSJacob Faibussowitsch . device - The PetscDevice
148030f984aSJacob Faibussowitsch 
149030f984aSJacob Faibussowitsch   Level: beginner
150030f984aSJacob Faibussowitsch 
151db781477SPatrick Sanan .seealso: `PetscDevice`, `PetscDeviceCreate()`, `PetscDeviceConfigure()`, `PetscDeviceView()`
152030f984aSJacob Faibussowitsch @*/
153030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceDestroy(PetscDevice *device)
154030f984aSJacob Faibussowitsch {
155a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
156a4af0ceeSJacob Faibussowitsch   if (!*device) PetscFunctionReturn(0);
157a4af0ceeSJacob Faibussowitsch   PetscValidDevice(*device,1);
1589566063dSJacob Faibussowitsch   PetscCall(PetscDeviceDereference_Internal(*device));
159a4af0ceeSJacob Faibussowitsch   if ((*device)->refcnt) {
160a4af0ceeSJacob Faibussowitsch     *device = PETSC_NULLPTR;
161a4af0ceeSJacob Faibussowitsch     PetscFunctionReturn(0);
162030f984aSJacob Faibussowitsch   }
1639566063dSJacob Faibussowitsch   PetscCall(PetscFree((*device)->data));
1649566063dSJacob Faibussowitsch   PetscCall(PetscFree(*device));
165030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
166030f984aSJacob Faibussowitsch }
167030f984aSJacob Faibussowitsch 
168a4af0ceeSJacob Faibussowitsch /*@C
169a4af0ceeSJacob Faibussowitsch   PetscDeviceConfigure - Configure a particular PetscDevice
170030f984aSJacob Faibussowitsch 
171a4af0ceeSJacob Faibussowitsch   Not Collective, Asynchronous
172a4af0ceeSJacob Faibussowitsch 
173a4af0ceeSJacob Faibussowitsch   Input Parameter:
174a4af0ceeSJacob Faibussowitsch . device - The PetscDevice to configure
175a4af0ceeSJacob Faibussowitsch 
176a4af0ceeSJacob Faibussowitsch   Notes:
177a4af0ceeSJacob Faibussowitsch   The user should not assume that this is a cheap operation
178a4af0ceeSJacob Faibussowitsch 
179a4af0ceeSJacob Faibussowitsch   Level: beginner
180a4af0ceeSJacob Faibussowitsch 
181db781477SPatrick Sanan .seealso: `PetscDevice`, `PetscDeviceCreate()`, `PetscDeviceView()`, `PetscDeviceDestroy()`
182a4af0ceeSJacob Faibussowitsch @*/
183a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceConfigure(PetscDevice device)
184030f984aSJacob Faibussowitsch {
185030f984aSJacob Faibussowitsch   PetscFunctionBegin;
186a4af0ceeSJacob Faibussowitsch   PetscValidDevice(device,1);
187a4af0ceeSJacob Faibussowitsch   if (PetscDefined(USE_DEBUG)) {
188cf3a2253SJacob Faibussowitsch     /*
189cf3a2253SJacob Faibussowitsch       if no available configuration is available, this cascades all the way down to default
190cf3a2253SJacob Faibussowitsch       and error
191cf3a2253SJacob Faibussowitsch     */
192a4af0ceeSJacob Faibussowitsch     switch (device->type) {
193a4af0ceeSJacob Faibussowitsch     case PETSC_DEVICE_CUDA: if (PetscDefined(HAVE_CUDA)) break;
194a4af0ceeSJacob Faibussowitsch     case PETSC_DEVICE_HIP:  if (PetscDefined(HAVE_HIP))  break;
195a2158755SJunchao Zhang     case PETSC_DEVICE_SYCL: if (PetscDefined(HAVE_SYCL)) break;
196a4af0ceeSJacob Faibussowitsch     default:
19798921bdaSJacob Faibussowitsch       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]);
198a4af0ceeSJacob Faibussowitsch     }
199a4af0ceeSJacob Faibussowitsch   }
200*dbbe0bcdSBarry Smith   PetscUseTypeMethod(device,configure);
201a4af0ceeSJacob Faibussowitsch   PetscFunctionReturn(0);
202a4af0ceeSJacob Faibussowitsch }
203a4af0ceeSJacob Faibussowitsch 
204a4af0ceeSJacob Faibussowitsch /*@C
205a4af0ceeSJacob Faibussowitsch   PetscDeviceView - View a PetscDevice
206a4af0ceeSJacob Faibussowitsch 
207a4af0ceeSJacob Faibussowitsch   Collective on viewer, Asynchronous
208a4af0ceeSJacob Faibussowitsch 
20991e63d38SStefano Zampini   Input Parameters:
210050c0c3dSJacob Faibussowitsch + device - The PetscDevice to view
211a4af0ceeSJacob Faibussowitsch - viewer - The PetscViewer to view the device with (NULL for PETSC_VIEWER_STDOUT_WORLD)
212a4af0ceeSJacob Faibussowitsch 
213a4af0ceeSJacob Faibussowitsch   Level: beginner
214a4af0ceeSJacob Faibussowitsch 
215db781477SPatrick Sanan .seealso: `PetscDevice`, `PetscDeviceCreate()`, `PetscDeviceConfigure()`, `PetscDeviceDestroy()`
216a4af0ceeSJacob Faibussowitsch @*/
217a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceView(PetscDevice device, PetscViewer viewer)
218a4af0ceeSJacob Faibussowitsch {
219a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
220a4af0ceeSJacob Faibussowitsch   PetscValidDevice(device,1);
2219566063dSJacob Faibussowitsch   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PETSC_COMM_WORLD,&viewer));
222a4af0ceeSJacob Faibussowitsch   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
223*dbbe0bcdSBarry Smith   PetscUseTypeMethod(device,view ,viewer);
224a4af0ceeSJacob Faibussowitsch   PetscFunctionReturn(0);
225a4af0ceeSJacob Faibussowitsch }
226a4af0ceeSJacob Faibussowitsch 
22791e63d38SStefano Zampini /*@C
22891e63d38SStefano Zampini   PetscDeviceGetDeviceId - Get the device id
22991e63d38SStefano Zampini 
23091e63d38SStefano Zampini   Not collective
23191e63d38SStefano Zampini 
23291e63d38SStefano Zampini   Input Parameter:
23391e63d38SStefano Zampini . device - The PetscDevice
23491e63d38SStefano Zampini 
23591e63d38SStefano Zampini   Output Parameter:
23691e63d38SStefano Zampini . id - The device id
23791e63d38SStefano Zampini 
23891e63d38SStefano Zampini   Level: beginner
23991e63d38SStefano Zampini 
240db781477SPatrick Sanan .seealso: `PetscDevice`, `PetscDeviceCreate()`, `PetscDeviceConfigure()`, `PetscDeviceDestroy()`
24191e63d38SStefano Zampini @*/
24291e63d38SStefano Zampini PetscErrorCode PetscDeviceGetDeviceId(PetscDevice device, PetscInt *id)
24391e63d38SStefano Zampini {
24491e63d38SStefano Zampini   PetscFunctionBegin;
24591e63d38SStefano Zampini   PetscValidDevice(device,1);
24691e63d38SStefano Zampini   PetscValidIntPointer(id,2);
24791e63d38SStefano Zampini   *id = device->deviceId;
24891e63d38SStefano Zampini   PetscFunctionReturn(0);
24991e63d38SStefano Zampini }
25091e63d38SStefano Zampini 
251a4af0ceeSJacob Faibussowitsch static std::array<bool,PETSC_DEVICE_MAX>        initializedDevice = {};
252a4af0ceeSJacob Faibussowitsch static std::array<PetscDevice,PETSC_DEVICE_MAX> defaultDevices    = {};
253a4af0ceeSJacob Faibussowitsch static_assert(initializedDevice.size() == defaultDevices.size(),"");
254a4af0ceeSJacob Faibussowitsch 
255a4af0ceeSJacob Faibussowitsch /*@C
256a4af0ceeSJacob Faibussowitsch   PetscDeviceInitialize - Initialize PetscDevice
257a4af0ceeSJacob Faibussowitsch 
258a4af0ceeSJacob Faibussowitsch   Not Collective, Possibly Synchronous
259a4af0ceeSJacob Faibussowitsch 
260a4af0ceeSJacob Faibussowitsch   Input Parameter:
261a4af0ceeSJacob Faibussowitsch . type - The PetscDeviceType to initialize
262a4af0ceeSJacob Faibussowitsch 
263a4af0ceeSJacob Faibussowitsch   Notes:
264a4af0ceeSJacob Faibussowitsch   Eagerly initializes the corresponding PetscDeviceType if needed.
265a4af0ceeSJacob Faibussowitsch 
266a4af0ceeSJacob Faibussowitsch   Level: beginner
267a4af0ceeSJacob Faibussowitsch 
268db781477SPatrick Sanan .seealso: `PetscDevice`, `PetscDeviceInitType`, `PetscDeviceInitialized()`, `PetscDeviceCreate()`, `PetscDeviceDestroy()`
269a4af0ceeSJacob Faibussowitsch @*/
270a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceInitialize(PetscDeviceType type)
271a4af0ceeSJacob Faibussowitsch {
272a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
273a4af0ceeSJacob Faibussowitsch   PetscValidDeviceType(type,1);
2749566063dSJacob Faibussowitsch   PetscCall(PetscDeviceInitializeDefaultDevice_Internal(type,PETSC_DECIDE));
275a4af0ceeSJacob Faibussowitsch   PetscFunctionReturn(0);
276a4af0ceeSJacob Faibussowitsch }
277a4af0ceeSJacob Faibussowitsch 
278a4af0ceeSJacob Faibussowitsch /*@C
279a4af0ceeSJacob Faibussowitsch   PetscDeviceInitialized - Determines whether PetscDevice is initialized for a particular
280a4af0ceeSJacob Faibussowitsch   PetscDeviceType
281a4af0ceeSJacob Faibussowitsch 
282a4af0ceeSJacob Faibussowitsch   Not Collective, Asynchronous
283a4af0ceeSJacob Faibussowitsch 
284a4af0ceeSJacob Faibussowitsch   Input Parameter:
285a4af0ceeSJacob Faibussowitsch . type - The PetscDeviceType to check
286a4af0ceeSJacob Faibussowitsch 
287a4af0ceeSJacob Faibussowitsch   Output Parameter:
288a4af0ceeSJacob Faibussowitsch . [return value] - PETSC_TRUE if type is initialized, PETSC_FALSE otherwise
289a4af0ceeSJacob Faibussowitsch 
290a4af0ceeSJacob Faibussowitsch   Notes:
291a4af0ceeSJacob Faibussowitsch   If one has not configured PETSc for a particular PetscDeviceType then this routine will
292a4af0ceeSJacob Faibussowitsch   return PETSC_FALSE for that PetscDeviceType.
293a4af0ceeSJacob Faibussowitsch 
294a4af0ceeSJacob Faibussowitsch   Level: beginner
295a4af0ceeSJacob Faibussowitsch 
296db781477SPatrick Sanan .seealso: `PetscDevice`, `PetscDeviceInitType`, `PetscDeviceInitialize()`, `PetscDeviceCreate()`, `PetscDeviceDestroy()`
297a4af0ceeSJacob Faibussowitsch @*/
298a4af0ceeSJacob Faibussowitsch PetscBool PetscDeviceInitialized(PetscDeviceType type)
299a4af0ceeSJacob Faibussowitsch {
300a4af0ceeSJacob Faibussowitsch   return static_cast<PetscBool>(PetscDeviceConfiguredFor_Internal(type) && initializedDevice[type]);
301a4af0ceeSJacob Faibussowitsch }
302a4af0ceeSJacob Faibussowitsch 
303cf3a2253SJacob Faibussowitsch /*
304cf3a2253SJacob Faibussowitsch   Actual intialization function; any functions claiming to initialize PetscDevice or
305cf3a2253SJacob Faibussowitsch   PetscDeviceContext will have to run through this one
306cf3a2253SJacob Faibussowitsch */
307a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceInitializeDefaultDevice_Internal(PetscDeviceType type, PetscInt defaultDeviceId)
308a4af0ceeSJacob Faibussowitsch {
309a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
310a4af0ceeSJacob Faibussowitsch   PetscValidDeviceType(type,1);
311a4af0ceeSJacob Faibussowitsch   if (PetscLikely(PetscDeviceInitialized(type))) PetscFunctionReturn(0);
312bf025ffbSJacob Faibussowitsch   PetscAssert(!defaultDevices[type],PETSC_COMM_SELF,PETSC_ERR_MEM,"Trying to overwrite existing default device of type %s",PetscDeviceTypes[type]);
3139566063dSJacob Faibussowitsch   PetscCall(PetscDeviceCreate(type,defaultDeviceId,&defaultDevices[type]));
3149566063dSJacob Faibussowitsch   PetscCall(PetscDeviceConfigure(defaultDevices[type]));
315a4af0ceeSJacob Faibussowitsch   initializedDevice[type] = true;
316a4af0ceeSJacob Faibussowitsch   PetscFunctionReturn(0);
317a4af0ceeSJacob Faibussowitsch }
318a4af0ceeSJacob Faibussowitsch 
319ce244043SStefano Zampini #if PetscDefined(USE_LOG)
320ce244043SStefano Zampini PETSC_INTERN PetscErrorCode PetscLogInitialize(void);
321ce244043SStefano Zampini #else
322ce244043SStefano Zampini #define PetscLogInitialize() 0
323ce244043SStefano Zampini #endif
324ce244043SStefano Zampini 
325a4af0ceeSJacob Faibussowitsch static PetscErrorCode PetscDeviceInitializeTypeFromOptions_Private(MPI_Comm comm, PetscDeviceType type, PetscInt defaultDeviceId, PetscBool defaultView, PetscDeviceInitType *defaultInitType)
326a4af0ceeSJacob Faibussowitsch {
327a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
328a4af0ceeSJacob Faibussowitsch   if (!PetscDeviceConfiguredFor_Internal(type)) {
3299566063dSJacob Faibussowitsch     PetscCall(PetscInfo(PETSC_NULLPTR,"PetscDeviceType %s not supported\n",PetscDeviceTypes[type]));
330a4af0ceeSJacob Faibussowitsch     defaultDevices[type] = PETSC_NULLPTR;
331a4af0ceeSJacob Faibussowitsch     PetscFunctionReturn(0);
332a4af0ceeSJacob Faibussowitsch   }
3339566063dSJacob Faibussowitsch   PetscCall(PetscInfo(PETSC_NULLPTR,"PetscDeviceType %s supported, initializing\n",PetscDeviceTypes[type]));
334a4af0ceeSJacob Faibussowitsch   /* ugly switch needed to pick the right global variable... could maybe do this as a union? */
335a4af0ceeSJacob Faibussowitsch   switch (type) {
336a4af0ceeSJacob Faibussowitsch     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(CUDA,initialize,comm,&defaultDeviceId,defaultInitType);
337a4af0ceeSJacob Faibussowitsch     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(HIP,initialize,comm,&defaultDeviceId,defaultInitType);
338a2158755SJunchao Zhang     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(SYCL,initialize,comm,&defaultDeviceId,defaultInitType);
339a4af0ceeSJacob Faibussowitsch   default:
34098921bdaSJacob Faibussowitsch     SETERRQ(comm,PETSC_ERR_PLIB,"PETSc was seemingly configured for PetscDeviceType %s but we've fallen through all cases in a switch",PetscDeviceTypes[type]);
341a4af0ceeSJacob Faibussowitsch   }
342cf3a2253SJacob Faibussowitsch   /*
343cf3a2253SJacob Faibussowitsch     defaultInitType and defaultDeviceId now represent what the individual TYPES have decided to
344cf3a2253SJacob Faibussowitsch     initialize as
345cf3a2253SJacob Faibussowitsch   */
346a4af0ceeSJacob Faibussowitsch   if (*defaultInitType == PETSC_DEVICE_INIT_EAGER) {
3477a101e5eSJacob Faibussowitsch     PetscCall(PetscLogInitialize());
3489566063dSJacob Faibussowitsch     PetscCall(PetscInfo(PETSC_NULLPTR,"Eagerly initializing %s PetscDevice\n",PetscDeviceTypes[type]));
3499566063dSJacob Faibussowitsch     PetscCall(PetscDeviceInitializeDefaultDevice_Internal(type,defaultDeviceId));
350a4af0ceeSJacob Faibussowitsch     if (defaultView) {
351a4af0ceeSJacob Faibussowitsch       PetscViewer vwr;
352a4af0ceeSJacob Faibussowitsch 
3539566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIGetStdout(comm,&vwr));
3549566063dSJacob Faibussowitsch       PetscCall(PetscDeviceView(defaultDevices[type],vwr));
355a4af0ceeSJacob Faibussowitsch     }
356030f984aSJacob Faibussowitsch   }
357030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
358030f984aSJacob Faibussowitsch }
359030f984aSJacob Faibussowitsch 
360030f984aSJacob Faibussowitsch /* called from PetscFinalize() do not call yourself! */
361a4af0ceeSJacob Faibussowitsch static PetscErrorCode PetscDeviceFinalize_Private(void)
362030f984aSJacob Faibussowitsch {
363030f984aSJacob Faibussowitsch   PetscFunctionBegin;
364a4af0ceeSJacob Faibussowitsch   if (PetscDefined(USE_DEBUG)) {
365bf025ffbSJacob Faibussowitsch     const auto PetscDeviceCheckAllDestroyedAfterFinalize = []{
366a4af0ceeSJacob Faibussowitsch       PetscFunctionBegin;
367bf025ffbSJacob Faibussowitsch       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);
368a4af0ceeSJacob Faibussowitsch       PetscFunctionReturn(0);
369a4af0ceeSJacob Faibussowitsch     };
370bf025ffbSJacob Faibussowitsch     /*
371bf025ffbSJacob Faibussowitsch       you might be thinking, why on earth are you registered yet another finalizer in a
372bf025ffbSJacob Faibussowitsch       function already called during PetscRegisterFinalizeAll()? If this seems stupid it's
373bf025ffbSJacob Faibussowitsch       because it is.
374bf025ffbSJacob Faibussowitsch 
375bf025ffbSJacob Faibussowitsch       The crux of the problem is that the initializer (and therefore the ~finalizer~) of
376bf025ffbSJacob Faibussowitsch       PetscDeviceContext is guaranteed to run after PetscDevice's. So if the global context had
377bf025ffbSJacob Faibussowitsch       a default PetscDevice attached, that PetscDevice will have a reference count >0 and hence
378bf025ffbSJacob Faibussowitsch       won't be destroyed yet. So we need to repeat the check that all devices have been
379bf025ffbSJacob Faibussowitsch       destroyed again ~after~ the global context is destroyed. In summary:
380bf025ffbSJacob Faibussowitsch 
381bf025ffbSJacob Faibussowitsch       1. This finalizer runs and destroys all devices, except it may not because the global
382bf025ffbSJacob Faibussowitsch          context may still hold a reference!
383bf025ffbSJacob Faibussowitsch       2. The global context finalizer runs and does the final reference count decrement
384bf025ffbSJacob Faibussowitsch          required, which actually destroys the held device.
385bf025ffbSJacob Faibussowitsch       3. Our newly added finalizer runs and checks that all is well.
386a4af0ceeSJacob Faibussowitsch     */
3879566063dSJacob Faibussowitsch     PetscCall(PetscRegisterFinalize(PetscDeviceCheckAllDestroyedAfterFinalize));
388a4af0ceeSJacob Faibussowitsch   }
3899566063dSJacob Faibussowitsch   for (auto &&device : defaultDevices) PetscCall(PetscDeviceDestroy(&device));
3909566063dSJacob Faibussowitsch   PetscCallCXX(initializedDevice.fill(false));
391030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
392030f984aSJacob Faibussowitsch }
393030f984aSJacob Faibussowitsch 
394cf3a2253SJacob Faibussowitsch /*
395cf3a2253SJacob Faibussowitsch   Begins the init proceeedings for the entire PetscDevice stack. there are 3 stages of
396cf3a2253SJacob Faibussowitsch   initialization types:
397cf3a2253SJacob Faibussowitsch 
398a4af0ceeSJacob Faibussowitsch   1. defaultInitType - how does PetscDevice as a whole expect to initialize?
399a4af0ceeSJacob Faibussowitsch   2. subTypeDefaultInitType - how does each PetscDevice implementation expect to initialize?
400a4af0ceeSJacob Faibussowitsch      e.g. you may want to blanket disable PetscDevice init (and disable say Kokkos init), but
401a4af0ceeSJacob Faibussowitsch      have all CUDA devices still initialize.
402a4af0ceeSJacob Faibussowitsch 
403a4af0ceeSJacob Faibussowitsch   All told the following happens:
404cf3a2253SJacob Faibussowitsch 
405a4af0ceeSJacob Faibussowitsch   0. defaultInitType -> LAZY
406a4af0ceeSJacob Faibussowitsch   1. Check for log_view/log_summary, if yes defaultInitType -> EAGER
407a4af0ceeSJacob Faibussowitsch   2. PetscDevice initializes each sub type with deviceDefaultInitType.
408a4af0ceeSJacob Faibussowitsch   2.1 Each enabled PetscDevice sub-type then does the above disable or view check in addition
409a4af0ceeSJacob Faibussowitsch       to checking for specific device init. if view or specific device init
410a4af0ceeSJacob Faibussowitsch       subTypeDefaultInitType -> EAGER. disabled once again overrides all.
411a4af0ceeSJacob Faibussowitsch */
412a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceInitializeFromOptions_Internal(MPI_Comm comm)
413030f984aSJacob Faibussowitsch {
4147a101e5eSJacob Faibussowitsch   auto                defaultView                    = PETSC_FALSE;
4157a101e5eSJacob Faibussowitsch   auto                initializeDeviceContextEagerly = PETSC_FALSE;
4167a101e5eSJacob Faibussowitsch   auto                defaultDevice                  = PetscInt{PETSC_DECIDE};
4177a101e5eSJacob Faibussowitsch   auto                deviceContextInitDevice        = PETSC_DEVICE_DEFAULT;
418a4af0ceeSJacob Faibussowitsch   PetscDeviceInitType defaultInitType;
419a4af0ceeSJacob Faibussowitsch 
420a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
421a4af0ceeSJacob Faibussowitsch   if (PetscDefined(USE_DEBUG)) {
422a4af0ceeSJacob Faibussowitsch     int result;
423a4af0ceeSJacob Faibussowitsch 
4249566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_compare(comm,PETSC_COMM_WORLD,&result));
425a4af0ceeSJacob Faibussowitsch     /* in order to accurately assign ranks to gpus we need to get the MPI_Comm_rank of the
426a4af0ceeSJacob Faibussowitsch      * global space */
427a4af0ceeSJacob Faibussowitsch     if (PetscUnlikely(result != MPI_IDENT)) {
428a4af0ceeSJacob Faibussowitsch       char name[MPI_MAX_OBJECT_NAME] = {};
429a4af0ceeSJacob Faibussowitsch       int  len; /* unused */
430a4af0ceeSJacob Faibussowitsch 
4319566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_get_name(comm,name,&len));
43298921bdaSJacob Faibussowitsch       SETERRQ(comm,PETSC_ERR_MPI,"Default devices being initialized on MPI_Comm '%s' not PETSC_COMM_WORLD",name);
433a4af0ceeSJacob Faibussowitsch     }
434a4af0ceeSJacob Faibussowitsch   }
435a4af0ceeSJacob Faibussowitsch   comm = PETSC_COMM_WORLD; /* from this point on we assume we're on PETSC_COMM_WORLD */
4369566063dSJacob Faibussowitsch   PetscCall(PetscRegisterFinalize(PetscDeviceFinalize_Private));
437a4af0ceeSJacob Faibussowitsch 
4387a101e5eSJacob Faibussowitsch   {
4397a101e5eSJacob Faibussowitsch     PetscInt  initIdx = PETSC_DEVICE_INIT_LAZY;
4407a101e5eSJacob Faibussowitsch     PetscBool flg;
4417a101e5eSJacob Faibussowitsch 
4427a101e5eSJacob Faibussowitsch     PetscCall(PetscOptionsHasName(PETSC_NULLPTR,PETSC_NULLPTR,"-log_view_gpu_time",&flg));
4437a101e5eSJacob Faibussowitsch     if (flg) PetscCall(PetscLogGpuTime());
4447a101e5eSJacob Faibussowitsch 
4457a101e5eSJacob Faibussowitsch     /* ----------------------------------------------------------------------------------- */
4467a101e5eSJacob Faibussowitsch     /*                              Global PetscDevice Options                             */
4477a101e5eSJacob Faibussowitsch     /* ----------------------------------------------------------------------------------- */
448d0609cedSBarry Smith     PetscOptionsBegin(comm,PETSC_NULLPTR,"PetscDevice Options","Sys");
4499566063dSJacob Faibussowitsch     PetscCall(PetscOptionsEList("-device_enable","How (or whether) to initialize PetscDevices","PetscDeviceInitializeFromOptions_Internal()",PetscDeviceInitTypes,3,PetscDeviceInitTypes[initIdx],&initIdx,PETSC_NULLPTR));
4509566063dSJacob Faibussowitsch     PetscCall(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()));
4519566063dSJacob Faibussowitsch     PetscCall(PetscOptionsBool("-device_view","Display device information and assignments (forces eager initialization)",PETSC_NULLPTR,defaultView,&defaultView,&flg));
452d0609cedSBarry Smith     PetscOptionsEnd();
4537a101e5eSJacob Faibussowitsch 
454a4af0ceeSJacob Faibussowitsch     if (initIdx == PETSC_DEVICE_INIT_NONE) {
455a4af0ceeSJacob Faibussowitsch       /* disabled all device initialization if devices are globally disabled */
456bf025ffbSJacob Faibussowitsch       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");
457a4af0ceeSJacob Faibussowitsch       defaultView = PETSC_FALSE;
458a4af0ceeSJacob Faibussowitsch     } else {
459a4af0ceeSJacob Faibussowitsch       defaultView = static_cast<decltype(defaultView)>(defaultView && flg);
460a4af0ceeSJacob Faibussowitsch       if (defaultView) initIdx = PETSC_DEVICE_INIT_EAGER;
461a4af0ceeSJacob Faibussowitsch     }
462a4af0ceeSJacob Faibussowitsch     defaultInitType = static_cast<decltype(defaultInitType)>(initIdx);
463a4af0ceeSJacob Faibussowitsch   }
464a4af0ceeSJacob Faibussowitsch   static_assert((PETSC_DEVICE_INVALID == 0) && (PETSC_DEVICE_MAX < std::numeric_limits<int>::max()),"");
465a4af0ceeSJacob Faibussowitsch   for (int i = 1; i < PETSC_DEVICE_MAX; ++i) {
466a4af0ceeSJacob Faibussowitsch     const auto deviceType = static_cast<PetscDeviceType>(i);
467a4af0ceeSJacob Faibussowitsch     auto initType         = defaultInitType;
468a4af0ceeSJacob Faibussowitsch 
4699566063dSJacob Faibussowitsch     PetscCall(PetscDeviceInitializeTypeFromOptions_Private(comm,deviceType,defaultDevice,defaultView,&initType));
470a4af0ceeSJacob Faibussowitsch     if (PetscDeviceConfiguredFor_Internal(deviceType) && (initType == PETSC_DEVICE_INIT_EAGER)) {
471a4af0ceeSJacob Faibussowitsch       initializeDeviceContextEagerly = PETSC_TRUE;
472a4af0ceeSJacob Faibussowitsch       deviceContextInitDevice        = deviceType;
4737a101e5eSJacob Faibussowitsch       PetscCall(PetscInfo(PETSC_NULLPTR,"PetscDevice %s set as default device type due to eager initialization\n",PetscDeviceTypes[deviceType]));
474a4af0ceeSJacob Faibussowitsch     }
475a4af0ceeSJacob Faibussowitsch   }
476a4af0ceeSJacob Faibussowitsch   if (initializeDeviceContextEagerly) {
477a4af0ceeSJacob Faibussowitsch     PetscDeviceContext dctx;
478a4af0ceeSJacob Faibussowitsch 
479cf3a2253SJacob Faibussowitsch     /*
480cf3a2253SJacob Faibussowitsch       somewhat inefficient here as the device context is potentially fully set up twice (once
481cf3a2253SJacob Faibussowitsch       when retrieved then the second time if setfromoptions makes changes)
482cf3a2253SJacob Faibussowitsch     */
4839566063dSJacob Faibussowitsch     PetscCall(PetscInfo(PETSC_NULLPTR,"Eagerly initializing PetscDeviceContext with %s device\n",PetscDeviceTypes[deviceContextInitDevice]));
4849566063dSJacob Faibussowitsch     PetscCall(PetscDeviceContextSetRootDeviceType_Internal(deviceContextInitDevice));
4859566063dSJacob Faibussowitsch     PetscCall(PetscDeviceContextGetCurrentContext(&dctx));
4869566063dSJacob Faibussowitsch     PetscCall(PetscDeviceContextSetFromOptions(comm,"root_",dctx));
4879566063dSJacob Faibussowitsch     PetscCall(PetscDeviceContextSetUp(dctx));
488a4af0ceeSJacob Faibussowitsch   }
489a4af0ceeSJacob Faibussowitsch   PetscFunctionReturn(0);
490a4af0ceeSJacob Faibussowitsch }
491a4af0ceeSJacob Faibussowitsch 
492a4af0ceeSJacob Faibussowitsch /* Get the default PetscDevice for a particular type and constructs them if lazily initialized. */
493a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceGetDefaultForType_Internal(PetscDeviceType type, PetscDevice *device)
494a4af0ceeSJacob Faibussowitsch {
495a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
496a4af0ceeSJacob Faibussowitsch   PetscValidPointer(device,2);
4979566063dSJacob Faibussowitsch   PetscCall(PetscDeviceInitialize(type));
498a4af0ceeSJacob Faibussowitsch   *device = defaultDevices[type];
499a4af0ceeSJacob Faibussowitsch   PetscFunctionReturn(0);
500030f984aSJacob Faibussowitsch }
501