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): { \ 5517f48955SJacob Faibussowitsch auto ierr_ = PetscConcat_(IMPLS,Device).func(__VA_ARGS__);CHKERRQ(ierr_); \ 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: { 68cf3a2253SJacob Faibussowitsch auto ierr = CUDADevice.myFunction(arg1,arg2);CHKERRQ(ierr); 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: { 80cf3a2253SJacob Faibussowitsch auto ierr = CUDADevice.myFunction(arg1,arg2);CHKERRQ(ierr); 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 108a4af0ceeSJacob Faibussowitsch .seealso: PetscDevice, PetscDeviceInitType, PetscDeviceInitialize(), 109a4af0ceeSJacob Faibussowitsch 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 PetscErrorCode ierr; 116030f984aSJacob Faibussowitsch 117030f984aSJacob Faibussowitsch PetscFunctionBegin; 118a4af0ceeSJacob Faibussowitsch PetscValidDeviceType(type,1); 119a4af0ceeSJacob Faibussowitsch PetscValidPointer(device,3); 120a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceInitializePackage();CHKERRQ(ierr); 121030f984aSJacob Faibussowitsch ierr = PetscNew(&dev);CHKERRQ(ierr); 122030f984aSJacob Faibussowitsch dev->id = PetscDeviceCounter++; 123a4af0ceeSJacob Faibussowitsch dev->type = type; 124a4af0ceeSJacob Faibussowitsch dev->refcnt = 1; 125cf3a2253SJacob Faibussowitsch /* 126cf3a2253SJacob Faibussowitsch if you are adding a device, you also need to add it's initialization in 127cf3a2253SJacob Faibussowitsch PetscDeviceInitializeTypeFromOptions_Private() below 128cf3a2253SJacob Faibussowitsch */ 129a4af0ceeSJacob Faibussowitsch switch (type) { 130a4af0ceeSJacob Faibussowitsch PETSC_DEVICE_CASE_IF_PETSC_DEFINED(CUDA,getDevice,dev,devid); 131a4af0ceeSJacob Faibussowitsch PETSC_DEVICE_CASE_IF_PETSC_DEFINED(HIP,getDevice,dev,devid); 132a2158755SJunchao Zhang PETSC_DEVICE_CASE_IF_PETSC_DEFINED(SYCL,getDevice,dev,devid); 133030f984aSJacob Faibussowitsch default: 13417f48955SJacob Faibussowitsch /* in case the above macros expand to nothing this silences any unused variable warnings */ 13517f48955SJacob Faibussowitsch (void)(devid); 13698921bdaSJacob 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]); 137030f984aSJacob Faibussowitsch } 138030f984aSJacob Faibussowitsch *device = dev; 139030f984aSJacob Faibussowitsch PetscFunctionReturn(0); 140030f984aSJacob Faibussowitsch } 141030f984aSJacob Faibussowitsch 142030f984aSJacob Faibussowitsch /*@C 143030f984aSJacob Faibussowitsch PetscDeviceDestroy - Free a PetscDevice 144030f984aSJacob Faibussowitsch 145030f984aSJacob Faibussowitsch Not Collective, Asynchronous 146030f984aSJacob Faibussowitsch 147030f984aSJacob Faibussowitsch Input Parameter: 148030f984aSJacob Faibussowitsch . device - The PetscDevice 149030f984aSJacob Faibussowitsch 150030f984aSJacob Faibussowitsch Level: beginner 151030f984aSJacob Faibussowitsch 152a4af0ceeSJacob Faibussowitsch .seealso: PetscDevice, PetscDeviceCreate(), PetscDeviceConfigure(), PetscDeviceView() 153030f984aSJacob Faibussowitsch @*/ 154030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceDestroy(PetscDevice *device) 155030f984aSJacob Faibussowitsch { 156030f984aSJacob Faibussowitsch PetscErrorCode ierr; 157030f984aSJacob Faibussowitsch 158a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 159a4af0ceeSJacob Faibussowitsch if (!*device) PetscFunctionReturn(0); 160a4af0ceeSJacob Faibussowitsch PetscValidDevice(*device,1); 161a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceDereference_Internal(*device);CHKERRQ(ierr); 162a4af0ceeSJacob Faibussowitsch if ((*device)->refcnt) { 163a4af0ceeSJacob Faibussowitsch *device = PETSC_NULLPTR; 164a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 165030f984aSJacob Faibussowitsch } 166a4af0ceeSJacob Faibussowitsch ierr = PetscFree((*device)->data);CHKERRQ(ierr); 167a4af0ceeSJacob Faibussowitsch ierr = PetscFree(*device);CHKERRQ(ierr); 168030f984aSJacob Faibussowitsch PetscFunctionReturn(0); 169030f984aSJacob Faibussowitsch } 170030f984aSJacob Faibussowitsch 171a4af0ceeSJacob Faibussowitsch /*@C 172a4af0ceeSJacob Faibussowitsch PetscDeviceConfigure - Configure a particular PetscDevice 173030f984aSJacob Faibussowitsch 174a4af0ceeSJacob Faibussowitsch Not Collective, Asynchronous 175a4af0ceeSJacob Faibussowitsch 176a4af0ceeSJacob Faibussowitsch Input Parameter: 177a4af0ceeSJacob Faibussowitsch . device - The PetscDevice to configure 178a4af0ceeSJacob Faibussowitsch 179a4af0ceeSJacob Faibussowitsch Notes: 180a4af0ceeSJacob Faibussowitsch The user should not assume that this is a cheap operation 181a4af0ceeSJacob Faibussowitsch 182a4af0ceeSJacob Faibussowitsch Level: beginner 183a4af0ceeSJacob Faibussowitsch 184a4af0ceeSJacob Faibussowitsch .seealso: PetscDevice, PetscDeviceCreate(), PetscDeviceView(), PetscDeviceDestroy() 185a4af0ceeSJacob Faibussowitsch @*/ 186a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceConfigure(PetscDevice device) 187030f984aSJacob Faibussowitsch { 188030f984aSJacob Faibussowitsch PetscErrorCode ierr; 189030f984aSJacob Faibussowitsch 190030f984aSJacob Faibussowitsch PetscFunctionBegin; 191a4af0ceeSJacob Faibussowitsch PetscValidDevice(device,1); 192a4af0ceeSJacob Faibussowitsch if (PetscDefined(USE_DEBUG)) { 193cf3a2253SJacob Faibussowitsch /* 194cf3a2253SJacob Faibussowitsch if no available configuration is available, this cascades all the way down to default 195cf3a2253SJacob Faibussowitsch and error 196cf3a2253SJacob Faibussowitsch */ 197a4af0ceeSJacob Faibussowitsch switch (device->type) { 198a4af0ceeSJacob Faibussowitsch case PETSC_DEVICE_CUDA: if (PetscDefined(HAVE_CUDA)) break; 199a4af0ceeSJacob Faibussowitsch case PETSC_DEVICE_HIP: if (PetscDefined(HAVE_HIP)) break; 200a2158755SJunchao Zhang case PETSC_DEVICE_SYCL: if (PetscDefined(HAVE_SYCL)) break; 201a4af0ceeSJacob Faibussowitsch default: 20298921bdaSJacob 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]); 203a4af0ceeSJacob Faibussowitsch } 204a4af0ceeSJacob Faibussowitsch } 205a4af0ceeSJacob Faibussowitsch ierr = (*device->ops->configure)(device);CHKERRQ(ierr); 206a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 207a4af0ceeSJacob Faibussowitsch } 208a4af0ceeSJacob Faibussowitsch 209a4af0ceeSJacob Faibussowitsch /*@C 210a4af0ceeSJacob Faibussowitsch PetscDeviceView - View a PetscDevice 211a4af0ceeSJacob Faibussowitsch 212a4af0ceeSJacob Faibussowitsch Collective on viewer, Asynchronous 213a4af0ceeSJacob Faibussowitsch 214*91e63d38SStefano Zampini Input Parameters: 215050c0c3dSJacob Faibussowitsch + device - The PetscDevice to view 216a4af0ceeSJacob Faibussowitsch - viewer - The PetscViewer to view the device with (NULL for PETSC_VIEWER_STDOUT_WORLD) 217a4af0ceeSJacob Faibussowitsch 218a4af0ceeSJacob Faibussowitsch Level: beginner 219a4af0ceeSJacob Faibussowitsch 220a4af0ceeSJacob Faibussowitsch .seealso: PetscDevice, PetscDeviceCreate(), PetscDeviceConfigure(), PetscDeviceDestroy() 221a4af0ceeSJacob Faibussowitsch @*/ 222a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceView(PetscDevice device, PetscViewer viewer) 223a4af0ceeSJacob Faibussowitsch { 224a4af0ceeSJacob Faibussowitsch PetscErrorCode ierr; 225a4af0ceeSJacob Faibussowitsch 226a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 227a4af0ceeSJacob Faibussowitsch PetscValidDevice(device,1); 228a4af0ceeSJacob Faibussowitsch if (!viewer) {ierr = PetscViewerASCIIGetStdout(PETSC_COMM_WORLD,&viewer);CHKERRQ(ierr);} 229a4af0ceeSJacob Faibussowitsch PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2); 230a4af0ceeSJacob Faibussowitsch ierr = (*device->ops->view)(device,viewer);CHKERRQ(ierr); 231a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 232a4af0ceeSJacob Faibussowitsch } 233a4af0ceeSJacob Faibussowitsch 234*91e63d38SStefano Zampini /*@C 235*91e63d38SStefano Zampini PetscDeviceGetDeviceId - Get the device id 236*91e63d38SStefano Zampini 237*91e63d38SStefano Zampini Not collective 238*91e63d38SStefano Zampini 239*91e63d38SStefano Zampini Input Parameter: 240*91e63d38SStefano Zampini . device - The PetscDevice 241*91e63d38SStefano Zampini 242*91e63d38SStefano Zampini Output Parameter: 243*91e63d38SStefano Zampini . id - The device id 244*91e63d38SStefano Zampini 245*91e63d38SStefano Zampini Level: beginner 246*91e63d38SStefano Zampini 247*91e63d38SStefano Zampini .seealso: PetscDevice, PetscDeviceCreate(), PetscDeviceConfigure(), PetscDeviceDestroy() 248*91e63d38SStefano Zampini @*/ 249*91e63d38SStefano Zampini PetscErrorCode PetscDeviceGetDeviceId(PetscDevice device, PetscInt *id) 250*91e63d38SStefano Zampini { 251*91e63d38SStefano Zampini PetscFunctionBegin; 252*91e63d38SStefano Zampini PetscValidDevice(device,1); 253*91e63d38SStefano Zampini PetscValidIntPointer(id,2); 254*91e63d38SStefano Zampini *id = device->deviceId; 255*91e63d38SStefano Zampini PetscFunctionReturn(0); 256*91e63d38SStefano Zampini } 257*91e63d38SStefano Zampini 258a4af0ceeSJacob Faibussowitsch static std::array<bool,PETSC_DEVICE_MAX> initializedDevice = {}; 259a4af0ceeSJacob Faibussowitsch static std::array<PetscDevice,PETSC_DEVICE_MAX> defaultDevices = {}; 260a4af0ceeSJacob Faibussowitsch static_assert(initializedDevice.size() == defaultDevices.size(),""); 261a4af0ceeSJacob Faibussowitsch 262a4af0ceeSJacob Faibussowitsch /*@C 263a4af0ceeSJacob Faibussowitsch PetscDeviceInitialize - Initialize PetscDevice 264a4af0ceeSJacob Faibussowitsch 265a4af0ceeSJacob Faibussowitsch Not Collective, Possibly Synchronous 266a4af0ceeSJacob Faibussowitsch 267a4af0ceeSJacob Faibussowitsch Input Parameter: 268a4af0ceeSJacob Faibussowitsch . type - The PetscDeviceType to initialize 269a4af0ceeSJacob Faibussowitsch 270a4af0ceeSJacob Faibussowitsch Notes: 271a4af0ceeSJacob Faibussowitsch Eagerly initializes the corresponding PetscDeviceType if needed. 272a4af0ceeSJacob Faibussowitsch 273a4af0ceeSJacob Faibussowitsch Level: beginner 274a4af0ceeSJacob Faibussowitsch 275a4af0ceeSJacob Faibussowitsch .seealso: PetscDevice, PetscDeviceInitType, PetscDeviceInitialized(), PetscDeviceCreate(), PetscDeviceDestroy() 276a4af0ceeSJacob Faibussowitsch @*/ 277a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceInitialize(PetscDeviceType type) 278a4af0ceeSJacob Faibussowitsch { 279a4af0ceeSJacob Faibussowitsch PetscErrorCode ierr; 280a4af0ceeSJacob Faibussowitsch 281a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 282a4af0ceeSJacob Faibussowitsch PetscValidDeviceType(type,1); 283a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceInitializeDefaultDevice_Internal(type,PETSC_DECIDE);CHKERRQ(ierr); 284a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 285a4af0ceeSJacob Faibussowitsch } 286a4af0ceeSJacob Faibussowitsch 287a4af0ceeSJacob Faibussowitsch /*@C 288a4af0ceeSJacob Faibussowitsch PetscDeviceInitialized - Determines whether PetscDevice is initialized for a particular 289a4af0ceeSJacob Faibussowitsch PetscDeviceType 290a4af0ceeSJacob Faibussowitsch 291a4af0ceeSJacob Faibussowitsch Not Collective, Asynchronous 292a4af0ceeSJacob Faibussowitsch 293a4af0ceeSJacob Faibussowitsch Input Parameter: 294a4af0ceeSJacob Faibussowitsch . type - The PetscDeviceType to check 295a4af0ceeSJacob Faibussowitsch 296a4af0ceeSJacob Faibussowitsch Output Parameter: 297a4af0ceeSJacob Faibussowitsch . [return value] - PETSC_TRUE if type is initialized, PETSC_FALSE otherwise 298a4af0ceeSJacob Faibussowitsch 299a4af0ceeSJacob Faibussowitsch Notes: 300a4af0ceeSJacob Faibussowitsch If one has not configured PETSc for a particular PetscDeviceType then this routine will 301a4af0ceeSJacob Faibussowitsch return PETSC_FALSE for that PetscDeviceType. 302a4af0ceeSJacob Faibussowitsch 303a4af0ceeSJacob Faibussowitsch Level: beginner 304a4af0ceeSJacob Faibussowitsch 305a4af0ceeSJacob Faibussowitsch .seealso: PetscDevice, PetscDeviceInitType, PetscDeviceInitialize(), PetscDeviceCreate(), PetscDeviceDestroy() 306a4af0ceeSJacob Faibussowitsch @*/ 307a4af0ceeSJacob Faibussowitsch PetscBool PetscDeviceInitialized(PetscDeviceType type) 308a4af0ceeSJacob Faibussowitsch { 309a4af0ceeSJacob Faibussowitsch return static_cast<PetscBool>(PetscDeviceConfiguredFor_Internal(type) && initializedDevice[type]); 310a4af0ceeSJacob Faibussowitsch } 311a4af0ceeSJacob Faibussowitsch 312cf3a2253SJacob Faibussowitsch /* 313cf3a2253SJacob Faibussowitsch Actual intialization function; any functions claiming to initialize PetscDevice or 314cf3a2253SJacob Faibussowitsch PetscDeviceContext will have to run through this one 315cf3a2253SJacob Faibussowitsch */ 316a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceInitializeDefaultDevice_Internal(PetscDeviceType type, PetscInt defaultDeviceId) 317a4af0ceeSJacob Faibussowitsch { 318a4af0ceeSJacob Faibussowitsch PetscErrorCode ierr; 319a4af0ceeSJacob Faibussowitsch 320a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 321a4af0ceeSJacob Faibussowitsch PetscValidDeviceType(type,1); 322a4af0ceeSJacob Faibussowitsch if (PetscLikely(PetscDeviceInitialized(type))) PetscFunctionReturn(0); 323bf025ffbSJacob Faibussowitsch PetscAssert(!defaultDevices[type],PETSC_COMM_SELF,PETSC_ERR_MEM,"Trying to overwrite existing default device of type %s",PetscDeviceTypes[type]); 324a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceCreate(type,defaultDeviceId,&defaultDevices[type]);CHKERRQ(ierr); 325a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceConfigure(defaultDevices[type]);CHKERRQ(ierr); 326a4af0ceeSJacob Faibussowitsch initializedDevice[type] = true; 327a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 328a4af0ceeSJacob Faibussowitsch } 329a4af0ceeSJacob Faibussowitsch 330ce244043SStefano Zampini #if PetscDefined(USE_LOG) 331ce244043SStefano Zampini PETSC_INTERN PetscErrorCode PetscLogInitialize(void); 332ce244043SStefano Zampini #else 333ce244043SStefano Zampini #define PetscLogInitialize() 0 334ce244043SStefano Zampini #endif 335ce244043SStefano Zampini 336a4af0ceeSJacob Faibussowitsch static PetscErrorCode PetscDeviceInitializeTypeFromOptions_Private(MPI_Comm comm, PetscDeviceType type, PetscInt defaultDeviceId, PetscBool defaultView, PetscDeviceInitType *defaultInitType) 337a4af0ceeSJacob Faibussowitsch { 338a4af0ceeSJacob Faibussowitsch PetscErrorCode ierr; 339a4af0ceeSJacob Faibussowitsch 340a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 341a4af0ceeSJacob Faibussowitsch if (!PetscDeviceConfiguredFor_Internal(type)) { 3427d3de750SJacob Faibussowitsch ierr = PetscInfo(PETSC_NULLPTR,"PetscDeviceType %s not supported\n",PetscDeviceTypes[type]);CHKERRQ(ierr); 343a4af0ceeSJacob Faibussowitsch defaultDevices[type] = PETSC_NULLPTR; 344a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 345a4af0ceeSJacob Faibussowitsch } 3467d3de750SJacob Faibussowitsch ierr = PetscInfo(PETSC_NULLPTR,"PetscDeviceType %s supported, initializing\n",PetscDeviceTypes[type]);CHKERRQ(ierr); 347a4af0ceeSJacob Faibussowitsch /* ugly switch needed to pick the right global variable... could maybe do this as a union? */ 348a4af0ceeSJacob Faibussowitsch switch (type) { 349a4af0ceeSJacob Faibussowitsch PETSC_DEVICE_CASE_IF_PETSC_DEFINED(CUDA,initialize,comm,&defaultDeviceId,defaultInitType); 350a4af0ceeSJacob Faibussowitsch PETSC_DEVICE_CASE_IF_PETSC_DEFINED(HIP,initialize,comm,&defaultDeviceId,defaultInitType); 351a2158755SJunchao Zhang PETSC_DEVICE_CASE_IF_PETSC_DEFINED(SYCL,initialize,comm,&defaultDeviceId,defaultInitType); 352a4af0ceeSJacob Faibussowitsch default: 35398921bdaSJacob 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]); 354a4af0ceeSJacob Faibussowitsch } 355cf3a2253SJacob Faibussowitsch /* 356cf3a2253SJacob Faibussowitsch defaultInitType and defaultDeviceId now represent what the individual TYPES have decided to 357cf3a2253SJacob Faibussowitsch initialize as 358cf3a2253SJacob Faibussowitsch */ 359a4af0ceeSJacob Faibussowitsch if (*defaultInitType == PETSC_DEVICE_INIT_EAGER) { 3607d3de750SJacob Faibussowitsch ierr = PetscInfo(PETSC_NULLPTR,"Eagerly initializing %s PetscDevice\n",PetscDeviceTypes[type]);CHKERRQ(ierr); 361a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceInitializeDefaultDevice_Internal(type,defaultDeviceId);CHKERRQ(ierr); 362a4af0ceeSJacob Faibussowitsch if (defaultView) { 363a4af0ceeSJacob Faibussowitsch PetscViewer vwr; 364a4af0ceeSJacob Faibussowitsch 365ce244043SStefano Zampini ierr = PetscLogInitialize();CHKERRQ(ierr); 366a4af0ceeSJacob Faibussowitsch ierr = PetscViewerASCIIGetStdout(comm,&vwr);CHKERRQ(ierr); 367a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceView(defaultDevices[type],vwr);CHKERRQ(ierr); 368a4af0ceeSJacob Faibussowitsch } 369030f984aSJacob Faibussowitsch } 370030f984aSJacob Faibussowitsch PetscFunctionReturn(0); 371030f984aSJacob Faibussowitsch } 372030f984aSJacob Faibussowitsch 373030f984aSJacob Faibussowitsch /* called from PetscFinalize() do not call yourself! */ 374a4af0ceeSJacob Faibussowitsch static PetscErrorCode PetscDeviceFinalize_Private(void) 375030f984aSJacob Faibussowitsch { 376030f984aSJacob Faibussowitsch PetscErrorCode ierr; 377030f984aSJacob Faibussowitsch 378030f984aSJacob Faibussowitsch PetscFunctionBegin; 379a4af0ceeSJacob Faibussowitsch if (PetscDefined(USE_DEBUG)) { 380bf025ffbSJacob Faibussowitsch const auto PetscDeviceCheckAllDestroyedAfterFinalize = []{ 381a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 382bf025ffbSJacob 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); 383a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 384a4af0ceeSJacob Faibussowitsch }; 385bf025ffbSJacob Faibussowitsch /* 386bf025ffbSJacob Faibussowitsch you might be thinking, why on earth are you registered yet another finalizer in a 387bf025ffbSJacob Faibussowitsch function already called during PetscRegisterFinalizeAll()? If this seems stupid it's 388bf025ffbSJacob Faibussowitsch because it is. 389bf025ffbSJacob Faibussowitsch 390bf025ffbSJacob Faibussowitsch The crux of the problem is that the initializer (and therefore the ~finalizer~) of 391bf025ffbSJacob Faibussowitsch PetscDeviceContext is guaranteed to run after PetscDevice's. So if the global context had 392bf025ffbSJacob Faibussowitsch a default PetscDevice attached, that PetscDevice will have a reference count >0 and hence 393bf025ffbSJacob Faibussowitsch won't be destroyed yet. So we need to repeat the check that all devices have been 394bf025ffbSJacob Faibussowitsch destroyed again ~after~ the global context is destroyed. In summary: 395bf025ffbSJacob Faibussowitsch 396bf025ffbSJacob Faibussowitsch 1. This finalizer runs and destroys all devices, except it may not because the global 397bf025ffbSJacob Faibussowitsch context may still hold a reference! 398bf025ffbSJacob Faibussowitsch 2. The global context finalizer runs and does the final reference count decrement 399bf025ffbSJacob Faibussowitsch required, which actually destroys the held device. 400bf025ffbSJacob Faibussowitsch 3. Our newly added finalizer runs and checks that all is well. 401a4af0ceeSJacob Faibussowitsch */ 402a4af0ceeSJacob Faibussowitsch ierr = PetscRegisterFinalize(PetscDeviceCheckAllDestroyedAfterFinalize);CHKERRQ(ierr); 403a4af0ceeSJacob Faibussowitsch } 404a4af0ceeSJacob Faibussowitsch for (auto &&device : defaultDevices) {ierr = PetscDeviceDestroy(&device);CHKERRQ(ierr);} 405a4af0ceeSJacob Faibussowitsch CHKERRCXX(initializedDevice.fill(false)); 406030f984aSJacob Faibussowitsch PetscFunctionReturn(0); 407030f984aSJacob Faibussowitsch } 408030f984aSJacob Faibussowitsch 409cf3a2253SJacob Faibussowitsch /* 410cf3a2253SJacob Faibussowitsch Begins the init proceeedings for the entire PetscDevice stack. there are 3 stages of 411cf3a2253SJacob Faibussowitsch initialization types: 412cf3a2253SJacob Faibussowitsch 413a4af0ceeSJacob Faibussowitsch 1. defaultInitType - how does PetscDevice as a whole expect to initialize? 414a4af0ceeSJacob Faibussowitsch 2. subTypeDefaultInitType - how does each PetscDevice implementation expect to initialize? 415a4af0ceeSJacob Faibussowitsch e.g. you may want to blanket disable PetscDevice init (and disable say Kokkos init), but 416a4af0ceeSJacob Faibussowitsch have all CUDA devices still initialize. 417a4af0ceeSJacob Faibussowitsch 418a4af0ceeSJacob Faibussowitsch All told the following happens: 419cf3a2253SJacob Faibussowitsch 420a4af0ceeSJacob Faibussowitsch 0. defaultInitType -> LAZY 421a4af0ceeSJacob Faibussowitsch 1. Check for log_view/log_summary, if yes defaultInitType -> EAGER 422a4af0ceeSJacob Faibussowitsch 2. PetscDevice initializes each sub type with deviceDefaultInitType. 423a4af0ceeSJacob Faibussowitsch 2.1 Each enabled PetscDevice sub-type then does the above disable or view check in addition 424a4af0ceeSJacob Faibussowitsch to checking for specific device init. if view or specific device init 425a4af0ceeSJacob Faibussowitsch subTypeDefaultInitType -> EAGER. disabled once again overrides all. 426a4af0ceeSJacob Faibussowitsch */ 427a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceInitializeFromOptions_Internal(MPI_Comm comm) 428030f984aSJacob Faibussowitsch { 429a4af0ceeSJacob Faibussowitsch PetscBool flg,defaultView = PETSC_FALSE,initializeDeviceContextEagerly = PETSC_FALSE; 430a4af0ceeSJacob Faibussowitsch PetscInt defaultDevice = PETSC_DECIDE; 431a4af0ceeSJacob Faibussowitsch PetscDeviceType deviceContextInitDevice = PETSC_DEVICE_DEFAULT; 432a4af0ceeSJacob Faibussowitsch PetscDeviceInitType defaultInitType; 433a4af0ceeSJacob Faibussowitsch PetscErrorCode ierr; 434a4af0ceeSJacob Faibussowitsch 435a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 436a4af0ceeSJacob Faibussowitsch if (PetscDefined(USE_DEBUG)) { 437a4af0ceeSJacob Faibussowitsch int result; 438a4af0ceeSJacob Faibussowitsch 439a4af0ceeSJacob Faibussowitsch ierr = MPI_Comm_compare(comm,PETSC_COMM_WORLD,&result);CHKERRMPI(ierr); 440a4af0ceeSJacob Faibussowitsch /* in order to accurately assign ranks to gpus we need to get the MPI_Comm_rank of the 441a4af0ceeSJacob Faibussowitsch * global space */ 442a4af0ceeSJacob Faibussowitsch if (PetscUnlikely(result != MPI_IDENT)) { 443a4af0ceeSJacob Faibussowitsch char name[MPI_MAX_OBJECT_NAME] = {}; 444a4af0ceeSJacob Faibussowitsch int len; /* unused */ 445a4af0ceeSJacob Faibussowitsch 446a4af0ceeSJacob Faibussowitsch ierr = MPI_Comm_get_name(comm,name,&len);CHKERRMPI(ierr); 44798921bdaSJacob Faibussowitsch SETERRQ(comm,PETSC_ERR_MPI,"Default devices being initialized on MPI_Comm '%s' not PETSC_COMM_WORLD",name); 448a4af0ceeSJacob Faibussowitsch } 449a4af0ceeSJacob Faibussowitsch } 450a4af0ceeSJacob Faibussowitsch comm = PETSC_COMM_WORLD; /* from this point on we assume we're on PETSC_COMM_WORLD */ 451a4af0ceeSJacob Faibussowitsch ierr = PetscRegisterFinalize(PetscDeviceFinalize_Private);CHKERRQ(ierr); 452a4af0ceeSJacob Faibussowitsch ierr = PetscOptionsHasName(PETSC_NULLPTR,PETSC_NULLPTR,"-log_view",&flg);CHKERRQ(ierr); 453a4af0ceeSJacob Faibussowitsch if (!flg) { 454a4af0ceeSJacob Faibussowitsch ierr = PetscOptionsHasName(PETSC_NULLPTR,PETSC_NULLPTR,"-log_summary",&flg);CHKERRQ(ierr); 455a4af0ceeSJacob Faibussowitsch } 456a4af0ceeSJacob Faibussowitsch { 457a4af0ceeSJacob Faibussowitsch PetscInt initIdx = flg ? PETSC_DEVICE_INIT_EAGER : PETSC_DEVICE_INIT_LAZY; 458a4af0ceeSJacob Faibussowitsch 459a4af0ceeSJacob Faibussowitsch ierr = PetscOptionsBegin(comm,PETSC_NULLPTR,"PetscDevice Options","Sys");CHKERRQ(ierr); 460a4af0ceeSJacob Faibussowitsch ierr = PetscOptionsEList("-device_enable","How (or whether) to initialize PetscDevices","PetscDeviceInitializeFromOptions_Internal()",PetscDeviceInitTypes,3,PetscDeviceInitTypes[initIdx],&initIdx,PETSC_NULLPTR);CHKERRQ(ierr); 46117f48955SJacob Faibussowitsch ierr = 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());CHKERRQ(ierr); 462a4af0ceeSJacob Faibussowitsch ierr = PetscOptionsBool("-device_view","Display device information and assignments (forces eager initialization)",PETSC_NULLPTR,defaultView,&defaultView,&flg);CHKERRQ(ierr); 463a4af0ceeSJacob Faibussowitsch ierr = PetscOptionsEnd();CHKERRQ(ierr); 464a4af0ceeSJacob Faibussowitsch if (initIdx == PETSC_DEVICE_INIT_NONE) { 465a4af0ceeSJacob Faibussowitsch /* disabled all device initialization if devices are globally disabled */ 466bf025ffbSJacob 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"); 467a4af0ceeSJacob Faibussowitsch defaultView = PETSC_FALSE; 468a4af0ceeSJacob Faibussowitsch } else { 469a4af0ceeSJacob Faibussowitsch defaultView = static_cast<decltype(defaultView)>(defaultView && flg); 470a4af0ceeSJacob Faibussowitsch if (defaultView) initIdx = PETSC_DEVICE_INIT_EAGER; 471a4af0ceeSJacob Faibussowitsch } 472a4af0ceeSJacob Faibussowitsch defaultInitType = static_cast<decltype(defaultInitType)>(initIdx); 473a4af0ceeSJacob Faibussowitsch } 474a4af0ceeSJacob Faibussowitsch static_assert((PETSC_DEVICE_INVALID == 0) && (PETSC_DEVICE_MAX < std::numeric_limits<int>::max()),""); 475a4af0ceeSJacob Faibussowitsch for (int i = 1; i < PETSC_DEVICE_MAX; ++i) { 476a4af0ceeSJacob Faibussowitsch const auto deviceType = static_cast<PetscDeviceType>(i); 477a4af0ceeSJacob Faibussowitsch auto initType = defaultInitType; 478a4af0ceeSJacob Faibussowitsch 479a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceInitializeTypeFromOptions_Private(comm,deviceType,defaultDevice,defaultView,&initType);CHKERRQ(ierr); 480a4af0ceeSJacob Faibussowitsch if (PetscDeviceConfiguredFor_Internal(deviceType) && (initType == PETSC_DEVICE_INIT_EAGER)) { 481a4af0ceeSJacob Faibussowitsch initializeDeviceContextEagerly = PETSC_TRUE; 482a4af0ceeSJacob Faibussowitsch deviceContextInitDevice = deviceType; 483a4af0ceeSJacob Faibussowitsch } 484a4af0ceeSJacob Faibussowitsch } 485a4af0ceeSJacob Faibussowitsch if (initializeDeviceContextEagerly) { 486a4af0ceeSJacob Faibussowitsch PetscDeviceContext dctx; 487a4af0ceeSJacob Faibussowitsch 488cf3a2253SJacob Faibussowitsch /* 489cf3a2253SJacob Faibussowitsch somewhat inefficient here as the device context is potentially fully set up twice (once 490cf3a2253SJacob Faibussowitsch when retrieved then the second time if setfromoptions makes changes) 491cf3a2253SJacob Faibussowitsch */ 4927d3de750SJacob Faibussowitsch ierr = PetscInfo(PETSC_NULLPTR,"Eagerly initializing PetscDeviceContext with %s device\n",PetscDeviceTypes[deviceContextInitDevice]);CHKERRQ(ierr); 493a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceContextSetRootDeviceType_Internal(deviceContextInitDevice);CHKERRQ(ierr); 494a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceContextGetCurrentContext(&dctx);CHKERRQ(ierr); 495a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceContextSetFromOptions(comm,"root_",dctx);CHKERRQ(ierr); 496a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceContextSetUp(dctx);CHKERRQ(ierr); 497a4af0ceeSJacob Faibussowitsch } 498a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 499a4af0ceeSJacob Faibussowitsch } 500a4af0ceeSJacob Faibussowitsch 501a4af0ceeSJacob Faibussowitsch /* Get the default PetscDevice for a particular type and constructs them if lazily initialized. */ 502a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceGetDefaultForType_Internal(PetscDeviceType type, PetscDevice *device) 503a4af0ceeSJacob Faibussowitsch { 504a4af0ceeSJacob Faibussowitsch PetscErrorCode ierr; 505a4af0ceeSJacob Faibussowitsch 506a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 507a4af0ceeSJacob Faibussowitsch PetscValidPointer(device,2); 508a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceInitialize(type);CHKERRQ(ierr); 509a4af0ceeSJacob Faibussowitsch *device = defaultDevices[type]; 510a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 511030f984aSJacob Faibussowitsch } 512