xref: /petsc/src/sys/objects/device/interface/device.cxx (revision 811af0c4b09a35de4306c442f88bd09fdc09897d)
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, "");
269371c9d4SSatish 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, "");
319371c9d4SSatish Balay const char *const PetscDeviceInitTypes[] = {"none", "lazy", "eager", "PetscDeviceInitType", "PETSC_DEVICE_INIT_", PETSC_NULLPTR};
329371c9d4SSatish 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 
34a16fd2c9SJacob Faibussowitsch const char *const PetscDeviceAttributes[] = {"shared_mem_per_block", "max", "PetscDeviceAttribute", "PETSC_DEVICE_ATTR_", nullptr};
35a16fd2c9SJacob Faibussowitsch 
3617f48955SJacob Faibussowitsch #define PETSC_DEVICE_CASE(IMPLS, func, ...) \
3717f48955SJacob Faibussowitsch   case PetscConcat_(PETSC_DEVICE_, IMPLS): { \
389566063dSJacob Faibussowitsch     PetscCall(PetscConcat_(IMPLS, Device).func(__VA_ARGS__)); \
3917f48955SJacob Faibussowitsch   } break
40a4af0ceeSJacob Faibussowitsch 
41cf3a2253SJacob Faibussowitsch /*
42cf3a2253SJacob Faibussowitsch   Suppose you have:
43cf3a2253SJacob Faibussowitsch 
44cf3a2253SJacob Faibussowitsch   CUDADevice.myFunction(arg1,arg2)
45cf3a2253SJacob Faibussowitsch 
46cf3a2253SJacob Faibussowitsch   that you would like to conditionally define and call in a switch-case:
47cf3a2253SJacob Faibussowitsch 
48cf3a2253SJacob Faibussowitsch   switch(PetscDeviceType) {
49cf3a2253SJacob Faibussowitsch   #if PetscDefined(HAVE_CUDA)
50cf3a2253SJacob Faibussowitsch   case PETSC_DEVICE_CUDA: {
519566063dSJacob Faibussowitsch     PetscCall(CUDADevice.myFunction(arg1,arg2));
52cf3a2253SJacob Faibussowitsch   } break;
53cf3a2253SJacob Faibussowitsch   #endif
54cf3a2253SJacob Faibussowitsch   }
55cf3a2253SJacob Faibussowitsch 
56cf3a2253SJacob Faibussowitsch   then calling this macro:
57cf3a2253SJacob Faibussowitsch 
58cf3a2253SJacob Faibussowitsch   PETSC_DEVICE_CASE_IF_PETSC_DEFINED(CUDA,myFunction,arg1,arg2)
59cf3a2253SJacob Faibussowitsch 
60cf3a2253SJacob Faibussowitsch   will expand to the following case statement:
61cf3a2253SJacob Faibussowitsch 
62cf3a2253SJacob Faibussowitsch   case PETSC_DEVICE_CUDA: {
639566063dSJacob Faibussowitsch     PetscCall(CUDADevice.myFunction(arg1,arg2));
64cf3a2253SJacob Faibussowitsch   } break
65cf3a2253SJacob Faibussowitsch 
66cf3a2253SJacob Faibussowitsch   if PetscDefined(HAVE_CUDA) evaluates to 1, and expand to nothing otherwise
6717f48955SJacob Faibussowitsch */
689371c9d4SSatish Balay #define PETSC_DEVICE_CASE_IF_PETSC_DEFINED(IMPLS, func, ...) PetscIfPetscDefined(PetscConcat_(HAVE_, IMPLS), PETSC_DEVICE_CASE, PetscExpandToNothing)(IMPLS, func, __VA_ARGS__)
69030f984aSJacob Faibussowitsch 
70030f984aSJacob Faibussowitsch /*@C
71*811af0c4SBarry Smith   PetscDeviceCreate - Get a new handle for a particular device (often a GPU) type
72030f984aSJacob Faibussowitsch 
73030f984aSJacob Faibussowitsch   Not Collective, Possibly Synchronous
74030f984aSJacob Faibussowitsch 
75f1a722f8SMatthew G. Knepley   Input Parameters:
76*811af0c4SBarry Smith + type  - The type of `PetscDevice`
77*811af0c4SBarry Smith - devid - The numeric ID# of the device (pass `PETSC_DECIDE` to assign automatically)
78030f984aSJacob Faibussowitsch 
79030f984aSJacob Faibussowitsch   Output Parameter:
80*811af0c4SBarry Smith . device - The `PetscDevice`
81030f984aSJacob Faibussowitsch 
82030f984aSJacob Faibussowitsch   Notes:
83*811af0c4SBarry Smith   This routine may initialize `PetscDevice`. If this is the case, this will most likely cause
84a4af0ceeSJacob Faibussowitsch   some sort of device synchronization.
85a4af0ceeSJacob Faibussowitsch 
86*811af0c4SBarry Smith   `devid` is what you might pass to `cudaSetDevice()` for example.
87030f984aSJacob Faibussowitsch 
88030f984aSJacob Faibussowitsch   Level: beginner
89030f984aSJacob Faibussowitsch 
90db781477SPatrick Sanan .seealso: `PetscDevice`, `PetscDeviceInitType`, `PetscDeviceInitialize()`,
91db781477SPatrick Sanan           `PetscDeviceInitialized()`, `PetscDeviceConfigure()`, `PetscDeviceView()`, `PetscDeviceDestroy()`
92030f984aSJacob Faibussowitsch @*/
939371c9d4SSatish Balay PetscErrorCode PetscDeviceCreate(PetscDeviceType type, PetscInt devid, PetscDevice *device) {
94030f984aSJacob Faibussowitsch   static PetscInt PetscDeviceCounter = 0;
95030f984aSJacob Faibussowitsch   PetscDevice     dev;
96030f984aSJacob Faibussowitsch 
97030f984aSJacob Faibussowitsch   PetscFunctionBegin;
98a4af0ceeSJacob Faibussowitsch   PetscValidDeviceType(type, 1);
99a4af0ceeSJacob Faibussowitsch   PetscValidPointer(device, 3);
1009566063dSJacob Faibussowitsch   PetscCall(PetscDeviceInitializePackage());
1019566063dSJacob Faibussowitsch   PetscCall(PetscNew(&dev));
102030f984aSJacob Faibussowitsch   dev->id     = PetscDeviceCounter++;
103a4af0ceeSJacob Faibussowitsch   dev->type   = type;
104a4af0ceeSJacob Faibussowitsch   dev->refcnt = 1;
105cf3a2253SJacob Faibussowitsch   /*
106cf3a2253SJacob Faibussowitsch     if you are adding a device, you also need to add it's initialization in
107cf3a2253SJacob Faibussowitsch     PetscDeviceInitializeTypeFromOptions_Private() below
108cf3a2253SJacob Faibussowitsch   */
109a4af0ceeSJacob Faibussowitsch   switch (type) {
110a4af0ceeSJacob Faibussowitsch     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(CUDA, getDevice, dev, devid);
111a4af0ceeSJacob Faibussowitsch     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(HIP, getDevice, dev, devid);
112a2158755SJunchao Zhang     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(SYCL, getDevice, dev, devid);
113030f984aSJacob Faibussowitsch   default:
11417f48955SJacob Faibussowitsch     /* in case the above macros expand to nothing this silences any unused variable warnings */
11517f48955SJacob Faibussowitsch     (void)(devid);
11698921bdaSJacob 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]);
117030f984aSJacob Faibussowitsch   }
118030f984aSJacob Faibussowitsch   *device = dev;
119030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
120030f984aSJacob Faibussowitsch }
121030f984aSJacob Faibussowitsch 
122030f984aSJacob Faibussowitsch /*@C
123*811af0c4SBarry Smith   PetscDeviceDestroy - Free a `PetscDevice`
124030f984aSJacob Faibussowitsch 
125030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
126030f984aSJacob Faibussowitsch 
127030f984aSJacob Faibussowitsch   Input Parameter:
128030f984aSJacob Faibussowitsch . device - The PetscDevice
129030f984aSJacob Faibussowitsch 
130030f984aSJacob Faibussowitsch   Level: beginner
131030f984aSJacob Faibussowitsch 
132db781477SPatrick Sanan .seealso: `PetscDevice`, `PetscDeviceCreate()`, `PetscDeviceConfigure()`, `PetscDeviceView()`
133030f984aSJacob Faibussowitsch @*/
1349371c9d4SSatish Balay PetscErrorCode PetscDeviceDestroy(PetscDevice *device) {
135a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
136a4af0ceeSJacob Faibussowitsch   if (!*device) PetscFunctionReturn(0);
137a4af0ceeSJacob Faibussowitsch   PetscValidDevice(*device, 1);
1389566063dSJacob Faibussowitsch   PetscCall(PetscDeviceDereference_Internal(*device));
139a4af0ceeSJacob Faibussowitsch   if ((*device)->refcnt) {
140a4af0ceeSJacob Faibussowitsch     *device = PETSC_NULLPTR;
141a4af0ceeSJacob Faibussowitsch     PetscFunctionReturn(0);
142030f984aSJacob Faibussowitsch   }
1439566063dSJacob Faibussowitsch   PetscCall(PetscFree((*device)->data));
1449566063dSJacob Faibussowitsch   PetscCall(PetscFree(*device));
145030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
146030f984aSJacob Faibussowitsch }
147030f984aSJacob Faibussowitsch 
148a4af0ceeSJacob Faibussowitsch /*@C
149*811af0c4SBarry Smith   PetscDeviceConfigure - Configure a particular `PetscDevice`
150030f984aSJacob Faibussowitsch 
151a4af0ceeSJacob Faibussowitsch   Not Collective, Asynchronous
152a4af0ceeSJacob Faibussowitsch 
153a4af0ceeSJacob Faibussowitsch   Input Parameter:
154*811af0c4SBarry Smith . device - The `PetscDevice` to configure
155a4af0ceeSJacob Faibussowitsch 
156*811af0c4SBarry Smith   Note:
157a4af0ceeSJacob Faibussowitsch   The user should not assume that this is a cheap operation
158a4af0ceeSJacob Faibussowitsch 
159a4af0ceeSJacob Faibussowitsch   Level: beginner
160a4af0ceeSJacob Faibussowitsch 
161db781477SPatrick Sanan .seealso: `PetscDevice`, `PetscDeviceCreate()`, `PetscDeviceView()`, `PetscDeviceDestroy()`
162a4af0ceeSJacob Faibussowitsch @*/
1639371c9d4SSatish Balay PetscErrorCode PetscDeviceConfigure(PetscDevice device) {
164030f984aSJacob Faibussowitsch   PetscFunctionBegin;
165a4af0ceeSJacob Faibussowitsch   PetscValidDevice(device, 1);
166a4af0ceeSJacob Faibussowitsch   if (PetscDefined(USE_DEBUG)) {
167cf3a2253SJacob Faibussowitsch     /*
168cf3a2253SJacob Faibussowitsch       if no available configuration is available, this cascades all the way down to default
169cf3a2253SJacob Faibussowitsch       and error
170cf3a2253SJacob Faibussowitsch     */
171a4af0ceeSJacob Faibussowitsch     switch (device->type) {
1729371c9d4SSatish Balay     case PETSC_DEVICE_CUDA:
1739371c9d4SSatish Balay       if (PetscDefined(HAVE_CUDA)) break;
1749371c9d4SSatish Balay     case PETSC_DEVICE_HIP:
1759371c9d4SSatish Balay       if (PetscDefined(HAVE_HIP)) break;
1769371c9d4SSatish Balay     case PETSC_DEVICE_SYCL:
1779371c9d4SSatish Balay       if (PetscDefined(HAVE_SYCL)) break;
1789371c9d4SSatish 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]);
179a4af0ceeSJacob Faibussowitsch     }
180a4af0ceeSJacob Faibussowitsch   }
181dbbe0bcdSBarry Smith   PetscUseTypeMethod(device, configure);
182a4af0ceeSJacob Faibussowitsch   PetscFunctionReturn(0);
183a4af0ceeSJacob Faibussowitsch }
184a4af0ceeSJacob Faibussowitsch 
185a4af0ceeSJacob Faibussowitsch /*@C
186*811af0c4SBarry Smith   PetscDeviceView - View a `PetscDevice`
187a4af0ceeSJacob Faibussowitsch 
188a4af0ceeSJacob Faibussowitsch   Collective on viewer, Asynchronous
189a4af0ceeSJacob Faibussowitsch 
19091e63d38SStefano Zampini   Input Parameters:
191*811af0c4SBarry Smith + device - The `PetscDevice` to view
192*811af0c4SBarry Smith - viewer - The `PetscViewer` to view the device with (NULL for `PETSC_VIEWER_STDOUT_WORLD`)
193a4af0ceeSJacob Faibussowitsch 
194a4af0ceeSJacob Faibussowitsch   Level: beginner
195a4af0ceeSJacob Faibussowitsch 
196db781477SPatrick Sanan .seealso: `PetscDevice`, `PetscDeviceCreate()`, `PetscDeviceConfigure()`, `PetscDeviceDestroy()`
197a4af0ceeSJacob Faibussowitsch @*/
1989371c9d4SSatish Balay PetscErrorCode PetscDeviceView(PetscDevice device, PetscViewer viewer) {
199a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
200a4af0ceeSJacob Faibussowitsch   PetscValidDevice(device, 1);
2019566063dSJacob Faibussowitsch   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PETSC_COMM_WORLD, &viewer));
202a4af0ceeSJacob Faibussowitsch   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
203dbbe0bcdSBarry Smith   PetscUseTypeMethod(device, view, viewer);
204a4af0ceeSJacob Faibussowitsch   PetscFunctionReturn(0);
205a4af0ceeSJacob Faibussowitsch }
206a4af0ceeSJacob Faibussowitsch 
20791e63d38SStefano Zampini /*@C
20891e63d38SStefano Zampini   PetscDeviceGetDeviceId - Get the device id
20991e63d38SStefano Zampini 
21091e63d38SStefano Zampini   Not collective
21191e63d38SStefano Zampini 
21291e63d38SStefano Zampini   Input Parameter:
213*811af0c4SBarry Smith . device - The `PetscDevice`
21491e63d38SStefano Zampini 
21591e63d38SStefano Zampini   Output Parameter:
21691e63d38SStefano Zampini . id - The device id
21791e63d38SStefano Zampini 
21891e63d38SStefano Zampini   Level: beginner
21991e63d38SStefano Zampini 
220db781477SPatrick Sanan .seealso: `PetscDevice`, `PetscDeviceCreate()`, `PetscDeviceConfigure()`, `PetscDeviceDestroy()`
22191e63d38SStefano Zampini @*/
2229371c9d4SSatish Balay PetscErrorCode PetscDeviceGetDeviceId(PetscDevice device, PetscInt *id) {
22391e63d38SStefano Zampini   PetscFunctionBegin;
22491e63d38SStefano Zampini   PetscValidDevice(device, 1);
22591e63d38SStefano Zampini   PetscValidIntPointer(id, 2);
22691e63d38SStefano Zampini   *id = device->deviceId;
22791e63d38SStefano Zampini   PetscFunctionReturn(0);
22891e63d38SStefano Zampini }
22991e63d38SStefano Zampini 
230a4af0ceeSJacob Faibussowitsch static std::array<bool, PETSC_DEVICE_MAX>        initializedDevice = {};
231a4af0ceeSJacob Faibussowitsch static std::array<PetscDevice, PETSC_DEVICE_MAX> defaultDevices    = {};
232a4af0ceeSJacob Faibussowitsch static_assert(initializedDevice.size() == defaultDevices.size(), "");
233a4af0ceeSJacob Faibussowitsch 
234a4af0ceeSJacob Faibussowitsch /*@C
235*811af0c4SBarry Smith   PetscDeviceInitialize - Initialize `PetscDevice`
236a4af0ceeSJacob Faibussowitsch 
237a4af0ceeSJacob Faibussowitsch   Not Collective, Possibly Synchronous
238a4af0ceeSJacob Faibussowitsch 
239a4af0ceeSJacob Faibussowitsch   Input Parameter:
240*811af0c4SBarry Smith . type - The `PetscDeviceType` to initialize
241a4af0ceeSJacob Faibussowitsch 
242*811af0c4SBarry Smith   Note:
243*811af0c4SBarry Smith   Eagerly initializes the corresponding `PetscDeviceType` if needed.
244a4af0ceeSJacob Faibussowitsch 
245a4af0ceeSJacob Faibussowitsch   Level: beginner
246a4af0ceeSJacob Faibussowitsch 
247db781477SPatrick Sanan .seealso: `PetscDevice`, `PetscDeviceInitType`, `PetscDeviceInitialized()`, `PetscDeviceCreate()`, `PetscDeviceDestroy()`
248a4af0ceeSJacob Faibussowitsch @*/
2499371c9d4SSatish Balay PetscErrorCode PetscDeviceInitialize(PetscDeviceType type) {
250a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
251a4af0ceeSJacob Faibussowitsch   PetscValidDeviceType(type, 1);
2529566063dSJacob Faibussowitsch   PetscCall(PetscDeviceInitializeDefaultDevice_Internal(type, PETSC_DECIDE));
253a4af0ceeSJacob Faibussowitsch   PetscFunctionReturn(0);
254a4af0ceeSJacob Faibussowitsch }
255a4af0ceeSJacob Faibussowitsch 
256a4af0ceeSJacob Faibussowitsch /*@C
257*811af0c4SBarry Smith   PetscDeviceInitialized - Determines whether `PetscDevice` is initialized for a particular
258*811af0c4SBarry Smith   `PetscDeviceType`
259a4af0ceeSJacob Faibussowitsch 
260a4af0ceeSJacob Faibussowitsch   Not Collective, Asynchronous
261a4af0ceeSJacob Faibussowitsch 
262a4af0ceeSJacob Faibussowitsch   Input Parameter:
263*811af0c4SBarry Smith . type - The `PetscDeviceType` to check
264a4af0ceeSJacob Faibussowitsch 
265a4af0ceeSJacob Faibussowitsch   Output Parameter:
266*811af0c4SBarry Smith . [return value] - `PETSC_TRUE` if type is initialized, `PETSC_FALSE` otherwise
267a4af0ceeSJacob Faibussowitsch 
268*811af0c4SBarry Smith   Note:
269*811af0c4SBarry Smith   If one has not configured PETSc for a particular `PetscDeviceType` then this routine will
270*811af0c4SBarry Smith   return `PETSC_FALSE` for that `PetscDeviceType`.
271a4af0ceeSJacob Faibussowitsch 
272a4af0ceeSJacob Faibussowitsch   Level: beginner
273a4af0ceeSJacob Faibussowitsch 
274db781477SPatrick Sanan .seealso: `PetscDevice`, `PetscDeviceInitType`, `PetscDeviceInitialize()`, `PetscDeviceCreate()`, `PetscDeviceDestroy()`
275a4af0ceeSJacob Faibussowitsch @*/
2769371c9d4SSatish Balay PetscBool PetscDeviceInitialized(PetscDeviceType type) {
277a4af0ceeSJacob Faibussowitsch   return static_cast<PetscBool>(PetscDeviceConfiguredFor_Internal(type) && initializedDevice[type]);
278a4af0ceeSJacob Faibussowitsch }
279a4af0ceeSJacob Faibussowitsch 
280a16fd2c9SJacob Faibussowitsch /*@C
281a16fd2c9SJacob Faibussowitsch   PetscDeviceGetAttribute - Query a particular attribute of a `PetscDevice`
282a16fd2c9SJacob Faibussowitsch 
283a16fd2c9SJacob Faibussowitsch   Not Collective, Asynchronous
284a16fd2c9SJacob Faibussowitsch 
285a16fd2c9SJacob Faibussowitsch   Input Parameters:
286a16fd2c9SJacob Faibussowitsch + device - The `PetscDevice`
287a16fd2c9SJacob Faibussowitsch - attr   - The attribute
288a16fd2c9SJacob Faibussowitsch 
289a16fd2c9SJacob Faibussowitsch   Output Parameter:
290a16fd2c9SJacob Faibussowitsch . value - The value of the attribute
291a16fd2c9SJacob Faibussowitsch 
292a16fd2c9SJacob Faibussowitsch   Notes:
293a16fd2c9SJacob Faibussowitsch   Since different attributes are often different types `value` is a `void *` to accommodate
294a16fd2c9SJacob Faibussowitsch   them all. The underlying type of the attribute is therefore included in the name of the
295a16fd2c9SJacob Faibussowitsch   `PetscDeviceAttribute` reponsible for querying it. For example,
296a16fd2c9SJacob Faibussowitsch   `PETSC_DEVICE_ATTR_SIZE_T_SHARED_MEM_PER_BLOCK` is of type `size_t`.
297a16fd2c9SJacob Faibussowitsch 
298a16fd2c9SJacob Faibussowitsch .seealso: `PetscDeviceAtrtibute`, `PetscDeviceConfigure()`, `PetscDevice`
299a16fd2c9SJacob Faibussowitsch @*/
300a16fd2c9SJacob Faibussowitsch PetscErrorCode PetscDeviceGetAttribute(PetscDevice device, PetscDeviceAttribute attr, void *value) {
301a16fd2c9SJacob Faibussowitsch   PetscFunctionBegin;
302a16fd2c9SJacob Faibussowitsch   PetscValidDevice(device, 1);
303a16fd2c9SJacob Faibussowitsch   PetscValidDeviceAttribute(attr, 2);
304a16fd2c9SJacob Faibussowitsch   PetscValidPointer(value, 3);
305a16fd2c9SJacob Faibussowitsch   PetscUseTypeMethod(device, getattribute, attr, value);
306a16fd2c9SJacob Faibussowitsch   PetscFunctionReturn(0);
307a16fd2c9SJacob Faibussowitsch }
308a16fd2c9SJacob Faibussowitsch 
309cf3a2253SJacob Faibussowitsch /*
310cf3a2253SJacob Faibussowitsch   Actual intialization function; any functions claiming to initialize PetscDevice or
311cf3a2253SJacob Faibussowitsch   PetscDeviceContext will have to run through this one
312cf3a2253SJacob Faibussowitsch */
3139371c9d4SSatish Balay PetscErrorCode PetscDeviceInitializeDefaultDevice_Internal(PetscDeviceType type, PetscInt defaultDeviceId) {
314a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
315a4af0ceeSJacob Faibussowitsch   PetscValidDeviceType(type, 1);
316a4af0ceeSJacob Faibussowitsch   if (PetscLikely(PetscDeviceInitialized(type))) PetscFunctionReturn(0);
317bf025ffbSJacob Faibussowitsch   PetscAssert(!defaultDevices[type], PETSC_COMM_SELF, PETSC_ERR_MEM, "Trying to overwrite existing default device of type %s", PetscDeviceTypes[type]);
3189566063dSJacob Faibussowitsch   PetscCall(PetscDeviceCreate(type, defaultDeviceId, &defaultDevices[type]));
3199566063dSJacob Faibussowitsch   PetscCall(PetscDeviceConfigure(defaultDevices[type]));
320a4af0ceeSJacob Faibussowitsch   initializedDevice[type] = true;
321a4af0ceeSJacob Faibussowitsch   PetscFunctionReturn(0);
322a4af0ceeSJacob Faibussowitsch }
323a4af0ceeSJacob Faibussowitsch 
324ce244043SStefano Zampini #if PetscDefined(USE_LOG)
325ce244043SStefano Zampini PETSC_INTERN PetscErrorCode PetscLogInitialize(void);
326ce244043SStefano Zampini #else
327ce244043SStefano Zampini #define PetscLogInitialize() 0
328ce244043SStefano Zampini #endif
329ce244043SStefano Zampini 
3309371c9d4SSatish Balay static PetscErrorCode PetscDeviceInitializeTypeFromOptions_Private(MPI_Comm comm, PetscDeviceType type, PetscInt defaultDeviceId, PetscBool defaultView, PetscDeviceInitType *defaultInitType) {
331a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
332a4af0ceeSJacob Faibussowitsch   if (!PetscDeviceConfiguredFor_Internal(type)) {
3339566063dSJacob Faibussowitsch     PetscCall(PetscInfo(PETSC_NULLPTR, "PetscDeviceType %s not supported\n", PetscDeviceTypes[type]));
334a4af0ceeSJacob Faibussowitsch     defaultDevices[type] = PETSC_NULLPTR;
335a4af0ceeSJacob Faibussowitsch     PetscFunctionReturn(0);
336a4af0ceeSJacob Faibussowitsch   }
3379566063dSJacob Faibussowitsch   PetscCall(PetscInfo(PETSC_NULLPTR, "PetscDeviceType %s supported, initializing\n", PetscDeviceTypes[type]));
338a4af0ceeSJacob Faibussowitsch   /* ugly switch needed to pick the right global variable... could maybe do this as a union? */
339a4af0ceeSJacob Faibussowitsch   switch (type) {
340a4af0ceeSJacob Faibussowitsch     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(CUDA, initialize, comm, &defaultDeviceId, defaultInitType);
341a4af0ceeSJacob Faibussowitsch     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(HIP, initialize, comm, &defaultDeviceId, defaultInitType);
342a2158755SJunchao Zhang     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(SYCL, initialize, comm, &defaultDeviceId, defaultInitType);
3439371c9d4SSatish 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]);
344a4af0ceeSJacob Faibussowitsch   }
345cf3a2253SJacob Faibussowitsch   /*
346cf3a2253SJacob Faibussowitsch     defaultInitType and defaultDeviceId now represent what the individual TYPES have decided to
347cf3a2253SJacob Faibussowitsch     initialize as
348cf3a2253SJacob Faibussowitsch   */
349a4af0ceeSJacob Faibussowitsch   if (*defaultInitType == PETSC_DEVICE_INIT_EAGER) {
3507a101e5eSJacob Faibussowitsch     PetscCall(PetscLogInitialize());
3519566063dSJacob Faibussowitsch     PetscCall(PetscInfo(PETSC_NULLPTR, "Eagerly initializing %s PetscDevice\n", PetscDeviceTypes[type]));
3529566063dSJacob Faibussowitsch     PetscCall(PetscDeviceInitializeDefaultDevice_Internal(type, defaultDeviceId));
353a4af0ceeSJacob Faibussowitsch     if (defaultView) {
354a4af0ceeSJacob Faibussowitsch       PetscViewer vwr;
355a4af0ceeSJacob Faibussowitsch 
3569566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIGetStdout(comm, &vwr));
3579566063dSJacob Faibussowitsch       PetscCall(PetscDeviceView(defaultDevices[type], vwr));
358a4af0ceeSJacob Faibussowitsch     }
359030f984aSJacob Faibussowitsch   }
360030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
361030f984aSJacob Faibussowitsch }
362030f984aSJacob Faibussowitsch 
363030f984aSJacob Faibussowitsch /* called from PetscFinalize() do not call yourself! */
3649371c9d4SSatish Balay static PetscErrorCode PetscDeviceFinalize_Private(void) {
365030f984aSJacob Faibussowitsch   PetscFunctionBegin;
366a4af0ceeSJacob Faibussowitsch   if (PetscDefined(USE_DEBUG)) {
367bf025ffbSJacob Faibussowitsch     const auto PetscDeviceCheckAllDestroyedAfterFinalize = [] {
368a4af0ceeSJacob Faibussowitsch       PetscFunctionBegin;
3699371c9d4SSatish Balay       for (auto &&device : defaultDevices)
3709371c9d4SSatish 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);
371a4af0ceeSJacob Faibussowitsch       PetscFunctionReturn(0);
372a4af0ceeSJacob Faibussowitsch     };
373bf025ffbSJacob Faibussowitsch     /*
374bf025ffbSJacob Faibussowitsch       you might be thinking, why on earth are you registered yet another finalizer in a
375bf025ffbSJacob Faibussowitsch       function already called during PetscRegisterFinalizeAll()? If this seems stupid it's
376bf025ffbSJacob Faibussowitsch       because it is.
377bf025ffbSJacob Faibussowitsch 
378bf025ffbSJacob Faibussowitsch       The crux of the problem is that the initializer (and therefore the ~finalizer~) of
379bf025ffbSJacob Faibussowitsch       PetscDeviceContext is guaranteed to run after PetscDevice's. So if the global context had
380bf025ffbSJacob Faibussowitsch       a default PetscDevice attached, that PetscDevice will have a reference count >0 and hence
381bf025ffbSJacob Faibussowitsch       won't be destroyed yet. So we need to repeat the check that all devices have been
382bf025ffbSJacob Faibussowitsch       destroyed again ~after~ the global context is destroyed. In summary:
383bf025ffbSJacob Faibussowitsch 
384bf025ffbSJacob Faibussowitsch       1. This finalizer runs and destroys all devices, except it may not because the global
385bf025ffbSJacob Faibussowitsch          context may still hold a reference!
386bf025ffbSJacob Faibussowitsch       2. The global context finalizer runs and does the final reference count decrement
387bf025ffbSJacob Faibussowitsch          required, which actually destroys the held device.
388bf025ffbSJacob Faibussowitsch       3. Our newly added finalizer runs and checks that all is well.
389a4af0ceeSJacob Faibussowitsch     */
3909566063dSJacob Faibussowitsch     PetscCall(PetscRegisterFinalize(PetscDeviceCheckAllDestroyedAfterFinalize));
391a4af0ceeSJacob Faibussowitsch   }
3929566063dSJacob Faibussowitsch   for (auto &&device : defaultDevices) PetscCall(PetscDeviceDestroy(&device));
3939566063dSJacob Faibussowitsch   PetscCallCXX(initializedDevice.fill(false));
394030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
395030f984aSJacob Faibussowitsch }
396030f984aSJacob Faibussowitsch 
397cf3a2253SJacob Faibussowitsch /*
398cf3a2253SJacob Faibussowitsch   Begins the init proceeedings for the entire PetscDevice stack. there are 3 stages of
399cf3a2253SJacob Faibussowitsch   initialization types:
400cf3a2253SJacob Faibussowitsch 
401a4af0ceeSJacob Faibussowitsch   1. defaultInitType - how does PetscDevice as a whole expect to initialize?
402a4af0ceeSJacob Faibussowitsch   2. subTypeDefaultInitType - how does each PetscDevice implementation expect to initialize?
403a4af0ceeSJacob Faibussowitsch      e.g. you may want to blanket disable PetscDevice init (and disable say Kokkos init), but
404a4af0ceeSJacob Faibussowitsch      have all CUDA devices still initialize.
405a4af0ceeSJacob Faibussowitsch 
406a4af0ceeSJacob Faibussowitsch   All told the following happens:
407cf3a2253SJacob Faibussowitsch 
408a4af0ceeSJacob Faibussowitsch   0. defaultInitType -> LAZY
409a4af0ceeSJacob Faibussowitsch   1. Check for log_view/log_summary, if yes defaultInitType -> EAGER
410a4af0ceeSJacob Faibussowitsch   2. PetscDevice initializes each sub type with deviceDefaultInitType.
411a4af0ceeSJacob Faibussowitsch   2.1 Each enabled PetscDevice sub-type then does the above disable or view check in addition
412a4af0ceeSJacob Faibussowitsch       to checking for specific device init. if view or specific device init
413a4af0ceeSJacob Faibussowitsch       subTypeDefaultInitType -> EAGER. disabled once again overrides all.
414a4af0ceeSJacob Faibussowitsch */
4159371c9d4SSatish Balay PetscErrorCode PetscDeviceInitializeFromOptions_Internal(MPI_Comm comm) {
4167a101e5eSJacob Faibussowitsch   auto                defaultView                    = PETSC_FALSE;
4177a101e5eSJacob Faibussowitsch   auto                initializeDeviceContextEagerly = PETSC_FALSE;
4187a101e5eSJacob Faibussowitsch   auto                defaultDevice                  = PetscInt{PETSC_DECIDE};
4197a101e5eSJacob Faibussowitsch   auto                deviceContextInitDevice        = PETSC_DEVICE_DEFAULT;
420a4af0ceeSJacob Faibussowitsch   PetscDeviceInitType defaultInitType;
421a4af0ceeSJacob Faibussowitsch 
422a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
423a4af0ceeSJacob Faibussowitsch   if (PetscDefined(USE_DEBUG)) {
424a4af0ceeSJacob Faibussowitsch     int result;
425a4af0ceeSJacob Faibussowitsch 
4269566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_compare(comm, PETSC_COMM_WORLD, &result));
427a4af0ceeSJacob Faibussowitsch     /* in order to accurately assign ranks to gpus we need to get the MPI_Comm_rank of the
428a4af0ceeSJacob Faibussowitsch      * global space */
429a4af0ceeSJacob Faibussowitsch     if (PetscUnlikely(result != MPI_IDENT)) {
430a4af0ceeSJacob Faibussowitsch       char name[MPI_MAX_OBJECT_NAME] = {};
431a4af0ceeSJacob Faibussowitsch       int  len; /* unused */
432a4af0ceeSJacob Faibussowitsch 
4339566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_get_name(comm, name, &len));
43498921bdaSJacob Faibussowitsch       SETERRQ(comm, PETSC_ERR_MPI, "Default devices being initialized on MPI_Comm '%s' not PETSC_COMM_WORLD", name);
435a4af0ceeSJacob Faibussowitsch     }
436a4af0ceeSJacob Faibussowitsch   }
437a4af0ceeSJacob Faibussowitsch   comm = PETSC_COMM_WORLD; /* from this point on we assume we're on PETSC_COMM_WORLD */
4389566063dSJacob Faibussowitsch   PetscCall(PetscRegisterFinalize(PetscDeviceFinalize_Private));
439a4af0ceeSJacob Faibussowitsch 
4407a101e5eSJacob Faibussowitsch   {
4417a101e5eSJacob Faibussowitsch     PetscInt  initIdx = PETSC_DEVICE_INIT_LAZY;
4427a101e5eSJacob Faibussowitsch     PetscBool flg;
4437a101e5eSJacob Faibussowitsch 
4447a101e5eSJacob Faibussowitsch     PetscCall(PetscOptionsHasName(PETSC_NULLPTR, PETSC_NULLPTR, "-log_view_gpu_time", &flg));
4457a101e5eSJacob Faibussowitsch     if (flg) PetscCall(PetscLogGpuTime());
4467a101e5eSJacob Faibussowitsch 
4477a101e5eSJacob Faibussowitsch     /* ----------------------------------------------------------------------------------- */
4487a101e5eSJacob Faibussowitsch     /*                              Global PetscDevice Options                             */
4497a101e5eSJacob Faibussowitsch     /* ----------------------------------------------------------------------------------- */
450d0609cedSBarry Smith     PetscOptionsBegin(comm, PETSC_NULLPTR, "PetscDevice Options", "Sys");
4519566063dSJacob Faibussowitsch     PetscCall(PetscOptionsEList("-device_enable", "How (or whether) to initialize PetscDevices", "PetscDeviceInitializeFromOptions_Internal()", PetscDeviceInitTypes, 3, PetscDeviceInitTypes[initIdx], &initIdx, PETSC_NULLPTR));
4529566063dSJacob 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()));
4539566063dSJacob Faibussowitsch     PetscCall(PetscOptionsBool("-device_view", "Display device information and assignments (forces eager initialization)", PETSC_NULLPTR, defaultView, &defaultView, &flg));
454d0609cedSBarry Smith     PetscOptionsEnd();
4557a101e5eSJacob Faibussowitsch 
456a4af0ceeSJacob Faibussowitsch     if (initIdx == PETSC_DEVICE_INIT_NONE) {
457a4af0ceeSJacob Faibussowitsch       /* disabled all device initialization if devices are globally disabled */
458bf025ffbSJacob 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");
459a4af0ceeSJacob Faibussowitsch       defaultView = PETSC_FALSE;
460a4af0ceeSJacob Faibussowitsch     } else {
461a4af0ceeSJacob Faibussowitsch       defaultView = static_cast<decltype(defaultView)>(defaultView && flg);
462a4af0ceeSJacob Faibussowitsch       if (defaultView) initIdx = PETSC_DEVICE_INIT_EAGER;
463a4af0ceeSJacob Faibussowitsch     }
464a4af0ceeSJacob Faibussowitsch     defaultInitType = static_cast<decltype(defaultInitType)>(initIdx);
465a4af0ceeSJacob Faibussowitsch   }
466a4af0ceeSJacob Faibussowitsch   static_assert((PETSC_DEVICE_INVALID == 0) && (PETSC_DEVICE_MAX < std::numeric_limits<int>::max()), "");
467a4af0ceeSJacob Faibussowitsch   for (int i = 1; i < PETSC_DEVICE_MAX; ++i) {
468a4af0ceeSJacob Faibussowitsch     const auto deviceType = static_cast<PetscDeviceType>(i);
469a4af0ceeSJacob Faibussowitsch     auto       initType   = defaultInitType;
470a4af0ceeSJacob Faibussowitsch 
4719566063dSJacob Faibussowitsch     PetscCall(PetscDeviceInitializeTypeFromOptions_Private(comm, deviceType, defaultDevice, defaultView, &initType));
472a4af0ceeSJacob Faibussowitsch     if (PetscDeviceConfiguredFor_Internal(deviceType) && (initType == PETSC_DEVICE_INIT_EAGER)) {
473a4af0ceeSJacob Faibussowitsch       initializeDeviceContextEagerly = PETSC_TRUE;
474a4af0ceeSJacob Faibussowitsch       deviceContextInitDevice        = deviceType;
4757a101e5eSJacob Faibussowitsch       PetscCall(PetscInfo(PETSC_NULLPTR, "PetscDevice %s set as default device type due to eager initialization\n", PetscDeviceTypes[deviceType]));
476a4af0ceeSJacob Faibussowitsch     }
477a4af0ceeSJacob Faibussowitsch   }
478a4af0ceeSJacob Faibussowitsch   if (initializeDeviceContextEagerly) {
479a4af0ceeSJacob Faibussowitsch     PetscDeviceContext dctx;
480a4af0ceeSJacob Faibussowitsch 
481cf3a2253SJacob Faibussowitsch     /*
482cf3a2253SJacob Faibussowitsch       somewhat inefficient here as the device context is potentially fully set up twice (once
483cf3a2253SJacob Faibussowitsch       when retrieved then the second time if setfromoptions makes changes)
484cf3a2253SJacob Faibussowitsch     */
4859566063dSJacob Faibussowitsch     PetscCall(PetscInfo(PETSC_NULLPTR, "Eagerly initializing PetscDeviceContext with %s device\n", PetscDeviceTypes[deviceContextInitDevice]));
4869566063dSJacob Faibussowitsch     PetscCall(PetscDeviceContextSetRootDeviceType_Internal(deviceContextInitDevice));
4879566063dSJacob Faibussowitsch     PetscCall(PetscDeviceContextGetCurrentContext(&dctx));
4889566063dSJacob Faibussowitsch     PetscCall(PetscDeviceContextSetFromOptions(comm, "root_", dctx));
4899566063dSJacob Faibussowitsch     PetscCall(PetscDeviceContextSetUp(dctx));
490a4af0ceeSJacob Faibussowitsch   }
491a4af0ceeSJacob Faibussowitsch   PetscFunctionReturn(0);
492a4af0ceeSJacob Faibussowitsch }
493a4af0ceeSJacob Faibussowitsch 
494a4af0ceeSJacob Faibussowitsch /* Get the default PetscDevice for a particular type and constructs them if lazily initialized. */
4959371c9d4SSatish Balay PetscErrorCode PetscDeviceGetDefaultForType_Internal(PetscDeviceType type, PetscDevice *device) {
496a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
497a4af0ceeSJacob Faibussowitsch   PetscValidPointer(device, 2);
4989566063dSJacob Faibussowitsch   PetscCall(PetscDeviceInitialize(type));
499a4af0ceeSJacob Faibussowitsch   *device = defaultDevices[type];
500a4af0ceeSJacob Faibussowitsch   PetscFunctionReturn(0);
501030f984aSJacob Faibussowitsch }
502