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