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,""); 26a4af0ceeSJacob Faibussowitsch const char *const PetscDeviceTypes[] = { 27a4af0ceeSJacob Faibussowitsch "invalid", 28a4af0ceeSJacob Faibussowitsch "cuda", 29a4af0ceeSJacob Faibussowitsch "hip", 30a2158755SJunchao Zhang "sycl", 31a4af0ceeSJacob Faibussowitsch "max", 32a4af0ceeSJacob Faibussowitsch "PetscDeviceType", 33a4af0ceeSJacob Faibussowitsch "PETSC_DEVICE_", 34a4af0ceeSJacob Faibussowitsch PETSC_NULLPTR 35a4af0ceeSJacob Faibussowitsch }; 36a4af0ceeSJacob Faibussowitsch 3717f48955SJacob Faibussowitsch static_assert(Petsc::util::integral_value(PETSC_DEVICE_INIT_NONE) == 0,""); 3817f48955SJacob Faibussowitsch static_assert(Petsc::util::integral_value(PETSC_DEVICE_INIT_LAZY) == 1,""); 3917f48955SJacob Faibussowitsch static_assert(Petsc::util::integral_value(PETSC_DEVICE_INIT_EAGER) == 2,""); 40a4af0ceeSJacob Faibussowitsch const char *const PetscDeviceInitTypes[] = { 41a4af0ceeSJacob Faibussowitsch "none", 42a4af0ceeSJacob Faibussowitsch "lazy", 43a4af0ceeSJacob Faibussowitsch "eager", 44a4af0ceeSJacob Faibussowitsch "PetscDeviceInitType", 45a4af0ceeSJacob Faibussowitsch "PETSC_DEVICE_INIT_", 46a4af0ceeSJacob Faibussowitsch PETSC_NULLPTR 47a4af0ceeSJacob Faibussowitsch }; 48a4af0ceeSJacob Faibussowitsch static_assert( 49a4af0ceeSJacob Faibussowitsch sizeof(PetscDeviceInitTypes)/sizeof(*PetscDeviceInitTypes) == 6, 50a4af0ceeSJacob Faibussowitsch "Must change CUPMDevice<T>::initialize number of enum values in -device_enable_cupm to match!" 51a4af0ceeSJacob Faibussowitsch ); 52a4af0ceeSJacob Faibussowitsch 5317f48955SJacob Faibussowitsch #define PETSC_DEVICE_CASE(IMPLS,func,...) \ 5417f48955SJacob Faibussowitsch case PetscConcat_(PETSC_DEVICE_,IMPLS): { \ 559566063dSJacob Faibussowitsch PetscCall(PetscConcat_(IMPLS,Device).func(__VA_ARGS__)); \ 5617f48955SJacob Faibussowitsch } break 57a4af0ceeSJacob Faibussowitsch 58cf3a2253SJacob Faibussowitsch /* 59cf3a2253SJacob Faibussowitsch Suppose you have: 60cf3a2253SJacob Faibussowitsch 61cf3a2253SJacob Faibussowitsch CUDADevice.myFunction(arg1,arg2) 62cf3a2253SJacob Faibussowitsch 63cf3a2253SJacob Faibussowitsch that you would like to conditionally define and call in a switch-case: 64cf3a2253SJacob Faibussowitsch 65cf3a2253SJacob Faibussowitsch switch(PetscDeviceType) { 66cf3a2253SJacob Faibussowitsch #if PetscDefined(HAVE_CUDA) 67cf3a2253SJacob Faibussowitsch case PETSC_DEVICE_CUDA: { 689566063dSJacob Faibussowitsch PetscCall(CUDADevice.myFunction(arg1,arg2)); 69cf3a2253SJacob Faibussowitsch } break; 70cf3a2253SJacob Faibussowitsch #endif 71cf3a2253SJacob Faibussowitsch } 72cf3a2253SJacob Faibussowitsch 73cf3a2253SJacob Faibussowitsch then calling this macro: 74cf3a2253SJacob Faibussowitsch 75cf3a2253SJacob Faibussowitsch PETSC_DEVICE_CASE_IF_PETSC_DEFINED(CUDA,myFunction,arg1,arg2) 76cf3a2253SJacob Faibussowitsch 77cf3a2253SJacob Faibussowitsch will expand to the following case statement: 78cf3a2253SJacob Faibussowitsch 79cf3a2253SJacob Faibussowitsch case PETSC_DEVICE_CUDA: { 809566063dSJacob Faibussowitsch PetscCall(CUDADevice.myFunction(arg1,arg2)); 81cf3a2253SJacob Faibussowitsch } break 82cf3a2253SJacob Faibussowitsch 83cf3a2253SJacob Faibussowitsch if PetscDefined(HAVE_CUDA) evaluates to 1, and expand to nothing otherwise 8417f48955SJacob Faibussowitsch */ 8517f48955SJacob Faibussowitsch #define PETSC_DEVICE_CASE_IF_PETSC_DEFINED(IMPLS,func,...) \ 8617f48955SJacob Faibussowitsch PetscIfPetscDefined(PetscConcat_(HAVE_,IMPLS),PETSC_DEVICE_CASE,PetscExpandToNothing)(IMPLS,func,__VA_ARGS__) 87030f984aSJacob Faibussowitsch 88030f984aSJacob Faibussowitsch /*@C 89a4af0ceeSJacob Faibussowitsch PetscDeviceCreate - Get a new handle for a particular device type 90030f984aSJacob Faibussowitsch 91030f984aSJacob Faibussowitsch Not Collective, Possibly Synchronous 92030f984aSJacob Faibussowitsch 93f1a722f8SMatthew G. Knepley Input Parameters: 94f1a722f8SMatthew G. Knepley + type - The type of PetscDevice 95f1a722f8SMatthew G. Knepley - devid - The numeric ID# of the device (pass PETSC_DECIDE to assign automatically) 96030f984aSJacob Faibussowitsch 97030f984aSJacob Faibussowitsch Output Parameter: 98030f984aSJacob Faibussowitsch . device - The PetscDevice 99030f984aSJacob Faibussowitsch 100030f984aSJacob Faibussowitsch Notes: 101a4af0ceeSJacob Faibussowitsch This routine may initialize PetscDevice. If this is the case, this will most likely cause 102a4af0ceeSJacob Faibussowitsch some sort of device synchronization. 103a4af0ceeSJacob Faibussowitsch 104a4af0ceeSJacob Faibussowitsch devid is what you might pass to cudaSetDevice() for example. 105030f984aSJacob Faibussowitsch 106030f984aSJacob Faibussowitsch Level: beginner 107030f984aSJacob Faibussowitsch 108db781477SPatrick Sanan .seealso: `PetscDevice`, `PetscDeviceInitType`, `PetscDeviceInitialize()`, 109db781477SPatrick Sanan `PetscDeviceInitialized()`, `PetscDeviceConfigure()`, `PetscDeviceView()`, `PetscDeviceDestroy()` 110030f984aSJacob Faibussowitsch @*/ 111a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceCreate(PetscDeviceType type, PetscInt devid, PetscDevice *device) 112030f984aSJacob Faibussowitsch { 113030f984aSJacob Faibussowitsch static PetscInt PetscDeviceCounter = 0; 114030f984aSJacob Faibussowitsch PetscDevice dev; 115030f984aSJacob Faibussowitsch 116030f984aSJacob Faibussowitsch PetscFunctionBegin; 117a4af0ceeSJacob Faibussowitsch PetscValidDeviceType(type,1); 118a4af0ceeSJacob Faibussowitsch PetscValidPointer(device,3); 1199566063dSJacob Faibussowitsch PetscCall(PetscDeviceInitializePackage()); 1209566063dSJacob Faibussowitsch PetscCall(PetscNew(&dev)); 121030f984aSJacob Faibussowitsch dev->id = PetscDeviceCounter++; 122a4af0ceeSJacob Faibussowitsch dev->type = type; 123a4af0ceeSJacob Faibussowitsch dev->refcnt = 1; 124cf3a2253SJacob Faibussowitsch /* 125cf3a2253SJacob Faibussowitsch if you are adding a device, you also need to add it's initialization in 126cf3a2253SJacob Faibussowitsch PetscDeviceInitializeTypeFromOptions_Private() below 127cf3a2253SJacob Faibussowitsch */ 128a4af0ceeSJacob Faibussowitsch switch (type) { 129a4af0ceeSJacob Faibussowitsch PETSC_DEVICE_CASE_IF_PETSC_DEFINED(CUDA,getDevice,dev,devid); 130a4af0ceeSJacob Faibussowitsch PETSC_DEVICE_CASE_IF_PETSC_DEFINED(HIP,getDevice,dev,devid); 131a2158755SJunchao Zhang PETSC_DEVICE_CASE_IF_PETSC_DEFINED(SYCL,getDevice,dev,devid); 132030f984aSJacob Faibussowitsch default: 13317f48955SJacob Faibussowitsch /* in case the above macros expand to nothing this silences any unused variable warnings */ 13417f48955SJacob Faibussowitsch (void)(devid); 13598921bdaSJacob 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]); 136030f984aSJacob Faibussowitsch } 137030f984aSJacob Faibussowitsch *device = dev; 138030f984aSJacob Faibussowitsch PetscFunctionReturn(0); 139030f984aSJacob Faibussowitsch } 140030f984aSJacob Faibussowitsch 141030f984aSJacob Faibussowitsch /*@C 142030f984aSJacob Faibussowitsch PetscDeviceDestroy - Free a PetscDevice 143030f984aSJacob Faibussowitsch 144030f984aSJacob Faibussowitsch Not Collective, Asynchronous 145030f984aSJacob Faibussowitsch 146030f984aSJacob Faibussowitsch Input Parameter: 147030f984aSJacob Faibussowitsch . device - The PetscDevice 148030f984aSJacob Faibussowitsch 149030f984aSJacob Faibussowitsch Level: beginner 150030f984aSJacob Faibussowitsch 151db781477SPatrick Sanan .seealso: `PetscDevice`, `PetscDeviceCreate()`, `PetscDeviceConfigure()`, `PetscDeviceView()` 152030f984aSJacob Faibussowitsch @*/ 153030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceDestroy(PetscDevice *device) 154030f984aSJacob Faibussowitsch { 155a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 156a4af0ceeSJacob Faibussowitsch if (!*device) PetscFunctionReturn(0); 157a4af0ceeSJacob Faibussowitsch PetscValidDevice(*device,1); 1589566063dSJacob Faibussowitsch PetscCall(PetscDeviceDereference_Internal(*device)); 159a4af0ceeSJacob Faibussowitsch if ((*device)->refcnt) { 160a4af0ceeSJacob Faibussowitsch *device = PETSC_NULLPTR; 161a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 162030f984aSJacob Faibussowitsch } 1639566063dSJacob Faibussowitsch PetscCall(PetscFree((*device)->data)); 1649566063dSJacob Faibussowitsch PetscCall(PetscFree(*device)); 165030f984aSJacob Faibussowitsch PetscFunctionReturn(0); 166030f984aSJacob Faibussowitsch } 167030f984aSJacob Faibussowitsch 168a4af0ceeSJacob Faibussowitsch /*@C 169a4af0ceeSJacob Faibussowitsch PetscDeviceConfigure - Configure a particular PetscDevice 170030f984aSJacob Faibussowitsch 171a4af0ceeSJacob Faibussowitsch Not Collective, Asynchronous 172a4af0ceeSJacob Faibussowitsch 173a4af0ceeSJacob Faibussowitsch Input Parameter: 174a4af0ceeSJacob Faibussowitsch . device - The PetscDevice to configure 175a4af0ceeSJacob Faibussowitsch 176a4af0ceeSJacob Faibussowitsch Notes: 177a4af0ceeSJacob Faibussowitsch The user should not assume that this is a cheap operation 178a4af0ceeSJacob Faibussowitsch 179a4af0ceeSJacob Faibussowitsch Level: beginner 180a4af0ceeSJacob Faibussowitsch 181db781477SPatrick Sanan .seealso: `PetscDevice`, `PetscDeviceCreate()`, `PetscDeviceView()`, `PetscDeviceDestroy()` 182a4af0ceeSJacob Faibussowitsch @*/ 183a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceConfigure(PetscDevice device) 184030f984aSJacob Faibussowitsch { 185030f984aSJacob Faibussowitsch PetscFunctionBegin; 186a4af0ceeSJacob Faibussowitsch PetscValidDevice(device,1); 187a4af0ceeSJacob Faibussowitsch if (PetscDefined(USE_DEBUG)) { 188cf3a2253SJacob Faibussowitsch /* 189cf3a2253SJacob Faibussowitsch if no available configuration is available, this cascades all the way down to default 190cf3a2253SJacob Faibussowitsch and error 191cf3a2253SJacob Faibussowitsch */ 192a4af0ceeSJacob Faibussowitsch switch (device->type) { 193a4af0ceeSJacob Faibussowitsch case PETSC_DEVICE_CUDA: if (PetscDefined(HAVE_CUDA)) break; 194a4af0ceeSJacob Faibussowitsch case PETSC_DEVICE_HIP: if (PetscDefined(HAVE_HIP)) break; 195a2158755SJunchao Zhang case PETSC_DEVICE_SYCL: if (PetscDefined(HAVE_SYCL)) break; 196a4af0ceeSJacob Faibussowitsch default: 19798921bdaSJacob 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[device->type]); 198a4af0ceeSJacob Faibussowitsch } 199a4af0ceeSJacob Faibussowitsch } 200*dbbe0bcdSBarry Smith PetscUseTypeMethod(device,configure); 201a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 202a4af0ceeSJacob Faibussowitsch } 203a4af0ceeSJacob Faibussowitsch 204a4af0ceeSJacob Faibussowitsch /*@C 205a4af0ceeSJacob Faibussowitsch PetscDeviceView - View a PetscDevice 206a4af0ceeSJacob Faibussowitsch 207a4af0ceeSJacob Faibussowitsch Collective on viewer, Asynchronous 208a4af0ceeSJacob Faibussowitsch 20991e63d38SStefano Zampini Input Parameters: 210050c0c3dSJacob Faibussowitsch + device - The PetscDevice to view 211a4af0ceeSJacob Faibussowitsch - viewer - The PetscViewer to view the device with (NULL for PETSC_VIEWER_STDOUT_WORLD) 212a4af0ceeSJacob Faibussowitsch 213a4af0ceeSJacob Faibussowitsch Level: beginner 214a4af0ceeSJacob Faibussowitsch 215db781477SPatrick Sanan .seealso: `PetscDevice`, `PetscDeviceCreate()`, `PetscDeviceConfigure()`, `PetscDeviceDestroy()` 216a4af0ceeSJacob Faibussowitsch @*/ 217a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceView(PetscDevice device, PetscViewer viewer) 218a4af0ceeSJacob Faibussowitsch { 219a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 220a4af0ceeSJacob Faibussowitsch PetscValidDevice(device,1); 2219566063dSJacob Faibussowitsch if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PETSC_COMM_WORLD,&viewer)); 222a4af0ceeSJacob Faibussowitsch PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2); 223*dbbe0bcdSBarry Smith PetscUseTypeMethod(device,view ,viewer); 224a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 225a4af0ceeSJacob Faibussowitsch } 226a4af0ceeSJacob Faibussowitsch 22791e63d38SStefano Zampini /*@C 22891e63d38SStefano Zampini PetscDeviceGetDeviceId - Get the device id 22991e63d38SStefano Zampini 23091e63d38SStefano Zampini Not collective 23191e63d38SStefano Zampini 23291e63d38SStefano Zampini Input Parameter: 23391e63d38SStefano Zampini . device - The PetscDevice 23491e63d38SStefano Zampini 23591e63d38SStefano Zampini Output Parameter: 23691e63d38SStefano Zampini . id - The device id 23791e63d38SStefano Zampini 23891e63d38SStefano Zampini Level: beginner 23991e63d38SStefano Zampini 240db781477SPatrick Sanan .seealso: `PetscDevice`, `PetscDeviceCreate()`, `PetscDeviceConfigure()`, `PetscDeviceDestroy()` 24191e63d38SStefano Zampini @*/ 24291e63d38SStefano Zampini PetscErrorCode PetscDeviceGetDeviceId(PetscDevice device, PetscInt *id) 24391e63d38SStefano Zampini { 24491e63d38SStefano Zampini PetscFunctionBegin; 24591e63d38SStefano Zampini PetscValidDevice(device,1); 24691e63d38SStefano Zampini PetscValidIntPointer(id,2); 24791e63d38SStefano Zampini *id = device->deviceId; 24891e63d38SStefano Zampini PetscFunctionReturn(0); 24991e63d38SStefano Zampini } 25091e63d38SStefano Zampini 251a4af0ceeSJacob Faibussowitsch static std::array<bool,PETSC_DEVICE_MAX> initializedDevice = {}; 252a4af0ceeSJacob Faibussowitsch static std::array<PetscDevice,PETSC_DEVICE_MAX> defaultDevices = {}; 253a4af0ceeSJacob Faibussowitsch static_assert(initializedDevice.size() == defaultDevices.size(),""); 254a4af0ceeSJacob Faibussowitsch 255a4af0ceeSJacob Faibussowitsch /*@C 256a4af0ceeSJacob Faibussowitsch PetscDeviceInitialize - Initialize PetscDevice 257a4af0ceeSJacob Faibussowitsch 258a4af0ceeSJacob Faibussowitsch Not Collective, Possibly Synchronous 259a4af0ceeSJacob Faibussowitsch 260a4af0ceeSJacob Faibussowitsch Input Parameter: 261a4af0ceeSJacob Faibussowitsch . type - The PetscDeviceType to initialize 262a4af0ceeSJacob Faibussowitsch 263a4af0ceeSJacob Faibussowitsch Notes: 264a4af0ceeSJacob Faibussowitsch Eagerly initializes the corresponding PetscDeviceType if needed. 265a4af0ceeSJacob Faibussowitsch 266a4af0ceeSJacob Faibussowitsch Level: beginner 267a4af0ceeSJacob Faibussowitsch 268db781477SPatrick Sanan .seealso: `PetscDevice`, `PetscDeviceInitType`, `PetscDeviceInitialized()`, `PetscDeviceCreate()`, `PetscDeviceDestroy()` 269a4af0ceeSJacob Faibussowitsch @*/ 270a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceInitialize(PetscDeviceType type) 271a4af0ceeSJacob Faibussowitsch { 272a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 273a4af0ceeSJacob Faibussowitsch PetscValidDeviceType(type,1); 2749566063dSJacob Faibussowitsch PetscCall(PetscDeviceInitializeDefaultDevice_Internal(type,PETSC_DECIDE)); 275a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 276a4af0ceeSJacob Faibussowitsch } 277a4af0ceeSJacob Faibussowitsch 278a4af0ceeSJacob Faibussowitsch /*@C 279a4af0ceeSJacob Faibussowitsch PetscDeviceInitialized - Determines whether PetscDevice is initialized for a particular 280a4af0ceeSJacob Faibussowitsch PetscDeviceType 281a4af0ceeSJacob Faibussowitsch 282a4af0ceeSJacob Faibussowitsch Not Collective, Asynchronous 283a4af0ceeSJacob Faibussowitsch 284a4af0ceeSJacob Faibussowitsch Input Parameter: 285a4af0ceeSJacob Faibussowitsch . type - The PetscDeviceType to check 286a4af0ceeSJacob Faibussowitsch 287a4af0ceeSJacob Faibussowitsch Output Parameter: 288a4af0ceeSJacob Faibussowitsch . [return value] - PETSC_TRUE if type is initialized, PETSC_FALSE otherwise 289a4af0ceeSJacob Faibussowitsch 290a4af0ceeSJacob Faibussowitsch Notes: 291a4af0ceeSJacob Faibussowitsch If one has not configured PETSc for a particular PetscDeviceType then this routine will 292a4af0ceeSJacob Faibussowitsch return PETSC_FALSE for that PetscDeviceType. 293a4af0ceeSJacob Faibussowitsch 294a4af0ceeSJacob Faibussowitsch Level: beginner 295a4af0ceeSJacob Faibussowitsch 296db781477SPatrick Sanan .seealso: `PetscDevice`, `PetscDeviceInitType`, `PetscDeviceInitialize()`, `PetscDeviceCreate()`, `PetscDeviceDestroy()` 297a4af0ceeSJacob Faibussowitsch @*/ 298a4af0ceeSJacob Faibussowitsch PetscBool PetscDeviceInitialized(PetscDeviceType type) 299a4af0ceeSJacob Faibussowitsch { 300a4af0ceeSJacob Faibussowitsch return static_cast<PetscBool>(PetscDeviceConfiguredFor_Internal(type) && initializedDevice[type]); 301a4af0ceeSJacob Faibussowitsch } 302a4af0ceeSJacob Faibussowitsch 303cf3a2253SJacob Faibussowitsch /* 304cf3a2253SJacob Faibussowitsch Actual intialization function; any functions claiming to initialize PetscDevice or 305cf3a2253SJacob Faibussowitsch PetscDeviceContext will have to run through this one 306cf3a2253SJacob Faibussowitsch */ 307a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceInitializeDefaultDevice_Internal(PetscDeviceType type, PetscInt defaultDeviceId) 308a4af0ceeSJacob Faibussowitsch { 309a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 310a4af0ceeSJacob Faibussowitsch PetscValidDeviceType(type,1); 311a4af0ceeSJacob Faibussowitsch if (PetscLikely(PetscDeviceInitialized(type))) PetscFunctionReturn(0); 312bf025ffbSJacob Faibussowitsch PetscAssert(!defaultDevices[type],PETSC_COMM_SELF,PETSC_ERR_MEM,"Trying to overwrite existing default device of type %s",PetscDeviceTypes[type]); 3139566063dSJacob Faibussowitsch PetscCall(PetscDeviceCreate(type,defaultDeviceId,&defaultDevices[type])); 3149566063dSJacob Faibussowitsch PetscCall(PetscDeviceConfigure(defaultDevices[type])); 315a4af0ceeSJacob Faibussowitsch initializedDevice[type] = true; 316a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 317a4af0ceeSJacob Faibussowitsch } 318a4af0ceeSJacob Faibussowitsch 319ce244043SStefano Zampini #if PetscDefined(USE_LOG) 320ce244043SStefano Zampini PETSC_INTERN PetscErrorCode PetscLogInitialize(void); 321ce244043SStefano Zampini #else 322ce244043SStefano Zampini #define PetscLogInitialize() 0 323ce244043SStefano Zampini #endif 324ce244043SStefano Zampini 325a4af0ceeSJacob Faibussowitsch static PetscErrorCode PetscDeviceInitializeTypeFromOptions_Private(MPI_Comm comm, PetscDeviceType type, PetscInt defaultDeviceId, PetscBool defaultView, PetscDeviceInitType *defaultInitType) 326a4af0ceeSJacob Faibussowitsch { 327a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 328a4af0ceeSJacob Faibussowitsch if (!PetscDeviceConfiguredFor_Internal(type)) { 3299566063dSJacob Faibussowitsch PetscCall(PetscInfo(PETSC_NULLPTR,"PetscDeviceType %s not supported\n",PetscDeviceTypes[type])); 330a4af0ceeSJacob Faibussowitsch defaultDevices[type] = PETSC_NULLPTR; 331a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 332a4af0ceeSJacob Faibussowitsch } 3339566063dSJacob Faibussowitsch PetscCall(PetscInfo(PETSC_NULLPTR,"PetscDeviceType %s supported, initializing\n",PetscDeviceTypes[type])); 334a4af0ceeSJacob Faibussowitsch /* ugly switch needed to pick the right global variable... could maybe do this as a union? */ 335a4af0ceeSJacob Faibussowitsch switch (type) { 336a4af0ceeSJacob Faibussowitsch PETSC_DEVICE_CASE_IF_PETSC_DEFINED(CUDA,initialize,comm,&defaultDeviceId,defaultInitType); 337a4af0ceeSJacob Faibussowitsch PETSC_DEVICE_CASE_IF_PETSC_DEFINED(HIP,initialize,comm,&defaultDeviceId,defaultInitType); 338a2158755SJunchao Zhang PETSC_DEVICE_CASE_IF_PETSC_DEFINED(SYCL,initialize,comm,&defaultDeviceId,defaultInitType); 339a4af0ceeSJacob Faibussowitsch default: 34098921bdaSJacob 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]); 341a4af0ceeSJacob Faibussowitsch } 342cf3a2253SJacob Faibussowitsch /* 343cf3a2253SJacob Faibussowitsch defaultInitType and defaultDeviceId now represent what the individual TYPES have decided to 344cf3a2253SJacob Faibussowitsch initialize as 345cf3a2253SJacob Faibussowitsch */ 346a4af0ceeSJacob Faibussowitsch if (*defaultInitType == PETSC_DEVICE_INIT_EAGER) { 3477a101e5eSJacob Faibussowitsch PetscCall(PetscLogInitialize()); 3489566063dSJacob Faibussowitsch PetscCall(PetscInfo(PETSC_NULLPTR,"Eagerly initializing %s PetscDevice\n",PetscDeviceTypes[type])); 3499566063dSJacob Faibussowitsch PetscCall(PetscDeviceInitializeDefaultDevice_Internal(type,defaultDeviceId)); 350a4af0ceeSJacob Faibussowitsch if (defaultView) { 351a4af0ceeSJacob Faibussowitsch PetscViewer vwr; 352a4af0ceeSJacob Faibussowitsch 3539566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIGetStdout(comm,&vwr)); 3549566063dSJacob Faibussowitsch PetscCall(PetscDeviceView(defaultDevices[type],vwr)); 355a4af0ceeSJacob Faibussowitsch } 356030f984aSJacob Faibussowitsch } 357030f984aSJacob Faibussowitsch PetscFunctionReturn(0); 358030f984aSJacob Faibussowitsch } 359030f984aSJacob Faibussowitsch 360030f984aSJacob Faibussowitsch /* called from PetscFinalize() do not call yourself! */ 361a4af0ceeSJacob Faibussowitsch static PetscErrorCode PetscDeviceFinalize_Private(void) 362030f984aSJacob Faibussowitsch { 363030f984aSJacob Faibussowitsch PetscFunctionBegin; 364a4af0ceeSJacob Faibussowitsch if (PetscDefined(USE_DEBUG)) { 365bf025ffbSJacob Faibussowitsch const auto PetscDeviceCheckAllDestroyedAfterFinalize = []{ 366a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 367bf025ffbSJacob Faibussowitsch for (auto&& device : defaultDevices) 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); 368a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 369a4af0ceeSJacob Faibussowitsch }; 370bf025ffbSJacob Faibussowitsch /* 371bf025ffbSJacob Faibussowitsch you might be thinking, why on earth are you registered yet another finalizer in a 372bf025ffbSJacob Faibussowitsch function already called during PetscRegisterFinalizeAll()? If this seems stupid it's 373bf025ffbSJacob Faibussowitsch because it is. 374bf025ffbSJacob Faibussowitsch 375bf025ffbSJacob Faibussowitsch The crux of the problem is that the initializer (and therefore the ~finalizer~) of 376bf025ffbSJacob Faibussowitsch PetscDeviceContext is guaranteed to run after PetscDevice's. So if the global context had 377bf025ffbSJacob Faibussowitsch a default PetscDevice attached, that PetscDevice will have a reference count >0 and hence 378bf025ffbSJacob Faibussowitsch won't be destroyed yet. So we need to repeat the check that all devices have been 379bf025ffbSJacob Faibussowitsch destroyed again ~after~ the global context is destroyed. In summary: 380bf025ffbSJacob Faibussowitsch 381bf025ffbSJacob Faibussowitsch 1. This finalizer runs and destroys all devices, except it may not because the global 382bf025ffbSJacob Faibussowitsch context may still hold a reference! 383bf025ffbSJacob Faibussowitsch 2. The global context finalizer runs and does the final reference count decrement 384bf025ffbSJacob Faibussowitsch required, which actually destroys the held device. 385bf025ffbSJacob Faibussowitsch 3. Our newly added finalizer runs and checks that all is well. 386a4af0ceeSJacob Faibussowitsch */ 3879566063dSJacob Faibussowitsch PetscCall(PetscRegisterFinalize(PetscDeviceCheckAllDestroyedAfterFinalize)); 388a4af0ceeSJacob Faibussowitsch } 3899566063dSJacob Faibussowitsch for (auto &&device : defaultDevices) PetscCall(PetscDeviceDestroy(&device)); 3909566063dSJacob Faibussowitsch PetscCallCXX(initializedDevice.fill(false)); 391030f984aSJacob Faibussowitsch PetscFunctionReturn(0); 392030f984aSJacob Faibussowitsch } 393030f984aSJacob Faibussowitsch 394cf3a2253SJacob Faibussowitsch /* 395cf3a2253SJacob Faibussowitsch Begins the init proceeedings for the entire PetscDevice stack. there are 3 stages of 396cf3a2253SJacob Faibussowitsch initialization types: 397cf3a2253SJacob Faibussowitsch 398a4af0ceeSJacob Faibussowitsch 1. defaultInitType - how does PetscDevice as a whole expect to initialize? 399a4af0ceeSJacob Faibussowitsch 2. subTypeDefaultInitType - how does each PetscDevice implementation expect to initialize? 400a4af0ceeSJacob Faibussowitsch e.g. you may want to blanket disable PetscDevice init (and disable say Kokkos init), but 401a4af0ceeSJacob Faibussowitsch have all CUDA devices still initialize. 402a4af0ceeSJacob Faibussowitsch 403a4af0ceeSJacob Faibussowitsch All told the following happens: 404cf3a2253SJacob Faibussowitsch 405a4af0ceeSJacob Faibussowitsch 0. defaultInitType -> LAZY 406a4af0ceeSJacob Faibussowitsch 1. Check for log_view/log_summary, if yes defaultInitType -> EAGER 407a4af0ceeSJacob Faibussowitsch 2. PetscDevice initializes each sub type with deviceDefaultInitType. 408a4af0ceeSJacob Faibussowitsch 2.1 Each enabled PetscDevice sub-type then does the above disable or view check in addition 409a4af0ceeSJacob Faibussowitsch to checking for specific device init. if view or specific device init 410a4af0ceeSJacob Faibussowitsch subTypeDefaultInitType -> EAGER. disabled once again overrides all. 411a4af0ceeSJacob Faibussowitsch */ 412a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceInitializeFromOptions_Internal(MPI_Comm comm) 413030f984aSJacob Faibussowitsch { 4147a101e5eSJacob Faibussowitsch auto defaultView = PETSC_FALSE; 4157a101e5eSJacob Faibussowitsch auto initializeDeviceContextEagerly = PETSC_FALSE; 4167a101e5eSJacob Faibussowitsch auto defaultDevice = PetscInt{PETSC_DECIDE}; 4177a101e5eSJacob Faibussowitsch auto deviceContextInitDevice = PETSC_DEVICE_DEFAULT; 418a4af0ceeSJacob Faibussowitsch PetscDeviceInitType defaultInitType; 419a4af0ceeSJacob Faibussowitsch 420a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 421a4af0ceeSJacob Faibussowitsch if (PetscDefined(USE_DEBUG)) { 422a4af0ceeSJacob Faibussowitsch int result; 423a4af0ceeSJacob Faibussowitsch 4249566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_compare(comm,PETSC_COMM_WORLD,&result)); 425a4af0ceeSJacob Faibussowitsch /* in order to accurately assign ranks to gpus we need to get the MPI_Comm_rank of the 426a4af0ceeSJacob Faibussowitsch * global space */ 427a4af0ceeSJacob Faibussowitsch if (PetscUnlikely(result != MPI_IDENT)) { 428a4af0ceeSJacob Faibussowitsch char name[MPI_MAX_OBJECT_NAME] = {}; 429a4af0ceeSJacob Faibussowitsch int len; /* unused */ 430a4af0ceeSJacob Faibussowitsch 4319566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_get_name(comm,name,&len)); 43298921bdaSJacob Faibussowitsch SETERRQ(comm,PETSC_ERR_MPI,"Default devices being initialized on MPI_Comm '%s' not PETSC_COMM_WORLD",name); 433a4af0ceeSJacob Faibussowitsch } 434a4af0ceeSJacob Faibussowitsch } 435a4af0ceeSJacob Faibussowitsch comm = PETSC_COMM_WORLD; /* from this point on we assume we're on PETSC_COMM_WORLD */ 4369566063dSJacob Faibussowitsch PetscCall(PetscRegisterFinalize(PetscDeviceFinalize_Private)); 437a4af0ceeSJacob Faibussowitsch 4387a101e5eSJacob Faibussowitsch { 4397a101e5eSJacob Faibussowitsch PetscInt initIdx = PETSC_DEVICE_INIT_LAZY; 4407a101e5eSJacob Faibussowitsch PetscBool flg; 4417a101e5eSJacob Faibussowitsch 4427a101e5eSJacob Faibussowitsch PetscCall(PetscOptionsHasName(PETSC_NULLPTR,PETSC_NULLPTR,"-log_view_gpu_time",&flg)); 4437a101e5eSJacob Faibussowitsch if (flg) PetscCall(PetscLogGpuTime()); 4447a101e5eSJacob Faibussowitsch 4457a101e5eSJacob Faibussowitsch /* ----------------------------------------------------------------------------------- */ 4467a101e5eSJacob Faibussowitsch /* Global PetscDevice Options */ 4477a101e5eSJacob Faibussowitsch /* ----------------------------------------------------------------------------------- */ 448d0609cedSBarry Smith PetscOptionsBegin(comm,PETSC_NULLPTR,"PetscDevice Options","Sys"); 4499566063dSJacob Faibussowitsch PetscCall(PetscOptionsEList("-device_enable","How (or whether) to initialize PetscDevices","PetscDeviceInitializeFromOptions_Internal()",PetscDeviceInitTypes,3,PetscDeviceInitTypes[initIdx],&initIdx,PETSC_NULLPTR)); 4509566063dSJacob 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())); 4519566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-device_view","Display device information and assignments (forces eager initialization)",PETSC_NULLPTR,defaultView,&defaultView,&flg)); 452d0609cedSBarry Smith PetscOptionsEnd(); 4537a101e5eSJacob Faibussowitsch 454a4af0ceeSJacob Faibussowitsch if (initIdx == PETSC_DEVICE_INIT_NONE) { 455a4af0ceeSJacob Faibussowitsch /* disabled all device initialization if devices are globally disabled */ 456bf025ffbSJacob 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"); 457a4af0ceeSJacob Faibussowitsch defaultView = PETSC_FALSE; 458a4af0ceeSJacob Faibussowitsch } else { 459a4af0ceeSJacob Faibussowitsch defaultView = static_cast<decltype(defaultView)>(defaultView && flg); 460a4af0ceeSJacob Faibussowitsch if (defaultView) initIdx = PETSC_DEVICE_INIT_EAGER; 461a4af0ceeSJacob Faibussowitsch } 462a4af0ceeSJacob Faibussowitsch defaultInitType = static_cast<decltype(defaultInitType)>(initIdx); 463a4af0ceeSJacob Faibussowitsch } 464a4af0ceeSJacob Faibussowitsch static_assert((PETSC_DEVICE_INVALID == 0) && (PETSC_DEVICE_MAX < std::numeric_limits<int>::max()),""); 465a4af0ceeSJacob Faibussowitsch for (int i = 1; i < PETSC_DEVICE_MAX; ++i) { 466a4af0ceeSJacob Faibussowitsch const auto deviceType = static_cast<PetscDeviceType>(i); 467a4af0ceeSJacob Faibussowitsch auto initType = defaultInitType; 468a4af0ceeSJacob Faibussowitsch 4699566063dSJacob Faibussowitsch PetscCall(PetscDeviceInitializeTypeFromOptions_Private(comm,deviceType,defaultDevice,defaultView,&initType)); 470a4af0ceeSJacob Faibussowitsch if (PetscDeviceConfiguredFor_Internal(deviceType) && (initType == PETSC_DEVICE_INIT_EAGER)) { 471a4af0ceeSJacob Faibussowitsch initializeDeviceContextEagerly = PETSC_TRUE; 472a4af0ceeSJacob Faibussowitsch deviceContextInitDevice = deviceType; 4737a101e5eSJacob Faibussowitsch PetscCall(PetscInfo(PETSC_NULLPTR,"PetscDevice %s set as default device type due to eager initialization\n",PetscDeviceTypes[deviceType])); 474a4af0ceeSJacob Faibussowitsch } 475a4af0ceeSJacob Faibussowitsch } 476a4af0ceeSJacob Faibussowitsch if (initializeDeviceContextEagerly) { 477a4af0ceeSJacob Faibussowitsch PetscDeviceContext dctx; 478a4af0ceeSJacob Faibussowitsch 479cf3a2253SJacob Faibussowitsch /* 480cf3a2253SJacob Faibussowitsch somewhat inefficient here as the device context is potentially fully set up twice (once 481cf3a2253SJacob Faibussowitsch when retrieved then the second time if setfromoptions makes changes) 482cf3a2253SJacob Faibussowitsch */ 4839566063dSJacob Faibussowitsch PetscCall(PetscInfo(PETSC_NULLPTR,"Eagerly initializing PetscDeviceContext with %s device\n",PetscDeviceTypes[deviceContextInitDevice])); 4849566063dSJacob Faibussowitsch PetscCall(PetscDeviceContextSetRootDeviceType_Internal(deviceContextInitDevice)); 4859566063dSJacob Faibussowitsch PetscCall(PetscDeviceContextGetCurrentContext(&dctx)); 4869566063dSJacob Faibussowitsch PetscCall(PetscDeviceContextSetFromOptions(comm,"root_",dctx)); 4879566063dSJacob Faibussowitsch PetscCall(PetscDeviceContextSetUp(dctx)); 488a4af0ceeSJacob Faibussowitsch } 489a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 490a4af0ceeSJacob Faibussowitsch } 491a4af0ceeSJacob Faibussowitsch 492a4af0ceeSJacob Faibussowitsch /* Get the default PetscDevice for a particular type and constructs them if lazily initialized. */ 493a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceGetDefaultForType_Internal(PetscDeviceType type, PetscDevice *device) 494a4af0ceeSJacob Faibussowitsch { 495a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 496a4af0ceeSJacob Faibussowitsch PetscValidPointer(device,2); 4979566063dSJacob Faibussowitsch PetscCall(PetscDeviceInitialize(type)); 498a4af0ceeSJacob Faibussowitsch *device = defaultDevices[type]; 499a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 500030f984aSJacob Faibussowitsch } 501