10e6b6b59SJacob Faibussowitsch #include "petscdevice_interface_internal.hpp" /*I <petscdevice.h> I*/ 217f48955SJacob Faibussowitsch #include <petsc/private/petscadvancedmacros.h> 3030f984aSJacob Faibussowitsch 4*bbfde98dSJacob Faibussowitsch #include <petsc/private/cpp/register_finalize.hpp> 5*bbfde98dSJacob Faibussowitsch 60e6b6b59SJacob Faibussowitsch #include "../impls/host/hostdevice.hpp" 7*bbfde98dSJacob Faibussowitsch #if PetscDefined(HAVE_CUPM) 80e6b6b59SJacob Faibussowitsch #include "../impls/cupm/cupmdevice.hpp" 9*bbfde98dSJacob Faibussowitsch #endif 10*bbfde98dSJacob Faibussowitsch #if PetscDefined(HAVE_SYCL) 110e6b6b59SJacob Faibussowitsch #include "../impls/sycl/sycldevice.hpp" 12*bbfde98dSJacob Faibussowitsch #endif 130e6b6b59SJacob Faibussowitsch 140e6b6b59SJacob Faibussowitsch #include <utility> // std::make_pair 150e6b6b59SJacob Faibussowitsch 160e6b6b59SJacob Faibussowitsch using namespace Petsc::device; 17030f984aSJacob Faibussowitsch 18*bbfde98dSJacob Faibussowitsch namespace 19*bbfde98dSJacob Faibussowitsch { 20*bbfde98dSJacob Faibussowitsch 21cf3a2253SJacob Faibussowitsch /* 22cf3a2253SJacob Faibussowitsch note to anyone adding more classes, the name must be ALL_CAPS_SHORT_NAME + Device exactly to 23cf3a2253SJacob Faibussowitsch be picked up by the switch-case macros below 24cf3a2253SJacob Faibussowitsch */ 25*bbfde98dSJacob Faibussowitsch host::Device HOSTDevice{PetscDeviceContextCreate_HOST}; 26030f984aSJacob Faibussowitsch #if PetscDefined(HAVE_CUDA) 27*bbfde98dSJacob Faibussowitsch cupm::Device<cupm::DeviceType::CUDA> CUDADevice{PetscDeviceContextCreate_CUDA}; 28030f984aSJacob Faibussowitsch #endif 29030f984aSJacob Faibussowitsch #if PetscDefined(HAVE_HIP) 30*bbfde98dSJacob Faibussowitsch cupm::Device<cupm::DeviceType::HIP> HIPDevice{PetscDeviceContextCreate_HIP}; 31030f984aSJacob Faibussowitsch #endif 32a2158755SJunchao Zhang #if PetscDefined(HAVE_SYCL) 33*bbfde98dSJacob Faibussowitsch sycl::Device SYCLDevice{PetscDeviceContextCreate_SYCL}; 34a2158755SJunchao Zhang #endif 35030f984aSJacob Faibussowitsch 36*bbfde98dSJacob Faibussowitsch } // namespace 37*bbfde98dSJacob Faibussowitsch 3817f48955SJacob Faibussowitsch #define PETSC_DEVICE_CASE(IMPLS, func, ...) \ 3917f48955SJacob Faibussowitsch case PetscConcat_(PETSC_DEVICE_, IMPLS): { \ 409566063dSJacob Faibussowitsch PetscCall(PetscConcat_(IMPLS, Device).func(__VA_ARGS__)); \ 4117f48955SJacob Faibussowitsch } break 42a4af0ceeSJacob Faibussowitsch 43394bf645SJacob Faibussowitsch #define PETSC_VOID_0(...) ((void)0) 44394bf645SJacob Faibussowitsch 45cf3a2253SJacob Faibussowitsch /* 46cf3a2253SJacob Faibussowitsch Suppose you have: 47cf3a2253SJacob Faibussowitsch 48cf3a2253SJacob Faibussowitsch CUDADevice.myFunction(arg1,arg2) 49cf3a2253SJacob Faibussowitsch 50cf3a2253SJacob Faibussowitsch that you would like to conditionally define and call in a switch-case: 51cf3a2253SJacob Faibussowitsch 52cf3a2253SJacob Faibussowitsch switch(PetscDeviceType) { 53cf3a2253SJacob Faibussowitsch #if PetscDefined(HAVE_CUDA) 54cf3a2253SJacob Faibussowitsch case PETSC_DEVICE_CUDA: { 559566063dSJacob Faibussowitsch PetscCall(CUDADevice.myFunction(arg1,arg2)); 56cf3a2253SJacob Faibussowitsch } break; 57cf3a2253SJacob Faibussowitsch #endif 58cf3a2253SJacob Faibussowitsch } 59cf3a2253SJacob Faibussowitsch 60cf3a2253SJacob Faibussowitsch then calling this macro: 61cf3a2253SJacob Faibussowitsch 62cf3a2253SJacob Faibussowitsch PETSC_DEVICE_CASE_IF_PETSC_DEFINED(CUDA,myFunction,arg1,arg2) 63cf3a2253SJacob Faibussowitsch 64cf3a2253SJacob Faibussowitsch will expand to the following case statement: 65cf3a2253SJacob Faibussowitsch 66cf3a2253SJacob Faibussowitsch case PETSC_DEVICE_CUDA: { 679566063dSJacob Faibussowitsch PetscCall(CUDADevice.myFunction(arg1,arg2)); 68cf3a2253SJacob Faibussowitsch } break 69cf3a2253SJacob Faibussowitsch 70cf3a2253SJacob Faibussowitsch if PetscDefined(HAVE_CUDA) evaluates to 1, and expand to nothing otherwise 7117f48955SJacob Faibussowitsch */ 72394bf645SJacob Faibussowitsch #define PETSC_DEVICE_CASE_IF_PETSC_DEFINED(IMPLS, func, ...) PetscIfPetscDefined(PetscConcat_(HAVE_, IMPLS), PETSC_DEVICE_CASE, PETSC_VOID_0)(IMPLS, func, __VA_ARGS__) 73030f984aSJacob Faibussowitsch 74030f984aSJacob Faibussowitsch /*@C 75811af0c4SBarry Smith PetscDeviceCreate - Get a new handle for a particular device (often a GPU) type 76030f984aSJacob Faibussowitsch 770e6b6b59SJacob Faibussowitsch Not Collective 78030f984aSJacob Faibussowitsch 79f1a722f8SMatthew G. Knepley Input Parameters: 80811af0c4SBarry Smith + type - The type of `PetscDevice` 81811af0c4SBarry Smith - devid - The numeric ID# of the device (pass `PETSC_DECIDE` to assign automatically) 82030f984aSJacob Faibussowitsch 83030f984aSJacob Faibussowitsch Output Parameter: 84811af0c4SBarry Smith . device - The `PetscDevice` 85030f984aSJacob Faibussowitsch 862fe279fdSBarry Smith Level: beginner 872fe279fdSBarry Smith 88030f984aSJacob Faibussowitsch Notes: 890e6b6b59SJacob Faibussowitsch This routine may initialize `PetscDevice`. If this is the case, it may cause some sort of 900e6b6b59SJacob Faibussowitsch device synchronization. 91a4af0ceeSJacob Faibussowitsch 92811af0c4SBarry Smith `devid` is what you might pass to `cudaSetDevice()` for example. 93030f984aSJacob Faibussowitsch 940e6b6b59SJacob Faibussowitsch .seealso: `PetscDevice`, `PetscDeviceInitType`, 950e6b6b59SJacob Faibussowitsch `PetscDeviceInitialize()`, `PetscDeviceInitialized()`, `PetscDeviceConfigure()`, 960e6b6b59SJacob Faibussowitsch `PetscDeviceView()`, `PetscDeviceDestroy()` 97030f984aSJacob Faibussowitsch @*/ 98d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceCreate(PetscDeviceType type, PetscInt devid, PetscDevice *device) 99d71ae5a4SJacob Faibussowitsch { 100030f984aSJacob Faibussowitsch static PetscInt PetscDeviceCounter = 0; 101030f984aSJacob Faibussowitsch 102030f984aSJacob Faibussowitsch PetscFunctionBegin; 103a4af0ceeSJacob Faibussowitsch PetscValidDeviceType(type, 1); 104a4af0ceeSJacob Faibussowitsch PetscValidPointer(device, 3); 1059566063dSJacob Faibussowitsch PetscCall(PetscDeviceInitializePackage()); 1060e6b6b59SJacob Faibussowitsch PetscCall(PetscNew(device)); 1070e6b6b59SJacob Faibussowitsch (*device)->id = PetscDeviceCounter++; 1080e6b6b59SJacob Faibussowitsch (*device)->type = type; 1090e6b6b59SJacob Faibussowitsch (*device)->refcnt = 1; 110cf3a2253SJacob Faibussowitsch /* 11191c35059SPierre Jolivet if you are adding a device, you also need to add its initialization in 112cf3a2253SJacob Faibussowitsch PetscDeviceInitializeTypeFromOptions_Private() below 113cf3a2253SJacob Faibussowitsch */ 114a4af0ceeSJacob Faibussowitsch switch (type) { 1150e6b6b59SJacob Faibussowitsch PETSC_DEVICE_CASE_IF_PETSC_DEFINED(HOST, getDevice, *device, devid); 1160e6b6b59SJacob Faibussowitsch PETSC_DEVICE_CASE_IF_PETSC_DEFINED(CUDA, getDevice, *device, devid); 1170e6b6b59SJacob Faibussowitsch PETSC_DEVICE_CASE_IF_PETSC_DEFINED(HIP, getDevice, *device, devid); 1180e6b6b59SJacob Faibussowitsch PETSC_DEVICE_CASE_IF_PETSC_DEFINED(SYCL, getDevice, *device, devid); 119030f984aSJacob Faibussowitsch default: 12017f48955SJacob Faibussowitsch /* in case the above macros expand to nothing this silences any unused variable warnings */ 12117f48955SJacob Faibussowitsch (void)(devid); 12298921bdaSJacob 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]); 123030f984aSJacob Faibussowitsch } 1243ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 125030f984aSJacob Faibussowitsch } 126030f984aSJacob Faibussowitsch 127030f984aSJacob Faibussowitsch /*@C 128811af0c4SBarry Smith PetscDeviceDestroy - Free a `PetscDevice` 129030f984aSJacob Faibussowitsch 1300e6b6b59SJacob Faibussowitsch Not Collective 131030f984aSJacob Faibussowitsch 132030f984aSJacob Faibussowitsch Input Parameter: 1330e6b6b59SJacob Faibussowitsch . device - The `PetscDevice` 134030f984aSJacob Faibussowitsch 135030f984aSJacob Faibussowitsch Level: beginner 136030f984aSJacob Faibussowitsch 1370e6b6b59SJacob Faibussowitsch .seealso: `PetscDevice`, `PetscDeviceCreate()`, `PetscDeviceConfigure()`, `PetscDeviceView()`, 1380e6b6b59SJacob Faibussowitsch `PetscDeviceGetType()`, `PetscDeviceGetDeviceId()` 139030f984aSJacob Faibussowitsch @*/ 140d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceDestroy(PetscDevice *device) 141d71ae5a4SJacob Faibussowitsch { 142a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 1430e6b6b59SJacob Faibussowitsch PetscValidPointer(device, 1); 1443ba16761SJacob Faibussowitsch if (!*device) PetscFunctionReturn(PETSC_SUCCESS); 145a4af0ceeSJacob Faibussowitsch PetscValidDevice(*device, 1); 1469566063dSJacob Faibussowitsch PetscCall(PetscDeviceDereference_Internal(*device)); 147a4af0ceeSJacob Faibussowitsch if ((*device)->refcnt) { 1480e6b6b59SJacob Faibussowitsch *device = nullptr; 1493ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 150030f984aSJacob Faibussowitsch } 1519566063dSJacob Faibussowitsch PetscCall(PetscFree((*device)->data)); 1529566063dSJacob Faibussowitsch PetscCall(PetscFree(*device)); 1533ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 154030f984aSJacob Faibussowitsch } 155030f984aSJacob Faibussowitsch 156a4af0ceeSJacob Faibussowitsch /*@C 157811af0c4SBarry Smith PetscDeviceConfigure - Configure a particular `PetscDevice` 158030f984aSJacob Faibussowitsch 1590e6b6b59SJacob Faibussowitsch Not Collective 160a4af0ceeSJacob Faibussowitsch 161a4af0ceeSJacob Faibussowitsch Input Parameter: 162811af0c4SBarry Smith . device - The `PetscDevice` to configure 163a4af0ceeSJacob Faibussowitsch 1642fe279fdSBarry Smith Level: beginner 1652fe279fdSBarry Smith 1660e6b6b59SJacob Faibussowitsch Notes: 1670e6b6b59SJacob Faibussowitsch The user should not assume that this is a cheap operation. 168a4af0ceeSJacob Faibussowitsch 1690e6b6b59SJacob Faibussowitsch .seealso: `PetscDevice`, `PetscDeviceCreate()`, `PetscDeviceView()`, `PetscDeviceDestroy()`, 1700e6b6b59SJacob Faibussowitsch `PetscDeviceGetType()`, `PetscDeviceGetDeviceId()` 171a4af0ceeSJacob Faibussowitsch @*/ 172d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceConfigure(PetscDevice device) 173d71ae5a4SJacob Faibussowitsch { 174030f984aSJacob Faibussowitsch PetscFunctionBegin; 175a4af0ceeSJacob Faibussowitsch PetscValidDevice(device, 1); 176cf3a2253SJacob Faibussowitsch /* 177cf3a2253SJacob Faibussowitsch if no available configuration is available, this cascades all the way down to default 178cf3a2253SJacob Faibussowitsch and error 179cf3a2253SJacob Faibussowitsch */ 1800e6b6b59SJacob Faibussowitsch switch (const auto dtype = device->type) { 1810e6b6b59SJacob Faibussowitsch case PETSC_DEVICE_HOST: 1820e6b6b59SJacob Faibussowitsch if (PetscDefined(HAVE_HOST)) break; // always true 1839371c9d4SSatish Balay case PETSC_DEVICE_CUDA: 1849371c9d4SSatish Balay if (PetscDefined(HAVE_CUDA)) break; 1850e6b6b59SJacob Faibussowitsch goto error; 1869371c9d4SSatish Balay case PETSC_DEVICE_HIP: 1879371c9d4SSatish Balay if (PetscDefined(HAVE_HIP)) break; 1880e6b6b59SJacob Faibussowitsch goto error; 1899371c9d4SSatish Balay case PETSC_DEVICE_SYCL: 1909371c9d4SSatish Balay if (PetscDefined(HAVE_SYCL)) break; 191f4d061e9SPierre Jolivet goto error; 1920e6b6b59SJacob Faibussowitsch default: 1930e6b6b59SJacob Faibussowitsch error: 1940e6b6b59SJacob Faibussowitsch SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "PETSc was not configured for PetscDeviceType %s", PetscDeviceTypes[dtype]); 195a4af0ceeSJacob Faibussowitsch } 196dbbe0bcdSBarry Smith PetscUseTypeMethod(device, configure); 1973ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 198a4af0ceeSJacob Faibussowitsch } 199a4af0ceeSJacob Faibussowitsch 200a4af0ceeSJacob Faibussowitsch /*@C 201811af0c4SBarry Smith PetscDeviceView - View a `PetscDevice` 202a4af0ceeSJacob Faibussowitsch 2030e6b6b59SJacob Faibussowitsch Collective on viewer 204a4af0ceeSJacob Faibussowitsch 20591e63d38SStefano Zampini Input Parameters: 206811af0c4SBarry Smith + device - The `PetscDevice` to view 2070e6b6b59SJacob Faibussowitsch - viewer - The `PetscViewer` to view the device with (`NULL` for `PETSC_VIEWER_STDOUT_WORLD`) 208a4af0ceeSJacob Faibussowitsch 209a4af0ceeSJacob Faibussowitsch Level: beginner 210a4af0ceeSJacob Faibussowitsch 2110e6b6b59SJacob Faibussowitsch .seealso: `PetscDevice`, `PetscDeviceCreate()`, `PetscDeviceConfigure()`, 2120e6b6b59SJacob Faibussowitsch `PetscDeviceDestroy()`, `PetscDeviceGetType()`, `PetscDeviceGetDeviceId()` 213a4af0ceeSJacob Faibussowitsch @*/ 214d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceView(PetscDevice device, PetscViewer viewer) 215d71ae5a4SJacob Faibussowitsch { 2160e6b6b59SJacob Faibussowitsch auto sub = viewer; 2170e6b6b59SJacob Faibussowitsch PetscBool iascii; 2180e6b6b59SJacob Faibussowitsch 219a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 220a4af0ceeSJacob Faibussowitsch PetscValidDevice(device, 1); 2210e6b6b59SJacob Faibussowitsch if (viewer) { 222a4af0ceeSJacob Faibussowitsch PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2230e6b6b59SJacob Faibussowitsch PetscCall(PetscObjectTypeCompare(PetscObjectCast(viewer), PETSCVIEWERASCII, &iascii)); 2240e6b6b59SJacob Faibussowitsch } else { 2250e6b6b59SJacob Faibussowitsch PetscCall(PetscViewerASCIIGetStdout(PETSC_COMM_WORLD, &viewer)); 2260e6b6b59SJacob Faibussowitsch iascii = PETSC_TRUE; 2270e6b6b59SJacob Faibussowitsch } 2280e6b6b59SJacob Faibussowitsch 2290e6b6b59SJacob Faibussowitsch if (iascii) { 2300e6b6b59SJacob Faibussowitsch auto dtype = PETSC_DEVICE_HOST; 2310e6b6b59SJacob Faibussowitsch MPI_Comm comm; 2320e6b6b59SJacob Faibussowitsch PetscMPIInt size; 2330e6b6b59SJacob Faibussowitsch PetscInt id = 0; 2340e6b6b59SJacob Faibussowitsch 2350e6b6b59SJacob Faibussowitsch PetscCall(PetscObjectGetComm(PetscObjectCast(viewer), &comm)); 2360e6b6b59SJacob Faibussowitsch PetscCallMPI(MPI_Comm_size(comm, &size)); 2370e6b6b59SJacob Faibussowitsch 2380e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceGetDeviceId(device, &id)); 2390e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceGetType(device, &dtype)); 2400e6b6b59SJacob Faibussowitsch PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sub)); 2410e6b6b59SJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(sub, "PetscDevice Object: %d MPI %s\n", size, size == 1 ? "process" : "processes")); 2420e6b6b59SJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(sub)); 2430e6b6b59SJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(sub, "type: %s\n", PetscDeviceTypes[dtype])); 2440e6b6b59SJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(sub, "id: %" PetscInt_FMT "\n", id)); 2450e6b6b59SJacob Faibussowitsch } 2460e6b6b59SJacob Faibussowitsch 2470e6b6b59SJacob Faibussowitsch // see if impls has extra viewer stuff 2480e6b6b59SJacob Faibussowitsch PetscTryTypeMethod(device, view, sub); 2490e6b6b59SJacob Faibussowitsch 2500e6b6b59SJacob Faibussowitsch if (iascii) { 2510e6b6b59SJacob Faibussowitsch // undo the ASCII specific stuff 2520e6b6b59SJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(sub)); 2530e6b6b59SJacob Faibussowitsch PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sub)); 2540e6b6b59SJacob Faibussowitsch PetscCall(PetscViewerFlush(viewer)); 2550e6b6b59SJacob Faibussowitsch } 2563ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 257a4af0ceeSJacob Faibussowitsch } 258a4af0ceeSJacob Faibussowitsch 25991e63d38SStefano Zampini /*@C 2600e6b6b59SJacob Faibussowitsch PetscDeviceGetType - Get the type of device 26191e63d38SStefano Zampini 2620e6b6b59SJacob Faibussowitsch Not Collective 26391e63d38SStefano Zampini 26491e63d38SStefano Zampini Input Parameter: 265811af0c4SBarry Smith . device - The `PetscDevice` 26691e63d38SStefano Zampini 26791e63d38SStefano Zampini Output Parameter: 2680e6b6b59SJacob Faibussowitsch . type - The `PetscDeviceType` 26991e63d38SStefano Zampini 27091e63d38SStefano Zampini Level: beginner 27191e63d38SStefano Zampini 2720e6b6b59SJacob Faibussowitsch .seealso: `PetscDevice`, `PetscDeviceType`, `PetscDeviceSetDefaultDeviceType()`, 2730e6b6b59SJacob Faibussowitsch `PetscDeviceCreate()`, `PetscDeviceConfigure()`, `PetscDeviceDestroy()`, 2740e6b6b59SJacob Faibussowitsch `PetscDeviceGetDeviceId()`, `PETSC_DEVICE_DEFAULT()` 2750e6b6b59SJacob Faibussowitsch @*/ 276d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceGetType(PetscDevice device, PetscDeviceType *type) 277d71ae5a4SJacob Faibussowitsch { 2780e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 2790e6b6b59SJacob Faibussowitsch PetscValidDevice(device, 1); 2800e6b6b59SJacob Faibussowitsch PetscValidPointer(type, 2); 2810e6b6b59SJacob Faibussowitsch *type = device->type; 2823ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2830e6b6b59SJacob Faibussowitsch } 2840e6b6b59SJacob Faibussowitsch 2850e6b6b59SJacob Faibussowitsch /*@C 2860e6b6b59SJacob Faibussowitsch PetscDeviceGetDeviceId - Get the device ID for a `PetscDevice` 2870e6b6b59SJacob Faibussowitsch 2880e6b6b59SJacob Faibussowitsch Not Collective 2890e6b6b59SJacob Faibussowitsch 2900e6b6b59SJacob Faibussowitsch Input Parameter: 2910e6b6b59SJacob Faibussowitsch . device - The `PetscDevice` 2920e6b6b59SJacob Faibussowitsch 2930e6b6b59SJacob Faibussowitsch Output Parameter: 2940e6b6b59SJacob Faibussowitsch . id - The id 2950e6b6b59SJacob Faibussowitsch 2962fe279fdSBarry Smith Level: beginner 2972fe279fdSBarry Smith 2980e6b6b59SJacob Faibussowitsch Notes: 2990e6b6b59SJacob Faibussowitsch The returned ID may have been assigned by the underlying device backend. For example if the 3000e6b6b59SJacob Faibussowitsch backend is CUDA then `id` is exactly the value returned by `cudaGetDevice()` at the time when 3010e6b6b59SJacob Faibussowitsch this device was configured. 3020e6b6b59SJacob Faibussowitsch 3030e6b6b59SJacob Faibussowitsch .seealso: `PetscDevice`, `PetscDeviceCreate()`, `PetscDeviceGetType()` 30491e63d38SStefano Zampini @*/ 305d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceGetDeviceId(PetscDevice device, PetscInt *id) 306d71ae5a4SJacob Faibussowitsch { 30791e63d38SStefano Zampini PetscFunctionBegin; 30891e63d38SStefano Zampini PetscValidDevice(device, 1); 30991e63d38SStefano Zampini PetscValidIntPointer(id, 2); 31091e63d38SStefano Zampini *id = device->deviceId; 3113ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 31291e63d38SStefano Zampini } 31391e63d38SStefano Zampini 314*bbfde98dSJacob Faibussowitsch namespace 315*bbfde98dSJacob Faibussowitsch { 316*bbfde98dSJacob Faibussowitsch 3170e6b6b59SJacob Faibussowitsch struct DefaultDeviceType : public Petsc::RegisterFinalizeable<DefaultDeviceType> { 3180e6b6b59SJacob Faibussowitsch PetscDeviceType type = PETSC_DEVICE_HARDWARE_DEFAULT_TYPE; 3190e6b6b59SJacob Faibussowitsch 320089fb57cSJacob Faibussowitsch PetscErrorCode finalize_() noexcept 321d71ae5a4SJacob Faibussowitsch { 3220e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 3230e6b6b59SJacob Faibussowitsch type = PETSC_DEVICE_HARDWARE_DEFAULT_TYPE; 3243ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3250e6b6b59SJacob Faibussowitsch } 3260e6b6b59SJacob Faibussowitsch }; 3270e6b6b59SJacob Faibussowitsch 328*bbfde98dSJacob Faibussowitsch auto default_device_type = DefaultDeviceType(); 329*bbfde98dSJacob Faibussowitsch 330*bbfde98dSJacob Faibussowitsch } // namespace 3310e6b6b59SJacob Faibussowitsch 3320e6b6b59SJacob Faibussowitsch /*@C 3330e6b6b59SJacob Faibussowitsch PETSC_DEVICE_DEFAULT - Retrieve the current default `PetscDeviceType` 3340e6b6b59SJacob Faibussowitsch 3350e6b6b59SJacob Faibussowitsch Not Collective 3360e6b6b59SJacob Faibussowitsch 3372fe279fdSBarry Smith Level: beginner 3382fe279fdSBarry Smith 3390e6b6b59SJacob Faibussowitsch Notes: 3400e6b6b59SJacob Faibussowitsch Unless selected by the user, the default device is selected in the following order\: 3410e6b6b59SJacob Faibussowitsch `PETSC_DEVICE_HIP`, `PETSC_DEVICE_CUDA`, `PETSC_DEVICE_SYCL`, `PETSC_DEVICE_HOST`. 3420e6b6b59SJacob Faibussowitsch 3430e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceType`, `PetscDeviceSetDefaultDeviceType()`, `PetscDeviceGetType()` 3440e6b6b59SJacob Faibussowitsch @*/ 345d71ae5a4SJacob Faibussowitsch PetscDeviceType PETSC_DEVICE_DEFAULT(void) 346d71ae5a4SJacob Faibussowitsch { 3470e6b6b59SJacob Faibussowitsch return default_device_type.type; 3480e6b6b59SJacob Faibussowitsch } 3490e6b6b59SJacob Faibussowitsch 3500e6b6b59SJacob Faibussowitsch /*@C 3510e6b6b59SJacob Faibussowitsch PetscDeviceSetDefaultDeviceType - Set the default device type for `PetscDevice` 3520e6b6b59SJacob Faibussowitsch 3530e6b6b59SJacob Faibussowitsch Not Collective 3540e6b6b59SJacob Faibussowitsch 3550e6b6b59SJacob Faibussowitsch Input Parameter: 3560e6b6b59SJacob Faibussowitsch . type - the new default device type 3570e6b6b59SJacob Faibussowitsch 3582fe279fdSBarry Smith Level: beginner 3592fe279fdSBarry Smith 3600e6b6b59SJacob Faibussowitsch Notes: 3610e6b6b59SJacob Faibussowitsch This sets the `PetscDeviceType` returned by `PETSC_DEVICE_DEFAULT()`. 3620e6b6b59SJacob Faibussowitsch 3630e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceType`, `PetscDeviceGetType`, 3640e6b6b59SJacob Faibussowitsch @*/ 365d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceSetDefaultDeviceType(PetscDeviceType type) 366d71ae5a4SJacob Faibussowitsch { 3670e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 3680e6b6b59SJacob Faibussowitsch PetscValidDeviceType(type, 1); 3690e6b6b59SJacob Faibussowitsch if (default_device_type.type != type) { 3700e6b6b59SJacob Faibussowitsch // no need to waster a PetscRegisterFinalize() slot if we don't change it 3710e6b6b59SJacob Faibussowitsch default_device_type.type = type; 3720e6b6b59SJacob Faibussowitsch PetscCall(default_device_type.register_finalize()); 3730e6b6b59SJacob Faibussowitsch } 3743ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3750e6b6b59SJacob Faibussowitsch } 3760e6b6b59SJacob Faibussowitsch 377*bbfde98dSJacob Faibussowitsch namespace 378*bbfde98dSJacob Faibussowitsch { 379*bbfde98dSJacob Faibussowitsch 380*bbfde98dSJacob Faibussowitsch std::array<std::pair<PetscDevice, bool>, PETSC_DEVICE_MAX> defaultDevices = {}; 3810e6b6b59SJacob Faibussowitsch 3820e6b6b59SJacob Faibussowitsch /* 383da81f932SPierre Jolivet Actual initialization function; any functions claiming to initialize PetscDevice or 3840e6b6b59SJacob Faibussowitsch PetscDeviceContext will have to run through this one 3850e6b6b59SJacob Faibussowitsch */ 386*bbfde98dSJacob Faibussowitsch PetscErrorCode PetscDeviceInitializeDefaultDevice_Internal(PetscDeviceType type, PetscInt defaultDeviceId) 387d71ae5a4SJacob Faibussowitsch { 3880e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 3890e6b6b59SJacob Faibussowitsch PetscValidDeviceType(type, 1); 3900e6b6b59SJacob Faibussowitsch if (PetscUnlikely(!PetscDeviceInitialized(type))) { 3910e6b6b59SJacob Faibussowitsch auto &dev = defaultDevices[type].first; 3920e6b6b59SJacob Faibussowitsch auto &init = defaultDevices[type].second; 3930e6b6b59SJacob Faibussowitsch 3940e6b6b59SJacob Faibussowitsch PetscAssert(!dev, PETSC_COMM_SELF, PETSC_ERR_MEM, "Trying to overwrite existing default device of type %s", PetscDeviceTypes[type]); 3950e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceCreate(type, defaultDeviceId, &dev)); 3960e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceConfigure(dev)); 3970e6b6b59SJacob Faibussowitsch init = true; 3980e6b6b59SJacob Faibussowitsch } 3993ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 4000e6b6b59SJacob Faibussowitsch } 401a4af0ceeSJacob Faibussowitsch 402*bbfde98dSJacob Faibussowitsch } // namespace 403*bbfde98dSJacob Faibussowitsch 404a4af0ceeSJacob Faibussowitsch /*@C 405811af0c4SBarry Smith PetscDeviceInitialize - Initialize `PetscDevice` 406a4af0ceeSJacob Faibussowitsch 4070e6b6b59SJacob Faibussowitsch Not Collective 408a4af0ceeSJacob Faibussowitsch 409a4af0ceeSJacob Faibussowitsch Input Parameter: 410811af0c4SBarry Smith . type - The `PetscDeviceType` to initialize 411a4af0ceeSJacob Faibussowitsch 4122fe279fdSBarry Smith Level: beginner 4132fe279fdSBarry Smith 4140e6b6b59SJacob Faibussowitsch Notes: 4150e6b6b59SJacob Faibussowitsch Eagerly initializes the corresponding `PetscDeviceType` if needed. If this is the case it may 4160e6b6b59SJacob Faibussowitsch result in device synchronization. 417a4af0ceeSJacob Faibussowitsch 4180e6b6b59SJacob Faibussowitsch .seealso: `PetscDevice`, `PetscDeviceInitType`, `PetscDeviceInitialized()`, 4190e6b6b59SJacob Faibussowitsch `PetscDeviceCreate()`, `PetscDeviceDestroy()` 420a4af0ceeSJacob Faibussowitsch @*/ 421d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceInitialize(PetscDeviceType type) 422d71ae5a4SJacob Faibussowitsch { 423a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 424a4af0ceeSJacob Faibussowitsch PetscValidDeviceType(type, 1); 4259566063dSJacob Faibussowitsch PetscCall(PetscDeviceInitializeDefaultDevice_Internal(type, PETSC_DECIDE)); 4263ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 427a4af0ceeSJacob Faibussowitsch } 428a4af0ceeSJacob Faibussowitsch 429a4af0ceeSJacob Faibussowitsch /*@C 430811af0c4SBarry Smith PetscDeviceInitialized - Determines whether `PetscDevice` is initialized for a particular 431811af0c4SBarry Smith `PetscDeviceType` 432a4af0ceeSJacob Faibussowitsch 4330e6b6b59SJacob Faibussowitsch Not Collective 434a4af0ceeSJacob Faibussowitsch 435a4af0ceeSJacob Faibussowitsch Input Parameter: 436811af0c4SBarry Smith . type - The `PetscDeviceType` to check 437a4af0ceeSJacob Faibussowitsch 4382fe279fdSBarry Smith Level: beginner 4392fe279fdSBarry Smith 4400e6b6b59SJacob Faibussowitsch Notes: 4410e6b6b59SJacob Faibussowitsch Returns `PETSC_TRUE` if `type` is initialized, `PETSC_FALSE` otherwise. 442a4af0ceeSJacob Faibussowitsch 443811af0c4SBarry Smith If one has not configured PETSc for a particular `PetscDeviceType` then this routine will 444811af0c4SBarry Smith return `PETSC_FALSE` for that `PetscDeviceType`. 445a4af0ceeSJacob Faibussowitsch 4460e6b6b59SJacob Faibussowitsch .seealso: `PetscDevice`, `PetscDeviceInitType`, `PetscDeviceInitialize()`, 4470e6b6b59SJacob Faibussowitsch `PetscDeviceCreate()`, `PetscDeviceDestroy()` 448a4af0ceeSJacob Faibussowitsch @*/ 449d71ae5a4SJacob Faibussowitsch PetscBool PetscDeviceInitialized(PetscDeviceType type) 450d71ae5a4SJacob Faibussowitsch { 4510e6b6b59SJacob Faibussowitsch return static_cast<PetscBool>(PetscDeviceConfiguredFor_Internal(type) && defaultDevices[type].second); 4520e6b6b59SJacob Faibussowitsch } 4530e6b6b59SJacob Faibussowitsch 4540e6b6b59SJacob Faibussowitsch /* Get the default PetscDevice for a particular type and constructs them if lazily initialized. */ 455d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceGetDefaultForType_Internal(PetscDeviceType type, PetscDevice *device) 456d71ae5a4SJacob Faibussowitsch { 4570e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 4580e6b6b59SJacob Faibussowitsch PetscValidPointer(device, 2); 4590e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceInitialize(type)); 4600e6b6b59SJacob Faibussowitsch *device = defaultDevices[type].first; 4613ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 462a4af0ceeSJacob Faibussowitsch } 463a4af0ceeSJacob Faibussowitsch 464a16fd2c9SJacob Faibussowitsch /*@C 465a16fd2c9SJacob Faibussowitsch PetscDeviceGetAttribute - Query a particular attribute of a `PetscDevice` 466a16fd2c9SJacob Faibussowitsch 4670e6b6b59SJacob Faibussowitsch Not Collective 468a16fd2c9SJacob Faibussowitsch 469a16fd2c9SJacob Faibussowitsch Input Parameters: 470a16fd2c9SJacob Faibussowitsch + device - The `PetscDevice` 471a16fd2c9SJacob Faibussowitsch - attr - The attribute 472a16fd2c9SJacob Faibussowitsch 473a16fd2c9SJacob Faibussowitsch Output Parameter: 474a16fd2c9SJacob Faibussowitsch . value - The value of the attribute 475a16fd2c9SJacob Faibussowitsch 4762fe279fdSBarry Smith Level: intermediate 4772fe279fdSBarry Smith 478a16fd2c9SJacob Faibussowitsch Notes: 479a16fd2c9SJacob Faibussowitsch Since different attributes are often different types `value` is a `void *` to accommodate 480a16fd2c9SJacob Faibussowitsch them all. The underlying type of the attribute is therefore included in the name of the 481da81f932SPierre Jolivet `PetscDeviceAttribute` responsible for querying it. For example, 482a16fd2c9SJacob Faibussowitsch `PETSC_DEVICE_ATTR_SIZE_T_SHARED_MEM_PER_BLOCK` is of type `size_t`. 483a16fd2c9SJacob Faibussowitsch 484a16fd2c9SJacob Faibussowitsch .seealso: `PetscDeviceAtrtibute`, `PetscDeviceConfigure()`, `PetscDevice` 485a16fd2c9SJacob Faibussowitsch @*/ 486d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceGetAttribute(PetscDevice device, PetscDeviceAttribute attr, void *value) 487d71ae5a4SJacob Faibussowitsch { 488a16fd2c9SJacob Faibussowitsch PetscFunctionBegin; 489a16fd2c9SJacob Faibussowitsch PetscValidDevice(device, 1); 490a16fd2c9SJacob Faibussowitsch PetscValidDeviceAttribute(attr, 2); 491a16fd2c9SJacob Faibussowitsch PetscValidPointer(value, 3); 492a16fd2c9SJacob Faibussowitsch PetscUseTypeMethod(device, getattribute, attr, value); 4933ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 494a16fd2c9SJacob Faibussowitsch } 495a16fd2c9SJacob Faibussowitsch 496*bbfde98dSJacob Faibussowitsch namespace 497*bbfde98dSJacob Faibussowitsch { 498*bbfde98dSJacob Faibussowitsch 499*bbfde98dSJacob Faibussowitsch PetscErrorCode PetscDeviceInitializeTypeFromOptions_Private(MPI_Comm comm, PetscDeviceType type, PetscInt defaultDeviceId, PetscBool defaultView, PetscDeviceInitType *defaultInitType) 500d71ae5a4SJacob Faibussowitsch { 501a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 502a4af0ceeSJacob Faibussowitsch if (!PetscDeviceConfiguredFor_Internal(type)) { 5030e6b6b59SJacob Faibussowitsch PetscCall(PetscInfo(nullptr, "PetscDeviceType %s not available\n", PetscDeviceTypes[type])); 5040e6b6b59SJacob Faibussowitsch defaultDevices[type].first = nullptr; 5053ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 506a4af0ceeSJacob Faibussowitsch } 5070e6b6b59SJacob Faibussowitsch PetscCall(PetscInfo(nullptr, "PetscDeviceType %s available, initializing\n", PetscDeviceTypes[type])); 508a4af0ceeSJacob Faibussowitsch /* ugly switch needed to pick the right global variable... could maybe do this as a union? */ 509a4af0ceeSJacob Faibussowitsch switch (type) { 5100e6b6b59SJacob Faibussowitsch PETSC_DEVICE_CASE_IF_PETSC_DEFINED(HOST, initialize, comm, &defaultDeviceId, &defaultView, defaultInitType); 5110e6b6b59SJacob Faibussowitsch PETSC_DEVICE_CASE_IF_PETSC_DEFINED(CUDA, initialize, comm, &defaultDeviceId, &defaultView, defaultInitType); 5120e6b6b59SJacob Faibussowitsch PETSC_DEVICE_CASE_IF_PETSC_DEFINED(HIP, initialize, comm, &defaultDeviceId, &defaultView, defaultInitType); 5130e6b6b59SJacob Faibussowitsch PETSC_DEVICE_CASE_IF_PETSC_DEFINED(SYCL, initialize, comm, &defaultDeviceId, &defaultView, defaultInitType); 514d71ae5a4SJacob Faibussowitsch default: 515d71ae5a4SJacob 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]); 516a4af0ceeSJacob Faibussowitsch } 517bd2fcf0cSJacob 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)])); 518cf3a2253SJacob Faibussowitsch /* 5190e6b6b59SJacob Faibussowitsch defaultInitType, defaultView and defaultDeviceId now represent what the individual TYPES 5200e6b6b59SJacob Faibussowitsch have decided to initialize as 521cf3a2253SJacob Faibussowitsch */ 5220e6b6b59SJacob Faibussowitsch if ((*defaultInitType == PETSC_DEVICE_INIT_EAGER) || defaultView) { 5230e6b6b59SJacob Faibussowitsch PetscCall(PetscInfo(nullptr, "Eagerly initializing %s PetscDevice\n", PetscDeviceTypes[type])); 5249566063dSJacob Faibussowitsch PetscCall(PetscDeviceInitializeDefaultDevice_Internal(type, defaultDeviceId)); 5250e6b6b59SJacob Faibussowitsch if (defaultView) PetscCall(PetscDeviceView(defaultDevices[type].first, nullptr)); 5260e6b6b59SJacob Faibussowitsch } 5273ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 5280e6b6b59SJacob Faibussowitsch } 529a4af0ceeSJacob Faibussowitsch 530*bbfde98dSJacob Faibussowitsch PetscErrorCode PetscDeviceInitializeQueryOptions_Private(MPI_Comm comm, PetscDeviceType *deviceContextInitDevice, PetscDeviceInitType *defaultInitType, PetscInt *defaultDevice, PetscBool *defaultDeviceSet, PetscBool *defaultView) 531d71ae5a4SJacob Faibussowitsch { 5320e6b6b59SJacob Faibussowitsch PetscInt initIdx = PETSC_DEVICE_INIT_LAZY; 5330e6b6b59SJacob Faibussowitsch auto initDeviceIdx = static_cast<PetscInt>(*deviceContextInitDevice); 5340e6b6b59SJacob Faibussowitsch auto flg = PETSC_FALSE; 5350e6b6b59SJacob Faibussowitsch 5360e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 5370e6b6b59SJacob Faibussowitsch PetscCall(PetscOptionsHasName(nullptr, nullptr, "-log_view_gpu_time", &flg)); 5380e6b6b59SJacob Faibussowitsch if (flg) PetscCall(PetscLogGpuTime()); 5390e6b6b59SJacob Faibussowitsch 5400e6b6b59SJacob Faibussowitsch PetscOptionsBegin(comm, nullptr, "PetscDevice Options", "Sys"); 5410e6b6b59SJacob Faibussowitsch PetscCall(PetscOptionsEList("-device_enable", "How (or whether) to initialize PetscDevices", "PetscDeviceInitialize()", PetscDeviceInitTypes, 3, PetscDeviceInitTypes[initIdx], &initIdx, nullptr)); 5420e6b6b59SJacob Faibussowitsch PetscCall(PetscOptionsEList("-default_device_type", "Set the PetscDeviceType returned by PETSC_DEVICE_DEFAULT()", "PetscDeviceSetDefaultDeviceType()", PetscDeviceTypes, PETSC_DEVICE_MAX, PetscDeviceTypes[initDeviceIdx], &initDeviceIdx, defaultDeviceSet)); 5430e6b6b59SJacob 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)); 5440e6b6b59SJacob Faibussowitsch PetscCall(PetscOptionsBool("-device_view", "Display device information and assignments (forces eager initialization)", "PetscDeviceView()", *defaultView, defaultView, &flg)); 5450e6b6b59SJacob Faibussowitsch PetscOptionsEnd(); 5460e6b6b59SJacob Faibussowitsch 5470e6b6b59SJacob Faibussowitsch if (initIdx == PETSC_DEVICE_INIT_NONE) { 5480e6b6b59SJacob Faibussowitsch /* disabled all device initialization if devices are globally disabled */ 549da81f932SPierre 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"); 5500e6b6b59SJacob Faibussowitsch *defaultView = PETSC_FALSE; 5510e6b6b59SJacob Faibussowitsch initDeviceIdx = PETSC_DEVICE_HOST; 5520e6b6b59SJacob Faibussowitsch } else { 5530e6b6b59SJacob Faibussowitsch *defaultView = static_cast<PetscBool>(*defaultView && flg); 5540e6b6b59SJacob Faibussowitsch if (*defaultView) initIdx = PETSC_DEVICE_INIT_EAGER; 555a4af0ceeSJacob Faibussowitsch } 5560e6b6b59SJacob Faibussowitsch *defaultInitType = PetscDeviceInitTypeCast(initIdx); 5570e6b6b59SJacob Faibussowitsch *deviceContextInitDevice = PetscDeviceTypeCast(initDeviceIdx); 5583ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 559030f984aSJacob Faibussowitsch } 560030f984aSJacob Faibussowitsch 561030f984aSJacob Faibussowitsch /* called from PetscFinalize() do not call yourself! */ 562*bbfde98dSJacob Faibussowitsch PetscErrorCode PetscDeviceFinalize_Private() 563d71ae5a4SJacob Faibussowitsch { 564030f984aSJacob Faibussowitsch PetscFunctionBegin; 565a4af0ceeSJacob Faibussowitsch if (PetscDefined(USE_DEBUG)) { 566bf025ffbSJacob Faibussowitsch /* 567bf025ffbSJacob Faibussowitsch you might be thinking, why on earth are you registered yet another finalizer in a 568bf025ffbSJacob Faibussowitsch function already called during PetscRegisterFinalizeAll()? If this seems stupid it's 569bf025ffbSJacob Faibussowitsch because it is. 570bf025ffbSJacob Faibussowitsch 571bf025ffbSJacob Faibussowitsch The crux of the problem is that the initializer (and therefore the ~finalizer~) of 572bf025ffbSJacob Faibussowitsch PetscDeviceContext is guaranteed to run after PetscDevice's. So if the global context had 573bf025ffbSJacob Faibussowitsch a default PetscDevice attached, that PetscDevice will have a reference count >0 and hence 574bf025ffbSJacob Faibussowitsch won't be destroyed yet. So we need to repeat the check that all devices have been 575bf025ffbSJacob Faibussowitsch destroyed again ~after~ the global context is destroyed. In summary: 576bf025ffbSJacob Faibussowitsch 577bf025ffbSJacob Faibussowitsch 1. This finalizer runs and destroys all devices, except it may not because the global 578bf025ffbSJacob Faibussowitsch context may still hold a reference! 579bf025ffbSJacob Faibussowitsch 2. The global context finalizer runs and does the final reference count decrement 580bf025ffbSJacob Faibussowitsch required, which actually destroys the held device. 581bf025ffbSJacob Faibussowitsch 3. Our newly added finalizer runs and checks that all is well. 582a4af0ceeSJacob Faibussowitsch */ 583*bbfde98dSJacob Faibussowitsch PetscCall(PetscRegisterFinalize([] { 584*bbfde98dSJacob Faibussowitsch PetscFunctionBegin; 585*bbfde98dSJacob Faibussowitsch for (auto &&device : defaultDevices) { 586*bbfde98dSJacob Faibussowitsch const auto dev = device.first; 587*bbfde98dSJacob Faibussowitsch 588*bbfde98dSJacob 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); 589*bbfde98dSJacob Faibussowitsch } 590*bbfde98dSJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 591*bbfde98dSJacob Faibussowitsch })); 592a4af0ceeSJacob Faibussowitsch } 5930e6b6b59SJacob Faibussowitsch for (auto &&device : defaultDevices) { 5940e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceDestroy(&device.first)); 5950e6b6b59SJacob Faibussowitsch device.second = false; 5960e6b6b59SJacob Faibussowitsch } 5973ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 598030f984aSJacob Faibussowitsch } 599030f984aSJacob Faibussowitsch 600*bbfde98dSJacob Faibussowitsch } // namespace 601*bbfde98dSJacob Faibussowitsch 602cf3a2253SJacob Faibussowitsch /* 603cf3a2253SJacob Faibussowitsch Begins the init proceeedings for the entire PetscDevice stack. there are 3 stages of 604cf3a2253SJacob Faibussowitsch initialization types: 605cf3a2253SJacob Faibussowitsch 606a4af0ceeSJacob Faibussowitsch 1. defaultInitType - how does PetscDevice as a whole expect to initialize? 607a4af0ceeSJacob Faibussowitsch 2. subTypeDefaultInitType - how does each PetscDevice implementation expect to initialize? 608a4af0ceeSJacob Faibussowitsch e.g. you may want to blanket disable PetscDevice init (and disable say Kokkos init), but 609a4af0ceeSJacob Faibussowitsch have all CUDA devices still initialize. 610a4af0ceeSJacob Faibussowitsch 611a4af0ceeSJacob Faibussowitsch All told the following happens: 612cf3a2253SJacob Faibussowitsch 613a4af0ceeSJacob Faibussowitsch 0. defaultInitType -> LAZY 614a4af0ceeSJacob Faibussowitsch 1. Check for log_view/log_summary, if yes defaultInitType -> EAGER 615a4af0ceeSJacob Faibussowitsch 2. PetscDevice initializes each sub type with deviceDefaultInitType. 616a4af0ceeSJacob Faibussowitsch 2.1 Each enabled PetscDevice sub-type then does the above disable or view check in addition 617a4af0ceeSJacob Faibussowitsch to checking for specific device init. if view or specific device init 618a4af0ceeSJacob Faibussowitsch subTypeDefaultInitType -> EAGER. disabled once again overrides all. 619a4af0ceeSJacob Faibussowitsch */ 6200e6b6b59SJacob Faibussowitsch 621d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceInitializeFromOptions_Internal(MPI_Comm comm) 622d71ae5a4SJacob Faibussowitsch { 6237a101e5eSJacob Faibussowitsch auto defaultView = PETSC_FALSE; 6247a101e5eSJacob Faibussowitsch auto initializeDeviceContextEagerly = PETSC_FALSE; 6250e6b6b59SJacob Faibussowitsch auto defaultDeviceSet = PETSC_FALSE; 6267a101e5eSJacob Faibussowitsch auto defaultDevice = PetscInt{PETSC_DECIDE}; 6270e6b6b59SJacob Faibussowitsch auto deviceContextInitDevice = PETSC_DEVICE_DEFAULT(); 6280e6b6b59SJacob Faibussowitsch auto defaultInitType = PETSC_DEVICE_INIT_LAZY; 629a4af0ceeSJacob Faibussowitsch 630a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 631a4af0ceeSJacob Faibussowitsch if (PetscDefined(USE_DEBUG)) { 632a4af0ceeSJacob Faibussowitsch int result; 633a4af0ceeSJacob Faibussowitsch 6349566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_compare(comm, PETSC_COMM_WORLD, &result)); 635a4af0ceeSJacob Faibussowitsch /* in order to accurately assign ranks to gpus we need to get the MPI_Comm_rank of the 636a4af0ceeSJacob Faibussowitsch * global space */ 637a4af0ceeSJacob Faibussowitsch if (PetscUnlikely(result != MPI_IDENT)) { 638a4af0ceeSJacob Faibussowitsch char name[MPI_MAX_OBJECT_NAME] = {}; 639a4af0ceeSJacob Faibussowitsch int len; /* unused */ 640a4af0ceeSJacob Faibussowitsch 6419566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_get_name(comm, name, &len)); 64298921bdaSJacob Faibussowitsch SETERRQ(comm, PETSC_ERR_MPI, "Default devices being initialized on MPI_Comm '%s' not PETSC_COMM_WORLD", name); 643a4af0ceeSJacob Faibussowitsch } 644a4af0ceeSJacob Faibussowitsch } 645a4af0ceeSJacob Faibussowitsch comm = PETSC_COMM_WORLD; /* from this point on we assume we're on PETSC_COMM_WORLD */ 6469566063dSJacob Faibussowitsch PetscCall(PetscRegisterFinalize(PetscDeviceFinalize_Private)); 647a4af0ceeSJacob Faibussowitsch 6480e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceInitializeQueryOptions_Private(comm, &deviceContextInitDevice, &defaultInitType, &defaultDevice, &defaultDeviceSet, &defaultView)); 6497a101e5eSJacob Faibussowitsch 6500e6b6b59SJacob Faibussowitsch // the precise values don't matter here, so long as they are sequential 651bd2fcf0cSJacob Faibussowitsch static_assert(Petsc::util::to_underlying(PETSC_DEVICE_HOST) == 0, ""); 652bd2fcf0cSJacob Faibussowitsch static_assert(Petsc::util::to_underlying(PETSC_DEVICE_CUDA) == 1, ""); 653bd2fcf0cSJacob Faibussowitsch static_assert(Petsc::util::to_underlying(PETSC_DEVICE_HIP) == 2, ""); 654bd2fcf0cSJacob Faibussowitsch static_assert(Petsc::util::to_underlying(PETSC_DEVICE_SYCL) == 3, ""); 655bd2fcf0cSJacob Faibussowitsch static_assert(Petsc::util::to_underlying(PETSC_DEVICE_MAX) == 4, ""); 6560e6b6b59SJacob Faibussowitsch for (int i = PETSC_DEVICE_HOST; i < PETSC_DEVICE_MAX; ++i) { 6570e6b6b59SJacob Faibussowitsch const auto deviceType = PetscDeviceTypeCast(i); 658a4af0ceeSJacob Faibussowitsch auto initType = defaultInitType; 659a4af0ceeSJacob Faibussowitsch 6609566063dSJacob Faibussowitsch PetscCall(PetscDeviceInitializeTypeFromOptions_Private(comm, deviceType, defaultDevice, defaultView, &initType)); 6610e6b6b59SJacob Faibussowitsch if (PetscDeviceConfiguredFor_Internal(deviceType)) { 6620e6b6b59SJacob Faibussowitsch if (initType == PETSC_DEVICE_INIT_EAGER) { 663a4af0ceeSJacob Faibussowitsch initializeDeviceContextEagerly = PETSC_TRUE; 6640e6b6b59SJacob Faibussowitsch // only update the default device if the user hasn't set it previously 6650e6b6b59SJacob Faibussowitsch if (!defaultDeviceSet) { 666a4af0ceeSJacob Faibussowitsch deviceContextInitDevice = deviceType; 6670e6b6b59SJacob Faibussowitsch PetscCall(PetscInfo(nullptr, "PetscDevice %s set as default device type due to eager initialization\n", PetscDeviceTypes[deviceType])); 6680e6b6b59SJacob Faibussowitsch } 6690e6b6b59SJacob Faibussowitsch } else if (initType == PETSC_DEVICE_INIT_NONE) { 6701015a2a4SJacob 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]); 671a4af0ceeSJacob Faibussowitsch } 672a4af0ceeSJacob Faibussowitsch } 6730e6b6b59SJacob Faibussowitsch } 6740e6b6b59SJacob Faibussowitsch 6750e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceSetDefaultDeviceType(deviceContextInitDevice)); 6760e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextSetRootDeviceType_Internal(PETSC_DEVICE_DEFAULT())); 6770e6b6b59SJacob Faibussowitsch /* ----------------------------------------------------------------------------------- */ 6780e6b6b59SJacob Faibussowitsch /* PetscDevice is now fully initialized */ 6790e6b6b59SJacob Faibussowitsch /* ----------------------------------------------------------------------------------- */ 6800e6b6b59SJacob Faibussowitsch { 6810e6b6b59SJacob Faibussowitsch /* 6820e6b6b59SJacob Faibussowitsch query the options db to get the root settings from the user (if any). 6830e6b6b59SJacob Faibussowitsch 6840e6b6b59SJacob Faibussowitsch This section is a bit of a hack. We have to reach across to dcontext.cxx to all but call 6850e6b6b59SJacob Faibussowitsch PetscDeviceContextSetFromOptions() before we even have one, then set a few static 6860e6b6b59SJacob Faibussowitsch variables in that file with the results. 6870e6b6b59SJacob Faibussowitsch */ 6880e6b6b59SJacob Faibussowitsch auto dtype = std::make_pair(PETSC_DEVICE_DEFAULT(), PETSC_FALSE); 6890e6b6b59SJacob Faibussowitsch auto stype = std::make_pair(PETSC_DEVICE_CONTEXT_DEFAULT_STREAM_TYPE, PETSC_FALSE); 6900e6b6b59SJacob Faibussowitsch 6910e6b6b59SJacob Faibussowitsch PetscOptionsBegin(comm, "root_", "Root PetscDeviceContext Options", "Sys"); 6920e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextQueryOptions_Internal(PetscOptionsObject, dtype, stype)); 6930e6b6b59SJacob Faibussowitsch PetscOptionsEnd(); 6940e6b6b59SJacob Faibussowitsch 6950e6b6b59SJacob Faibussowitsch if (dtype.second) PetscCall(PetscDeviceContextSetRootDeviceType_Internal(dtype.first)); 6960e6b6b59SJacob Faibussowitsch if (stype.second) PetscCall(PetscDeviceContextSetRootStreamType_Internal(stype.first)); 6970e6b6b59SJacob Faibussowitsch } 6980e6b6b59SJacob Faibussowitsch 699a4af0ceeSJacob Faibussowitsch if (initializeDeviceContextEagerly) { 700a4af0ceeSJacob Faibussowitsch PetscDeviceContext dctx; 701a4af0ceeSJacob Faibussowitsch 7020e6b6b59SJacob Faibussowitsch PetscCall(PetscInfo(nullptr, "Eagerly initializing PetscDeviceContext with %s device\n", PetscDeviceTypes[deviceContextInitDevice])); 7030e6b6b59SJacob Faibussowitsch /* instantiates the device context */ 7049566063dSJacob Faibussowitsch PetscCall(PetscDeviceContextGetCurrentContext(&dctx)); 7059566063dSJacob Faibussowitsch PetscCall(PetscDeviceContextSetUp(dctx)); 706a4af0ceeSJacob Faibussowitsch } 7073ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 708a4af0ceeSJacob Faibussowitsch } 709