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 @*/ 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 */ 126*57508eceSPierre 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 @*/ 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 @*/ 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 @*/ 219d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceView(PetscDevice device, PetscViewer viewer) 220d71ae5a4SJacob Faibussowitsch { 2210e6b6b59SJacob Faibussowitsch auto sub = viewer; 2220e6b6b59SJacob Faibussowitsch PetscBool iascii; 2230e6b6b59SJacob Faibussowitsch 224a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 225a4af0ceeSJacob Faibussowitsch PetscValidDevice(device, 1); 2260e6b6b59SJacob Faibussowitsch if (viewer) { 227a4af0ceeSJacob Faibussowitsch PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2280e6b6b59SJacob Faibussowitsch PetscCall(PetscObjectTypeCompare(PetscObjectCast(viewer), PETSCVIEWERASCII, &iascii)); 2290e6b6b59SJacob Faibussowitsch } else { 2300e6b6b59SJacob Faibussowitsch PetscCall(PetscViewerASCIIGetStdout(PETSC_COMM_WORLD, &viewer)); 2310e6b6b59SJacob Faibussowitsch iascii = PETSC_TRUE; 2320e6b6b59SJacob Faibussowitsch } 2330e6b6b59SJacob Faibussowitsch 2340e6b6b59SJacob Faibussowitsch if (iascii) { 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 2550e6b6b59SJacob Faibussowitsch if (iascii) { 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 @*/ 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 @*/ 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 324089fb57cSJacob 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 @*/ 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 @*/ 369d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceSetDefaultDeviceType(PetscDeviceType type) 370d71ae5a4SJacob Faibussowitsch { 3710e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 3720e6b6b59SJacob Faibussowitsch PetscValidDeviceType(type, 1); 3730e6b6b59SJacob Faibussowitsch if (default_device_type.type != type) { 3740e6b6b59SJacob Faibussowitsch // no need to waster 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 */ 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 @*/ 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 @*/ 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. */ 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 @*/ 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 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 534bbfde98dSJacob Faibussowitsch PetscErrorCode PetscDeviceInitializeQueryOptions_Private(MPI_Comm comm, PetscDeviceType *deviceContextInitDevice, PetscDeviceInitType *defaultInitType, PetscInt *defaultDevice, PetscBool *defaultDeviceSet, 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()); 5430e6b6b59SJacob Faibussowitsch 5440e6b6b59SJacob Faibussowitsch PetscOptionsBegin(comm, nullptr, "PetscDevice Options", "Sys"); 5450e6b6b59SJacob Faibussowitsch PetscCall(PetscOptionsEList("-device_enable", "How (or whether) to initialize PetscDevices", "PetscDeviceInitialize()", PetscDeviceInitTypes, 3, PetscDeviceInitTypes[initIdx], &initIdx, nullptr)); 5460e6b6b59SJacob Faibussowitsch PetscCall(PetscOptionsEList("-default_device_type", "Set the PetscDeviceType returned by PETSC_DEVICE_DEFAULT()", "PetscDeviceSetDefaultDeviceType()", PetscDeviceTypes, PETSC_DEVICE_MAX, PetscDeviceTypes[initDeviceIdx], &initDeviceIdx, defaultDeviceSet)); 5470e6b6b59SJacob 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)); 5480e6b6b59SJacob Faibussowitsch PetscCall(PetscOptionsBool("-device_view", "Display device information and assignments (forces eager initialization)", "PetscDeviceView()", *defaultView, defaultView, &flg)); 5490e6b6b59SJacob Faibussowitsch PetscOptionsEnd(); 5500e6b6b59SJacob Faibussowitsch 5510e6b6b59SJacob Faibussowitsch if (initIdx == PETSC_DEVICE_INIT_NONE) { 5520e6b6b59SJacob Faibussowitsch /* disabled all device initialization if devices are globally disabled */ 553da81f932SPierre 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"); 5540e6b6b59SJacob Faibussowitsch *defaultView = PETSC_FALSE; 5550e6b6b59SJacob Faibussowitsch initDeviceIdx = PETSC_DEVICE_HOST; 5560e6b6b59SJacob Faibussowitsch } else { 5570e6b6b59SJacob Faibussowitsch *defaultView = static_cast<PetscBool>(*defaultView && flg); 5580e6b6b59SJacob Faibussowitsch if (*defaultView) initIdx = PETSC_DEVICE_INIT_EAGER; 559a4af0ceeSJacob Faibussowitsch } 5600e6b6b59SJacob Faibussowitsch *defaultInitType = PetscDeviceInitTypeCast(initIdx); 5610e6b6b59SJacob Faibussowitsch *deviceContextInitDevice = PetscDeviceTypeCast(initDeviceIdx); 5623ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 563030f984aSJacob Faibussowitsch } 564030f984aSJacob Faibussowitsch 565030f984aSJacob Faibussowitsch /* called from PetscFinalize() do not call yourself! */ 566bbfde98dSJacob Faibussowitsch PetscErrorCode PetscDeviceFinalize_Private() 567d71ae5a4SJacob Faibussowitsch { 568030f984aSJacob Faibussowitsch PetscFunctionBegin; 569a4af0ceeSJacob Faibussowitsch if (PetscDefined(USE_DEBUG)) { 570bf025ffbSJacob Faibussowitsch /* 571bf025ffbSJacob Faibussowitsch you might be thinking, why on earth are you registered yet another finalizer in a 572bf025ffbSJacob Faibussowitsch function already called during PetscRegisterFinalizeAll()? If this seems stupid it's 573bf025ffbSJacob Faibussowitsch because it is. 574bf025ffbSJacob Faibussowitsch 575bf025ffbSJacob Faibussowitsch The crux of the problem is that the initializer (and therefore the ~finalizer~) of 576bf025ffbSJacob Faibussowitsch PetscDeviceContext is guaranteed to run after PetscDevice's. So if the global context had 577bf025ffbSJacob Faibussowitsch a default PetscDevice attached, that PetscDevice will have a reference count >0 and hence 578bf025ffbSJacob Faibussowitsch won't be destroyed yet. So we need to repeat the check that all devices have been 579bf025ffbSJacob Faibussowitsch destroyed again ~after~ the global context is destroyed. In summary: 580bf025ffbSJacob Faibussowitsch 581bf025ffbSJacob Faibussowitsch 1. This finalizer runs and destroys all devices, except it may not because the global 582bf025ffbSJacob Faibussowitsch context may still hold a reference! 583bf025ffbSJacob Faibussowitsch 2. The global context finalizer runs and does the final reference count decrement 584bf025ffbSJacob Faibussowitsch required, which actually destroys the held device. 585bf025ffbSJacob Faibussowitsch 3. Our newly added finalizer runs and checks that all is well. 586a4af0ceeSJacob Faibussowitsch */ 587bbfde98dSJacob Faibussowitsch PetscCall(PetscRegisterFinalize([] { 588bbfde98dSJacob Faibussowitsch PetscFunctionBegin; 589bbfde98dSJacob Faibussowitsch for (auto &&device : defaultDevices) { 590bbfde98dSJacob Faibussowitsch const auto dev = device.first; 591bbfde98dSJacob Faibussowitsch 592bbfde98dSJacob 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); 593bbfde98dSJacob Faibussowitsch } 594bbfde98dSJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 595bbfde98dSJacob Faibussowitsch })); 596a4af0ceeSJacob Faibussowitsch } 5970e6b6b59SJacob Faibussowitsch for (auto &&device : defaultDevices) { 5980e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceDestroy(&device.first)); 5990e6b6b59SJacob Faibussowitsch device.second = false; 6000e6b6b59SJacob Faibussowitsch } 6013ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 602030f984aSJacob Faibussowitsch } 603030f984aSJacob Faibussowitsch 604bbfde98dSJacob Faibussowitsch } // namespace 605bbfde98dSJacob Faibussowitsch 606cf3a2253SJacob Faibussowitsch /* 607cf3a2253SJacob Faibussowitsch Begins the init proceeedings for the entire PetscDevice stack. there are 3 stages of 608cf3a2253SJacob Faibussowitsch initialization types: 609cf3a2253SJacob Faibussowitsch 610a4af0ceeSJacob Faibussowitsch 1. defaultInitType - how does PetscDevice as a whole expect to initialize? 611a4af0ceeSJacob Faibussowitsch 2. subTypeDefaultInitType - how does each PetscDevice implementation expect to initialize? 612a4af0ceeSJacob Faibussowitsch e.g. you may want to blanket disable PetscDevice init (and disable say Kokkos init), but 613a4af0ceeSJacob Faibussowitsch have all CUDA devices still initialize. 614a4af0ceeSJacob Faibussowitsch 615a4af0ceeSJacob Faibussowitsch All told the following happens: 616cf3a2253SJacob Faibussowitsch 617a4af0ceeSJacob Faibussowitsch 0. defaultInitType -> LAZY 618a4af0ceeSJacob Faibussowitsch 1. Check for log_view/log_summary, if yes defaultInitType -> EAGER 619a4af0ceeSJacob Faibussowitsch 2. PetscDevice initializes each sub type with deviceDefaultInitType. 620a4af0ceeSJacob Faibussowitsch 2.1 Each enabled PetscDevice sub-type then does the above disable or view check in addition 621a4af0ceeSJacob Faibussowitsch to checking for specific device init. if view or specific device init 622a4af0ceeSJacob Faibussowitsch subTypeDefaultInitType -> EAGER. disabled once again overrides all. 623a4af0ceeSJacob Faibussowitsch */ 6240e6b6b59SJacob Faibussowitsch 625d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceInitializeFromOptions_Internal(MPI_Comm comm) 626d71ae5a4SJacob Faibussowitsch { 6277a101e5eSJacob Faibussowitsch auto defaultView = PETSC_FALSE; 6287a101e5eSJacob Faibussowitsch auto initializeDeviceContextEagerly = PETSC_FALSE; 6290e6b6b59SJacob Faibussowitsch auto defaultDeviceSet = PETSC_FALSE; 6307a101e5eSJacob Faibussowitsch auto defaultDevice = PetscInt{PETSC_DECIDE}; 6310e6b6b59SJacob Faibussowitsch auto deviceContextInitDevice = PETSC_DEVICE_DEFAULT(); 6320e6b6b59SJacob Faibussowitsch auto defaultInitType = PETSC_DEVICE_INIT_LAZY; 633a4af0ceeSJacob Faibussowitsch 634a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 635a4af0ceeSJacob Faibussowitsch if (PetscDefined(USE_DEBUG)) { 636a4af0ceeSJacob Faibussowitsch int result; 637a4af0ceeSJacob Faibussowitsch 6389566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_compare(comm, PETSC_COMM_WORLD, &result)); 639a4af0ceeSJacob Faibussowitsch /* in order to accurately assign ranks to gpus we need to get the MPI_Comm_rank of the 640a4af0ceeSJacob Faibussowitsch * global space */ 641a4af0ceeSJacob Faibussowitsch if (PetscUnlikely(result != MPI_IDENT)) { 642a4af0ceeSJacob Faibussowitsch char name[MPI_MAX_OBJECT_NAME] = {}; 643a4af0ceeSJacob Faibussowitsch int len; /* unused */ 644a4af0ceeSJacob Faibussowitsch 6459566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_get_name(comm, name, &len)); 64698921bdaSJacob Faibussowitsch SETERRQ(comm, PETSC_ERR_MPI, "Default devices being initialized on MPI_Comm '%s' not PETSC_COMM_WORLD", name); 647a4af0ceeSJacob Faibussowitsch } 648a4af0ceeSJacob Faibussowitsch } 649a4af0ceeSJacob Faibussowitsch comm = PETSC_COMM_WORLD; /* from this point on we assume we're on PETSC_COMM_WORLD */ 6509566063dSJacob Faibussowitsch PetscCall(PetscRegisterFinalize(PetscDeviceFinalize_Private)); 651a4af0ceeSJacob Faibussowitsch 6520e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceInitializeQueryOptions_Private(comm, &deviceContextInitDevice, &defaultInitType, &defaultDevice, &defaultDeviceSet, &defaultView)); 6537a101e5eSJacob Faibussowitsch 6540e6b6b59SJacob Faibussowitsch // the precise values don't matter here, so long as they are sequential 655bd2fcf0cSJacob Faibussowitsch static_assert(Petsc::util::to_underlying(PETSC_DEVICE_HOST) == 0, ""); 656bd2fcf0cSJacob Faibussowitsch static_assert(Petsc::util::to_underlying(PETSC_DEVICE_CUDA) == 1, ""); 657bd2fcf0cSJacob Faibussowitsch static_assert(Petsc::util::to_underlying(PETSC_DEVICE_HIP) == 2, ""); 658bd2fcf0cSJacob Faibussowitsch static_assert(Petsc::util::to_underlying(PETSC_DEVICE_SYCL) == 3, ""); 659bd2fcf0cSJacob Faibussowitsch static_assert(Petsc::util::to_underlying(PETSC_DEVICE_MAX) == 4, ""); 6600e6b6b59SJacob Faibussowitsch for (int i = PETSC_DEVICE_HOST; i < PETSC_DEVICE_MAX; ++i) { 6610e6b6b59SJacob Faibussowitsch const auto deviceType = PetscDeviceTypeCast(i); 662a4af0ceeSJacob Faibussowitsch auto initType = defaultInitType; 663a4af0ceeSJacob Faibussowitsch 6649566063dSJacob Faibussowitsch PetscCall(PetscDeviceInitializeTypeFromOptions_Private(comm, deviceType, defaultDevice, defaultView, &initType)); 6650e6b6b59SJacob Faibussowitsch if (PetscDeviceConfiguredFor_Internal(deviceType)) { 6660e6b6b59SJacob Faibussowitsch if (initType == PETSC_DEVICE_INIT_EAGER) { 667a4af0ceeSJacob Faibussowitsch initializeDeviceContextEagerly = PETSC_TRUE; 6680e6b6b59SJacob Faibussowitsch // only update the default device if the user hasn't set it previously 6690e6b6b59SJacob Faibussowitsch if (!defaultDeviceSet) { 670a4af0ceeSJacob Faibussowitsch deviceContextInitDevice = deviceType; 6710e6b6b59SJacob Faibussowitsch PetscCall(PetscInfo(nullptr, "PetscDevice %s set as default device type due to eager initialization\n", PetscDeviceTypes[deviceType])); 6720e6b6b59SJacob Faibussowitsch } 6730e6b6b59SJacob Faibussowitsch } else if (initType == PETSC_DEVICE_INIT_NONE) { 6741015a2a4SJacob 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]); 675a4af0ceeSJacob Faibussowitsch } 676a4af0ceeSJacob Faibussowitsch } 6770e6b6b59SJacob Faibussowitsch } 6780e6b6b59SJacob Faibussowitsch 6790e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceSetDefaultDeviceType(deviceContextInitDevice)); 6800e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextSetRootDeviceType_Internal(PETSC_DEVICE_DEFAULT())); 6810e6b6b59SJacob Faibussowitsch /* ----------------------------------------------------------------------------------- */ 6820e6b6b59SJacob Faibussowitsch /* PetscDevice is now fully initialized */ 6830e6b6b59SJacob Faibussowitsch /* ----------------------------------------------------------------------------------- */ 6840e6b6b59SJacob Faibussowitsch { 6850e6b6b59SJacob Faibussowitsch /* 6860e6b6b59SJacob Faibussowitsch query the options db to get the root settings from the user (if any). 6870e6b6b59SJacob Faibussowitsch 6880e6b6b59SJacob Faibussowitsch This section is a bit of a hack. We have to reach across to dcontext.cxx to all but call 6890e6b6b59SJacob Faibussowitsch PetscDeviceContextSetFromOptions() before we even have one, then set a few static 6900e6b6b59SJacob Faibussowitsch variables in that file with the results. 6910e6b6b59SJacob Faibussowitsch */ 6920e6b6b59SJacob Faibussowitsch auto dtype = std::make_pair(PETSC_DEVICE_DEFAULT(), PETSC_FALSE); 6930e6b6b59SJacob Faibussowitsch auto stype = std::make_pair(PETSC_DEVICE_CONTEXT_DEFAULT_STREAM_TYPE, PETSC_FALSE); 6940e6b6b59SJacob Faibussowitsch 6950e6b6b59SJacob Faibussowitsch PetscOptionsBegin(comm, "root_", "Root PetscDeviceContext Options", "Sys"); 6960e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextQueryOptions_Internal(PetscOptionsObject, dtype, stype)); 6970e6b6b59SJacob Faibussowitsch PetscOptionsEnd(); 6980e6b6b59SJacob Faibussowitsch 6990e6b6b59SJacob Faibussowitsch if (dtype.second) PetscCall(PetscDeviceContextSetRootDeviceType_Internal(dtype.first)); 7000e6b6b59SJacob Faibussowitsch if (stype.second) PetscCall(PetscDeviceContextSetRootStreamType_Internal(stype.first)); 7010e6b6b59SJacob Faibussowitsch } 7020e6b6b59SJacob Faibussowitsch 703a4af0ceeSJacob Faibussowitsch if (initializeDeviceContextEagerly) { 704a4af0ceeSJacob Faibussowitsch PetscDeviceContext dctx; 705a4af0ceeSJacob Faibussowitsch 7060e6b6b59SJacob Faibussowitsch PetscCall(PetscInfo(nullptr, "Eagerly initializing PetscDeviceContext with %s device\n", PetscDeviceTypes[deviceContextInitDevice])); 7070e6b6b59SJacob Faibussowitsch /* instantiates the device context */ 7089566063dSJacob Faibussowitsch PetscCall(PetscDeviceContextGetCurrentContext(&dctx)); 7099566063dSJacob Faibussowitsch PetscCall(PetscDeviceContextSetUp(dctx)); 710a4af0ceeSJacob Faibussowitsch } 7113ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 712a4af0ceeSJacob Faibussowitsch } 713