xref: /petsc/src/sys/objects/device/interface/device.cxx (revision 9371c9d470a9602b6d10a8bf50c9b2280a79e45a)
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, "");
26*9371c9d4SSatish Balay const char *const PetscDeviceTypes[] = {"invalid", "cuda", "hip", "sycl", "max", "PetscDeviceType", "PETSC_DEVICE_", PETSC_NULLPTR};
27a4af0ceeSJacob Faibussowitsch 
2817f48955SJacob Faibussowitsch static_assert(Petsc::util::integral_value(PETSC_DEVICE_INIT_NONE) == 0, "");
2917f48955SJacob Faibussowitsch static_assert(Petsc::util::integral_value(PETSC_DEVICE_INIT_LAZY) == 1, "");
3017f48955SJacob Faibussowitsch static_assert(Petsc::util::integral_value(PETSC_DEVICE_INIT_EAGER) == 2, "");
31*9371c9d4SSatish Balay const char *const PetscDeviceInitTypes[] = {"none", "lazy", "eager", "PetscDeviceInitType", "PETSC_DEVICE_INIT_", PETSC_NULLPTR};
32*9371c9d4SSatish Balay static_assert(sizeof(PetscDeviceInitTypes) / sizeof(*PetscDeviceInitTypes) == 6, "Must change CUPMDevice<T>::initialize number of enum values in -device_enable_cupm to match!");
33a4af0ceeSJacob Faibussowitsch 
3417f48955SJacob Faibussowitsch #define PETSC_DEVICE_CASE(IMPLS, func, ...) \
3517f48955SJacob Faibussowitsch   case PetscConcat_(PETSC_DEVICE_, IMPLS): { \
369566063dSJacob Faibussowitsch     PetscCall(PetscConcat_(IMPLS, Device).func(__VA_ARGS__)); \
3717f48955SJacob Faibussowitsch   } break
38a4af0ceeSJacob Faibussowitsch 
39cf3a2253SJacob Faibussowitsch /*
40cf3a2253SJacob Faibussowitsch   Suppose you have:
41cf3a2253SJacob Faibussowitsch 
42cf3a2253SJacob Faibussowitsch   CUDADevice.myFunction(arg1,arg2)
43cf3a2253SJacob Faibussowitsch 
44cf3a2253SJacob Faibussowitsch   that you would like to conditionally define and call in a switch-case:
45cf3a2253SJacob Faibussowitsch 
46cf3a2253SJacob Faibussowitsch   switch(PetscDeviceType) {
47cf3a2253SJacob Faibussowitsch   #if PetscDefined(HAVE_CUDA)
48cf3a2253SJacob Faibussowitsch   case PETSC_DEVICE_CUDA: {
499566063dSJacob Faibussowitsch     PetscCall(CUDADevice.myFunction(arg1,arg2));
50cf3a2253SJacob Faibussowitsch   } break;
51cf3a2253SJacob Faibussowitsch   #endif
52cf3a2253SJacob Faibussowitsch   }
53cf3a2253SJacob Faibussowitsch 
54cf3a2253SJacob Faibussowitsch   then calling this macro:
55cf3a2253SJacob Faibussowitsch 
56cf3a2253SJacob Faibussowitsch   PETSC_DEVICE_CASE_IF_PETSC_DEFINED(CUDA,myFunction,arg1,arg2)
57cf3a2253SJacob Faibussowitsch 
58cf3a2253SJacob Faibussowitsch   will expand to the following case statement:
59cf3a2253SJacob Faibussowitsch 
60cf3a2253SJacob Faibussowitsch   case PETSC_DEVICE_CUDA: {
619566063dSJacob Faibussowitsch     PetscCall(CUDADevice.myFunction(arg1,arg2));
62cf3a2253SJacob Faibussowitsch   } break
63cf3a2253SJacob Faibussowitsch 
64cf3a2253SJacob Faibussowitsch   if PetscDefined(HAVE_CUDA) evaluates to 1, and expand to nothing otherwise
6517f48955SJacob Faibussowitsch */
66*9371c9d4SSatish Balay #define PETSC_DEVICE_CASE_IF_PETSC_DEFINED(IMPLS, func, ...) PetscIfPetscDefined(PetscConcat_(HAVE_, IMPLS), PETSC_DEVICE_CASE, PetscExpandToNothing)(IMPLS, func, __VA_ARGS__)
67030f984aSJacob Faibussowitsch 
68030f984aSJacob Faibussowitsch /*@C
69a4af0ceeSJacob Faibussowitsch   PetscDeviceCreate - Get a new handle for a particular device type
70030f984aSJacob Faibussowitsch 
71030f984aSJacob Faibussowitsch   Not Collective, Possibly Synchronous
72030f984aSJacob Faibussowitsch 
73f1a722f8SMatthew G. Knepley   Input Parameters:
74f1a722f8SMatthew G. Knepley + type  - The type of PetscDevice
75f1a722f8SMatthew G. Knepley - devid - The numeric ID# of the device (pass PETSC_DECIDE to assign automatically)
76030f984aSJacob Faibussowitsch 
77030f984aSJacob Faibussowitsch   Output Parameter:
78030f984aSJacob Faibussowitsch . device - The PetscDevice
79030f984aSJacob Faibussowitsch 
80030f984aSJacob Faibussowitsch   Notes:
81a4af0ceeSJacob Faibussowitsch   This routine may initialize PetscDevice. If this is the case, this will most likely cause
82a4af0ceeSJacob Faibussowitsch   some sort of device synchronization.
83a4af0ceeSJacob Faibussowitsch 
84a4af0ceeSJacob Faibussowitsch   devid is what you might pass to cudaSetDevice() for example.
85030f984aSJacob Faibussowitsch 
86030f984aSJacob Faibussowitsch   Level: beginner
87030f984aSJacob Faibussowitsch 
88db781477SPatrick Sanan .seealso: `PetscDevice`, `PetscDeviceInitType`, `PetscDeviceInitialize()`,
89db781477SPatrick Sanan           `PetscDeviceInitialized()`, `PetscDeviceConfigure()`, `PetscDeviceView()`, `PetscDeviceDestroy()`
90030f984aSJacob Faibussowitsch @*/
91*9371c9d4SSatish Balay PetscErrorCode PetscDeviceCreate(PetscDeviceType type, PetscInt devid, PetscDevice *device) {
92030f984aSJacob Faibussowitsch   static PetscInt PetscDeviceCounter = 0;
93030f984aSJacob Faibussowitsch   PetscDevice     dev;
94030f984aSJacob Faibussowitsch 
95030f984aSJacob Faibussowitsch   PetscFunctionBegin;
96a4af0ceeSJacob Faibussowitsch   PetscValidDeviceType(type, 1);
97a4af0ceeSJacob Faibussowitsch   PetscValidPointer(device, 3);
989566063dSJacob Faibussowitsch   PetscCall(PetscDeviceInitializePackage());
999566063dSJacob Faibussowitsch   PetscCall(PetscNew(&dev));
100030f984aSJacob Faibussowitsch   dev->id     = PetscDeviceCounter++;
101a4af0ceeSJacob Faibussowitsch   dev->type   = type;
102a4af0ceeSJacob Faibussowitsch   dev->refcnt = 1;
103cf3a2253SJacob Faibussowitsch   /*
104cf3a2253SJacob Faibussowitsch     if you are adding a device, you also need to add it's initialization in
105cf3a2253SJacob Faibussowitsch     PetscDeviceInitializeTypeFromOptions_Private() below
106cf3a2253SJacob Faibussowitsch   */
107a4af0ceeSJacob Faibussowitsch   switch (type) {
108a4af0ceeSJacob Faibussowitsch     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(CUDA, getDevice, dev, devid);
109a4af0ceeSJacob Faibussowitsch     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(HIP, getDevice, dev, devid);
110a2158755SJunchao Zhang     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(SYCL, getDevice, dev, devid);
111030f984aSJacob Faibussowitsch   default:
11217f48955SJacob Faibussowitsch     /* in case the above macros expand to nothing this silences any unused variable warnings */
11317f48955SJacob Faibussowitsch     (void)(devid);
11498921bdaSJacob 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]);
115030f984aSJacob Faibussowitsch   }
116030f984aSJacob Faibussowitsch   *device = dev;
117030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
118030f984aSJacob Faibussowitsch }
119030f984aSJacob Faibussowitsch 
120030f984aSJacob Faibussowitsch /*@C
121030f984aSJacob Faibussowitsch   PetscDeviceDestroy - Free a PetscDevice
122030f984aSJacob Faibussowitsch 
123030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
124030f984aSJacob Faibussowitsch 
125030f984aSJacob Faibussowitsch   Input Parameter:
126030f984aSJacob Faibussowitsch . device - The PetscDevice
127030f984aSJacob Faibussowitsch 
128030f984aSJacob Faibussowitsch   Level: beginner
129030f984aSJacob Faibussowitsch 
130db781477SPatrick Sanan .seealso: `PetscDevice`, `PetscDeviceCreate()`, `PetscDeviceConfigure()`, `PetscDeviceView()`
131030f984aSJacob Faibussowitsch @*/
132*9371c9d4SSatish Balay PetscErrorCode PetscDeviceDestroy(PetscDevice *device) {
133a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
134a4af0ceeSJacob Faibussowitsch   if (!*device) PetscFunctionReturn(0);
135a4af0ceeSJacob Faibussowitsch   PetscValidDevice(*device, 1);
1369566063dSJacob Faibussowitsch   PetscCall(PetscDeviceDereference_Internal(*device));
137a4af0ceeSJacob Faibussowitsch   if ((*device)->refcnt) {
138a4af0ceeSJacob Faibussowitsch     *device = PETSC_NULLPTR;
139a4af0ceeSJacob Faibussowitsch     PetscFunctionReturn(0);
140030f984aSJacob Faibussowitsch   }
1419566063dSJacob Faibussowitsch   PetscCall(PetscFree((*device)->data));
1429566063dSJacob Faibussowitsch   PetscCall(PetscFree(*device));
143030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
144030f984aSJacob Faibussowitsch }
145030f984aSJacob Faibussowitsch 
146a4af0ceeSJacob Faibussowitsch /*@C
147a4af0ceeSJacob Faibussowitsch   PetscDeviceConfigure - Configure a particular PetscDevice
148030f984aSJacob Faibussowitsch 
149a4af0ceeSJacob Faibussowitsch   Not Collective, Asynchronous
150a4af0ceeSJacob Faibussowitsch 
151a4af0ceeSJacob Faibussowitsch   Input Parameter:
152a4af0ceeSJacob Faibussowitsch . device - The PetscDevice to configure
153a4af0ceeSJacob Faibussowitsch 
154a4af0ceeSJacob Faibussowitsch   Notes:
155a4af0ceeSJacob Faibussowitsch   The user should not assume that this is a cheap operation
156a4af0ceeSJacob Faibussowitsch 
157a4af0ceeSJacob Faibussowitsch   Level: beginner
158a4af0ceeSJacob Faibussowitsch 
159db781477SPatrick Sanan .seealso: `PetscDevice`, `PetscDeviceCreate()`, `PetscDeviceView()`, `PetscDeviceDestroy()`
160a4af0ceeSJacob Faibussowitsch @*/
161*9371c9d4SSatish Balay PetscErrorCode PetscDeviceConfigure(PetscDevice device) {
162030f984aSJacob Faibussowitsch   PetscFunctionBegin;
163a4af0ceeSJacob Faibussowitsch   PetscValidDevice(device, 1);
164a4af0ceeSJacob Faibussowitsch   if (PetscDefined(USE_DEBUG)) {
165cf3a2253SJacob Faibussowitsch     /*
166cf3a2253SJacob Faibussowitsch       if no available configuration is available, this cascades all the way down to default
167cf3a2253SJacob Faibussowitsch       and error
168cf3a2253SJacob Faibussowitsch     */
169a4af0ceeSJacob Faibussowitsch     switch (device->type) {
170*9371c9d4SSatish Balay     case PETSC_DEVICE_CUDA:
171*9371c9d4SSatish Balay       if (PetscDefined(HAVE_CUDA)) break;
172*9371c9d4SSatish Balay     case PETSC_DEVICE_HIP:
173*9371c9d4SSatish Balay       if (PetscDefined(HAVE_HIP)) break;
174*9371c9d4SSatish Balay     case PETSC_DEVICE_SYCL:
175*9371c9d4SSatish Balay       if (PetscDefined(HAVE_SYCL)) break;
176*9371c9d4SSatish Balay     default: 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]);
177a4af0ceeSJacob Faibussowitsch     }
178a4af0ceeSJacob Faibussowitsch   }
179dbbe0bcdSBarry Smith   PetscUseTypeMethod(device, configure);
180a4af0ceeSJacob Faibussowitsch   PetscFunctionReturn(0);
181a4af0ceeSJacob Faibussowitsch }
182a4af0ceeSJacob Faibussowitsch 
183a4af0ceeSJacob Faibussowitsch /*@C
184a4af0ceeSJacob Faibussowitsch   PetscDeviceView - View a PetscDevice
185a4af0ceeSJacob Faibussowitsch 
186a4af0ceeSJacob Faibussowitsch   Collective on viewer, Asynchronous
187a4af0ceeSJacob Faibussowitsch 
18891e63d38SStefano Zampini   Input Parameters:
189050c0c3dSJacob Faibussowitsch + device - The PetscDevice to view
190a4af0ceeSJacob Faibussowitsch - viewer - The PetscViewer to view the device with (NULL for PETSC_VIEWER_STDOUT_WORLD)
191a4af0ceeSJacob Faibussowitsch 
192a4af0ceeSJacob Faibussowitsch   Level: beginner
193a4af0ceeSJacob Faibussowitsch 
194db781477SPatrick Sanan .seealso: `PetscDevice`, `PetscDeviceCreate()`, `PetscDeviceConfigure()`, `PetscDeviceDestroy()`
195a4af0ceeSJacob Faibussowitsch @*/
196*9371c9d4SSatish Balay PetscErrorCode PetscDeviceView(PetscDevice device, PetscViewer viewer) {
197a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
198a4af0ceeSJacob Faibussowitsch   PetscValidDevice(device, 1);
1999566063dSJacob Faibussowitsch   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PETSC_COMM_WORLD, &viewer));
200a4af0ceeSJacob Faibussowitsch   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
201dbbe0bcdSBarry Smith   PetscUseTypeMethod(device, view, viewer);
202a4af0ceeSJacob Faibussowitsch   PetscFunctionReturn(0);
203a4af0ceeSJacob Faibussowitsch }
204a4af0ceeSJacob Faibussowitsch 
20591e63d38SStefano Zampini /*@C
20691e63d38SStefano Zampini   PetscDeviceGetDeviceId - Get the device id
20791e63d38SStefano Zampini 
20891e63d38SStefano Zampini   Not collective
20991e63d38SStefano Zampini 
21091e63d38SStefano Zampini   Input Parameter:
21191e63d38SStefano Zampini . device - The PetscDevice
21291e63d38SStefano Zampini 
21391e63d38SStefano Zampini   Output Parameter:
21491e63d38SStefano Zampini . id - The device id
21591e63d38SStefano Zampini 
21691e63d38SStefano Zampini   Level: beginner
21791e63d38SStefano Zampini 
218db781477SPatrick Sanan .seealso: `PetscDevice`, `PetscDeviceCreate()`, `PetscDeviceConfigure()`, `PetscDeviceDestroy()`
21991e63d38SStefano Zampini @*/
220*9371c9d4SSatish Balay PetscErrorCode PetscDeviceGetDeviceId(PetscDevice device, PetscInt *id) {
22191e63d38SStefano Zampini   PetscFunctionBegin;
22291e63d38SStefano Zampini   PetscValidDevice(device, 1);
22391e63d38SStefano Zampini   PetscValidIntPointer(id, 2);
22491e63d38SStefano Zampini   *id = device->deviceId;
22591e63d38SStefano Zampini   PetscFunctionReturn(0);
22691e63d38SStefano Zampini }
22791e63d38SStefano Zampini 
228a4af0ceeSJacob Faibussowitsch static std::array<bool, PETSC_DEVICE_MAX>        initializedDevice = {};
229a4af0ceeSJacob Faibussowitsch static std::array<PetscDevice, PETSC_DEVICE_MAX> defaultDevices    = {};
230a4af0ceeSJacob Faibussowitsch static_assert(initializedDevice.size() == defaultDevices.size(), "");
231a4af0ceeSJacob Faibussowitsch 
232a4af0ceeSJacob Faibussowitsch /*@C
233a4af0ceeSJacob Faibussowitsch   PetscDeviceInitialize - Initialize PetscDevice
234a4af0ceeSJacob Faibussowitsch 
235a4af0ceeSJacob Faibussowitsch   Not Collective, Possibly Synchronous
236a4af0ceeSJacob Faibussowitsch 
237a4af0ceeSJacob Faibussowitsch   Input Parameter:
238a4af0ceeSJacob Faibussowitsch . type - The PetscDeviceType to initialize
239a4af0ceeSJacob Faibussowitsch 
240a4af0ceeSJacob Faibussowitsch   Notes:
241a4af0ceeSJacob Faibussowitsch   Eagerly initializes the corresponding PetscDeviceType if needed.
242a4af0ceeSJacob Faibussowitsch 
243a4af0ceeSJacob Faibussowitsch   Level: beginner
244a4af0ceeSJacob Faibussowitsch 
245db781477SPatrick Sanan .seealso: `PetscDevice`, `PetscDeviceInitType`, `PetscDeviceInitialized()`, `PetscDeviceCreate()`, `PetscDeviceDestroy()`
246a4af0ceeSJacob Faibussowitsch @*/
247*9371c9d4SSatish Balay PetscErrorCode PetscDeviceInitialize(PetscDeviceType type) {
248a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
249a4af0ceeSJacob Faibussowitsch   PetscValidDeviceType(type, 1);
2509566063dSJacob Faibussowitsch   PetscCall(PetscDeviceInitializeDefaultDevice_Internal(type, PETSC_DECIDE));
251a4af0ceeSJacob Faibussowitsch   PetscFunctionReturn(0);
252a4af0ceeSJacob Faibussowitsch }
253a4af0ceeSJacob Faibussowitsch 
254a4af0ceeSJacob Faibussowitsch /*@C
255a4af0ceeSJacob Faibussowitsch   PetscDeviceInitialized - Determines whether PetscDevice is initialized for a particular
256a4af0ceeSJacob Faibussowitsch   PetscDeviceType
257a4af0ceeSJacob Faibussowitsch 
258a4af0ceeSJacob Faibussowitsch   Not Collective, Asynchronous
259a4af0ceeSJacob Faibussowitsch 
260a4af0ceeSJacob Faibussowitsch   Input Parameter:
261a4af0ceeSJacob Faibussowitsch . type - The PetscDeviceType to check
262a4af0ceeSJacob Faibussowitsch 
263a4af0ceeSJacob Faibussowitsch   Output Parameter:
264a4af0ceeSJacob Faibussowitsch . [return value] - PETSC_TRUE if type is initialized, PETSC_FALSE otherwise
265a4af0ceeSJacob Faibussowitsch 
266a4af0ceeSJacob Faibussowitsch   Notes:
267a4af0ceeSJacob Faibussowitsch   If one has not configured PETSc for a particular PetscDeviceType then this routine will
268a4af0ceeSJacob Faibussowitsch   return PETSC_FALSE for that PetscDeviceType.
269a4af0ceeSJacob Faibussowitsch 
270a4af0ceeSJacob Faibussowitsch   Level: beginner
271a4af0ceeSJacob Faibussowitsch 
272db781477SPatrick Sanan .seealso: `PetscDevice`, `PetscDeviceInitType`, `PetscDeviceInitialize()`, `PetscDeviceCreate()`, `PetscDeviceDestroy()`
273a4af0ceeSJacob Faibussowitsch @*/
274*9371c9d4SSatish Balay PetscBool PetscDeviceInitialized(PetscDeviceType type) {
275a4af0ceeSJacob Faibussowitsch   return static_cast<PetscBool>(PetscDeviceConfiguredFor_Internal(type) && initializedDevice[type]);
276a4af0ceeSJacob Faibussowitsch }
277a4af0ceeSJacob Faibussowitsch 
278cf3a2253SJacob Faibussowitsch /*
279cf3a2253SJacob Faibussowitsch   Actual intialization function; any functions claiming to initialize PetscDevice or
280cf3a2253SJacob Faibussowitsch   PetscDeviceContext will have to run through this one
281cf3a2253SJacob Faibussowitsch */
282*9371c9d4SSatish Balay PetscErrorCode PetscDeviceInitializeDefaultDevice_Internal(PetscDeviceType type, PetscInt defaultDeviceId) {
283a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
284a4af0ceeSJacob Faibussowitsch   PetscValidDeviceType(type, 1);
285a4af0ceeSJacob Faibussowitsch   if (PetscLikely(PetscDeviceInitialized(type))) PetscFunctionReturn(0);
286bf025ffbSJacob Faibussowitsch   PetscAssert(!defaultDevices[type], PETSC_COMM_SELF, PETSC_ERR_MEM, "Trying to overwrite existing default device of type %s", PetscDeviceTypes[type]);
2879566063dSJacob Faibussowitsch   PetscCall(PetscDeviceCreate(type, defaultDeviceId, &defaultDevices[type]));
2889566063dSJacob Faibussowitsch   PetscCall(PetscDeviceConfigure(defaultDevices[type]));
289a4af0ceeSJacob Faibussowitsch   initializedDevice[type] = true;
290a4af0ceeSJacob Faibussowitsch   PetscFunctionReturn(0);
291a4af0ceeSJacob Faibussowitsch }
292a4af0ceeSJacob Faibussowitsch 
293ce244043SStefano Zampini #if PetscDefined(USE_LOG)
294ce244043SStefano Zampini PETSC_INTERN PetscErrorCode PetscLogInitialize(void);
295ce244043SStefano Zampini #else
296ce244043SStefano Zampini #define PetscLogInitialize() 0
297ce244043SStefano Zampini #endif
298ce244043SStefano Zampini 
299*9371c9d4SSatish Balay static PetscErrorCode PetscDeviceInitializeTypeFromOptions_Private(MPI_Comm comm, PetscDeviceType type, PetscInt defaultDeviceId, PetscBool defaultView, PetscDeviceInitType *defaultInitType) {
300a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
301a4af0ceeSJacob Faibussowitsch   if (!PetscDeviceConfiguredFor_Internal(type)) {
3029566063dSJacob Faibussowitsch     PetscCall(PetscInfo(PETSC_NULLPTR, "PetscDeviceType %s not supported\n", PetscDeviceTypes[type]));
303a4af0ceeSJacob Faibussowitsch     defaultDevices[type] = PETSC_NULLPTR;
304a4af0ceeSJacob Faibussowitsch     PetscFunctionReturn(0);
305a4af0ceeSJacob Faibussowitsch   }
3069566063dSJacob Faibussowitsch   PetscCall(PetscInfo(PETSC_NULLPTR, "PetscDeviceType %s supported, initializing\n", PetscDeviceTypes[type]));
307a4af0ceeSJacob Faibussowitsch   /* ugly switch needed to pick the right global variable... could maybe do this as a union? */
308a4af0ceeSJacob Faibussowitsch   switch (type) {
309a4af0ceeSJacob Faibussowitsch     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(CUDA, initialize, comm, &defaultDeviceId, defaultInitType);
310a4af0ceeSJacob Faibussowitsch     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(HIP, initialize, comm, &defaultDeviceId, defaultInitType);
311a2158755SJunchao Zhang     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(SYCL, initialize, comm, &defaultDeviceId, defaultInitType);
312*9371c9d4SSatish Balay   default: SETERRQ(comm, PETSC_ERR_PLIB, "PETSc was seemingly configured for PetscDeviceType %s but we've fallen through all cases in a switch", PetscDeviceTypes[type]);
313a4af0ceeSJacob Faibussowitsch   }
314cf3a2253SJacob Faibussowitsch   /*
315cf3a2253SJacob Faibussowitsch     defaultInitType and defaultDeviceId now represent what the individual TYPES have decided to
316cf3a2253SJacob Faibussowitsch     initialize as
317cf3a2253SJacob Faibussowitsch   */
318a4af0ceeSJacob Faibussowitsch   if (*defaultInitType == PETSC_DEVICE_INIT_EAGER) {
3197a101e5eSJacob Faibussowitsch     PetscCall(PetscLogInitialize());
3209566063dSJacob Faibussowitsch     PetscCall(PetscInfo(PETSC_NULLPTR, "Eagerly initializing %s PetscDevice\n", PetscDeviceTypes[type]));
3219566063dSJacob Faibussowitsch     PetscCall(PetscDeviceInitializeDefaultDevice_Internal(type, defaultDeviceId));
322a4af0ceeSJacob Faibussowitsch     if (defaultView) {
323a4af0ceeSJacob Faibussowitsch       PetscViewer vwr;
324a4af0ceeSJacob Faibussowitsch 
3259566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIGetStdout(comm, &vwr));
3269566063dSJacob Faibussowitsch       PetscCall(PetscDeviceView(defaultDevices[type], vwr));
327a4af0ceeSJacob Faibussowitsch     }
328030f984aSJacob Faibussowitsch   }
329030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
330030f984aSJacob Faibussowitsch }
331030f984aSJacob Faibussowitsch 
332030f984aSJacob Faibussowitsch /* called from PetscFinalize() do not call yourself! */
333*9371c9d4SSatish Balay static PetscErrorCode PetscDeviceFinalize_Private(void) {
334030f984aSJacob Faibussowitsch   PetscFunctionBegin;
335a4af0ceeSJacob Faibussowitsch   if (PetscDefined(USE_DEBUG)) {
336bf025ffbSJacob Faibussowitsch     const auto PetscDeviceCheckAllDestroyedAfterFinalize = [] {
337a4af0ceeSJacob Faibussowitsch       PetscFunctionBegin;
338*9371c9d4SSatish Balay       for (auto &&device : defaultDevices)
339*9371c9d4SSatish Balay         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);
340a4af0ceeSJacob Faibussowitsch       PetscFunctionReturn(0);
341a4af0ceeSJacob Faibussowitsch     };
342bf025ffbSJacob Faibussowitsch     /*
343bf025ffbSJacob Faibussowitsch       you might be thinking, why on earth are you registered yet another finalizer in a
344bf025ffbSJacob Faibussowitsch       function already called during PetscRegisterFinalizeAll()? If this seems stupid it's
345bf025ffbSJacob Faibussowitsch       because it is.
346bf025ffbSJacob Faibussowitsch 
347bf025ffbSJacob Faibussowitsch       The crux of the problem is that the initializer (and therefore the ~finalizer~) of
348bf025ffbSJacob Faibussowitsch       PetscDeviceContext is guaranteed to run after PetscDevice's. So if the global context had
349bf025ffbSJacob Faibussowitsch       a default PetscDevice attached, that PetscDevice will have a reference count >0 and hence
350bf025ffbSJacob Faibussowitsch       won't be destroyed yet. So we need to repeat the check that all devices have been
351bf025ffbSJacob Faibussowitsch       destroyed again ~after~ the global context is destroyed. In summary:
352bf025ffbSJacob Faibussowitsch 
353bf025ffbSJacob Faibussowitsch       1. This finalizer runs and destroys all devices, except it may not because the global
354bf025ffbSJacob Faibussowitsch          context may still hold a reference!
355bf025ffbSJacob Faibussowitsch       2. The global context finalizer runs and does the final reference count decrement
356bf025ffbSJacob Faibussowitsch          required, which actually destroys the held device.
357bf025ffbSJacob Faibussowitsch       3. Our newly added finalizer runs and checks that all is well.
358a4af0ceeSJacob Faibussowitsch     */
3599566063dSJacob Faibussowitsch     PetscCall(PetscRegisterFinalize(PetscDeviceCheckAllDestroyedAfterFinalize));
360a4af0ceeSJacob Faibussowitsch   }
3619566063dSJacob Faibussowitsch   for (auto &&device : defaultDevices) PetscCall(PetscDeviceDestroy(&device));
3629566063dSJacob Faibussowitsch   PetscCallCXX(initializedDevice.fill(false));
363030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
364030f984aSJacob Faibussowitsch }
365030f984aSJacob Faibussowitsch 
366cf3a2253SJacob Faibussowitsch /*
367cf3a2253SJacob Faibussowitsch   Begins the init proceeedings for the entire PetscDevice stack. there are 3 stages of
368cf3a2253SJacob Faibussowitsch   initialization types:
369cf3a2253SJacob Faibussowitsch 
370a4af0ceeSJacob Faibussowitsch   1. defaultInitType - how does PetscDevice as a whole expect to initialize?
371a4af0ceeSJacob Faibussowitsch   2. subTypeDefaultInitType - how does each PetscDevice implementation expect to initialize?
372a4af0ceeSJacob Faibussowitsch      e.g. you may want to blanket disable PetscDevice init (and disable say Kokkos init), but
373a4af0ceeSJacob Faibussowitsch      have all CUDA devices still initialize.
374a4af0ceeSJacob Faibussowitsch 
375a4af0ceeSJacob Faibussowitsch   All told the following happens:
376cf3a2253SJacob Faibussowitsch 
377a4af0ceeSJacob Faibussowitsch   0. defaultInitType -> LAZY
378a4af0ceeSJacob Faibussowitsch   1. Check for log_view/log_summary, if yes defaultInitType -> EAGER
379a4af0ceeSJacob Faibussowitsch   2. PetscDevice initializes each sub type with deviceDefaultInitType.
380a4af0ceeSJacob Faibussowitsch   2.1 Each enabled PetscDevice sub-type then does the above disable or view check in addition
381a4af0ceeSJacob Faibussowitsch       to checking for specific device init. if view or specific device init
382a4af0ceeSJacob Faibussowitsch       subTypeDefaultInitType -> EAGER. disabled once again overrides all.
383a4af0ceeSJacob Faibussowitsch */
384*9371c9d4SSatish Balay PetscErrorCode PetscDeviceInitializeFromOptions_Internal(MPI_Comm comm) {
3857a101e5eSJacob Faibussowitsch   auto                defaultView                    = PETSC_FALSE;
3867a101e5eSJacob Faibussowitsch   auto                initializeDeviceContextEagerly = PETSC_FALSE;
3877a101e5eSJacob Faibussowitsch   auto                defaultDevice                  = PetscInt{PETSC_DECIDE};
3887a101e5eSJacob Faibussowitsch   auto                deviceContextInitDevice        = PETSC_DEVICE_DEFAULT;
389a4af0ceeSJacob Faibussowitsch   PetscDeviceInitType defaultInitType;
390a4af0ceeSJacob Faibussowitsch 
391a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
392a4af0ceeSJacob Faibussowitsch   if (PetscDefined(USE_DEBUG)) {
393a4af0ceeSJacob Faibussowitsch     int result;
394a4af0ceeSJacob Faibussowitsch 
3959566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_compare(comm, PETSC_COMM_WORLD, &result));
396a4af0ceeSJacob Faibussowitsch     /* in order to accurately assign ranks to gpus we need to get the MPI_Comm_rank of the
397a4af0ceeSJacob Faibussowitsch      * global space */
398a4af0ceeSJacob Faibussowitsch     if (PetscUnlikely(result != MPI_IDENT)) {
399a4af0ceeSJacob Faibussowitsch       char name[MPI_MAX_OBJECT_NAME] = {};
400a4af0ceeSJacob Faibussowitsch       int  len; /* unused */
401a4af0ceeSJacob Faibussowitsch 
4029566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_get_name(comm, name, &len));
40398921bdaSJacob Faibussowitsch       SETERRQ(comm, PETSC_ERR_MPI, "Default devices being initialized on MPI_Comm '%s' not PETSC_COMM_WORLD", name);
404a4af0ceeSJacob Faibussowitsch     }
405a4af0ceeSJacob Faibussowitsch   }
406a4af0ceeSJacob Faibussowitsch   comm = PETSC_COMM_WORLD; /* from this point on we assume we're on PETSC_COMM_WORLD */
4079566063dSJacob Faibussowitsch   PetscCall(PetscRegisterFinalize(PetscDeviceFinalize_Private));
408a4af0ceeSJacob Faibussowitsch 
4097a101e5eSJacob Faibussowitsch   {
4107a101e5eSJacob Faibussowitsch     PetscInt  initIdx = PETSC_DEVICE_INIT_LAZY;
4117a101e5eSJacob Faibussowitsch     PetscBool flg;
4127a101e5eSJacob Faibussowitsch 
4137a101e5eSJacob Faibussowitsch     PetscCall(PetscOptionsHasName(PETSC_NULLPTR, PETSC_NULLPTR, "-log_view_gpu_time", &flg));
4147a101e5eSJacob Faibussowitsch     if (flg) PetscCall(PetscLogGpuTime());
4157a101e5eSJacob Faibussowitsch 
4167a101e5eSJacob Faibussowitsch     /* ----------------------------------------------------------------------------------- */
4177a101e5eSJacob Faibussowitsch     /*                              Global PetscDevice Options                             */
4187a101e5eSJacob Faibussowitsch     /* ----------------------------------------------------------------------------------- */
419d0609cedSBarry Smith     PetscOptionsBegin(comm, PETSC_NULLPTR, "PetscDevice Options", "Sys");
4209566063dSJacob Faibussowitsch     PetscCall(PetscOptionsEList("-device_enable", "How (or whether) to initialize PetscDevices", "PetscDeviceInitializeFromOptions_Internal()", PetscDeviceInitTypes, 3, PetscDeviceInitTypes[initIdx], &initIdx, PETSC_NULLPTR));
4219566063dSJacob 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()));
4229566063dSJacob Faibussowitsch     PetscCall(PetscOptionsBool("-device_view", "Display device information and assignments (forces eager initialization)", PETSC_NULLPTR, defaultView, &defaultView, &flg));
423d0609cedSBarry Smith     PetscOptionsEnd();
4247a101e5eSJacob Faibussowitsch 
425a4af0ceeSJacob Faibussowitsch     if (initIdx == PETSC_DEVICE_INIT_NONE) {
426a4af0ceeSJacob Faibussowitsch       /* disabled all device initialization if devices are globally disabled */
427bf025ffbSJacob 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");
428a4af0ceeSJacob Faibussowitsch       defaultView = PETSC_FALSE;
429a4af0ceeSJacob Faibussowitsch     } else {
430a4af0ceeSJacob Faibussowitsch       defaultView = static_cast<decltype(defaultView)>(defaultView && flg);
431a4af0ceeSJacob Faibussowitsch       if (defaultView) initIdx = PETSC_DEVICE_INIT_EAGER;
432a4af0ceeSJacob Faibussowitsch     }
433a4af0ceeSJacob Faibussowitsch     defaultInitType = static_cast<decltype(defaultInitType)>(initIdx);
434a4af0ceeSJacob Faibussowitsch   }
435a4af0ceeSJacob Faibussowitsch   static_assert((PETSC_DEVICE_INVALID == 0) && (PETSC_DEVICE_MAX < std::numeric_limits<int>::max()), "");
436a4af0ceeSJacob Faibussowitsch   for (int i = 1; i < PETSC_DEVICE_MAX; ++i) {
437a4af0ceeSJacob Faibussowitsch     const auto deviceType = static_cast<PetscDeviceType>(i);
438a4af0ceeSJacob Faibussowitsch     auto       initType   = defaultInitType;
439a4af0ceeSJacob Faibussowitsch 
4409566063dSJacob Faibussowitsch     PetscCall(PetscDeviceInitializeTypeFromOptions_Private(comm, deviceType, defaultDevice, defaultView, &initType));
441a4af0ceeSJacob Faibussowitsch     if (PetscDeviceConfiguredFor_Internal(deviceType) && (initType == PETSC_DEVICE_INIT_EAGER)) {
442a4af0ceeSJacob Faibussowitsch       initializeDeviceContextEagerly = PETSC_TRUE;
443a4af0ceeSJacob Faibussowitsch       deviceContextInitDevice        = deviceType;
4447a101e5eSJacob Faibussowitsch       PetscCall(PetscInfo(PETSC_NULLPTR, "PetscDevice %s set as default device type due to eager initialization\n", PetscDeviceTypes[deviceType]));
445a4af0ceeSJacob Faibussowitsch     }
446a4af0ceeSJacob Faibussowitsch   }
447a4af0ceeSJacob Faibussowitsch   if (initializeDeviceContextEagerly) {
448a4af0ceeSJacob Faibussowitsch     PetscDeviceContext dctx;
449a4af0ceeSJacob Faibussowitsch 
450cf3a2253SJacob Faibussowitsch     /*
451cf3a2253SJacob Faibussowitsch       somewhat inefficient here as the device context is potentially fully set up twice (once
452cf3a2253SJacob Faibussowitsch       when retrieved then the second time if setfromoptions makes changes)
453cf3a2253SJacob Faibussowitsch     */
4549566063dSJacob Faibussowitsch     PetscCall(PetscInfo(PETSC_NULLPTR, "Eagerly initializing PetscDeviceContext with %s device\n", PetscDeviceTypes[deviceContextInitDevice]));
4559566063dSJacob Faibussowitsch     PetscCall(PetscDeviceContextSetRootDeviceType_Internal(deviceContextInitDevice));
4569566063dSJacob Faibussowitsch     PetscCall(PetscDeviceContextGetCurrentContext(&dctx));
4579566063dSJacob Faibussowitsch     PetscCall(PetscDeviceContextSetFromOptions(comm, "root_", dctx));
4589566063dSJacob Faibussowitsch     PetscCall(PetscDeviceContextSetUp(dctx));
459a4af0ceeSJacob Faibussowitsch   }
460a4af0ceeSJacob Faibussowitsch   PetscFunctionReturn(0);
461a4af0ceeSJacob Faibussowitsch }
462a4af0ceeSJacob Faibussowitsch 
463a4af0ceeSJacob Faibussowitsch /* Get the default PetscDevice for a particular type and constructs them if lazily initialized. */
464*9371c9d4SSatish Balay PetscErrorCode PetscDeviceGetDefaultForType_Internal(PetscDeviceType type, PetscDevice *device) {
465a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
466a4af0ceeSJacob Faibussowitsch   PetscValidPointer(device, 2);
4679566063dSJacob Faibussowitsch   PetscCall(PetscDeviceInitialize(type));
468a4af0ceeSJacob Faibussowitsch   *device = defaultDevices[type];
469a4af0ceeSJacob Faibussowitsch   PetscFunctionReturn(0);
470030f984aSJacob Faibussowitsch }
471