xref: /petsc/src/sys/objects/device/interface/device.cxx (revision 456dbbcd9876bdf1526b93d27a05ea9aadb1fa98)
10e6b6b59SJacob Faibussowitsch #include "petscdevice_interface_internal.hpp" /*I <petscdevice.h> I*/
217f48955SJacob Faibussowitsch #include <petsc/private/petscadvancedmacros.h>
3030f984aSJacob Faibussowitsch 
4bbfde98dSJacob Faibussowitsch #include <petsc/private/cpp/register_finalize.hpp>
5bbfde98dSJacob Faibussowitsch 
60e6b6b59SJacob Faibussowitsch #include "../impls/host/hostdevice.hpp"
7bbfde98dSJacob Faibussowitsch #if PetscDefined(HAVE_CUPM)
80e6b6b59SJacob Faibussowitsch   #include "../impls/cupm/cupmdevice.hpp"
9bbfde98dSJacob Faibussowitsch #endif
10bbfde98dSJacob Faibussowitsch #if PetscDefined(HAVE_SYCL)
110e6b6b59SJacob Faibussowitsch   #include "../impls/sycl/sycldevice.hpp"
12bbfde98dSJacob Faibussowitsch #endif
130e6b6b59SJacob Faibussowitsch 
140e6b6b59SJacob Faibussowitsch #include <utility> // std::make_pair
150e6b6b59SJacob Faibussowitsch 
160e6b6b59SJacob Faibussowitsch using namespace Petsc::device;
17030f984aSJacob Faibussowitsch 
18*456dbbcdSJunchao Zhang #if defined(PETSC_HAVE_CUPM)
19*456dbbcdSJunchao Zhang int PetscDeviceCUPMRuntimeArch = 0;
20*456dbbcdSJunchao Zhang #endif
21*456dbbcdSJunchao Zhang 
22bbfde98dSJacob Faibussowitsch namespace
23bbfde98dSJacob Faibussowitsch {
24bbfde98dSJacob Faibussowitsch 
25cf3a2253SJacob Faibussowitsch /*
26cf3a2253SJacob Faibussowitsch   note to anyone adding more classes, the name must be ALL_CAPS_SHORT_NAME + Device exactly to
27cf3a2253SJacob Faibussowitsch   be picked up by the switch-case macros below
28cf3a2253SJacob Faibussowitsch */
29bbfde98dSJacob Faibussowitsch host::Device HOSTDevice{PetscDeviceContextCreate_HOST};
30030f984aSJacob Faibussowitsch #if PetscDefined(HAVE_CUDA)
31bbfde98dSJacob Faibussowitsch cupm::Device<cupm::DeviceType::CUDA> CUDADevice{PetscDeviceContextCreate_CUDA};
32030f984aSJacob Faibussowitsch #endif
33030f984aSJacob Faibussowitsch #if PetscDefined(HAVE_HIP)
34bbfde98dSJacob Faibussowitsch cupm::Device<cupm::DeviceType::HIP> HIPDevice{PetscDeviceContextCreate_HIP};
35030f984aSJacob Faibussowitsch #endif
36a2158755SJunchao Zhang #if PetscDefined(HAVE_SYCL)
37bbfde98dSJacob Faibussowitsch sycl::Device SYCLDevice{PetscDeviceContextCreate_SYCL};
38a2158755SJunchao Zhang #endif
39030f984aSJacob Faibussowitsch 
40bbfde98dSJacob Faibussowitsch } // namespace
41bbfde98dSJacob Faibussowitsch 
4217f48955SJacob Faibussowitsch #define PETSC_DEVICE_CASE(IMPLS, func, ...) \
4317f48955SJacob Faibussowitsch   case PetscConcat_(PETSC_DEVICE_, IMPLS): { \
449566063dSJacob Faibussowitsch     PetscCall(PetscConcat_(IMPLS, Device).func(__VA_ARGS__)); \
4517f48955SJacob Faibussowitsch   } break
46a4af0ceeSJacob Faibussowitsch 
47394bf645SJacob Faibussowitsch #define PETSC_VOID_0(...) ((void)0)
48394bf645SJacob Faibussowitsch 
49cf3a2253SJacob Faibussowitsch /*
50cf3a2253SJacob Faibussowitsch   Suppose you have:
51cf3a2253SJacob Faibussowitsch 
52cf3a2253SJacob Faibussowitsch   CUDADevice.myFunction(arg1,arg2)
53cf3a2253SJacob Faibussowitsch 
54cf3a2253SJacob Faibussowitsch   that you would like to conditionally define and call in a switch-case:
55cf3a2253SJacob Faibussowitsch 
56cf3a2253SJacob Faibussowitsch   switch(PetscDeviceType) {
57cf3a2253SJacob Faibussowitsch   #if PetscDefined(HAVE_CUDA)
58cf3a2253SJacob Faibussowitsch   case PETSC_DEVICE_CUDA: {
599566063dSJacob Faibussowitsch     PetscCall(CUDADevice.myFunction(arg1,arg2));
60cf3a2253SJacob Faibussowitsch   } break;
61cf3a2253SJacob Faibussowitsch   #endif
62cf3a2253SJacob Faibussowitsch   }
63cf3a2253SJacob Faibussowitsch 
64cf3a2253SJacob Faibussowitsch   then calling this macro:
65cf3a2253SJacob Faibussowitsch 
66cf3a2253SJacob Faibussowitsch   PETSC_DEVICE_CASE_IF_PETSC_DEFINED(CUDA,myFunction,arg1,arg2)
67cf3a2253SJacob Faibussowitsch 
68cf3a2253SJacob Faibussowitsch   will expand to the following case statement:
69cf3a2253SJacob Faibussowitsch 
70cf3a2253SJacob Faibussowitsch   case PETSC_DEVICE_CUDA: {
719566063dSJacob Faibussowitsch     PetscCall(CUDADevice.myFunction(arg1,arg2));
72cf3a2253SJacob Faibussowitsch   } break
73cf3a2253SJacob Faibussowitsch 
74cf3a2253SJacob Faibussowitsch   if PetscDefined(HAVE_CUDA) evaluates to 1, and expand to nothing otherwise
7517f48955SJacob Faibussowitsch */
76394bf645SJacob Faibussowitsch #define PETSC_DEVICE_CASE_IF_PETSC_DEFINED(IMPLS, func, ...) PetscIfPetscDefined(PetscConcat_(HAVE_, IMPLS), PETSC_DEVICE_CASE, PETSC_VOID_0)(IMPLS, func, __VA_ARGS__)
77030f984aSJacob Faibussowitsch 
78030f984aSJacob Faibussowitsch /*@C
79811af0c4SBarry Smith   PetscDeviceCreate - Get a new handle for a particular device (often a GPU) type
80030f984aSJacob Faibussowitsch 
810e6b6b59SJacob Faibussowitsch   Not Collective
82030f984aSJacob Faibussowitsch 
83f1a722f8SMatthew G. Knepley   Input Parameters:
84811af0c4SBarry Smith + type  - The type of `PetscDevice`
85811af0c4SBarry Smith - devid - The numeric ID# of the device (pass `PETSC_DECIDE` to assign automatically)
86030f984aSJacob Faibussowitsch 
87030f984aSJacob Faibussowitsch   Output Parameter:
88811af0c4SBarry Smith . device - The `PetscDevice`
89030f984aSJacob Faibussowitsch 
902fe279fdSBarry Smith   Level: beginner
912fe279fdSBarry Smith 
92030f984aSJacob Faibussowitsch   Notes:
930e6b6b59SJacob Faibussowitsch   This routine may initialize `PetscDevice`. If this is the case, it may cause some sort of
940e6b6b59SJacob Faibussowitsch   device synchronization.
95a4af0ceeSJacob Faibussowitsch 
96811af0c4SBarry Smith   `devid` is what you might pass to `cudaSetDevice()` for example.
97030f984aSJacob Faibussowitsch 
980e6b6b59SJacob Faibussowitsch .seealso: `PetscDevice`, `PetscDeviceInitType`,
990e6b6b59SJacob Faibussowitsch `PetscDeviceInitialize()`, `PetscDeviceInitialized()`, `PetscDeviceConfigure()`,
1000e6b6b59SJacob Faibussowitsch `PetscDeviceView()`, `PetscDeviceDestroy()`
101030f984aSJacob Faibussowitsch @*/
102d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceCreate(PetscDeviceType type, PetscInt devid, PetscDevice *device)
103d71ae5a4SJacob Faibussowitsch {
104030f984aSJacob Faibussowitsch   static PetscInt PetscDeviceCounter = 0;
105030f984aSJacob Faibussowitsch 
106030f984aSJacob Faibussowitsch   PetscFunctionBegin;
107a4af0ceeSJacob Faibussowitsch   PetscValidDeviceType(type, 1);
1084f572ea9SToby Isaac   PetscAssertPointer(device, 3);
1099566063dSJacob Faibussowitsch   PetscCall(PetscDeviceInitializePackage());
1100e6b6b59SJacob Faibussowitsch   PetscCall(PetscNew(device));
1110e6b6b59SJacob Faibussowitsch   (*device)->id     = PetscDeviceCounter++;
1120e6b6b59SJacob Faibussowitsch   (*device)->type   = type;
1130e6b6b59SJacob Faibussowitsch   (*device)->refcnt = 1;
114cf3a2253SJacob Faibussowitsch   /*
11591c35059SPierre Jolivet     if you are adding a device, you also need to add its initialization in
116cf3a2253SJacob Faibussowitsch     PetscDeviceInitializeTypeFromOptions_Private() below
117cf3a2253SJacob Faibussowitsch   */
118a4af0ceeSJacob Faibussowitsch   switch (type) {
1190e6b6b59SJacob Faibussowitsch     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(HOST, getDevice, *device, devid);
1200e6b6b59SJacob Faibussowitsch     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(CUDA, getDevice, *device, devid);
1210e6b6b59SJacob Faibussowitsch     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(HIP, getDevice, *device, devid);
1220e6b6b59SJacob Faibussowitsch     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(SYCL, getDevice, *device, devid);
123030f984aSJacob Faibussowitsch   default:
12417f48955SJacob Faibussowitsch     /* in case the above macros expand to nothing this silences any unused variable warnings */
12517f48955SJacob Faibussowitsch     (void)(devid);
12698921bdaSJacob 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]);
127030f984aSJacob Faibussowitsch   }
1283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
129030f984aSJacob Faibussowitsch }
130030f984aSJacob Faibussowitsch 
131030f984aSJacob Faibussowitsch /*@C
132811af0c4SBarry Smith   PetscDeviceDestroy - Free a `PetscDevice`
133030f984aSJacob Faibussowitsch 
1340e6b6b59SJacob Faibussowitsch   Not Collective
135030f984aSJacob Faibussowitsch 
136030f984aSJacob Faibussowitsch   Input Parameter:
1370e6b6b59SJacob Faibussowitsch . device - The `PetscDevice`
138030f984aSJacob Faibussowitsch 
139030f984aSJacob Faibussowitsch   Level: beginner
140030f984aSJacob Faibussowitsch 
1410e6b6b59SJacob Faibussowitsch .seealso: `PetscDevice`, `PetscDeviceCreate()`, `PetscDeviceConfigure()`, `PetscDeviceView()`,
1420e6b6b59SJacob Faibussowitsch `PetscDeviceGetType()`, `PetscDeviceGetDeviceId()`
143030f984aSJacob Faibussowitsch @*/
144d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceDestroy(PetscDevice *device)
145d71ae5a4SJacob Faibussowitsch {
146a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
1474f572ea9SToby Isaac   PetscAssertPointer(device, 1);
1483ba16761SJacob Faibussowitsch   if (!*device) PetscFunctionReturn(PETSC_SUCCESS);
149a4af0ceeSJacob Faibussowitsch   PetscValidDevice(*device, 1);
1509566063dSJacob Faibussowitsch   PetscCall(PetscDeviceDereference_Internal(*device));
151a4af0ceeSJacob Faibussowitsch   if ((*device)->refcnt) {
1520e6b6b59SJacob Faibussowitsch     *device = nullptr;
1533ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
154030f984aSJacob Faibussowitsch   }
1559566063dSJacob Faibussowitsch   PetscCall(PetscFree((*device)->data));
1569566063dSJacob Faibussowitsch   PetscCall(PetscFree(*device));
1573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
158030f984aSJacob Faibussowitsch }
159030f984aSJacob Faibussowitsch 
160a4af0ceeSJacob Faibussowitsch /*@C
161811af0c4SBarry Smith   PetscDeviceConfigure - Configure a particular `PetscDevice`
162030f984aSJacob Faibussowitsch 
1630e6b6b59SJacob Faibussowitsch   Not Collective
164a4af0ceeSJacob Faibussowitsch 
165a4af0ceeSJacob Faibussowitsch   Input Parameter:
166811af0c4SBarry Smith . device - The `PetscDevice` to configure
167a4af0ceeSJacob Faibussowitsch 
1682fe279fdSBarry Smith   Level: beginner
1692fe279fdSBarry Smith 
1700e6b6b59SJacob Faibussowitsch   Notes:
1710e6b6b59SJacob Faibussowitsch   The user should not assume that this is a cheap operation.
172a4af0ceeSJacob Faibussowitsch 
1730e6b6b59SJacob Faibussowitsch .seealso: `PetscDevice`, `PetscDeviceCreate()`, `PetscDeviceView()`, `PetscDeviceDestroy()`,
1740e6b6b59SJacob Faibussowitsch `PetscDeviceGetType()`, `PetscDeviceGetDeviceId()`
175a4af0ceeSJacob Faibussowitsch @*/
176d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceConfigure(PetscDevice device)
177d71ae5a4SJacob Faibussowitsch {
178030f984aSJacob Faibussowitsch   PetscFunctionBegin;
179a4af0ceeSJacob Faibussowitsch   PetscValidDevice(device, 1);
180cf3a2253SJacob Faibussowitsch   /*
181cf3a2253SJacob Faibussowitsch     if no available configuration is available, this cascades all the way down to default
182cf3a2253SJacob Faibussowitsch     and error
183cf3a2253SJacob Faibussowitsch   */
1840e6b6b59SJacob Faibussowitsch   switch (const auto dtype = device->type) {
1850e6b6b59SJacob Faibussowitsch   case PETSC_DEVICE_HOST:
1860e6b6b59SJacob Faibussowitsch     if (PetscDefined(HAVE_HOST)) break; // always true
1879371c9d4SSatish Balay   case PETSC_DEVICE_CUDA:
1889371c9d4SSatish Balay     if (PetscDefined(HAVE_CUDA)) break;
1890e6b6b59SJacob Faibussowitsch     goto error;
1909371c9d4SSatish Balay   case PETSC_DEVICE_HIP:
1919371c9d4SSatish Balay     if (PetscDefined(HAVE_HIP)) break;
1920e6b6b59SJacob Faibussowitsch     goto error;
1939371c9d4SSatish Balay   case PETSC_DEVICE_SYCL:
1949371c9d4SSatish Balay     if (PetscDefined(HAVE_SYCL)) break;
195f4d061e9SPierre Jolivet     goto error;
1960e6b6b59SJacob Faibussowitsch   default:
1970e6b6b59SJacob Faibussowitsch   error:
1980e6b6b59SJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "PETSc was not configured for PetscDeviceType %s", PetscDeviceTypes[dtype]);
199a4af0ceeSJacob Faibussowitsch   }
200dbbe0bcdSBarry Smith   PetscUseTypeMethod(device, configure);
2013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
202a4af0ceeSJacob Faibussowitsch }
203a4af0ceeSJacob Faibussowitsch 
204a4af0ceeSJacob Faibussowitsch /*@C
205811af0c4SBarry Smith   PetscDeviceView - View a `PetscDevice`
206a4af0ceeSJacob Faibussowitsch 
2070e6b6b59SJacob Faibussowitsch   Collective on viewer
208a4af0ceeSJacob Faibussowitsch 
20991e63d38SStefano Zampini   Input Parameters:
210811af0c4SBarry Smith + device - The `PetscDevice` to view
2110e6b6b59SJacob Faibussowitsch - viewer - The `PetscViewer` to view the device with (`NULL` for `PETSC_VIEWER_STDOUT_WORLD`)
212a4af0ceeSJacob Faibussowitsch 
213a4af0ceeSJacob Faibussowitsch   Level: beginner
214a4af0ceeSJacob Faibussowitsch 
2150e6b6b59SJacob Faibussowitsch .seealso: `PetscDevice`, `PetscDeviceCreate()`, `PetscDeviceConfigure()`,
2160e6b6b59SJacob Faibussowitsch `PetscDeviceDestroy()`, `PetscDeviceGetType()`, `PetscDeviceGetDeviceId()`
217a4af0ceeSJacob Faibussowitsch @*/
218d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceView(PetscDevice device, PetscViewer viewer)
219d71ae5a4SJacob Faibussowitsch {
2200e6b6b59SJacob Faibussowitsch   auto      sub = viewer;
2210e6b6b59SJacob Faibussowitsch   PetscBool iascii;
2220e6b6b59SJacob Faibussowitsch 
223a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
224a4af0ceeSJacob Faibussowitsch   PetscValidDevice(device, 1);
2250e6b6b59SJacob Faibussowitsch   if (viewer) {
226a4af0ceeSJacob Faibussowitsch     PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2270e6b6b59SJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare(PetscObjectCast(viewer), PETSCVIEWERASCII, &iascii));
2280e6b6b59SJacob Faibussowitsch   } else {
2290e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerASCIIGetStdout(PETSC_COMM_WORLD, &viewer));
2300e6b6b59SJacob Faibussowitsch     iascii = PETSC_TRUE;
2310e6b6b59SJacob Faibussowitsch   }
2320e6b6b59SJacob Faibussowitsch 
2330e6b6b59SJacob Faibussowitsch   if (iascii) {
2340e6b6b59SJacob Faibussowitsch     auto        dtype = PETSC_DEVICE_HOST;
2350e6b6b59SJacob Faibussowitsch     MPI_Comm    comm;
2360e6b6b59SJacob Faibussowitsch     PetscMPIInt size;
2370e6b6b59SJacob Faibussowitsch     PetscInt    id = 0;
2380e6b6b59SJacob Faibussowitsch 
2390e6b6b59SJacob Faibussowitsch     PetscCall(PetscObjectGetComm(PetscObjectCast(viewer), &comm));
2400e6b6b59SJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(comm, &size));
2410e6b6b59SJacob Faibussowitsch 
2420e6b6b59SJacob Faibussowitsch     PetscCall(PetscDeviceGetDeviceId(device, &id));
2430e6b6b59SJacob Faibussowitsch     PetscCall(PetscDeviceGetType(device, &dtype));
2440e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sub));
2450e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(sub, "PetscDevice Object: %d MPI %s\n", size, size == 1 ? "process" : "processes"));
2460e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(sub));
2470e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(sub, "type: %s\n", PetscDeviceTypes[dtype]));
2480e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(sub, "id: %" PetscInt_FMT "\n", id));
2490e6b6b59SJacob Faibussowitsch   }
2500e6b6b59SJacob Faibussowitsch 
2510e6b6b59SJacob Faibussowitsch   // see if impls has extra viewer stuff
2520e6b6b59SJacob Faibussowitsch   PetscTryTypeMethod(device, view, sub);
2530e6b6b59SJacob Faibussowitsch 
2540e6b6b59SJacob Faibussowitsch   if (iascii) {
2550e6b6b59SJacob Faibussowitsch     // undo the ASCII specific stuff
2560e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(sub));
2570e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sub));
2580e6b6b59SJacob Faibussowitsch   }
2593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
260a4af0ceeSJacob Faibussowitsch }
261a4af0ceeSJacob Faibussowitsch 
26291e63d38SStefano Zampini /*@C
2630e6b6b59SJacob Faibussowitsch   PetscDeviceGetType - Get the type of device
26491e63d38SStefano Zampini 
2650e6b6b59SJacob Faibussowitsch   Not Collective
26691e63d38SStefano Zampini 
26791e63d38SStefano Zampini   Input Parameter:
268811af0c4SBarry Smith . device - The `PetscDevice`
26991e63d38SStefano Zampini 
27091e63d38SStefano Zampini   Output Parameter:
2710e6b6b59SJacob Faibussowitsch . type - The `PetscDeviceType`
27291e63d38SStefano Zampini 
27391e63d38SStefano Zampini   Level: beginner
27491e63d38SStefano Zampini 
2750e6b6b59SJacob Faibussowitsch .seealso: `PetscDevice`, `PetscDeviceType`, `PetscDeviceSetDefaultDeviceType()`,
2760e6b6b59SJacob Faibussowitsch `PetscDeviceCreate()`, `PetscDeviceConfigure()`, `PetscDeviceDestroy()`,
2770e6b6b59SJacob Faibussowitsch `PetscDeviceGetDeviceId()`, `PETSC_DEVICE_DEFAULT()`
2780e6b6b59SJacob Faibussowitsch @*/
279d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceGetType(PetscDevice device, PetscDeviceType *type)
280d71ae5a4SJacob Faibussowitsch {
2810e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
2820e6b6b59SJacob Faibussowitsch   PetscValidDevice(device, 1);
2834f572ea9SToby Isaac   PetscAssertPointer(type, 2);
2840e6b6b59SJacob Faibussowitsch   *type = device->type;
2853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2860e6b6b59SJacob Faibussowitsch }
2870e6b6b59SJacob Faibussowitsch 
2880e6b6b59SJacob Faibussowitsch /*@C
2890e6b6b59SJacob Faibussowitsch   PetscDeviceGetDeviceId - Get the device ID for a `PetscDevice`
2900e6b6b59SJacob Faibussowitsch 
2910e6b6b59SJacob Faibussowitsch   Not Collective
2920e6b6b59SJacob Faibussowitsch 
2930e6b6b59SJacob Faibussowitsch   Input Parameter:
2940e6b6b59SJacob Faibussowitsch . device - The `PetscDevice`
2950e6b6b59SJacob Faibussowitsch 
2960e6b6b59SJacob Faibussowitsch   Output Parameter:
2970e6b6b59SJacob Faibussowitsch . id - The id
2980e6b6b59SJacob Faibussowitsch 
2992fe279fdSBarry Smith   Level: beginner
3002fe279fdSBarry Smith 
3010e6b6b59SJacob Faibussowitsch   Notes:
3020e6b6b59SJacob Faibussowitsch   The returned ID may have been assigned by the underlying device backend. For example if the
3030e6b6b59SJacob Faibussowitsch   backend is CUDA then `id` is exactly the value returned by `cudaGetDevice()` at the time when
3040e6b6b59SJacob Faibussowitsch   this device was configured.
3050e6b6b59SJacob Faibussowitsch 
3060e6b6b59SJacob Faibussowitsch .seealso: `PetscDevice`, `PetscDeviceCreate()`, `PetscDeviceGetType()`
30791e63d38SStefano Zampini @*/
308d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceGetDeviceId(PetscDevice device, PetscInt *id)
309d71ae5a4SJacob Faibussowitsch {
31091e63d38SStefano Zampini   PetscFunctionBegin;
31191e63d38SStefano Zampini   PetscValidDevice(device, 1);
3124f572ea9SToby Isaac   PetscAssertPointer(id, 2);
31391e63d38SStefano Zampini   *id = device->deviceId;
3143ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
31591e63d38SStefano Zampini }
31691e63d38SStefano Zampini 
317bbfde98dSJacob Faibussowitsch namespace
318bbfde98dSJacob Faibussowitsch {
319bbfde98dSJacob Faibussowitsch 
3200e6b6b59SJacob Faibussowitsch struct DefaultDeviceType : public Petsc::RegisterFinalizeable<DefaultDeviceType> {
3210e6b6b59SJacob Faibussowitsch   PetscDeviceType type = PETSC_DEVICE_HARDWARE_DEFAULT_TYPE;
3220e6b6b59SJacob Faibussowitsch 
323089fb57cSJacob Faibussowitsch   PetscErrorCode finalize_() noexcept
324d71ae5a4SJacob Faibussowitsch   {
3250e6b6b59SJacob Faibussowitsch     PetscFunctionBegin;
3260e6b6b59SJacob Faibussowitsch     type = PETSC_DEVICE_HARDWARE_DEFAULT_TYPE;
3273ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
3280e6b6b59SJacob Faibussowitsch   }
3290e6b6b59SJacob Faibussowitsch };
3300e6b6b59SJacob Faibussowitsch 
331bbfde98dSJacob Faibussowitsch auto default_device_type = DefaultDeviceType();
332bbfde98dSJacob Faibussowitsch 
333bbfde98dSJacob Faibussowitsch } // namespace
3340e6b6b59SJacob Faibussowitsch 
3350e6b6b59SJacob Faibussowitsch /*@C
3360e6b6b59SJacob Faibussowitsch   PETSC_DEVICE_DEFAULT - Retrieve the current default `PetscDeviceType`
3370e6b6b59SJacob Faibussowitsch 
3380e6b6b59SJacob Faibussowitsch   Not Collective
3390e6b6b59SJacob Faibussowitsch 
3402fe279fdSBarry Smith   Level: beginner
3412fe279fdSBarry Smith 
3420e6b6b59SJacob Faibussowitsch   Notes:
3430e6b6b59SJacob Faibussowitsch   Unless selected by the user, the default device is selected in the following order\:
3440e6b6b59SJacob Faibussowitsch   `PETSC_DEVICE_HIP`, `PETSC_DEVICE_CUDA`, `PETSC_DEVICE_SYCL`, `PETSC_DEVICE_HOST`.
3450e6b6b59SJacob Faibussowitsch 
3460e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceType`, `PetscDeviceSetDefaultDeviceType()`, `PetscDeviceGetType()`
3470e6b6b59SJacob Faibussowitsch @*/
348d71ae5a4SJacob Faibussowitsch PetscDeviceType PETSC_DEVICE_DEFAULT(void)
349d71ae5a4SJacob Faibussowitsch {
3500e6b6b59SJacob Faibussowitsch   return default_device_type.type;
3510e6b6b59SJacob Faibussowitsch }
3520e6b6b59SJacob Faibussowitsch 
3530e6b6b59SJacob Faibussowitsch /*@C
3540e6b6b59SJacob Faibussowitsch   PetscDeviceSetDefaultDeviceType - Set the default device type for `PetscDevice`
3550e6b6b59SJacob Faibussowitsch 
3560e6b6b59SJacob Faibussowitsch   Not Collective
3570e6b6b59SJacob Faibussowitsch 
3580e6b6b59SJacob Faibussowitsch   Input Parameter:
3590e6b6b59SJacob Faibussowitsch . type - the new default device type
3600e6b6b59SJacob Faibussowitsch 
3612fe279fdSBarry Smith   Level: beginner
3622fe279fdSBarry Smith 
3630e6b6b59SJacob Faibussowitsch   Notes:
3640e6b6b59SJacob Faibussowitsch   This sets the `PetscDeviceType` returned by `PETSC_DEVICE_DEFAULT()`.
3650e6b6b59SJacob Faibussowitsch 
3660e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceType`, `PetscDeviceGetType`,
3670e6b6b59SJacob Faibussowitsch @*/
368d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceSetDefaultDeviceType(PetscDeviceType type)
369d71ae5a4SJacob Faibussowitsch {
3700e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
3710e6b6b59SJacob Faibussowitsch   PetscValidDeviceType(type, 1);
3720e6b6b59SJacob Faibussowitsch   if (default_device_type.type != type) {
3730e6b6b59SJacob Faibussowitsch     // no need to waster a PetscRegisterFinalize() slot if we don't change it
3740e6b6b59SJacob Faibussowitsch     default_device_type.type = type;
3750e6b6b59SJacob Faibussowitsch     PetscCall(default_device_type.register_finalize());
3760e6b6b59SJacob Faibussowitsch   }
3773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3780e6b6b59SJacob Faibussowitsch }
3790e6b6b59SJacob Faibussowitsch 
380bbfde98dSJacob Faibussowitsch namespace
381bbfde98dSJacob Faibussowitsch {
382bbfde98dSJacob Faibussowitsch 
383bbfde98dSJacob Faibussowitsch std::array<std::pair<PetscDevice, bool>, PETSC_DEVICE_MAX> defaultDevices = {};
3840e6b6b59SJacob Faibussowitsch 
3850e6b6b59SJacob Faibussowitsch /*
386da81f932SPierre Jolivet   Actual initialization function; any functions claiming to initialize PetscDevice or
3870e6b6b59SJacob Faibussowitsch   PetscDeviceContext will have to run through this one
3880e6b6b59SJacob Faibussowitsch */
389bbfde98dSJacob Faibussowitsch PetscErrorCode PetscDeviceInitializeDefaultDevice_Internal(PetscDeviceType type, PetscInt defaultDeviceId)
390d71ae5a4SJacob Faibussowitsch {
3910e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
3920e6b6b59SJacob Faibussowitsch   PetscValidDeviceType(type, 1);
3930e6b6b59SJacob Faibussowitsch   if (PetscUnlikely(!PetscDeviceInitialized(type))) {
3940e6b6b59SJacob Faibussowitsch     auto &dev  = defaultDevices[type].first;
3950e6b6b59SJacob Faibussowitsch     auto &init = defaultDevices[type].second;
3960e6b6b59SJacob Faibussowitsch 
3970e6b6b59SJacob Faibussowitsch     PetscAssert(!dev, PETSC_COMM_SELF, PETSC_ERR_MEM, "Trying to overwrite existing default device of type %s", PetscDeviceTypes[type]);
3980e6b6b59SJacob Faibussowitsch     PetscCall(PetscDeviceCreate(type, defaultDeviceId, &dev));
3990e6b6b59SJacob Faibussowitsch     PetscCall(PetscDeviceConfigure(dev));
4000e6b6b59SJacob Faibussowitsch     init = true;
4010e6b6b59SJacob Faibussowitsch   }
4023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4030e6b6b59SJacob Faibussowitsch }
404a4af0ceeSJacob Faibussowitsch 
405bbfde98dSJacob Faibussowitsch } // namespace
406bbfde98dSJacob Faibussowitsch 
407a4af0ceeSJacob Faibussowitsch /*@C
408811af0c4SBarry Smith   PetscDeviceInitialize - Initialize `PetscDevice`
409a4af0ceeSJacob Faibussowitsch 
4100e6b6b59SJacob Faibussowitsch   Not Collective
411a4af0ceeSJacob Faibussowitsch 
412a4af0ceeSJacob Faibussowitsch   Input Parameter:
413811af0c4SBarry Smith . type - The `PetscDeviceType` to initialize
414a4af0ceeSJacob Faibussowitsch 
4152fe279fdSBarry Smith   Level: beginner
4162fe279fdSBarry Smith 
4170e6b6b59SJacob Faibussowitsch   Notes:
4180e6b6b59SJacob Faibussowitsch   Eagerly initializes the corresponding `PetscDeviceType` if needed. If this is the case it may
4190e6b6b59SJacob Faibussowitsch   result in device synchronization.
420a4af0ceeSJacob Faibussowitsch 
4210e6b6b59SJacob Faibussowitsch .seealso: `PetscDevice`, `PetscDeviceInitType`, `PetscDeviceInitialized()`,
4220e6b6b59SJacob Faibussowitsch `PetscDeviceCreate()`, `PetscDeviceDestroy()`
423a4af0ceeSJacob Faibussowitsch @*/
424d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceInitialize(PetscDeviceType type)
425d71ae5a4SJacob Faibussowitsch {
426a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
427a4af0ceeSJacob Faibussowitsch   PetscValidDeviceType(type, 1);
4289566063dSJacob Faibussowitsch   PetscCall(PetscDeviceInitializeDefaultDevice_Internal(type, PETSC_DECIDE));
4293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
430a4af0ceeSJacob Faibussowitsch }
431a4af0ceeSJacob Faibussowitsch 
432a4af0ceeSJacob Faibussowitsch /*@C
433811af0c4SBarry Smith   PetscDeviceInitialized - Determines whether `PetscDevice` is initialized for a particular
434811af0c4SBarry Smith   `PetscDeviceType`
435a4af0ceeSJacob Faibussowitsch 
4360e6b6b59SJacob Faibussowitsch   Not Collective
437a4af0ceeSJacob Faibussowitsch 
438a4af0ceeSJacob Faibussowitsch   Input Parameter:
439811af0c4SBarry Smith . type - The `PetscDeviceType` to check
440a4af0ceeSJacob Faibussowitsch 
4412fe279fdSBarry Smith   Level: beginner
4422fe279fdSBarry Smith 
4430e6b6b59SJacob Faibussowitsch   Notes:
4440e6b6b59SJacob Faibussowitsch   Returns `PETSC_TRUE` if `type` is initialized, `PETSC_FALSE` otherwise.
445a4af0ceeSJacob Faibussowitsch 
446811af0c4SBarry Smith   If one has not configured PETSc for a particular `PetscDeviceType` then this routine will
447811af0c4SBarry Smith   return `PETSC_FALSE` for that `PetscDeviceType`.
448a4af0ceeSJacob Faibussowitsch 
4490e6b6b59SJacob Faibussowitsch .seealso: `PetscDevice`, `PetscDeviceInitType`, `PetscDeviceInitialize()`,
4500e6b6b59SJacob Faibussowitsch `PetscDeviceCreate()`, `PetscDeviceDestroy()`
451a4af0ceeSJacob Faibussowitsch @*/
452d71ae5a4SJacob Faibussowitsch PetscBool PetscDeviceInitialized(PetscDeviceType type)
453d71ae5a4SJacob Faibussowitsch {
4540e6b6b59SJacob Faibussowitsch   return static_cast<PetscBool>(PetscDeviceConfiguredFor_Internal(type) && defaultDevices[type].second);
4550e6b6b59SJacob Faibussowitsch }
4560e6b6b59SJacob Faibussowitsch 
4570e6b6b59SJacob Faibussowitsch /* Get the default PetscDevice for a particular type and constructs them if lazily initialized. */
458d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceGetDefaultForType_Internal(PetscDeviceType type, PetscDevice *device)
459d71ae5a4SJacob Faibussowitsch {
4600e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
4614f572ea9SToby Isaac   PetscAssertPointer(device, 2);
4620e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceInitialize(type));
4630e6b6b59SJacob Faibussowitsch   *device = defaultDevices[type].first;
4643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
465a4af0ceeSJacob Faibussowitsch }
466a4af0ceeSJacob Faibussowitsch 
467a16fd2c9SJacob Faibussowitsch /*@C
468a16fd2c9SJacob Faibussowitsch   PetscDeviceGetAttribute - Query a particular attribute of a `PetscDevice`
469a16fd2c9SJacob Faibussowitsch 
4700e6b6b59SJacob Faibussowitsch   Not Collective
471a16fd2c9SJacob Faibussowitsch 
472a16fd2c9SJacob Faibussowitsch   Input Parameters:
473a16fd2c9SJacob Faibussowitsch + device - The `PetscDevice`
474a16fd2c9SJacob Faibussowitsch - attr   - The attribute
475a16fd2c9SJacob Faibussowitsch 
476a16fd2c9SJacob Faibussowitsch   Output Parameter:
477a16fd2c9SJacob Faibussowitsch . value - The value of the attribute
478a16fd2c9SJacob Faibussowitsch 
4792fe279fdSBarry Smith   Level: intermediate
4802fe279fdSBarry Smith 
481a16fd2c9SJacob Faibussowitsch   Notes:
482a16fd2c9SJacob Faibussowitsch   Since different attributes are often different types `value` is a `void *` to accommodate
483a16fd2c9SJacob Faibussowitsch   them all. The underlying type of the attribute is therefore included in the name of the
484da81f932SPierre Jolivet   `PetscDeviceAttribute` responsible for querying it. For example,
485a16fd2c9SJacob Faibussowitsch   `PETSC_DEVICE_ATTR_SIZE_T_SHARED_MEM_PER_BLOCK` is of type `size_t`.
486a16fd2c9SJacob Faibussowitsch 
487a16fd2c9SJacob Faibussowitsch .seealso: `PetscDeviceAtrtibute`, `PetscDeviceConfigure()`, `PetscDevice`
488a16fd2c9SJacob Faibussowitsch @*/
489d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceGetAttribute(PetscDevice device, PetscDeviceAttribute attr, void *value)
490d71ae5a4SJacob Faibussowitsch {
491a16fd2c9SJacob Faibussowitsch   PetscFunctionBegin;
492a16fd2c9SJacob Faibussowitsch   PetscValidDevice(device, 1);
493a16fd2c9SJacob Faibussowitsch   PetscValidDeviceAttribute(attr, 2);
4944f572ea9SToby Isaac   PetscAssertPointer(value, 3);
495a16fd2c9SJacob Faibussowitsch   PetscUseTypeMethod(device, getattribute, attr, value);
4963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
497a16fd2c9SJacob Faibussowitsch }
498a16fd2c9SJacob Faibussowitsch 
499bbfde98dSJacob Faibussowitsch namespace
500bbfde98dSJacob Faibussowitsch {
501bbfde98dSJacob Faibussowitsch 
502bbfde98dSJacob Faibussowitsch PetscErrorCode PetscDeviceInitializeTypeFromOptions_Private(MPI_Comm comm, PetscDeviceType type, PetscInt defaultDeviceId, PetscBool defaultView, PetscDeviceInitType *defaultInitType)
503d71ae5a4SJacob Faibussowitsch {
504a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
505a4af0ceeSJacob Faibussowitsch   if (!PetscDeviceConfiguredFor_Internal(type)) {
5060e6b6b59SJacob Faibussowitsch     PetscCall(PetscInfo(nullptr, "PetscDeviceType %s not available\n", PetscDeviceTypes[type]));
5070e6b6b59SJacob Faibussowitsch     defaultDevices[type].first = nullptr;
5083ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
509a4af0ceeSJacob Faibussowitsch   }
5100e6b6b59SJacob Faibussowitsch   PetscCall(PetscInfo(nullptr, "PetscDeviceType %s available, initializing\n", PetscDeviceTypes[type]));
511a4af0ceeSJacob Faibussowitsch   /* ugly switch needed to pick the right global variable... could maybe do this as a union? */
512a4af0ceeSJacob Faibussowitsch   switch (type) {
5130e6b6b59SJacob Faibussowitsch     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(HOST, initialize, comm, &defaultDeviceId, &defaultView, defaultInitType);
5140e6b6b59SJacob Faibussowitsch     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(CUDA, initialize, comm, &defaultDeviceId, &defaultView, defaultInitType);
5150e6b6b59SJacob Faibussowitsch     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(HIP, initialize, comm, &defaultDeviceId, &defaultView, defaultInitType);
5160e6b6b59SJacob Faibussowitsch     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(SYCL, initialize, comm, &defaultDeviceId, &defaultView, defaultInitType);
517d71ae5a4SJacob Faibussowitsch   default:
518d71ae5a4SJacob 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]);
519a4af0ceeSJacob Faibussowitsch   }
520bd2fcf0cSJacob Faibussowitsch   PetscCall(PetscInfo(nullptr, "PetscDevice %s initialized, default device id %" PetscInt_FMT ", view %s, init type %s\n", PetscDeviceTypes[type], defaultDeviceId, PetscBools[defaultView], PetscDeviceInitTypes[Petsc::util::to_underlying(*defaultInitType)]));
521cf3a2253SJacob Faibussowitsch   /*
5220e6b6b59SJacob Faibussowitsch     defaultInitType, defaultView  and defaultDeviceId now represent what the individual TYPES
5230e6b6b59SJacob Faibussowitsch     have decided to initialize as
524cf3a2253SJacob Faibussowitsch   */
5250e6b6b59SJacob Faibussowitsch   if ((*defaultInitType == PETSC_DEVICE_INIT_EAGER) || defaultView) {
5260e6b6b59SJacob Faibussowitsch     PetscCall(PetscInfo(nullptr, "Eagerly initializing %s PetscDevice\n", PetscDeviceTypes[type]));
5279566063dSJacob Faibussowitsch     PetscCall(PetscDeviceInitializeDefaultDevice_Internal(type, defaultDeviceId));
5280e6b6b59SJacob Faibussowitsch     if (defaultView) PetscCall(PetscDeviceView(defaultDevices[type].first, nullptr));
5290e6b6b59SJacob Faibussowitsch   }
5303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5310e6b6b59SJacob Faibussowitsch }
532a4af0ceeSJacob Faibussowitsch 
533bbfde98dSJacob Faibussowitsch PetscErrorCode PetscDeviceInitializeQueryOptions_Private(MPI_Comm comm, PetscDeviceType *deviceContextInitDevice, PetscDeviceInitType *defaultInitType, PetscInt *defaultDevice, PetscBool *defaultDeviceSet, PetscBool *defaultView)
534d71ae5a4SJacob Faibussowitsch {
5350e6b6b59SJacob Faibussowitsch   PetscInt initIdx       = PETSC_DEVICE_INIT_LAZY;
5360e6b6b59SJacob Faibussowitsch   auto     initDeviceIdx = static_cast<PetscInt>(*deviceContextInitDevice);
5370e6b6b59SJacob Faibussowitsch   auto     flg           = PETSC_FALSE;
5380e6b6b59SJacob Faibussowitsch 
5390e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
5400e6b6b59SJacob Faibussowitsch   PetscCall(PetscOptionsHasName(nullptr, nullptr, "-log_view_gpu_time", &flg));
5410e6b6b59SJacob Faibussowitsch   if (flg) PetscCall(PetscLogGpuTime());
5420e6b6b59SJacob Faibussowitsch 
5430e6b6b59SJacob Faibussowitsch   PetscOptionsBegin(comm, nullptr, "PetscDevice Options", "Sys");
5440e6b6b59SJacob Faibussowitsch   PetscCall(PetscOptionsEList("-device_enable", "How (or whether) to initialize PetscDevices", "PetscDeviceInitialize()", PetscDeviceInitTypes, 3, PetscDeviceInitTypes[initIdx], &initIdx, nullptr));
5450e6b6b59SJacob Faibussowitsch   PetscCall(PetscOptionsEList("-default_device_type", "Set the PetscDeviceType returned by PETSC_DEVICE_DEFAULT()", "PetscDeviceSetDefaultDeviceType()", PetscDeviceTypes, PETSC_DEVICE_MAX, PetscDeviceTypes[initDeviceIdx], &initDeviceIdx, defaultDeviceSet));
5460e6b6b59SJacob Faibussowitsch   PetscCall(PetscOptionsRangeInt("-device_select", "Which device to use. Pass " PetscStringize(PETSC_DECIDE) " to have PETSc decide or (given they exist) [0-" PetscStringize(PETSC_DEVICE_MAX_DEVICES) ") for a specific device", "PetscDeviceCreate()", *defaultDevice, defaultDevice, nullptr, PETSC_DECIDE, PETSC_DEVICE_MAX_DEVICES));
5470e6b6b59SJacob Faibussowitsch   PetscCall(PetscOptionsBool("-device_view", "Display device information and assignments (forces eager initialization)", "PetscDeviceView()", *defaultView, defaultView, &flg));
5480e6b6b59SJacob Faibussowitsch   PetscOptionsEnd();
5490e6b6b59SJacob Faibussowitsch 
5500e6b6b59SJacob Faibussowitsch   if (initIdx == PETSC_DEVICE_INIT_NONE) {
5510e6b6b59SJacob Faibussowitsch     /* disabled all device initialization if devices are globally disabled */
552da81f932SPierre Jolivet     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 exclusive");
5530e6b6b59SJacob Faibussowitsch     *defaultView  = PETSC_FALSE;
5540e6b6b59SJacob Faibussowitsch     initDeviceIdx = PETSC_DEVICE_HOST;
5550e6b6b59SJacob Faibussowitsch   } else {
5560e6b6b59SJacob Faibussowitsch     *defaultView = static_cast<PetscBool>(*defaultView && flg);
5570e6b6b59SJacob Faibussowitsch     if (*defaultView) initIdx = PETSC_DEVICE_INIT_EAGER;
558a4af0ceeSJacob Faibussowitsch   }
5590e6b6b59SJacob Faibussowitsch   *defaultInitType         = PetscDeviceInitTypeCast(initIdx);
5600e6b6b59SJacob Faibussowitsch   *deviceContextInitDevice = PetscDeviceTypeCast(initDeviceIdx);
5613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
562030f984aSJacob Faibussowitsch }
563030f984aSJacob Faibussowitsch 
564030f984aSJacob Faibussowitsch /* called from PetscFinalize() do not call yourself! */
565bbfde98dSJacob Faibussowitsch PetscErrorCode PetscDeviceFinalize_Private()
566d71ae5a4SJacob Faibussowitsch {
567030f984aSJacob Faibussowitsch   PetscFunctionBegin;
568a4af0ceeSJacob Faibussowitsch   if (PetscDefined(USE_DEBUG)) {
569bf025ffbSJacob Faibussowitsch     /*
570bf025ffbSJacob Faibussowitsch       you might be thinking, why on earth are you registered yet another finalizer in a
571bf025ffbSJacob Faibussowitsch       function already called during PetscRegisterFinalizeAll()? If this seems stupid it's
572bf025ffbSJacob Faibussowitsch       because it is.
573bf025ffbSJacob Faibussowitsch 
574bf025ffbSJacob Faibussowitsch       The crux of the problem is that the initializer (and therefore the ~finalizer~) of
575bf025ffbSJacob Faibussowitsch       PetscDeviceContext is guaranteed to run after PetscDevice's. So if the global context had
576bf025ffbSJacob Faibussowitsch       a default PetscDevice attached, that PetscDevice will have a reference count >0 and hence
577bf025ffbSJacob Faibussowitsch       won't be destroyed yet. So we need to repeat the check that all devices have been
578bf025ffbSJacob Faibussowitsch       destroyed again ~after~ the global context is destroyed. In summary:
579bf025ffbSJacob Faibussowitsch 
580bf025ffbSJacob Faibussowitsch       1. This finalizer runs and destroys all devices, except it may not because the global
581bf025ffbSJacob Faibussowitsch          context may still hold a reference!
582bf025ffbSJacob Faibussowitsch       2. The global context finalizer runs and does the final reference count decrement
583bf025ffbSJacob Faibussowitsch          required, which actually destroys the held device.
584bf025ffbSJacob Faibussowitsch       3. Our newly added finalizer runs and checks that all is well.
585a4af0ceeSJacob Faibussowitsch     */
586bbfde98dSJacob Faibussowitsch     PetscCall(PetscRegisterFinalize([] {
587bbfde98dSJacob Faibussowitsch       PetscFunctionBegin;
588bbfde98dSJacob Faibussowitsch       for (auto &&device : defaultDevices) {
589bbfde98dSJacob Faibussowitsch         const auto dev = device.first;
590bbfde98dSJacob Faibussowitsch 
591bbfde98dSJacob Faibussowitsch         PetscCheck(!dev, PETSC_COMM_WORLD, PETSC_ERR_COR, "Device of type '%s' had reference count %" PetscInt_FMT " and was not fully destroyed during PetscFinalize()", PetscDeviceTypes[dev->type], dev->refcnt);
592bbfde98dSJacob Faibussowitsch       }
593bbfde98dSJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
594bbfde98dSJacob Faibussowitsch     }));
595a4af0ceeSJacob Faibussowitsch   }
5960e6b6b59SJacob Faibussowitsch   for (auto &&device : defaultDevices) {
5970e6b6b59SJacob Faibussowitsch     PetscCall(PetscDeviceDestroy(&device.first));
5980e6b6b59SJacob Faibussowitsch     device.second = false;
5990e6b6b59SJacob Faibussowitsch   }
6003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
601030f984aSJacob Faibussowitsch }
602030f984aSJacob Faibussowitsch 
603bbfde98dSJacob Faibussowitsch } // namespace
604bbfde98dSJacob Faibussowitsch 
605cf3a2253SJacob Faibussowitsch /*
606cf3a2253SJacob Faibussowitsch   Begins the init proceeedings for the entire PetscDevice stack. there are 3 stages of
607cf3a2253SJacob Faibussowitsch   initialization types:
608cf3a2253SJacob Faibussowitsch 
609a4af0ceeSJacob Faibussowitsch   1. defaultInitType - how does PetscDevice as a whole expect to initialize?
610a4af0ceeSJacob Faibussowitsch   2. subTypeDefaultInitType - how does each PetscDevice implementation expect to initialize?
611a4af0ceeSJacob Faibussowitsch      e.g. you may want to blanket disable PetscDevice init (and disable say Kokkos init), but
612a4af0ceeSJacob Faibussowitsch      have all CUDA devices still initialize.
613a4af0ceeSJacob Faibussowitsch 
614a4af0ceeSJacob Faibussowitsch   All told the following happens:
615cf3a2253SJacob Faibussowitsch 
616a4af0ceeSJacob Faibussowitsch   0. defaultInitType -> LAZY
617a4af0ceeSJacob Faibussowitsch   1. Check for log_view/log_summary, if yes defaultInitType -> EAGER
618a4af0ceeSJacob Faibussowitsch   2. PetscDevice initializes each sub type with deviceDefaultInitType.
619a4af0ceeSJacob Faibussowitsch   2.1 Each enabled PetscDevice sub-type then does the above disable or view check in addition
620a4af0ceeSJacob Faibussowitsch       to checking for specific device init. if view or specific device init
621a4af0ceeSJacob Faibussowitsch       subTypeDefaultInitType -> EAGER. disabled once again overrides all.
622a4af0ceeSJacob Faibussowitsch */
6230e6b6b59SJacob Faibussowitsch 
624d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceInitializeFromOptions_Internal(MPI_Comm comm)
625d71ae5a4SJacob Faibussowitsch {
6267a101e5eSJacob Faibussowitsch   auto defaultView                    = PETSC_FALSE;
6277a101e5eSJacob Faibussowitsch   auto initializeDeviceContextEagerly = PETSC_FALSE;
6280e6b6b59SJacob Faibussowitsch   auto defaultDeviceSet               = PETSC_FALSE;
6297a101e5eSJacob Faibussowitsch   auto defaultDevice                  = PetscInt{PETSC_DECIDE};
6300e6b6b59SJacob Faibussowitsch   auto deviceContextInitDevice        = PETSC_DEVICE_DEFAULT();
6310e6b6b59SJacob Faibussowitsch   auto defaultInitType                = PETSC_DEVICE_INIT_LAZY;
632a4af0ceeSJacob Faibussowitsch 
633a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
634a4af0ceeSJacob Faibussowitsch   if (PetscDefined(USE_DEBUG)) {
635a4af0ceeSJacob Faibussowitsch     int result;
636a4af0ceeSJacob Faibussowitsch 
6379566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_compare(comm, PETSC_COMM_WORLD, &result));
638a4af0ceeSJacob Faibussowitsch     /* in order to accurately assign ranks to gpus we need to get the MPI_Comm_rank of the
639a4af0ceeSJacob Faibussowitsch      * global space */
640a4af0ceeSJacob Faibussowitsch     if (PetscUnlikely(result != MPI_IDENT)) {
641a4af0ceeSJacob Faibussowitsch       char name[MPI_MAX_OBJECT_NAME] = {};
642a4af0ceeSJacob Faibussowitsch       int  len; /* unused */
643a4af0ceeSJacob Faibussowitsch 
6449566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_get_name(comm, name, &len));
64598921bdaSJacob Faibussowitsch       SETERRQ(comm, PETSC_ERR_MPI, "Default devices being initialized on MPI_Comm '%s' not PETSC_COMM_WORLD", name);
646a4af0ceeSJacob Faibussowitsch     }
647a4af0ceeSJacob Faibussowitsch   }
648a4af0ceeSJacob Faibussowitsch   comm = PETSC_COMM_WORLD; /* from this point on we assume we're on PETSC_COMM_WORLD */
6499566063dSJacob Faibussowitsch   PetscCall(PetscRegisterFinalize(PetscDeviceFinalize_Private));
650a4af0ceeSJacob Faibussowitsch 
6510e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceInitializeQueryOptions_Private(comm, &deviceContextInitDevice, &defaultInitType, &defaultDevice, &defaultDeviceSet, &defaultView));
6527a101e5eSJacob Faibussowitsch 
6530e6b6b59SJacob Faibussowitsch   // the precise values don't matter here, so long as they are sequential
654bd2fcf0cSJacob Faibussowitsch   static_assert(Petsc::util::to_underlying(PETSC_DEVICE_HOST) == 0, "");
655bd2fcf0cSJacob Faibussowitsch   static_assert(Petsc::util::to_underlying(PETSC_DEVICE_CUDA) == 1, "");
656bd2fcf0cSJacob Faibussowitsch   static_assert(Petsc::util::to_underlying(PETSC_DEVICE_HIP) == 2, "");
657bd2fcf0cSJacob Faibussowitsch   static_assert(Petsc::util::to_underlying(PETSC_DEVICE_SYCL) == 3, "");
658bd2fcf0cSJacob Faibussowitsch   static_assert(Petsc::util::to_underlying(PETSC_DEVICE_MAX) == 4, "");
6590e6b6b59SJacob Faibussowitsch   for (int i = PETSC_DEVICE_HOST; i < PETSC_DEVICE_MAX; ++i) {
6600e6b6b59SJacob Faibussowitsch     const auto deviceType = PetscDeviceTypeCast(i);
661a4af0ceeSJacob Faibussowitsch     auto       initType   = defaultInitType;
662a4af0ceeSJacob Faibussowitsch 
6639566063dSJacob Faibussowitsch     PetscCall(PetscDeviceInitializeTypeFromOptions_Private(comm, deviceType, defaultDevice, defaultView, &initType));
6640e6b6b59SJacob Faibussowitsch     if (PetscDeviceConfiguredFor_Internal(deviceType)) {
6650e6b6b59SJacob Faibussowitsch       if (initType == PETSC_DEVICE_INIT_EAGER) {
666a4af0ceeSJacob Faibussowitsch         initializeDeviceContextEagerly = PETSC_TRUE;
6670e6b6b59SJacob Faibussowitsch         // only update the default device if the user hasn't set it previously
6680e6b6b59SJacob Faibussowitsch         if (!defaultDeviceSet) {
669a4af0ceeSJacob Faibussowitsch           deviceContextInitDevice = deviceType;
6700e6b6b59SJacob Faibussowitsch           PetscCall(PetscInfo(nullptr, "PetscDevice %s set as default device type due to eager initialization\n", PetscDeviceTypes[deviceType]));
6710e6b6b59SJacob Faibussowitsch         }
6720e6b6b59SJacob Faibussowitsch       } else if (initType == PETSC_DEVICE_INIT_NONE) {
6731015a2a4SJacob Faibussowitsch         if (deviceType != PETSC_DEVICE_HOST) PetscCheck(!defaultDeviceSet || (deviceType != deviceContextInitDevice), comm, PETSC_ERR_USER_INPUT, "Cannot explicitly disable the device set as default device type (%s)", PetscDeviceTypes[deviceType]);
674a4af0ceeSJacob Faibussowitsch       }
675a4af0ceeSJacob Faibussowitsch     }
6760e6b6b59SJacob Faibussowitsch   }
6770e6b6b59SJacob Faibussowitsch 
6780e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceSetDefaultDeviceType(deviceContextInitDevice));
6790e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextSetRootDeviceType_Internal(PETSC_DEVICE_DEFAULT()));
6800e6b6b59SJacob Faibussowitsch   /* ----------------------------------------------------------------------------------- */
6810e6b6b59SJacob Faibussowitsch   /*                       PetscDevice is now fully initialized                          */
6820e6b6b59SJacob Faibussowitsch   /* ----------------------------------------------------------------------------------- */
6830e6b6b59SJacob Faibussowitsch   {
6840e6b6b59SJacob Faibussowitsch     /*
6850e6b6b59SJacob Faibussowitsch       query the options db to get the root settings from the user (if any).
6860e6b6b59SJacob Faibussowitsch 
6870e6b6b59SJacob Faibussowitsch       This section is a bit of a hack. We have to reach across to dcontext.cxx to all but call
6880e6b6b59SJacob Faibussowitsch       PetscDeviceContextSetFromOptions() before we even have one, then set a few static
6890e6b6b59SJacob Faibussowitsch       variables in that file with the results.
6900e6b6b59SJacob Faibussowitsch     */
6910e6b6b59SJacob Faibussowitsch     auto dtype = std::make_pair(PETSC_DEVICE_DEFAULT(), PETSC_FALSE);
6920e6b6b59SJacob Faibussowitsch     auto stype = std::make_pair(PETSC_DEVICE_CONTEXT_DEFAULT_STREAM_TYPE, PETSC_FALSE);
6930e6b6b59SJacob Faibussowitsch 
6940e6b6b59SJacob Faibussowitsch     PetscOptionsBegin(comm, "root_", "Root PetscDeviceContext Options", "Sys");
6950e6b6b59SJacob Faibussowitsch     PetscCall(PetscDeviceContextQueryOptions_Internal(PetscOptionsObject, dtype, stype));
6960e6b6b59SJacob Faibussowitsch     PetscOptionsEnd();
6970e6b6b59SJacob Faibussowitsch 
6980e6b6b59SJacob Faibussowitsch     if (dtype.second) PetscCall(PetscDeviceContextSetRootDeviceType_Internal(dtype.first));
6990e6b6b59SJacob Faibussowitsch     if (stype.second) PetscCall(PetscDeviceContextSetRootStreamType_Internal(stype.first));
7000e6b6b59SJacob Faibussowitsch   }
7010e6b6b59SJacob Faibussowitsch 
702a4af0ceeSJacob Faibussowitsch   if (initializeDeviceContextEagerly) {
703a4af0ceeSJacob Faibussowitsch     PetscDeviceContext dctx;
704a4af0ceeSJacob Faibussowitsch 
7050e6b6b59SJacob Faibussowitsch     PetscCall(PetscInfo(nullptr, "Eagerly initializing PetscDeviceContext with %s device\n", PetscDeviceTypes[deviceContextInitDevice]));
7060e6b6b59SJacob Faibussowitsch     /* instantiates the device context */
7079566063dSJacob Faibussowitsch     PetscCall(PetscDeviceContextGetCurrentContext(&dctx));
7089566063dSJacob Faibussowitsch     PetscCall(PetscDeviceContextSetUp(dctx));
709a4af0ceeSJacob Faibussowitsch   }
7103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
711a4af0ceeSJacob Faibussowitsch }
712