1030f984aSJacob Faibussowitsch #include "cupmdevice.hpp" /* I "petscdevice.h" */ 217f48955SJacob Faibussowitsch #include <petsc/private/petscadvancedmacros.h> 3030f984aSJacob Faibussowitsch 417f48955SJacob Faibussowitsch using namespace Petsc::Device; 5030f984aSJacob Faibussowitsch 6cf3a2253SJacob Faibussowitsch /* 7cf3a2253SJacob Faibussowitsch note to anyone adding more classes, the name must be ALL_CAPS_SHORT_NAME + Device exactly to 8cf3a2253SJacob Faibussowitsch be picked up by the switch-case macros below 9cf3a2253SJacob Faibussowitsch */ 10030f984aSJacob Faibussowitsch #if PetscDefined(HAVE_CUDA) 1117f48955SJacob Faibussowitsch static CUPM::Device<CUPM::DeviceType::CUDA> CUDADevice(PetscDeviceContextCreate_CUDA); 12030f984aSJacob Faibussowitsch #endif 13030f984aSJacob Faibussowitsch #if PetscDefined(HAVE_HIP) 1417f48955SJacob Faibussowitsch static CUPM::Device<CUPM::DeviceType::HIP> HIPDevice(PetscDeviceContextCreate_HIP); 15030f984aSJacob Faibussowitsch #endif 16a2158755SJunchao Zhang #if PetscDefined(HAVE_SYCL) 17a2158755SJunchao Zhang #include "sycldevice.hpp" 1817f48955SJacob Faibussowitsch static SYCL::Device SYCLDevice(PetscDeviceContextCreate_SYCL); 19a2158755SJunchao Zhang #endif 20030f984aSJacob Faibussowitsch 2117f48955SJacob Faibussowitsch static_assert(Petsc::util::integral_value(PETSC_DEVICE_INVALID) == 0, ""); 2217f48955SJacob Faibussowitsch static_assert(Petsc::util::integral_value(PETSC_DEVICE_CUDA) == 1, ""); 2317f48955SJacob Faibussowitsch static_assert(Petsc::util::integral_value(PETSC_DEVICE_HIP) == 2, ""); 2417f48955SJacob Faibussowitsch static_assert(Petsc::util::integral_value(PETSC_DEVICE_SYCL) == 3, ""); 2517f48955SJacob Faibussowitsch static_assert(Petsc::util::integral_value(PETSC_DEVICE_MAX) == 4, ""); 269371c9d4SSatish Balay const char *const PetscDeviceTypes[] = {"invalid", "cuda", "hip", "sycl", "max", "PetscDeviceType", "PETSC_DEVICE_", PETSC_NULLPTR}; 27a4af0ceeSJacob Faibussowitsch 2817f48955SJacob Faibussowitsch static_assert(Petsc::util::integral_value(PETSC_DEVICE_INIT_NONE) == 0, ""); 2917f48955SJacob Faibussowitsch static_assert(Petsc::util::integral_value(PETSC_DEVICE_INIT_LAZY) == 1, ""); 3017f48955SJacob Faibussowitsch static_assert(Petsc::util::integral_value(PETSC_DEVICE_INIT_EAGER) == 2, ""); 319371c9d4SSatish Balay const char *const PetscDeviceInitTypes[] = {"none", "lazy", "eager", "PetscDeviceInitType", "PETSC_DEVICE_INIT_", PETSC_NULLPTR}; 329371c9d4SSatish Balay static_assert(sizeof(PetscDeviceInitTypes) / sizeof(*PetscDeviceInitTypes) == 6, "Must change CUPMDevice<T>::initialize number of enum values in -device_enable_cupm to match!"); 33a4af0ceeSJacob Faibussowitsch 34a16fd2c9SJacob Faibussowitsch const char *const PetscDeviceAttributes[] = {"shared_mem_per_block", "max", "PetscDeviceAttribute", "PETSC_DEVICE_ATTR_", nullptr}; 35a16fd2c9SJacob Faibussowitsch 3617f48955SJacob Faibussowitsch #define PETSC_DEVICE_CASE(IMPLS, func, ...) \ 3717f48955SJacob Faibussowitsch case PetscConcat_(PETSC_DEVICE_, IMPLS): { \ 389566063dSJacob Faibussowitsch PetscCall(PetscConcat_(IMPLS, Device).func(__VA_ARGS__)); \ 3917f48955SJacob Faibussowitsch } break 40a4af0ceeSJacob Faibussowitsch 41cf3a2253SJacob Faibussowitsch /* 42cf3a2253SJacob Faibussowitsch Suppose you have: 43cf3a2253SJacob Faibussowitsch 44cf3a2253SJacob Faibussowitsch CUDADevice.myFunction(arg1,arg2) 45cf3a2253SJacob Faibussowitsch 46cf3a2253SJacob Faibussowitsch that you would like to conditionally define and call in a switch-case: 47cf3a2253SJacob Faibussowitsch 48cf3a2253SJacob Faibussowitsch switch(PetscDeviceType) { 49cf3a2253SJacob Faibussowitsch #if PetscDefined(HAVE_CUDA) 50cf3a2253SJacob Faibussowitsch case PETSC_DEVICE_CUDA: { 519566063dSJacob Faibussowitsch PetscCall(CUDADevice.myFunction(arg1,arg2)); 52cf3a2253SJacob Faibussowitsch } break; 53cf3a2253SJacob Faibussowitsch #endif 54cf3a2253SJacob Faibussowitsch } 55cf3a2253SJacob Faibussowitsch 56cf3a2253SJacob Faibussowitsch then calling this macro: 57cf3a2253SJacob Faibussowitsch 58cf3a2253SJacob Faibussowitsch PETSC_DEVICE_CASE_IF_PETSC_DEFINED(CUDA,myFunction,arg1,arg2) 59cf3a2253SJacob Faibussowitsch 60cf3a2253SJacob Faibussowitsch will expand to the following case statement: 61cf3a2253SJacob Faibussowitsch 62cf3a2253SJacob Faibussowitsch case PETSC_DEVICE_CUDA: { 639566063dSJacob Faibussowitsch PetscCall(CUDADevice.myFunction(arg1,arg2)); 64cf3a2253SJacob Faibussowitsch } break 65cf3a2253SJacob Faibussowitsch 66cf3a2253SJacob Faibussowitsch if PetscDefined(HAVE_CUDA) evaluates to 1, and expand to nothing otherwise 6717f48955SJacob Faibussowitsch */ 689371c9d4SSatish Balay #define PETSC_DEVICE_CASE_IF_PETSC_DEFINED(IMPLS, func, ...) PetscIfPetscDefined(PetscConcat_(HAVE_, IMPLS), PETSC_DEVICE_CASE, PetscExpandToNothing)(IMPLS, func, __VA_ARGS__) 69030f984aSJacob Faibussowitsch 70030f984aSJacob Faibussowitsch /*@C 71*811af0c4SBarry Smith PetscDeviceCreate - Get a new handle for a particular device (often a GPU) type 72030f984aSJacob Faibussowitsch 73030f984aSJacob Faibussowitsch Not Collective, Possibly Synchronous 74030f984aSJacob Faibussowitsch 75f1a722f8SMatthew G. Knepley Input Parameters: 76*811af0c4SBarry Smith + type - The type of `PetscDevice` 77*811af0c4SBarry Smith - devid - The numeric ID# of the device (pass `PETSC_DECIDE` to assign automatically) 78030f984aSJacob Faibussowitsch 79030f984aSJacob Faibussowitsch Output Parameter: 80*811af0c4SBarry Smith . device - The `PetscDevice` 81030f984aSJacob Faibussowitsch 82030f984aSJacob Faibussowitsch Notes: 83*811af0c4SBarry Smith This routine may initialize `PetscDevice`. If this is the case, this will most likely cause 84a4af0ceeSJacob Faibussowitsch some sort of device synchronization. 85a4af0ceeSJacob Faibussowitsch 86*811af0c4SBarry Smith `devid` is what you might pass to `cudaSetDevice()` for example. 87030f984aSJacob Faibussowitsch 88030f984aSJacob Faibussowitsch Level: beginner 89030f984aSJacob Faibussowitsch 90db781477SPatrick Sanan .seealso: `PetscDevice`, `PetscDeviceInitType`, `PetscDeviceInitialize()`, 91db781477SPatrick Sanan `PetscDeviceInitialized()`, `PetscDeviceConfigure()`, `PetscDeviceView()`, `PetscDeviceDestroy()` 92030f984aSJacob Faibussowitsch @*/ 939371c9d4SSatish Balay PetscErrorCode PetscDeviceCreate(PetscDeviceType type, PetscInt devid, PetscDevice *device) { 94030f984aSJacob Faibussowitsch static PetscInt PetscDeviceCounter = 0; 95030f984aSJacob Faibussowitsch PetscDevice dev; 96030f984aSJacob Faibussowitsch 97030f984aSJacob Faibussowitsch PetscFunctionBegin; 98a4af0ceeSJacob Faibussowitsch PetscValidDeviceType(type, 1); 99a4af0ceeSJacob Faibussowitsch PetscValidPointer(device, 3); 1009566063dSJacob Faibussowitsch PetscCall(PetscDeviceInitializePackage()); 1019566063dSJacob Faibussowitsch PetscCall(PetscNew(&dev)); 102030f984aSJacob Faibussowitsch dev->id = PetscDeviceCounter++; 103a4af0ceeSJacob Faibussowitsch dev->type = type; 104a4af0ceeSJacob Faibussowitsch dev->refcnt = 1; 105cf3a2253SJacob Faibussowitsch /* 106cf3a2253SJacob Faibussowitsch if you are adding a device, you also need to add it's initialization in 107cf3a2253SJacob Faibussowitsch PetscDeviceInitializeTypeFromOptions_Private() below 108cf3a2253SJacob Faibussowitsch */ 109a4af0ceeSJacob Faibussowitsch switch (type) { 110a4af0ceeSJacob Faibussowitsch PETSC_DEVICE_CASE_IF_PETSC_DEFINED(CUDA, getDevice, dev, devid); 111a4af0ceeSJacob Faibussowitsch PETSC_DEVICE_CASE_IF_PETSC_DEFINED(HIP, getDevice, dev, devid); 112a2158755SJunchao Zhang PETSC_DEVICE_CASE_IF_PETSC_DEFINED(SYCL, getDevice, dev, devid); 113030f984aSJacob Faibussowitsch default: 11417f48955SJacob Faibussowitsch /* in case the above macros expand to nothing this silences any unused variable warnings */ 11517f48955SJacob Faibussowitsch (void)(devid); 11698921bdaSJacob 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]); 117030f984aSJacob Faibussowitsch } 118030f984aSJacob Faibussowitsch *device = dev; 119030f984aSJacob Faibussowitsch PetscFunctionReturn(0); 120030f984aSJacob Faibussowitsch } 121030f984aSJacob Faibussowitsch 122030f984aSJacob Faibussowitsch /*@C 123*811af0c4SBarry Smith PetscDeviceDestroy - Free a `PetscDevice` 124030f984aSJacob Faibussowitsch 125030f984aSJacob Faibussowitsch Not Collective, Asynchronous 126030f984aSJacob Faibussowitsch 127030f984aSJacob Faibussowitsch Input Parameter: 128030f984aSJacob Faibussowitsch . device - The PetscDevice 129030f984aSJacob Faibussowitsch 130030f984aSJacob Faibussowitsch Level: beginner 131030f984aSJacob Faibussowitsch 132db781477SPatrick Sanan .seealso: `PetscDevice`, `PetscDeviceCreate()`, `PetscDeviceConfigure()`, `PetscDeviceView()` 133030f984aSJacob Faibussowitsch @*/ 1349371c9d4SSatish Balay PetscErrorCode PetscDeviceDestroy(PetscDevice *device) { 135a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 136a4af0ceeSJacob Faibussowitsch if (!*device) PetscFunctionReturn(0); 137a4af0ceeSJacob Faibussowitsch PetscValidDevice(*device, 1); 1389566063dSJacob Faibussowitsch PetscCall(PetscDeviceDereference_Internal(*device)); 139a4af0ceeSJacob Faibussowitsch if ((*device)->refcnt) { 140a4af0ceeSJacob Faibussowitsch *device = PETSC_NULLPTR; 141a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 142030f984aSJacob Faibussowitsch } 1439566063dSJacob Faibussowitsch PetscCall(PetscFree((*device)->data)); 1449566063dSJacob Faibussowitsch PetscCall(PetscFree(*device)); 145030f984aSJacob Faibussowitsch PetscFunctionReturn(0); 146030f984aSJacob Faibussowitsch } 147030f984aSJacob Faibussowitsch 148a4af0ceeSJacob Faibussowitsch /*@C 149*811af0c4SBarry Smith PetscDeviceConfigure - Configure a particular `PetscDevice` 150030f984aSJacob Faibussowitsch 151a4af0ceeSJacob Faibussowitsch Not Collective, Asynchronous 152a4af0ceeSJacob Faibussowitsch 153a4af0ceeSJacob Faibussowitsch Input Parameter: 154*811af0c4SBarry Smith . device - The `PetscDevice` to configure 155a4af0ceeSJacob Faibussowitsch 156*811af0c4SBarry Smith Note: 157a4af0ceeSJacob Faibussowitsch The user should not assume that this is a cheap operation 158a4af0ceeSJacob Faibussowitsch 159a4af0ceeSJacob Faibussowitsch Level: beginner 160a4af0ceeSJacob Faibussowitsch 161db781477SPatrick Sanan .seealso: `PetscDevice`, `PetscDeviceCreate()`, `PetscDeviceView()`, `PetscDeviceDestroy()` 162a4af0ceeSJacob Faibussowitsch @*/ 1639371c9d4SSatish Balay PetscErrorCode PetscDeviceConfigure(PetscDevice device) { 164030f984aSJacob Faibussowitsch PetscFunctionBegin; 165a4af0ceeSJacob Faibussowitsch PetscValidDevice(device, 1); 166a4af0ceeSJacob Faibussowitsch if (PetscDefined(USE_DEBUG)) { 167cf3a2253SJacob Faibussowitsch /* 168cf3a2253SJacob Faibussowitsch if no available configuration is available, this cascades all the way down to default 169cf3a2253SJacob Faibussowitsch and error 170cf3a2253SJacob Faibussowitsch */ 171a4af0ceeSJacob Faibussowitsch switch (device->type) { 1729371c9d4SSatish Balay case PETSC_DEVICE_CUDA: 1739371c9d4SSatish Balay if (PetscDefined(HAVE_CUDA)) break; 1749371c9d4SSatish Balay case PETSC_DEVICE_HIP: 1759371c9d4SSatish Balay if (PetscDefined(HAVE_HIP)) break; 1769371c9d4SSatish Balay case PETSC_DEVICE_SYCL: 1779371c9d4SSatish Balay if (PetscDefined(HAVE_SYCL)) break; 1789371c9d4SSatish Balay default: 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[device->type]); 179a4af0ceeSJacob Faibussowitsch } 180a4af0ceeSJacob Faibussowitsch } 181dbbe0bcdSBarry Smith PetscUseTypeMethod(device, configure); 182a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 183a4af0ceeSJacob Faibussowitsch } 184a4af0ceeSJacob Faibussowitsch 185a4af0ceeSJacob Faibussowitsch /*@C 186*811af0c4SBarry Smith PetscDeviceView - View a `PetscDevice` 187a4af0ceeSJacob Faibussowitsch 188a4af0ceeSJacob Faibussowitsch Collective on viewer, Asynchronous 189a4af0ceeSJacob Faibussowitsch 19091e63d38SStefano Zampini Input Parameters: 191*811af0c4SBarry Smith + device - The `PetscDevice` to view 192*811af0c4SBarry Smith - viewer - The `PetscViewer` to view the device with (NULL for `PETSC_VIEWER_STDOUT_WORLD`) 193a4af0ceeSJacob Faibussowitsch 194a4af0ceeSJacob Faibussowitsch Level: beginner 195a4af0ceeSJacob Faibussowitsch 196db781477SPatrick Sanan .seealso: `PetscDevice`, `PetscDeviceCreate()`, `PetscDeviceConfigure()`, `PetscDeviceDestroy()` 197a4af0ceeSJacob Faibussowitsch @*/ 1989371c9d4SSatish Balay PetscErrorCode PetscDeviceView(PetscDevice device, PetscViewer viewer) { 199a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 200a4af0ceeSJacob Faibussowitsch PetscValidDevice(device, 1); 2019566063dSJacob Faibussowitsch if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PETSC_COMM_WORLD, &viewer)); 202a4af0ceeSJacob Faibussowitsch PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 203dbbe0bcdSBarry Smith PetscUseTypeMethod(device, view, viewer); 204a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 205a4af0ceeSJacob Faibussowitsch } 206a4af0ceeSJacob Faibussowitsch 20791e63d38SStefano Zampini /*@C 20891e63d38SStefano Zampini PetscDeviceGetDeviceId - Get the device id 20991e63d38SStefano Zampini 21091e63d38SStefano Zampini Not collective 21191e63d38SStefano Zampini 21291e63d38SStefano Zampini Input Parameter: 213*811af0c4SBarry Smith . device - The `PetscDevice` 21491e63d38SStefano Zampini 21591e63d38SStefano Zampini Output Parameter: 21691e63d38SStefano Zampini . id - The device id 21791e63d38SStefano Zampini 21891e63d38SStefano Zampini Level: beginner 21991e63d38SStefano Zampini 220db781477SPatrick Sanan .seealso: `PetscDevice`, `PetscDeviceCreate()`, `PetscDeviceConfigure()`, `PetscDeviceDestroy()` 22191e63d38SStefano Zampini @*/ 2229371c9d4SSatish Balay PetscErrorCode PetscDeviceGetDeviceId(PetscDevice device, PetscInt *id) { 22391e63d38SStefano Zampini PetscFunctionBegin; 22491e63d38SStefano Zampini PetscValidDevice(device, 1); 22591e63d38SStefano Zampini PetscValidIntPointer(id, 2); 22691e63d38SStefano Zampini *id = device->deviceId; 22791e63d38SStefano Zampini PetscFunctionReturn(0); 22891e63d38SStefano Zampini } 22991e63d38SStefano Zampini 230a4af0ceeSJacob Faibussowitsch static std::array<bool, PETSC_DEVICE_MAX> initializedDevice = {}; 231a4af0ceeSJacob Faibussowitsch static std::array<PetscDevice, PETSC_DEVICE_MAX> defaultDevices = {}; 232a4af0ceeSJacob Faibussowitsch static_assert(initializedDevice.size() == defaultDevices.size(), ""); 233a4af0ceeSJacob Faibussowitsch 234a4af0ceeSJacob Faibussowitsch /*@C 235*811af0c4SBarry Smith PetscDeviceInitialize - Initialize `PetscDevice` 236a4af0ceeSJacob Faibussowitsch 237a4af0ceeSJacob Faibussowitsch Not Collective, Possibly Synchronous 238a4af0ceeSJacob Faibussowitsch 239a4af0ceeSJacob Faibussowitsch Input Parameter: 240*811af0c4SBarry Smith . type - The `PetscDeviceType` to initialize 241a4af0ceeSJacob Faibussowitsch 242*811af0c4SBarry Smith Note: 243*811af0c4SBarry Smith Eagerly initializes the corresponding `PetscDeviceType` if needed. 244a4af0ceeSJacob Faibussowitsch 245a4af0ceeSJacob Faibussowitsch Level: beginner 246a4af0ceeSJacob Faibussowitsch 247db781477SPatrick Sanan .seealso: `PetscDevice`, `PetscDeviceInitType`, `PetscDeviceInitialized()`, `PetscDeviceCreate()`, `PetscDeviceDestroy()` 248a4af0ceeSJacob Faibussowitsch @*/ 2499371c9d4SSatish Balay PetscErrorCode PetscDeviceInitialize(PetscDeviceType type) { 250a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 251a4af0ceeSJacob Faibussowitsch PetscValidDeviceType(type, 1); 2529566063dSJacob Faibussowitsch PetscCall(PetscDeviceInitializeDefaultDevice_Internal(type, PETSC_DECIDE)); 253a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 254a4af0ceeSJacob Faibussowitsch } 255a4af0ceeSJacob Faibussowitsch 256a4af0ceeSJacob Faibussowitsch /*@C 257*811af0c4SBarry Smith PetscDeviceInitialized - Determines whether `PetscDevice` is initialized for a particular 258*811af0c4SBarry Smith `PetscDeviceType` 259a4af0ceeSJacob Faibussowitsch 260a4af0ceeSJacob Faibussowitsch Not Collective, Asynchronous 261a4af0ceeSJacob Faibussowitsch 262a4af0ceeSJacob Faibussowitsch Input Parameter: 263*811af0c4SBarry Smith . type - The `PetscDeviceType` to check 264a4af0ceeSJacob Faibussowitsch 265a4af0ceeSJacob Faibussowitsch Output Parameter: 266*811af0c4SBarry Smith . [return value] - `PETSC_TRUE` if type is initialized, `PETSC_FALSE` otherwise 267a4af0ceeSJacob Faibussowitsch 268*811af0c4SBarry Smith Note: 269*811af0c4SBarry Smith If one has not configured PETSc for a particular `PetscDeviceType` then this routine will 270*811af0c4SBarry Smith return `PETSC_FALSE` for that `PetscDeviceType`. 271a4af0ceeSJacob Faibussowitsch 272a4af0ceeSJacob Faibussowitsch Level: beginner 273a4af0ceeSJacob Faibussowitsch 274db781477SPatrick Sanan .seealso: `PetscDevice`, `PetscDeviceInitType`, `PetscDeviceInitialize()`, `PetscDeviceCreate()`, `PetscDeviceDestroy()` 275a4af0ceeSJacob Faibussowitsch @*/ 2769371c9d4SSatish Balay PetscBool PetscDeviceInitialized(PetscDeviceType type) { 277a4af0ceeSJacob Faibussowitsch return static_cast<PetscBool>(PetscDeviceConfiguredFor_Internal(type) && initializedDevice[type]); 278a4af0ceeSJacob Faibussowitsch } 279a4af0ceeSJacob Faibussowitsch 280a16fd2c9SJacob Faibussowitsch /*@C 281a16fd2c9SJacob Faibussowitsch PetscDeviceGetAttribute - Query a particular attribute of a `PetscDevice` 282a16fd2c9SJacob Faibussowitsch 283a16fd2c9SJacob Faibussowitsch Not Collective, Asynchronous 284a16fd2c9SJacob Faibussowitsch 285a16fd2c9SJacob Faibussowitsch Input Parameters: 286a16fd2c9SJacob Faibussowitsch + device - The `PetscDevice` 287a16fd2c9SJacob Faibussowitsch - attr - The attribute 288a16fd2c9SJacob Faibussowitsch 289a16fd2c9SJacob Faibussowitsch Output Parameter: 290a16fd2c9SJacob Faibussowitsch . value - The value of the attribute 291a16fd2c9SJacob Faibussowitsch 292a16fd2c9SJacob Faibussowitsch Notes: 293a16fd2c9SJacob Faibussowitsch Since different attributes are often different types `value` is a `void *` to accommodate 294a16fd2c9SJacob Faibussowitsch them all. The underlying type of the attribute is therefore included in the name of the 295a16fd2c9SJacob Faibussowitsch `PetscDeviceAttribute` reponsible for querying it. For example, 296a16fd2c9SJacob Faibussowitsch `PETSC_DEVICE_ATTR_SIZE_T_SHARED_MEM_PER_BLOCK` is of type `size_t`. 297a16fd2c9SJacob Faibussowitsch 298a16fd2c9SJacob Faibussowitsch .seealso: `PetscDeviceAtrtibute`, `PetscDeviceConfigure()`, `PetscDevice` 299a16fd2c9SJacob Faibussowitsch @*/ 300a16fd2c9SJacob Faibussowitsch PetscErrorCode PetscDeviceGetAttribute(PetscDevice device, PetscDeviceAttribute attr, void *value) { 301a16fd2c9SJacob Faibussowitsch PetscFunctionBegin; 302a16fd2c9SJacob Faibussowitsch PetscValidDevice(device, 1); 303a16fd2c9SJacob Faibussowitsch PetscValidDeviceAttribute(attr, 2); 304a16fd2c9SJacob Faibussowitsch PetscValidPointer(value, 3); 305a16fd2c9SJacob Faibussowitsch PetscUseTypeMethod(device, getattribute, attr, value); 306a16fd2c9SJacob Faibussowitsch PetscFunctionReturn(0); 307a16fd2c9SJacob Faibussowitsch } 308a16fd2c9SJacob Faibussowitsch 309cf3a2253SJacob Faibussowitsch /* 310cf3a2253SJacob Faibussowitsch Actual intialization function; any functions claiming to initialize PetscDevice or 311cf3a2253SJacob Faibussowitsch PetscDeviceContext will have to run through this one 312cf3a2253SJacob Faibussowitsch */ 3139371c9d4SSatish Balay PetscErrorCode PetscDeviceInitializeDefaultDevice_Internal(PetscDeviceType type, PetscInt defaultDeviceId) { 314a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 315a4af0ceeSJacob Faibussowitsch PetscValidDeviceType(type, 1); 316a4af0ceeSJacob Faibussowitsch if (PetscLikely(PetscDeviceInitialized(type))) PetscFunctionReturn(0); 317bf025ffbSJacob Faibussowitsch PetscAssert(!defaultDevices[type], PETSC_COMM_SELF, PETSC_ERR_MEM, "Trying to overwrite existing default device of type %s", PetscDeviceTypes[type]); 3189566063dSJacob Faibussowitsch PetscCall(PetscDeviceCreate(type, defaultDeviceId, &defaultDevices[type])); 3199566063dSJacob Faibussowitsch PetscCall(PetscDeviceConfigure(defaultDevices[type])); 320a4af0ceeSJacob Faibussowitsch initializedDevice[type] = true; 321a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 322a4af0ceeSJacob Faibussowitsch } 323a4af0ceeSJacob Faibussowitsch 324ce244043SStefano Zampini #if PetscDefined(USE_LOG) 325ce244043SStefano Zampini PETSC_INTERN PetscErrorCode PetscLogInitialize(void); 326ce244043SStefano Zampini #else 327ce244043SStefano Zampini #define PetscLogInitialize() 0 328ce244043SStefano Zampini #endif 329ce244043SStefano Zampini 3309371c9d4SSatish Balay static PetscErrorCode PetscDeviceInitializeTypeFromOptions_Private(MPI_Comm comm, PetscDeviceType type, PetscInt defaultDeviceId, PetscBool defaultView, PetscDeviceInitType *defaultInitType) { 331a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 332a4af0ceeSJacob Faibussowitsch if (!PetscDeviceConfiguredFor_Internal(type)) { 3339566063dSJacob Faibussowitsch PetscCall(PetscInfo(PETSC_NULLPTR, "PetscDeviceType %s not supported\n", PetscDeviceTypes[type])); 334a4af0ceeSJacob Faibussowitsch defaultDevices[type] = PETSC_NULLPTR; 335a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 336a4af0ceeSJacob Faibussowitsch } 3379566063dSJacob Faibussowitsch PetscCall(PetscInfo(PETSC_NULLPTR, "PetscDeviceType %s supported, initializing\n", PetscDeviceTypes[type])); 338a4af0ceeSJacob Faibussowitsch /* ugly switch needed to pick the right global variable... could maybe do this as a union? */ 339a4af0ceeSJacob Faibussowitsch switch (type) { 340a4af0ceeSJacob Faibussowitsch PETSC_DEVICE_CASE_IF_PETSC_DEFINED(CUDA, initialize, comm, &defaultDeviceId, defaultInitType); 341a4af0ceeSJacob Faibussowitsch PETSC_DEVICE_CASE_IF_PETSC_DEFINED(HIP, initialize, comm, &defaultDeviceId, defaultInitType); 342a2158755SJunchao Zhang PETSC_DEVICE_CASE_IF_PETSC_DEFINED(SYCL, initialize, comm, &defaultDeviceId, defaultInitType); 3439371c9d4SSatish Balay default: SETERRQ(comm, PETSC_ERR_PLIB, "PETSc was seemingly configured for PetscDeviceType %s but we've fallen through all cases in a switch", PetscDeviceTypes[type]); 344a4af0ceeSJacob Faibussowitsch } 345cf3a2253SJacob Faibussowitsch /* 346cf3a2253SJacob Faibussowitsch defaultInitType and defaultDeviceId now represent what the individual TYPES have decided to 347cf3a2253SJacob Faibussowitsch initialize as 348cf3a2253SJacob Faibussowitsch */ 349a4af0ceeSJacob Faibussowitsch if (*defaultInitType == PETSC_DEVICE_INIT_EAGER) { 3507a101e5eSJacob Faibussowitsch PetscCall(PetscLogInitialize()); 3519566063dSJacob Faibussowitsch PetscCall(PetscInfo(PETSC_NULLPTR, "Eagerly initializing %s PetscDevice\n", PetscDeviceTypes[type])); 3529566063dSJacob Faibussowitsch PetscCall(PetscDeviceInitializeDefaultDevice_Internal(type, defaultDeviceId)); 353a4af0ceeSJacob Faibussowitsch if (defaultView) { 354a4af0ceeSJacob Faibussowitsch PetscViewer vwr; 355a4af0ceeSJacob Faibussowitsch 3569566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIGetStdout(comm, &vwr)); 3579566063dSJacob Faibussowitsch PetscCall(PetscDeviceView(defaultDevices[type], vwr)); 358a4af0ceeSJacob Faibussowitsch } 359030f984aSJacob Faibussowitsch } 360030f984aSJacob Faibussowitsch PetscFunctionReturn(0); 361030f984aSJacob Faibussowitsch } 362030f984aSJacob Faibussowitsch 363030f984aSJacob Faibussowitsch /* called from PetscFinalize() do not call yourself! */ 3649371c9d4SSatish Balay static PetscErrorCode PetscDeviceFinalize_Private(void) { 365030f984aSJacob Faibussowitsch PetscFunctionBegin; 366a4af0ceeSJacob Faibussowitsch if (PetscDefined(USE_DEBUG)) { 367bf025ffbSJacob Faibussowitsch const auto PetscDeviceCheckAllDestroyedAfterFinalize = [] { 368a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 3699371c9d4SSatish Balay for (auto &&device : defaultDevices) 3709371c9d4SSatish Balay PetscCheck(!device, PETSC_COMM_WORLD, PETSC_ERR_COR, "Device of type '%s' had reference count %" PetscInt_FMT " and was not fully destroyed during PetscFinalize()", PetscDeviceTypes[device->type], device->refcnt); 371a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 372a4af0ceeSJacob Faibussowitsch }; 373bf025ffbSJacob Faibussowitsch /* 374bf025ffbSJacob Faibussowitsch you might be thinking, why on earth are you registered yet another finalizer in a 375bf025ffbSJacob Faibussowitsch function already called during PetscRegisterFinalizeAll()? If this seems stupid it's 376bf025ffbSJacob Faibussowitsch because it is. 377bf025ffbSJacob Faibussowitsch 378bf025ffbSJacob Faibussowitsch The crux of the problem is that the initializer (and therefore the ~finalizer~) of 379bf025ffbSJacob Faibussowitsch PetscDeviceContext is guaranteed to run after PetscDevice's. So if the global context had 380bf025ffbSJacob Faibussowitsch a default PetscDevice attached, that PetscDevice will have a reference count >0 and hence 381bf025ffbSJacob Faibussowitsch won't be destroyed yet. So we need to repeat the check that all devices have been 382bf025ffbSJacob Faibussowitsch destroyed again ~after~ the global context is destroyed. In summary: 383bf025ffbSJacob Faibussowitsch 384bf025ffbSJacob Faibussowitsch 1. This finalizer runs and destroys all devices, except it may not because the global 385bf025ffbSJacob Faibussowitsch context may still hold a reference! 386bf025ffbSJacob Faibussowitsch 2. The global context finalizer runs and does the final reference count decrement 387bf025ffbSJacob Faibussowitsch required, which actually destroys the held device. 388bf025ffbSJacob Faibussowitsch 3. Our newly added finalizer runs and checks that all is well. 389a4af0ceeSJacob Faibussowitsch */ 3909566063dSJacob Faibussowitsch PetscCall(PetscRegisterFinalize(PetscDeviceCheckAllDestroyedAfterFinalize)); 391a4af0ceeSJacob Faibussowitsch } 3929566063dSJacob Faibussowitsch for (auto &&device : defaultDevices) PetscCall(PetscDeviceDestroy(&device)); 3939566063dSJacob Faibussowitsch PetscCallCXX(initializedDevice.fill(false)); 394030f984aSJacob Faibussowitsch PetscFunctionReturn(0); 395030f984aSJacob Faibussowitsch } 396030f984aSJacob Faibussowitsch 397cf3a2253SJacob Faibussowitsch /* 398cf3a2253SJacob Faibussowitsch Begins the init proceeedings for the entire PetscDevice stack. there are 3 stages of 399cf3a2253SJacob Faibussowitsch initialization types: 400cf3a2253SJacob Faibussowitsch 401a4af0ceeSJacob Faibussowitsch 1. defaultInitType - how does PetscDevice as a whole expect to initialize? 402a4af0ceeSJacob Faibussowitsch 2. subTypeDefaultInitType - how does each PetscDevice implementation expect to initialize? 403a4af0ceeSJacob Faibussowitsch e.g. you may want to blanket disable PetscDevice init (and disable say Kokkos init), but 404a4af0ceeSJacob Faibussowitsch have all CUDA devices still initialize. 405a4af0ceeSJacob Faibussowitsch 406a4af0ceeSJacob Faibussowitsch All told the following happens: 407cf3a2253SJacob Faibussowitsch 408a4af0ceeSJacob Faibussowitsch 0. defaultInitType -> LAZY 409a4af0ceeSJacob Faibussowitsch 1. Check for log_view/log_summary, if yes defaultInitType -> EAGER 410a4af0ceeSJacob Faibussowitsch 2. PetscDevice initializes each sub type with deviceDefaultInitType. 411a4af0ceeSJacob Faibussowitsch 2.1 Each enabled PetscDevice sub-type then does the above disable or view check in addition 412a4af0ceeSJacob Faibussowitsch to checking for specific device init. if view or specific device init 413a4af0ceeSJacob Faibussowitsch subTypeDefaultInitType -> EAGER. disabled once again overrides all. 414a4af0ceeSJacob Faibussowitsch */ 4159371c9d4SSatish Balay PetscErrorCode PetscDeviceInitializeFromOptions_Internal(MPI_Comm comm) { 4167a101e5eSJacob Faibussowitsch auto defaultView = PETSC_FALSE; 4177a101e5eSJacob Faibussowitsch auto initializeDeviceContextEagerly = PETSC_FALSE; 4187a101e5eSJacob Faibussowitsch auto defaultDevice = PetscInt{PETSC_DECIDE}; 4197a101e5eSJacob Faibussowitsch auto deviceContextInitDevice = PETSC_DEVICE_DEFAULT; 420a4af0ceeSJacob Faibussowitsch PetscDeviceInitType defaultInitType; 421a4af0ceeSJacob Faibussowitsch 422a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 423a4af0ceeSJacob Faibussowitsch if (PetscDefined(USE_DEBUG)) { 424a4af0ceeSJacob Faibussowitsch int result; 425a4af0ceeSJacob Faibussowitsch 4269566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_compare(comm, PETSC_COMM_WORLD, &result)); 427a4af0ceeSJacob Faibussowitsch /* in order to accurately assign ranks to gpus we need to get the MPI_Comm_rank of the 428a4af0ceeSJacob Faibussowitsch * global space */ 429a4af0ceeSJacob Faibussowitsch if (PetscUnlikely(result != MPI_IDENT)) { 430a4af0ceeSJacob Faibussowitsch char name[MPI_MAX_OBJECT_NAME] = {}; 431a4af0ceeSJacob Faibussowitsch int len; /* unused */ 432a4af0ceeSJacob Faibussowitsch 4339566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_get_name(comm, name, &len)); 43498921bdaSJacob Faibussowitsch SETERRQ(comm, PETSC_ERR_MPI, "Default devices being initialized on MPI_Comm '%s' not PETSC_COMM_WORLD", name); 435a4af0ceeSJacob Faibussowitsch } 436a4af0ceeSJacob Faibussowitsch } 437a4af0ceeSJacob Faibussowitsch comm = PETSC_COMM_WORLD; /* from this point on we assume we're on PETSC_COMM_WORLD */ 4389566063dSJacob Faibussowitsch PetscCall(PetscRegisterFinalize(PetscDeviceFinalize_Private)); 439a4af0ceeSJacob Faibussowitsch 4407a101e5eSJacob Faibussowitsch { 4417a101e5eSJacob Faibussowitsch PetscInt initIdx = PETSC_DEVICE_INIT_LAZY; 4427a101e5eSJacob Faibussowitsch PetscBool flg; 4437a101e5eSJacob Faibussowitsch 4447a101e5eSJacob Faibussowitsch PetscCall(PetscOptionsHasName(PETSC_NULLPTR, PETSC_NULLPTR, "-log_view_gpu_time", &flg)); 4457a101e5eSJacob Faibussowitsch if (flg) PetscCall(PetscLogGpuTime()); 4467a101e5eSJacob Faibussowitsch 4477a101e5eSJacob Faibussowitsch /* ----------------------------------------------------------------------------------- */ 4487a101e5eSJacob Faibussowitsch /* Global PetscDevice Options */ 4497a101e5eSJacob Faibussowitsch /* ----------------------------------------------------------------------------------- */ 450d0609cedSBarry Smith PetscOptionsBegin(comm, PETSC_NULLPTR, "PetscDevice Options", "Sys"); 4519566063dSJacob Faibussowitsch PetscCall(PetscOptionsEList("-device_enable", "How (or whether) to initialize PetscDevices", "PetscDeviceInitializeFromOptions_Internal()", PetscDeviceInitTypes, 3, PetscDeviceInitTypes[initIdx], &initIdx, PETSC_NULLPTR)); 4529566063dSJacob Faibussowitsch PetscCall(PetscOptionsRangeInt("-device_select", "Which device to use. Pass " PetscStringize(PETSC_DECIDE) " to have PETSc decide or (given they exist) [0-NUM_DEVICE) for a specific device", "PetscDeviceCreate()", defaultDevice, &defaultDevice, PETSC_NULLPTR, PETSC_DECIDE, std::numeric_limits<int>::max())); 4539566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-device_view", "Display device information and assignments (forces eager initialization)", PETSC_NULLPTR, defaultView, &defaultView, &flg)); 454d0609cedSBarry Smith PetscOptionsEnd(); 4557a101e5eSJacob Faibussowitsch 456a4af0ceeSJacob Faibussowitsch if (initIdx == PETSC_DEVICE_INIT_NONE) { 457a4af0ceeSJacob Faibussowitsch /* disabled all device initialization if devices are globally disabled */ 458bf025ffbSJacob Faibussowitsch 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 exlusive"); 459a4af0ceeSJacob Faibussowitsch defaultView = PETSC_FALSE; 460a4af0ceeSJacob Faibussowitsch } else { 461a4af0ceeSJacob Faibussowitsch defaultView = static_cast<decltype(defaultView)>(defaultView && flg); 462a4af0ceeSJacob Faibussowitsch if (defaultView) initIdx = PETSC_DEVICE_INIT_EAGER; 463a4af0ceeSJacob Faibussowitsch } 464a4af0ceeSJacob Faibussowitsch defaultInitType = static_cast<decltype(defaultInitType)>(initIdx); 465a4af0ceeSJacob Faibussowitsch } 466a4af0ceeSJacob Faibussowitsch static_assert((PETSC_DEVICE_INVALID == 0) && (PETSC_DEVICE_MAX < std::numeric_limits<int>::max()), ""); 467a4af0ceeSJacob Faibussowitsch for (int i = 1; i < PETSC_DEVICE_MAX; ++i) { 468a4af0ceeSJacob Faibussowitsch const auto deviceType = static_cast<PetscDeviceType>(i); 469a4af0ceeSJacob Faibussowitsch auto initType = defaultInitType; 470a4af0ceeSJacob Faibussowitsch 4719566063dSJacob Faibussowitsch PetscCall(PetscDeviceInitializeTypeFromOptions_Private(comm, deviceType, defaultDevice, defaultView, &initType)); 472a4af0ceeSJacob Faibussowitsch if (PetscDeviceConfiguredFor_Internal(deviceType) && (initType == PETSC_DEVICE_INIT_EAGER)) { 473a4af0ceeSJacob Faibussowitsch initializeDeviceContextEagerly = PETSC_TRUE; 474a4af0ceeSJacob Faibussowitsch deviceContextInitDevice = deviceType; 4757a101e5eSJacob Faibussowitsch PetscCall(PetscInfo(PETSC_NULLPTR, "PetscDevice %s set as default device type due to eager initialization\n", PetscDeviceTypes[deviceType])); 476a4af0ceeSJacob Faibussowitsch } 477a4af0ceeSJacob Faibussowitsch } 478a4af0ceeSJacob Faibussowitsch if (initializeDeviceContextEagerly) { 479a4af0ceeSJacob Faibussowitsch PetscDeviceContext dctx; 480a4af0ceeSJacob Faibussowitsch 481cf3a2253SJacob Faibussowitsch /* 482cf3a2253SJacob Faibussowitsch somewhat inefficient here as the device context is potentially fully set up twice (once 483cf3a2253SJacob Faibussowitsch when retrieved then the second time if setfromoptions makes changes) 484cf3a2253SJacob Faibussowitsch */ 4859566063dSJacob Faibussowitsch PetscCall(PetscInfo(PETSC_NULLPTR, "Eagerly initializing PetscDeviceContext with %s device\n", PetscDeviceTypes[deviceContextInitDevice])); 4869566063dSJacob Faibussowitsch PetscCall(PetscDeviceContextSetRootDeviceType_Internal(deviceContextInitDevice)); 4879566063dSJacob Faibussowitsch PetscCall(PetscDeviceContextGetCurrentContext(&dctx)); 4889566063dSJacob Faibussowitsch PetscCall(PetscDeviceContextSetFromOptions(comm, "root_", dctx)); 4899566063dSJacob Faibussowitsch PetscCall(PetscDeviceContextSetUp(dctx)); 490a4af0ceeSJacob Faibussowitsch } 491a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 492a4af0ceeSJacob Faibussowitsch } 493a4af0ceeSJacob Faibussowitsch 494a4af0ceeSJacob Faibussowitsch /* Get the default PetscDevice for a particular type and constructs them if lazily initialized. */ 4959371c9d4SSatish Balay PetscErrorCode PetscDeviceGetDefaultForType_Internal(PetscDeviceType type, PetscDevice *device) { 496a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 497a4af0ceeSJacob Faibussowitsch PetscValidPointer(device, 2); 4989566063dSJacob Faibussowitsch PetscCall(PetscDeviceInitialize(type)); 499a4af0ceeSJacob Faibussowitsch *device = defaultDevices[type]; 500a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 501030f984aSJacob Faibussowitsch } 502