xref: /petsc/src/sys/objects/device/interface/device.cxx (revision 03047865b8d8757cf1cf9cda45785c1537b01dc1)
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 
18456dbbcdSJunchao Zhang #if defined(PETSC_HAVE_CUPM)
19456dbbcdSJunchao Zhang int PetscDeviceCUPMRuntimeArch = 0;
20456dbbcdSJunchao Zhang #endif
21456dbbcdSJunchao 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 @*/
PetscDeviceCreate(PetscDeviceType type,PetscInt devid,PetscDevice * device)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());
110377f809aSBarry Smith 
1110e6b6b59SJacob Faibussowitsch   PetscCall(PetscNew(device));
1120e6b6b59SJacob Faibussowitsch   (*device)->id     = PetscDeviceCounter++;
1130e6b6b59SJacob Faibussowitsch   (*device)->type   = type;
1140e6b6b59SJacob Faibussowitsch   (*device)->refcnt = 1;
115cf3a2253SJacob Faibussowitsch   /*
11691c35059SPierre Jolivet     if you are adding a device, you also need to add its initialization in
117cf3a2253SJacob Faibussowitsch     PetscDeviceInitializeTypeFromOptions_Private() below
118cf3a2253SJacob Faibussowitsch   */
119a4af0ceeSJacob Faibussowitsch   switch (type) {
1200e6b6b59SJacob Faibussowitsch     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(HOST, getDevice, *device, devid);
1210e6b6b59SJacob Faibussowitsch     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(CUDA, getDevice, *device, devid);
1220e6b6b59SJacob Faibussowitsch     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(HIP, getDevice, *device, devid);
1230e6b6b59SJacob Faibussowitsch     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(SYCL, getDevice, *device, devid);
124030f984aSJacob Faibussowitsch   default:
12517f48955SJacob Faibussowitsch     /* in case the above macros expand to nothing this silences any unused variable warnings */
12657508eceSPierre Jolivet     (void)devid;
12798921bdaSJacob 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]);
128030f984aSJacob Faibussowitsch   }
1293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
130030f984aSJacob Faibussowitsch }
131030f984aSJacob Faibussowitsch 
132030f984aSJacob Faibussowitsch /*@C
133811af0c4SBarry Smith   PetscDeviceDestroy - Free a `PetscDevice`
134030f984aSJacob Faibussowitsch 
1350e6b6b59SJacob Faibussowitsch   Not Collective
136030f984aSJacob Faibussowitsch 
137030f984aSJacob Faibussowitsch   Input Parameter:
1380e6b6b59SJacob Faibussowitsch . device - The `PetscDevice`
139030f984aSJacob Faibussowitsch 
140030f984aSJacob Faibussowitsch   Level: beginner
141030f984aSJacob Faibussowitsch 
1420e6b6b59SJacob Faibussowitsch .seealso: `PetscDevice`, `PetscDeviceCreate()`, `PetscDeviceConfigure()`, `PetscDeviceView()`,
1430e6b6b59SJacob Faibussowitsch `PetscDeviceGetType()`, `PetscDeviceGetDeviceId()`
144030f984aSJacob Faibussowitsch @*/
PetscDeviceDestroy(PetscDevice * device)145d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceDestroy(PetscDevice *device)
146d71ae5a4SJacob Faibussowitsch {
147a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
1484f572ea9SToby Isaac   PetscAssertPointer(device, 1);
1493ba16761SJacob Faibussowitsch   if (!*device) PetscFunctionReturn(PETSC_SUCCESS);
150a4af0ceeSJacob Faibussowitsch   PetscValidDevice(*device, 1);
1519566063dSJacob Faibussowitsch   PetscCall(PetscDeviceDereference_Internal(*device));
152a4af0ceeSJacob Faibussowitsch   if ((*device)->refcnt) {
1530e6b6b59SJacob Faibussowitsch     *device = nullptr;
1543ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
155030f984aSJacob Faibussowitsch   }
1569566063dSJacob Faibussowitsch   PetscCall(PetscFree((*device)->data));
1579566063dSJacob Faibussowitsch   PetscCall(PetscFree(*device));
1583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
159030f984aSJacob Faibussowitsch }
160030f984aSJacob Faibussowitsch 
161a4af0ceeSJacob Faibussowitsch /*@C
162811af0c4SBarry Smith   PetscDeviceConfigure - Configure a particular `PetscDevice`
163030f984aSJacob Faibussowitsch 
1640e6b6b59SJacob Faibussowitsch   Not Collective
165a4af0ceeSJacob Faibussowitsch 
166a4af0ceeSJacob Faibussowitsch   Input Parameter:
167811af0c4SBarry Smith . device - The `PetscDevice` to configure
168a4af0ceeSJacob Faibussowitsch 
1692fe279fdSBarry Smith   Level: beginner
1702fe279fdSBarry Smith 
1710e6b6b59SJacob Faibussowitsch   Notes:
1720e6b6b59SJacob Faibussowitsch   The user should not assume that this is a cheap operation.
173a4af0ceeSJacob Faibussowitsch 
1740e6b6b59SJacob Faibussowitsch .seealso: `PetscDevice`, `PetscDeviceCreate()`, `PetscDeviceView()`, `PetscDeviceDestroy()`,
1750e6b6b59SJacob Faibussowitsch `PetscDeviceGetType()`, `PetscDeviceGetDeviceId()`
176a4af0ceeSJacob Faibussowitsch @*/
PetscDeviceConfigure(PetscDevice device)177d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceConfigure(PetscDevice device)
178d71ae5a4SJacob Faibussowitsch {
179030f984aSJacob Faibussowitsch   PetscFunctionBegin;
180a4af0ceeSJacob Faibussowitsch   PetscValidDevice(device, 1);
181cf3a2253SJacob Faibussowitsch   /*
182cf3a2253SJacob Faibussowitsch     if no available configuration is available, this cascades all the way down to default
183cf3a2253SJacob Faibussowitsch     and error
184cf3a2253SJacob Faibussowitsch   */
1850e6b6b59SJacob Faibussowitsch   switch (const auto dtype = device->type) {
1860e6b6b59SJacob Faibussowitsch   case PETSC_DEVICE_HOST:
1870e6b6b59SJacob Faibussowitsch     if (PetscDefined(HAVE_HOST)) break; // always true
1889371c9d4SSatish Balay   case PETSC_DEVICE_CUDA:
1899371c9d4SSatish Balay     if (PetscDefined(HAVE_CUDA)) break;
1900e6b6b59SJacob Faibussowitsch     goto error;
1919371c9d4SSatish Balay   case PETSC_DEVICE_HIP:
1929371c9d4SSatish Balay     if (PetscDefined(HAVE_HIP)) break;
1930e6b6b59SJacob Faibussowitsch     goto error;
1949371c9d4SSatish Balay   case PETSC_DEVICE_SYCL:
1959371c9d4SSatish Balay     if (PetscDefined(HAVE_SYCL)) break;
196f4d061e9SPierre Jolivet     goto error;
1970e6b6b59SJacob Faibussowitsch   default:
1980e6b6b59SJacob Faibussowitsch   error:
1990e6b6b59SJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "PETSc was not configured for PetscDeviceType %s", PetscDeviceTypes[dtype]);
200a4af0ceeSJacob Faibussowitsch   }
201dbbe0bcdSBarry Smith   PetscUseTypeMethod(device, configure);
2023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
203a4af0ceeSJacob Faibussowitsch }
204a4af0ceeSJacob Faibussowitsch 
205ffeef943SBarry Smith /*@
206811af0c4SBarry Smith   PetscDeviceView - View a `PetscDevice`
207a4af0ceeSJacob Faibussowitsch 
2080e6b6b59SJacob Faibussowitsch   Collective on viewer
209a4af0ceeSJacob Faibussowitsch 
21091e63d38SStefano Zampini   Input Parameters:
211811af0c4SBarry Smith + device - The `PetscDevice` to view
2120e6b6b59SJacob Faibussowitsch - viewer - The `PetscViewer` to view the device with (`NULL` for `PETSC_VIEWER_STDOUT_WORLD`)
213a4af0ceeSJacob Faibussowitsch 
214a4af0ceeSJacob Faibussowitsch   Level: beginner
215a4af0ceeSJacob Faibussowitsch 
2160e6b6b59SJacob Faibussowitsch .seealso: `PetscDevice`, `PetscDeviceCreate()`, `PetscDeviceConfigure()`,
2170e6b6b59SJacob Faibussowitsch `PetscDeviceDestroy()`, `PetscDeviceGetType()`, `PetscDeviceGetDeviceId()`
218a4af0ceeSJacob Faibussowitsch @*/
PetscDeviceView(PetscDevice device,PetscViewer viewer)219d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceView(PetscDevice device, PetscViewer viewer)
220d71ae5a4SJacob Faibussowitsch {
2210e6b6b59SJacob Faibussowitsch   auto      sub = viewer;
2229f196a02SMartin Diehl   PetscBool isascii;
2230e6b6b59SJacob Faibussowitsch 
224a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
225a4af0ceeSJacob Faibussowitsch   PetscValidDevice(device, 1);
2260e6b6b59SJacob Faibussowitsch   if (viewer) {
227a4af0ceeSJacob Faibussowitsch     PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2289f196a02SMartin Diehl     PetscCall(PetscObjectTypeCompare(PetscObjectCast(viewer), PETSCVIEWERASCII, &isascii));
2290e6b6b59SJacob Faibussowitsch   } else {
2300e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerASCIIGetStdout(PETSC_COMM_WORLD, &viewer));
2319f196a02SMartin Diehl     isascii = PETSC_TRUE;
2320e6b6b59SJacob Faibussowitsch   }
2330e6b6b59SJacob Faibussowitsch 
2349f196a02SMartin Diehl   if (isascii) {
2350e6b6b59SJacob Faibussowitsch     auto        dtype = PETSC_DEVICE_HOST;
2360e6b6b59SJacob Faibussowitsch     MPI_Comm    comm;
2370e6b6b59SJacob Faibussowitsch     PetscMPIInt size;
2380e6b6b59SJacob Faibussowitsch     PetscInt    id = 0;
2390e6b6b59SJacob Faibussowitsch 
2400e6b6b59SJacob Faibussowitsch     PetscCall(PetscObjectGetComm(PetscObjectCast(viewer), &comm));
2410e6b6b59SJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(comm, &size));
2420e6b6b59SJacob Faibussowitsch 
2430e6b6b59SJacob Faibussowitsch     PetscCall(PetscDeviceGetDeviceId(device, &id));
2440e6b6b59SJacob Faibussowitsch     PetscCall(PetscDeviceGetType(device, &dtype));
2450e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sub));
2460e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(sub, "PetscDevice Object: %d MPI %s\n", size, size == 1 ? "process" : "processes"));
2470e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(sub));
2480e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(sub, "type: %s\n", PetscDeviceTypes[dtype]));
2490e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(sub, "id: %" PetscInt_FMT "\n", id));
2500e6b6b59SJacob Faibussowitsch   }
2510e6b6b59SJacob Faibussowitsch 
2520e6b6b59SJacob Faibussowitsch   // see if impls has extra viewer stuff
2530e6b6b59SJacob Faibussowitsch   PetscTryTypeMethod(device, view, sub);
2540e6b6b59SJacob Faibussowitsch 
2559f196a02SMartin Diehl   if (isascii) {
2560e6b6b59SJacob Faibussowitsch     // undo the ASCII specific stuff
2570e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(sub));
2580e6b6b59SJacob Faibussowitsch     PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sub));
2590e6b6b59SJacob Faibussowitsch   }
2603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
261a4af0ceeSJacob Faibussowitsch }
262a4af0ceeSJacob Faibussowitsch 
263cc4c1da9SBarry Smith /*@
2640e6b6b59SJacob Faibussowitsch   PetscDeviceGetType - Get the type of device
26591e63d38SStefano Zampini 
2660e6b6b59SJacob Faibussowitsch   Not Collective
26791e63d38SStefano Zampini 
26891e63d38SStefano Zampini   Input Parameter:
269811af0c4SBarry Smith . device - The `PetscDevice`
27091e63d38SStefano Zampini 
27191e63d38SStefano Zampini   Output Parameter:
2720e6b6b59SJacob Faibussowitsch . type - The `PetscDeviceType`
27391e63d38SStefano Zampini 
27491e63d38SStefano Zampini   Level: beginner
27591e63d38SStefano Zampini 
2760e6b6b59SJacob Faibussowitsch .seealso: `PetscDevice`, `PetscDeviceType`, `PetscDeviceSetDefaultDeviceType()`,
2770e6b6b59SJacob Faibussowitsch `PetscDeviceCreate()`, `PetscDeviceConfigure()`, `PetscDeviceDestroy()`,
2780e6b6b59SJacob Faibussowitsch `PetscDeviceGetDeviceId()`, `PETSC_DEVICE_DEFAULT()`
2790e6b6b59SJacob Faibussowitsch @*/
PetscDeviceGetType(PetscDevice device,PetscDeviceType * type)280d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceGetType(PetscDevice device, PetscDeviceType *type)
281d71ae5a4SJacob Faibussowitsch {
2820e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
2830e6b6b59SJacob Faibussowitsch   PetscValidDevice(device, 1);
2844f572ea9SToby Isaac   PetscAssertPointer(type, 2);
2850e6b6b59SJacob Faibussowitsch   *type = device->type;
2863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2870e6b6b59SJacob Faibussowitsch }
2880e6b6b59SJacob Faibussowitsch 
2890e6b6b59SJacob Faibussowitsch /*@C
2900e6b6b59SJacob Faibussowitsch   PetscDeviceGetDeviceId - Get the device ID for a `PetscDevice`
2910e6b6b59SJacob Faibussowitsch 
2920e6b6b59SJacob Faibussowitsch   Not Collective
2930e6b6b59SJacob Faibussowitsch 
2940e6b6b59SJacob Faibussowitsch   Input Parameter:
2950e6b6b59SJacob Faibussowitsch . device - The `PetscDevice`
2960e6b6b59SJacob Faibussowitsch 
2970e6b6b59SJacob Faibussowitsch   Output Parameter:
2980e6b6b59SJacob Faibussowitsch . id - The id
2990e6b6b59SJacob Faibussowitsch 
3002fe279fdSBarry Smith   Level: beginner
3012fe279fdSBarry Smith 
3020e6b6b59SJacob Faibussowitsch   Notes:
3030e6b6b59SJacob Faibussowitsch   The returned ID may have been assigned by the underlying device backend. For example if the
3040e6b6b59SJacob Faibussowitsch   backend is CUDA then `id` is exactly the value returned by `cudaGetDevice()` at the time when
3050e6b6b59SJacob Faibussowitsch   this device was configured.
3060e6b6b59SJacob Faibussowitsch 
3070e6b6b59SJacob Faibussowitsch .seealso: `PetscDevice`, `PetscDeviceCreate()`, `PetscDeviceGetType()`
30891e63d38SStefano Zampini @*/
PetscDeviceGetDeviceId(PetscDevice device,PetscInt * id)309d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceGetDeviceId(PetscDevice device, PetscInt *id)
310d71ae5a4SJacob Faibussowitsch {
31191e63d38SStefano Zampini   PetscFunctionBegin;
31291e63d38SStefano Zampini   PetscValidDevice(device, 1);
3134f572ea9SToby Isaac   PetscAssertPointer(id, 2);
31491e63d38SStefano Zampini   *id = device->deviceId;
3153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
31691e63d38SStefano Zampini }
31791e63d38SStefano Zampini 
318bbfde98dSJacob Faibussowitsch namespace
319bbfde98dSJacob Faibussowitsch {
320bbfde98dSJacob Faibussowitsch 
3210e6b6b59SJacob Faibussowitsch struct DefaultDeviceType : public Petsc::RegisterFinalizeable<DefaultDeviceType> {
3220e6b6b59SJacob Faibussowitsch   PetscDeviceType type = PETSC_DEVICE_HARDWARE_DEFAULT_TYPE;
3230e6b6b59SJacob Faibussowitsch 
finalize___anon8a21ce5b0211::DefaultDeviceType324089fb57cSJacob Faibussowitsch   PetscErrorCode finalize_() noexcept
325d71ae5a4SJacob Faibussowitsch   {
3260e6b6b59SJacob Faibussowitsch     PetscFunctionBegin;
3270e6b6b59SJacob Faibussowitsch     type = PETSC_DEVICE_HARDWARE_DEFAULT_TYPE;
3283ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
3290e6b6b59SJacob Faibussowitsch   }
3300e6b6b59SJacob Faibussowitsch };
3310e6b6b59SJacob Faibussowitsch 
332bbfde98dSJacob Faibussowitsch auto default_device_type = DefaultDeviceType();
333bbfde98dSJacob Faibussowitsch 
334bbfde98dSJacob Faibussowitsch } // namespace
3350e6b6b59SJacob Faibussowitsch 
3360e6b6b59SJacob Faibussowitsch /*@C
3370e6b6b59SJacob Faibussowitsch   PETSC_DEVICE_DEFAULT - Retrieve the current default `PetscDeviceType`
3380e6b6b59SJacob Faibussowitsch 
3390e6b6b59SJacob Faibussowitsch   Not Collective
3400e6b6b59SJacob Faibussowitsch 
3412fe279fdSBarry Smith   Level: beginner
3422fe279fdSBarry Smith 
3430e6b6b59SJacob Faibussowitsch   Notes:
3440e6b6b59SJacob Faibussowitsch   Unless selected by the user, the default device is selected in the following order\:
3450e6b6b59SJacob Faibussowitsch   `PETSC_DEVICE_HIP`, `PETSC_DEVICE_CUDA`, `PETSC_DEVICE_SYCL`, `PETSC_DEVICE_HOST`.
3460e6b6b59SJacob Faibussowitsch 
3470e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceType`, `PetscDeviceSetDefaultDeviceType()`, `PetscDeviceGetType()`
3480e6b6b59SJacob Faibussowitsch @*/
PETSC_DEVICE_DEFAULT(void)349d71ae5a4SJacob Faibussowitsch PetscDeviceType PETSC_DEVICE_DEFAULT(void)
350d71ae5a4SJacob Faibussowitsch {
3510e6b6b59SJacob Faibussowitsch   return default_device_type.type;
3520e6b6b59SJacob Faibussowitsch }
3530e6b6b59SJacob Faibussowitsch 
3540e6b6b59SJacob Faibussowitsch /*@C
3550e6b6b59SJacob Faibussowitsch   PetscDeviceSetDefaultDeviceType - Set the default device type for `PetscDevice`
3560e6b6b59SJacob Faibussowitsch 
3570e6b6b59SJacob Faibussowitsch   Not Collective
3580e6b6b59SJacob Faibussowitsch 
3590e6b6b59SJacob Faibussowitsch   Input Parameter:
3600e6b6b59SJacob Faibussowitsch . type - the new default device type
3610e6b6b59SJacob Faibussowitsch 
3622fe279fdSBarry Smith   Level: beginner
3632fe279fdSBarry Smith 
3640e6b6b59SJacob Faibussowitsch   Notes:
3650e6b6b59SJacob Faibussowitsch   This sets the `PetscDeviceType` returned by `PETSC_DEVICE_DEFAULT()`.
3660e6b6b59SJacob Faibussowitsch 
3670e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceType`, `PetscDeviceGetType`,
3680e6b6b59SJacob Faibussowitsch @*/
PetscDeviceSetDefaultDeviceType(PetscDeviceType type)369d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceSetDefaultDeviceType(PetscDeviceType type)
370d71ae5a4SJacob Faibussowitsch {
3710e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
3720e6b6b59SJacob Faibussowitsch   PetscValidDeviceType(type, 1);
3730e6b6b59SJacob Faibussowitsch   if (default_device_type.type != type) {
37427d4e10aSPierre Jolivet     // no need to waste a PetscRegisterFinalize() slot if we don't change it
3750e6b6b59SJacob Faibussowitsch     default_device_type.type = type;
3760e6b6b59SJacob Faibussowitsch     PetscCall(default_device_type.register_finalize());
3770e6b6b59SJacob Faibussowitsch   }
3783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3790e6b6b59SJacob Faibussowitsch }
3800e6b6b59SJacob Faibussowitsch 
381bbfde98dSJacob Faibussowitsch namespace
382bbfde98dSJacob Faibussowitsch {
383bbfde98dSJacob Faibussowitsch 
384bbfde98dSJacob Faibussowitsch std::array<std::pair<PetscDevice, bool>, PETSC_DEVICE_MAX> defaultDevices = {};
3850e6b6b59SJacob Faibussowitsch 
3860e6b6b59SJacob Faibussowitsch /*
387da81f932SPierre Jolivet   Actual initialization function; any functions claiming to initialize PetscDevice or
3880e6b6b59SJacob Faibussowitsch   PetscDeviceContext will have to run through this one
3890e6b6b59SJacob Faibussowitsch */
PetscDeviceInitializeDefaultDevice_Internal(PetscDeviceType type,PetscInt defaultDeviceId)390bbfde98dSJacob Faibussowitsch PetscErrorCode PetscDeviceInitializeDefaultDevice_Internal(PetscDeviceType type, PetscInt defaultDeviceId)
391d71ae5a4SJacob Faibussowitsch {
3920e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
3930e6b6b59SJacob Faibussowitsch   PetscValidDeviceType(type, 1);
3940e6b6b59SJacob Faibussowitsch   if (PetscUnlikely(!PetscDeviceInitialized(type))) {
3950e6b6b59SJacob Faibussowitsch     auto &dev  = defaultDevices[type].first;
3960e6b6b59SJacob Faibussowitsch     auto &init = defaultDevices[type].second;
3970e6b6b59SJacob Faibussowitsch 
3980e6b6b59SJacob Faibussowitsch     PetscAssert(!dev, PETSC_COMM_SELF, PETSC_ERR_MEM, "Trying to overwrite existing default device of type %s", PetscDeviceTypes[type]);
3990e6b6b59SJacob Faibussowitsch     PetscCall(PetscDeviceCreate(type, defaultDeviceId, &dev));
4000e6b6b59SJacob Faibussowitsch     PetscCall(PetscDeviceConfigure(dev));
4010e6b6b59SJacob Faibussowitsch     init = true;
4020e6b6b59SJacob Faibussowitsch   }
4033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4040e6b6b59SJacob Faibussowitsch }
405a4af0ceeSJacob Faibussowitsch 
406bbfde98dSJacob Faibussowitsch } // namespace
407bbfde98dSJacob Faibussowitsch 
408a4af0ceeSJacob Faibussowitsch /*@C
409811af0c4SBarry Smith   PetscDeviceInitialize - Initialize `PetscDevice`
410a4af0ceeSJacob Faibussowitsch 
4110e6b6b59SJacob Faibussowitsch   Not Collective
412a4af0ceeSJacob Faibussowitsch 
413a4af0ceeSJacob Faibussowitsch   Input Parameter:
414811af0c4SBarry Smith . type - The `PetscDeviceType` to initialize
415a4af0ceeSJacob Faibussowitsch 
4162fe279fdSBarry Smith   Level: beginner
4172fe279fdSBarry Smith 
4180e6b6b59SJacob Faibussowitsch   Notes:
4190e6b6b59SJacob Faibussowitsch   Eagerly initializes the corresponding `PetscDeviceType` if needed. If this is the case it may
4200e6b6b59SJacob Faibussowitsch   result in device synchronization.
421a4af0ceeSJacob Faibussowitsch 
4220e6b6b59SJacob Faibussowitsch .seealso: `PetscDevice`, `PetscDeviceInitType`, `PetscDeviceInitialized()`,
4230e6b6b59SJacob Faibussowitsch `PetscDeviceCreate()`, `PetscDeviceDestroy()`
424a4af0ceeSJacob Faibussowitsch @*/
PetscDeviceInitialize(PetscDeviceType type)425d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceInitialize(PetscDeviceType type)
426d71ae5a4SJacob Faibussowitsch {
427a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
428a4af0ceeSJacob Faibussowitsch   PetscValidDeviceType(type, 1);
4299566063dSJacob Faibussowitsch   PetscCall(PetscDeviceInitializeDefaultDevice_Internal(type, PETSC_DECIDE));
4303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
431a4af0ceeSJacob Faibussowitsch }
432a4af0ceeSJacob Faibussowitsch 
433a4af0ceeSJacob Faibussowitsch /*@C
434811af0c4SBarry Smith   PetscDeviceInitialized - Determines whether `PetscDevice` is initialized for a particular
435811af0c4SBarry Smith   `PetscDeviceType`
436a4af0ceeSJacob Faibussowitsch 
4370e6b6b59SJacob Faibussowitsch   Not Collective
438a4af0ceeSJacob Faibussowitsch 
439a4af0ceeSJacob Faibussowitsch   Input Parameter:
440811af0c4SBarry Smith . type - The `PetscDeviceType` to check
441a4af0ceeSJacob Faibussowitsch 
4422fe279fdSBarry Smith   Level: beginner
4432fe279fdSBarry Smith 
4440e6b6b59SJacob Faibussowitsch   Notes:
4450e6b6b59SJacob Faibussowitsch   Returns `PETSC_TRUE` if `type` is initialized, `PETSC_FALSE` otherwise.
446a4af0ceeSJacob Faibussowitsch 
447811af0c4SBarry Smith   If one has not configured PETSc for a particular `PetscDeviceType` then this routine will
448811af0c4SBarry Smith   return `PETSC_FALSE` for that `PetscDeviceType`.
449a4af0ceeSJacob Faibussowitsch 
4500e6b6b59SJacob Faibussowitsch .seealso: `PetscDevice`, `PetscDeviceInitType`, `PetscDeviceInitialize()`,
4510e6b6b59SJacob Faibussowitsch `PetscDeviceCreate()`, `PetscDeviceDestroy()`
452a4af0ceeSJacob Faibussowitsch @*/
PetscDeviceInitialized(PetscDeviceType type)453d71ae5a4SJacob Faibussowitsch PetscBool PetscDeviceInitialized(PetscDeviceType type)
454d71ae5a4SJacob Faibussowitsch {
4550e6b6b59SJacob Faibussowitsch   return static_cast<PetscBool>(PetscDeviceConfiguredFor_Internal(type) && defaultDevices[type].second);
4560e6b6b59SJacob Faibussowitsch }
4570e6b6b59SJacob Faibussowitsch 
4580e6b6b59SJacob Faibussowitsch /* Get the default PetscDevice for a particular type and constructs them if lazily initialized. */
PetscDeviceGetDefaultForType_Internal(PetscDeviceType type,PetscDevice * device)459d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceGetDefaultForType_Internal(PetscDeviceType type, PetscDevice *device)
460d71ae5a4SJacob Faibussowitsch {
4610e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
4624f572ea9SToby Isaac   PetscAssertPointer(device, 2);
4630e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceInitialize(type));
4640e6b6b59SJacob Faibussowitsch   *device = defaultDevices[type].first;
4653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
466a4af0ceeSJacob Faibussowitsch }
467a4af0ceeSJacob Faibussowitsch 
468a16fd2c9SJacob Faibussowitsch /*@C
469a16fd2c9SJacob Faibussowitsch   PetscDeviceGetAttribute - Query a particular attribute of a `PetscDevice`
470a16fd2c9SJacob Faibussowitsch 
4710e6b6b59SJacob Faibussowitsch   Not Collective
472a16fd2c9SJacob Faibussowitsch 
473a16fd2c9SJacob Faibussowitsch   Input Parameters:
474a16fd2c9SJacob Faibussowitsch + device - The `PetscDevice`
475a16fd2c9SJacob Faibussowitsch - attr   - The attribute
476a16fd2c9SJacob Faibussowitsch 
477a16fd2c9SJacob Faibussowitsch   Output Parameter:
478a16fd2c9SJacob Faibussowitsch . value - The value of the attribute
479a16fd2c9SJacob Faibussowitsch 
4802fe279fdSBarry Smith   Level: intermediate
4812fe279fdSBarry Smith 
482a16fd2c9SJacob Faibussowitsch   Notes:
483a16fd2c9SJacob Faibussowitsch   Since different attributes are often different types `value` is a `void *` to accommodate
484a16fd2c9SJacob Faibussowitsch   them all. The underlying type of the attribute is therefore included in the name of the
485da81f932SPierre Jolivet   `PetscDeviceAttribute` responsible for querying it. For example,
486a16fd2c9SJacob Faibussowitsch   `PETSC_DEVICE_ATTR_SIZE_T_SHARED_MEM_PER_BLOCK` is of type `size_t`.
487a16fd2c9SJacob Faibussowitsch 
488a16fd2c9SJacob Faibussowitsch .seealso: `PetscDeviceAtrtibute`, `PetscDeviceConfigure()`, `PetscDevice`
489a16fd2c9SJacob Faibussowitsch @*/
PetscDeviceGetAttribute(PetscDevice device,PetscDeviceAttribute attr,void * value)490d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceGetAttribute(PetscDevice device, PetscDeviceAttribute attr, void *value)
491d71ae5a4SJacob Faibussowitsch {
492a16fd2c9SJacob Faibussowitsch   PetscFunctionBegin;
493a16fd2c9SJacob Faibussowitsch   PetscValidDevice(device, 1);
494a16fd2c9SJacob Faibussowitsch   PetscValidDeviceAttribute(attr, 2);
4954f572ea9SToby Isaac   PetscAssertPointer(value, 3);
496a16fd2c9SJacob Faibussowitsch   PetscUseTypeMethod(device, getattribute, attr, value);
4973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
498a16fd2c9SJacob Faibussowitsch }
499a16fd2c9SJacob Faibussowitsch 
500bbfde98dSJacob Faibussowitsch namespace
501bbfde98dSJacob Faibussowitsch {
502bbfde98dSJacob Faibussowitsch 
PetscDeviceInitializeTypeFromOptions_Private(MPI_Comm comm,PetscDeviceType type,PetscInt defaultDeviceId,PetscBool defaultView,PetscDeviceInitType * defaultInitType)503bbfde98dSJacob Faibussowitsch PetscErrorCode PetscDeviceInitializeTypeFromOptions_Private(MPI_Comm comm, PetscDeviceType type, PetscInt defaultDeviceId, PetscBool defaultView, PetscDeviceInitType *defaultInitType)
504d71ae5a4SJacob Faibussowitsch {
505a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
506a4af0ceeSJacob Faibussowitsch   if (!PetscDeviceConfiguredFor_Internal(type)) {
5070e6b6b59SJacob Faibussowitsch     PetscCall(PetscInfo(nullptr, "PetscDeviceType %s not available\n", PetscDeviceTypes[type]));
5080e6b6b59SJacob Faibussowitsch     defaultDevices[type].first = nullptr;
5093ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
510a4af0ceeSJacob Faibussowitsch   }
5110e6b6b59SJacob Faibussowitsch   PetscCall(PetscInfo(nullptr, "PetscDeviceType %s available, initializing\n", PetscDeviceTypes[type]));
512a4af0ceeSJacob Faibussowitsch   /* ugly switch needed to pick the right global variable... could maybe do this as a union? */
513a4af0ceeSJacob Faibussowitsch   switch (type) {
5140e6b6b59SJacob Faibussowitsch     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(HOST, initialize, comm, &defaultDeviceId, &defaultView, defaultInitType);
5150e6b6b59SJacob Faibussowitsch     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(CUDA, initialize, comm, &defaultDeviceId, &defaultView, defaultInitType);
5160e6b6b59SJacob Faibussowitsch     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(HIP, initialize, comm, &defaultDeviceId, &defaultView, defaultInitType);
5170e6b6b59SJacob Faibussowitsch     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(SYCL, initialize, comm, &defaultDeviceId, &defaultView, defaultInitType);
518d71ae5a4SJacob Faibussowitsch   default:
519d71ae5a4SJacob 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]);
520a4af0ceeSJacob Faibussowitsch   }
521bd2fcf0cSJacob 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)]));
522cf3a2253SJacob Faibussowitsch   /*
5230e6b6b59SJacob Faibussowitsch     defaultInitType, defaultView  and defaultDeviceId now represent what the individual TYPES
5240e6b6b59SJacob Faibussowitsch     have decided to initialize as
525cf3a2253SJacob Faibussowitsch   */
5260e6b6b59SJacob Faibussowitsch   if ((*defaultInitType == PETSC_DEVICE_INIT_EAGER) || defaultView) {
5270e6b6b59SJacob Faibussowitsch     PetscCall(PetscInfo(nullptr, "Eagerly initializing %s PetscDevice\n", PetscDeviceTypes[type]));
5289566063dSJacob Faibussowitsch     PetscCall(PetscDeviceInitializeDefaultDevice_Internal(type, defaultDeviceId));
5290e6b6b59SJacob Faibussowitsch     if (defaultView) PetscCall(PetscDeviceView(defaultDevices[type].first, nullptr));
5300e6b6b59SJacob Faibussowitsch   }
5313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5320e6b6b59SJacob Faibussowitsch }
533a4af0ceeSJacob Faibussowitsch 
PetscDeviceInitializeQueryOptions_Private(MPI_Comm comm,PetscDeviceType * deviceContextInitDevice,PetscDeviceInitType * defaultInitType,PetscInt * defaultDeviceId,PetscBool * defaultDeviceIdSet,PetscBool * defaultView)534b291397eSBarry Smith PetscErrorCode PetscDeviceInitializeQueryOptions_Private(MPI_Comm comm, PetscDeviceType *deviceContextInitDevice, PetscDeviceInitType *defaultInitType, PetscInt *defaultDeviceId, PetscBool *defaultDeviceIdSet, PetscBool *defaultView)
535d71ae5a4SJacob Faibussowitsch {
5360e6b6b59SJacob Faibussowitsch   PetscInt initIdx       = PETSC_DEVICE_INIT_LAZY;
5370e6b6b59SJacob Faibussowitsch   auto     initDeviceIdx = static_cast<PetscInt>(*deviceContextInitDevice);
5380e6b6b59SJacob Faibussowitsch   auto     flg           = PETSC_FALSE;
5390e6b6b59SJacob Faibussowitsch 
5400e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
5410e6b6b59SJacob Faibussowitsch   PetscCall(PetscOptionsHasName(nullptr, nullptr, "-log_view_gpu_time", &flg));
5420e6b6b59SJacob Faibussowitsch   if (flg) PetscCall(PetscLogGpuTime());
543*5268dc8aSHong Zhang   PetscCall(PetscOptionsHasName(nullptr, nullptr, "-log_view_gpu_energy_meter", &flg));
544*5268dc8aSHong Zhang   if (flg) PetscCall(PetscLogGpuEnergyMeter());
545*5268dc8aSHong Zhang   PetscCall(PetscOptionsHasName(nullptr, nullptr, "-log_view_gpu_energy", &flg));
546*5268dc8aSHong Zhang   if (flg) PetscCall(PetscLogGpuEnergy());
5470e6b6b59SJacob Faibussowitsch 
5480e6b6b59SJacob Faibussowitsch   PetscOptionsBegin(comm, nullptr, "PetscDevice Options", "Sys");
5490e6b6b59SJacob Faibussowitsch   PetscCall(PetscOptionsEList("-device_enable", "How (or whether) to initialize PetscDevices", "PetscDeviceInitialize()", PetscDeviceInitTypes, 3, PetscDeviceInitTypes[initIdx], &initIdx, nullptr));
550b291397eSBarry Smith   PetscCall(PetscOptionsEList("-default_device_type", "Set the PetscDeviceType returned by PETSC_DEVICE_DEFAULT()", "PetscDeviceSetDefaultDeviceType()", PetscDeviceTypes, PETSC_DEVICE_MAX, PetscDeviceTypes[initDeviceIdx], &initDeviceIdx, defaultDeviceIdSet));
551b291397eSBarry Smith   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()", *defaultDeviceId, defaultDeviceId, nullptr, PETSC_DECIDE, PETSC_DEVICE_MAX_DEVICES));
5520e6b6b59SJacob Faibussowitsch   PetscCall(PetscOptionsBool("-device_view", "Display device information and assignments (forces eager initialization)", "PetscDeviceView()", *defaultView, defaultView, &flg));
5530e6b6b59SJacob Faibussowitsch   PetscOptionsEnd();
5540e6b6b59SJacob Faibussowitsch 
5550e6b6b59SJacob Faibussowitsch   if (initIdx == PETSC_DEVICE_INIT_NONE) {
5560e6b6b59SJacob Faibussowitsch     /* disabled all device initialization if devices are globally disabled */
557b291397eSBarry Smith     PetscCheck(*defaultDeviceId == PETSC_DECIDE, comm, PETSC_ERR_USER_INPUT, "You have disabled devices but also specified a particular device to use, these options are mutually exclusive");
5580e6b6b59SJacob Faibussowitsch     *defaultView  = PETSC_FALSE;
5590e6b6b59SJacob Faibussowitsch     initDeviceIdx = PETSC_DEVICE_HOST;
5600e6b6b59SJacob Faibussowitsch   } else {
5610e6b6b59SJacob Faibussowitsch     *defaultView = static_cast<PetscBool>(*defaultView && flg);
5620e6b6b59SJacob Faibussowitsch     if (*defaultView) initIdx = PETSC_DEVICE_INIT_EAGER;
563a4af0ceeSJacob Faibussowitsch   }
5640e6b6b59SJacob Faibussowitsch   *defaultInitType         = PetscDeviceInitTypeCast(initIdx);
5650e6b6b59SJacob Faibussowitsch   *deviceContextInitDevice = PetscDeviceTypeCast(initDeviceIdx);
5663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
567030f984aSJacob Faibussowitsch }
568030f984aSJacob Faibussowitsch 
569030f984aSJacob Faibussowitsch /* called from PetscFinalize() do not call yourself! */
PetscDeviceFinalize_Private()570bbfde98dSJacob Faibussowitsch PetscErrorCode PetscDeviceFinalize_Private()
571d71ae5a4SJacob Faibussowitsch {
572030f984aSJacob Faibussowitsch   PetscFunctionBegin;
573a4af0ceeSJacob Faibussowitsch   if (PetscDefined(USE_DEBUG)) {
574bf025ffbSJacob Faibussowitsch     /*
575bf025ffbSJacob Faibussowitsch       you might be thinking, why on earth are you registered yet another finalizer in a
576bf025ffbSJacob Faibussowitsch       function already called during PetscRegisterFinalizeAll()? If this seems stupid it's
577bf025ffbSJacob Faibussowitsch       because it is.
578bf025ffbSJacob Faibussowitsch 
579bf025ffbSJacob Faibussowitsch       The crux of the problem is that the initializer (and therefore the ~finalizer~) of
580bf025ffbSJacob Faibussowitsch       PetscDeviceContext is guaranteed to run after PetscDevice's. So if the global context had
581bf025ffbSJacob Faibussowitsch       a default PetscDevice attached, that PetscDevice will have a reference count >0 and hence
582bf025ffbSJacob Faibussowitsch       won't be destroyed yet. So we need to repeat the check that all devices have been
583bf025ffbSJacob Faibussowitsch       destroyed again ~after~ the global context is destroyed. In summary:
584bf025ffbSJacob Faibussowitsch 
585bf025ffbSJacob Faibussowitsch       1. This finalizer runs and destroys all devices, except it may not because the global
586bf025ffbSJacob Faibussowitsch          context may still hold a reference!
587bf025ffbSJacob Faibussowitsch       2. The global context finalizer runs and does the final reference count decrement
588bf025ffbSJacob Faibussowitsch          required, which actually destroys the held device.
589bf025ffbSJacob Faibussowitsch       3. Our newly added finalizer runs and checks that all is well.
590a4af0ceeSJacob Faibussowitsch     */
591bbfde98dSJacob Faibussowitsch     PetscCall(PetscRegisterFinalize([] {
592bbfde98dSJacob Faibussowitsch       PetscFunctionBegin;
593bbfde98dSJacob Faibussowitsch       for (auto &&device : defaultDevices) {
594bbfde98dSJacob Faibussowitsch         const auto dev = device.first;
595bbfde98dSJacob Faibussowitsch 
596bbfde98dSJacob 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);
597bbfde98dSJacob Faibussowitsch       }
598bbfde98dSJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
599bbfde98dSJacob Faibussowitsch     }));
600a4af0ceeSJacob Faibussowitsch   }
6010e6b6b59SJacob Faibussowitsch   for (auto &&device : defaultDevices) {
6020e6b6b59SJacob Faibussowitsch     PetscCall(PetscDeviceDestroy(&device.first));
6030e6b6b59SJacob Faibussowitsch     device.second = false;
6040e6b6b59SJacob Faibussowitsch   }
6053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
606030f984aSJacob Faibussowitsch }
607030f984aSJacob Faibussowitsch 
608bbfde98dSJacob Faibussowitsch } // namespace
609bbfde98dSJacob Faibussowitsch 
610cf3a2253SJacob Faibussowitsch /*
611cf3a2253SJacob Faibussowitsch   Begins the init proceeedings for the entire PetscDevice stack. there are 3 stages of
612cf3a2253SJacob Faibussowitsch   initialization types:
613cf3a2253SJacob Faibussowitsch 
614a4af0ceeSJacob Faibussowitsch   1. defaultInitType - how does PetscDevice as a whole expect to initialize?
615a4af0ceeSJacob Faibussowitsch   2. subTypeDefaultInitType - how does each PetscDevice implementation expect to initialize?
616a4af0ceeSJacob Faibussowitsch      e.g. you may want to blanket disable PetscDevice init (and disable say Kokkos init), but
617a4af0ceeSJacob Faibussowitsch      have all CUDA devices still initialize.
618a4af0ceeSJacob Faibussowitsch 
619a4af0ceeSJacob Faibussowitsch   All told the following happens:
620cf3a2253SJacob Faibussowitsch 
621a4af0ceeSJacob Faibussowitsch   0. defaultInitType -> LAZY
622a4af0ceeSJacob Faibussowitsch   1. Check for log_view/log_summary, if yes defaultInitType -> EAGER
623a4af0ceeSJacob Faibussowitsch   2. PetscDevice initializes each sub type with deviceDefaultInitType.
624a4af0ceeSJacob Faibussowitsch   2.1 Each enabled PetscDevice sub-type then does the above disable or view check in addition
625a4af0ceeSJacob Faibussowitsch       to checking for specific device init. if view or specific device init
626a4af0ceeSJacob Faibussowitsch       subTypeDefaultInitType -> EAGER. disabled once again overrides all.
627a4af0ceeSJacob Faibussowitsch */
6280e6b6b59SJacob Faibussowitsch 
PetscDeviceInitializeFromOptions_Internal(MPI_Comm comm)629d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceInitializeFromOptions_Internal(MPI_Comm comm)
630d71ae5a4SJacob Faibussowitsch {
6317a101e5eSJacob Faibussowitsch   auto defaultView                    = PETSC_FALSE;
6327a101e5eSJacob Faibussowitsch   auto initializeDeviceContextEagerly = PETSC_FALSE;
633b291397eSBarry Smith   auto defaultDeviceIdSet             = PETSC_FALSE;
634b291397eSBarry Smith   auto defaultDeviceId                = PetscInt{PETSC_DECIDE};
6350e6b6b59SJacob Faibussowitsch   auto deviceContextInitDevice        = PETSC_DEVICE_DEFAULT();
6360e6b6b59SJacob Faibussowitsch   auto defaultInitType                = PETSC_DEVICE_INIT_LAZY;
637a4af0ceeSJacob Faibussowitsch 
638a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
639a4af0ceeSJacob Faibussowitsch   if (PetscDefined(USE_DEBUG)) {
640a4af0ceeSJacob Faibussowitsch     int result;
641a4af0ceeSJacob Faibussowitsch 
6429566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_compare(comm, PETSC_COMM_WORLD, &result));
643a4af0ceeSJacob Faibussowitsch     /* in order to accurately assign ranks to gpus we need to get the MPI_Comm_rank of the
644a4af0ceeSJacob Faibussowitsch      * global space */
645a4af0ceeSJacob Faibussowitsch     if (PetscUnlikely(result != MPI_IDENT)) {
646a4af0ceeSJacob Faibussowitsch       char name[MPI_MAX_OBJECT_NAME] = {};
647a4af0ceeSJacob Faibussowitsch       int  len; /* unused */
648a4af0ceeSJacob Faibussowitsch 
6499566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_get_name(comm, name, &len));
65098921bdaSJacob Faibussowitsch       SETERRQ(comm, PETSC_ERR_MPI, "Default devices being initialized on MPI_Comm '%s' not PETSC_COMM_WORLD", name);
651a4af0ceeSJacob Faibussowitsch     }
652a4af0ceeSJacob Faibussowitsch   }
653a4af0ceeSJacob Faibussowitsch   comm = PETSC_COMM_WORLD; /* from this point on we assume we're on PETSC_COMM_WORLD */
6549566063dSJacob Faibussowitsch   PetscCall(PetscRegisterFinalize(PetscDeviceFinalize_Private));
655a4af0ceeSJacob Faibussowitsch 
656b291397eSBarry Smith   PetscCall(PetscDeviceInitializeQueryOptions_Private(comm, &deviceContextInitDevice, &defaultInitType, &defaultDeviceId, &defaultDeviceIdSet, &defaultView));
6577a101e5eSJacob Faibussowitsch 
6580e6b6b59SJacob Faibussowitsch   // the precise values don't matter here, so long as they are sequential
659bd2fcf0cSJacob Faibussowitsch   static_assert(Petsc::util::to_underlying(PETSC_DEVICE_HOST) == 0, "");
660bd2fcf0cSJacob Faibussowitsch   static_assert(Petsc::util::to_underlying(PETSC_DEVICE_CUDA) == 1, "");
661bd2fcf0cSJacob Faibussowitsch   static_assert(Petsc::util::to_underlying(PETSC_DEVICE_HIP) == 2, "");
662bd2fcf0cSJacob Faibussowitsch   static_assert(Petsc::util::to_underlying(PETSC_DEVICE_SYCL) == 3, "");
663bd2fcf0cSJacob Faibussowitsch   static_assert(Petsc::util::to_underlying(PETSC_DEVICE_MAX) == 4, "");
6640e6b6b59SJacob Faibussowitsch   for (int i = PETSC_DEVICE_HOST; i < PETSC_DEVICE_MAX; ++i) {
6650e6b6b59SJacob Faibussowitsch     const auto deviceType = PetscDeviceTypeCast(i);
666a4af0ceeSJacob Faibussowitsch     auto       initType   = defaultInitType;
667a4af0ceeSJacob Faibussowitsch 
668b291397eSBarry Smith     PetscCall(PetscDeviceInitializeTypeFromOptions_Private(comm, deviceType, defaultDeviceId, defaultView, &initType));
6690e6b6b59SJacob Faibussowitsch     if (PetscDeviceConfiguredFor_Internal(deviceType)) {
6700e6b6b59SJacob Faibussowitsch       if (initType == PETSC_DEVICE_INIT_EAGER) {
671a4af0ceeSJacob Faibussowitsch         initializeDeviceContextEagerly = PETSC_TRUE;
6720e6b6b59SJacob Faibussowitsch         // only update the default device if the user hasn't set it previously
673b291397eSBarry Smith         if (!defaultDeviceIdSet) {
674a4af0ceeSJacob Faibussowitsch           deviceContextInitDevice = deviceType;
6750e6b6b59SJacob Faibussowitsch           PetscCall(PetscInfo(nullptr, "PetscDevice %s set as default device type due to eager initialization\n", PetscDeviceTypes[deviceType]));
6760e6b6b59SJacob Faibussowitsch         }
6770e6b6b59SJacob Faibussowitsch       } else if (initType == PETSC_DEVICE_INIT_NONE) {
678b291397eSBarry Smith         if (deviceType != PETSC_DEVICE_HOST) PetscCheck(!defaultDeviceIdSet || (deviceType != deviceContextInitDevice), comm, PETSC_ERR_USER_INPUT, "Cannot explicitly disable the device set as default device type (%s)", PetscDeviceTypes[deviceType]);
679a4af0ceeSJacob Faibussowitsch       }
680a4af0ceeSJacob Faibussowitsch     }
6810e6b6b59SJacob Faibussowitsch   }
6820e6b6b59SJacob Faibussowitsch 
6830e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceSetDefaultDeviceType(deviceContextInitDevice));
6840e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextSetRootDeviceType_Internal(PETSC_DEVICE_DEFAULT()));
6850e6b6b59SJacob Faibussowitsch   /*                       PetscDevice is now fully initialized                          */
6860e6b6b59SJacob Faibussowitsch   {
6870e6b6b59SJacob Faibussowitsch     /*
6880e6b6b59SJacob Faibussowitsch       query the options db to get the root settings from the user (if any).
6890e6b6b59SJacob Faibussowitsch 
6900e6b6b59SJacob Faibussowitsch       This section is a bit of a hack. We have to reach across to dcontext.cxx to all but call
6910e6b6b59SJacob Faibussowitsch       PetscDeviceContextSetFromOptions() before we even have one, then set a few static
6920e6b6b59SJacob Faibussowitsch       variables in that file with the results.
6930e6b6b59SJacob Faibussowitsch     */
6940e6b6b59SJacob Faibussowitsch     auto dtype = std::make_pair(PETSC_DEVICE_DEFAULT(), PETSC_FALSE);
6950e6b6b59SJacob Faibussowitsch     auto stype = std::make_pair(PETSC_DEVICE_CONTEXT_DEFAULT_STREAM_TYPE, PETSC_FALSE);
6960e6b6b59SJacob Faibussowitsch 
6970e6b6b59SJacob Faibussowitsch     PetscOptionsBegin(comm, "root_", "Root PetscDeviceContext Options", "Sys");
6980e6b6b59SJacob Faibussowitsch     PetscCall(PetscDeviceContextQueryOptions_Internal(PetscOptionsObject, dtype, stype));
6990e6b6b59SJacob Faibussowitsch     PetscOptionsEnd();
7000e6b6b59SJacob Faibussowitsch 
7010e6b6b59SJacob Faibussowitsch     if (dtype.second) PetscCall(PetscDeviceContextSetRootDeviceType_Internal(dtype.first));
7020e6b6b59SJacob Faibussowitsch     if (stype.second) PetscCall(PetscDeviceContextSetRootStreamType_Internal(stype.first));
7030e6b6b59SJacob Faibussowitsch   }
7040e6b6b59SJacob Faibussowitsch 
705a4af0ceeSJacob Faibussowitsch   if (initializeDeviceContextEagerly) {
706a4af0ceeSJacob Faibussowitsch     PetscDeviceContext dctx;
707a4af0ceeSJacob Faibussowitsch 
7080e6b6b59SJacob Faibussowitsch     PetscCall(PetscInfo(nullptr, "Eagerly initializing PetscDeviceContext with %s device\n", PetscDeviceTypes[deviceContextInitDevice]));
7090e6b6b59SJacob Faibussowitsch     /* instantiates the device context */
7109566063dSJacob Faibussowitsch     PetscCall(PetscDeviceContextGetCurrentContext(&dctx));
7119566063dSJacob Faibussowitsch     PetscCall(PetscDeviceContextSetUp(dctx));
712a4af0ceeSJacob Faibussowitsch   }
7133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
714a4af0ceeSJacob Faibussowitsch }
715