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 93030f984aSJacob Faibussowitsch Input Parameter: 94a4af0ceeSJacob Faibussowitsch . type - The type of PetscDevice 95a4af0ceeSJacob Faibussowitsch . 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 214a4af0ceeSJacob Faibussowitsch Input Parameter: 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 234a4af0ceeSJacob Faibussowitsch static std::array<bool,PETSC_DEVICE_MAX> initializedDevice = {}; 235a4af0ceeSJacob Faibussowitsch static std::array<PetscDevice,PETSC_DEVICE_MAX> defaultDevices = {}; 236a4af0ceeSJacob Faibussowitsch static_assert(initializedDevice.size() == defaultDevices.size(),""); 237a4af0ceeSJacob Faibussowitsch 238a4af0ceeSJacob Faibussowitsch /*@C 239a4af0ceeSJacob Faibussowitsch PetscDeviceInitialize - Initialize PetscDevice 240a4af0ceeSJacob Faibussowitsch 241a4af0ceeSJacob Faibussowitsch Not Collective, Possibly Synchronous 242a4af0ceeSJacob Faibussowitsch 243a4af0ceeSJacob Faibussowitsch Input Parameter: 244a4af0ceeSJacob Faibussowitsch . type - The PetscDeviceType to initialize 245a4af0ceeSJacob Faibussowitsch 246a4af0ceeSJacob Faibussowitsch Notes: 247a4af0ceeSJacob Faibussowitsch Eagerly initializes the corresponding PetscDeviceType if needed. 248a4af0ceeSJacob Faibussowitsch 249a4af0ceeSJacob Faibussowitsch Level: beginner 250a4af0ceeSJacob Faibussowitsch 251a4af0ceeSJacob Faibussowitsch .seealso: PetscDevice, PetscDeviceInitType, PetscDeviceInitialized(), PetscDeviceCreate(), PetscDeviceDestroy() 252a4af0ceeSJacob Faibussowitsch @*/ 253a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceInitialize(PetscDeviceType type) 254a4af0ceeSJacob Faibussowitsch { 255a4af0ceeSJacob Faibussowitsch PetscErrorCode ierr; 256a4af0ceeSJacob Faibussowitsch 257a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 258a4af0ceeSJacob Faibussowitsch PetscValidDeviceType(type,1); 259a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceInitializeDefaultDevice_Internal(type,PETSC_DECIDE);CHKERRQ(ierr); 260a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 261a4af0ceeSJacob Faibussowitsch } 262a4af0ceeSJacob Faibussowitsch 263a4af0ceeSJacob Faibussowitsch /*@C 264a4af0ceeSJacob Faibussowitsch PetscDeviceInitialized - Determines whether PetscDevice is initialized for a particular 265a4af0ceeSJacob Faibussowitsch PetscDeviceType 266a4af0ceeSJacob Faibussowitsch 267a4af0ceeSJacob Faibussowitsch Not Collective, Asynchronous 268a4af0ceeSJacob Faibussowitsch 269a4af0ceeSJacob Faibussowitsch Input Parameter: 270a4af0ceeSJacob Faibussowitsch . type - The PetscDeviceType to check 271a4af0ceeSJacob Faibussowitsch 272a4af0ceeSJacob Faibussowitsch Output Parameter: 273a4af0ceeSJacob Faibussowitsch . [return value] - PETSC_TRUE if type is initialized, PETSC_FALSE otherwise 274a4af0ceeSJacob Faibussowitsch 275a4af0ceeSJacob Faibussowitsch Notes: 276a4af0ceeSJacob Faibussowitsch If one has not configured PETSc for a particular PetscDeviceType then this routine will 277a4af0ceeSJacob Faibussowitsch return PETSC_FALSE for that PetscDeviceType. 278a4af0ceeSJacob Faibussowitsch 279a4af0ceeSJacob Faibussowitsch Level: beginner 280a4af0ceeSJacob Faibussowitsch 281a4af0ceeSJacob Faibussowitsch .seealso: PetscDevice, PetscDeviceInitType, PetscDeviceInitialize(), PetscDeviceCreate(), PetscDeviceDestroy() 282a4af0ceeSJacob Faibussowitsch @*/ 283a4af0ceeSJacob Faibussowitsch PetscBool PetscDeviceInitialized(PetscDeviceType type) 284a4af0ceeSJacob Faibussowitsch { 285a4af0ceeSJacob Faibussowitsch return static_cast<PetscBool>(PetscDeviceConfiguredFor_Internal(type) && initializedDevice[type]); 286a4af0ceeSJacob Faibussowitsch } 287a4af0ceeSJacob Faibussowitsch 288cf3a2253SJacob Faibussowitsch /* 289cf3a2253SJacob Faibussowitsch Actual intialization function; any functions claiming to initialize PetscDevice or 290cf3a2253SJacob Faibussowitsch PetscDeviceContext will have to run through this one 291cf3a2253SJacob Faibussowitsch */ 292a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceInitializeDefaultDevice_Internal(PetscDeviceType type, PetscInt defaultDeviceId) 293a4af0ceeSJacob Faibussowitsch { 294a4af0ceeSJacob Faibussowitsch PetscErrorCode ierr; 295a4af0ceeSJacob Faibussowitsch 296a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 297a4af0ceeSJacob Faibussowitsch PetscValidDeviceType(type,1); 298a4af0ceeSJacob Faibussowitsch if (PetscLikely(PetscDeviceInitialized(type))) PetscFunctionReturn(0); 299*bf025ffbSJacob Faibussowitsch PetscAssert(!defaultDevices[type],PETSC_COMM_SELF,PETSC_ERR_MEM,"Trying to overwrite existing default device of type %s",PetscDeviceTypes[type]); 300a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceCreate(type,defaultDeviceId,&defaultDevices[type]);CHKERRQ(ierr); 301a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceConfigure(defaultDevices[type]);CHKERRQ(ierr); 302a4af0ceeSJacob Faibussowitsch initializedDevice[type] = true; 303a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 304a4af0ceeSJacob Faibussowitsch } 305a4af0ceeSJacob Faibussowitsch 306ce244043SStefano Zampini #if PetscDefined(USE_LOG) 307ce244043SStefano Zampini PETSC_INTERN PetscErrorCode PetscLogInitialize(void); 308ce244043SStefano Zampini #else 309ce244043SStefano Zampini #define PetscLogInitialize() 0 310ce244043SStefano Zampini #endif 311ce244043SStefano Zampini 312a4af0ceeSJacob Faibussowitsch static PetscErrorCode PetscDeviceInitializeTypeFromOptions_Private(MPI_Comm comm, PetscDeviceType type, PetscInt defaultDeviceId, PetscBool defaultView, PetscDeviceInitType *defaultInitType) 313a4af0ceeSJacob Faibussowitsch { 314a4af0ceeSJacob Faibussowitsch PetscErrorCode ierr; 315a4af0ceeSJacob Faibussowitsch 316a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 317a4af0ceeSJacob Faibussowitsch if (!PetscDeviceConfiguredFor_Internal(type)) { 3187d3de750SJacob Faibussowitsch ierr = PetscInfo(PETSC_NULLPTR,"PetscDeviceType %s not supported\n",PetscDeviceTypes[type]);CHKERRQ(ierr); 319a4af0ceeSJacob Faibussowitsch defaultDevices[type] = PETSC_NULLPTR; 320a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 321a4af0ceeSJacob Faibussowitsch } 3227d3de750SJacob Faibussowitsch ierr = PetscInfo(PETSC_NULLPTR,"PetscDeviceType %s supported, initializing\n",PetscDeviceTypes[type]);CHKERRQ(ierr); 323a4af0ceeSJacob Faibussowitsch /* ugly switch needed to pick the right global variable... could maybe do this as a union? */ 324a4af0ceeSJacob Faibussowitsch switch (type) { 325a4af0ceeSJacob Faibussowitsch PETSC_DEVICE_CASE_IF_PETSC_DEFINED(CUDA,initialize,comm,&defaultDeviceId,defaultInitType); 326a4af0ceeSJacob Faibussowitsch PETSC_DEVICE_CASE_IF_PETSC_DEFINED(HIP,initialize,comm,&defaultDeviceId,defaultInitType); 327a2158755SJunchao Zhang PETSC_DEVICE_CASE_IF_PETSC_DEFINED(SYCL,initialize,comm,&defaultDeviceId,defaultInitType); 328a4af0ceeSJacob Faibussowitsch default: 32998921bdaSJacob 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]); 330a4af0ceeSJacob Faibussowitsch } 331cf3a2253SJacob Faibussowitsch /* 332cf3a2253SJacob Faibussowitsch defaultInitType and defaultDeviceId now represent what the individual TYPES have decided to 333cf3a2253SJacob Faibussowitsch initialize as 334cf3a2253SJacob Faibussowitsch */ 335a4af0ceeSJacob Faibussowitsch if (*defaultInitType == PETSC_DEVICE_INIT_EAGER) { 3367d3de750SJacob Faibussowitsch ierr = PetscInfo(PETSC_NULLPTR,"Eagerly initializing %s PetscDevice\n",PetscDeviceTypes[type]);CHKERRQ(ierr); 337a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceInitializeDefaultDevice_Internal(type,defaultDeviceId);CHKERRQ(ierr); 338a4af0ceeSJacob Faibussowitsch if (defaultView) { 339a4af0ceeSJacob Faibussowitsch PetscViewer vwr; 340a4af0ceeSJacob Faibussowitsch 341ce244043SStefano Zampini ierr = PetscLogInitialize();CHKERRQ(ierr); 342a4af0ceeSJacob Faibussowitsch ierr = PetscViewerASCIIGetStdout(comm,&vwr);CHKERRQ(ierr); 343a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceView(defaultDevices[type],vwr);CHKERRQ(ierr); 344a4af0ceeSJacob Faibussowitsch } 345030f984aSJacob Faibussowitsch } 346030f984aSJacob Faibussowitsch PetscFunctionReturn(0); 347030f984aSJacob Faibussowitsch } 348030f984aSJacob Faibussowitsch 349030f984aSJacob Faibussowitsch /* called from PetscFinalize() do not call yourself! */ 350a4af0ceeSJacob Faibussowitsch static PetscErrorCode PetscDeviceFinalize_Private(void) 351030f984aSJacob Faibussowitsch { 352030f984aSJacob Faibussowitsch PetscErrorCode ierr; 353030f984aSJacob Faibussowitsch 354030f984aSJacob Faibussowitsch PetscFunctionBegin; 355a4af0ceeSJacob Faibussowitsch if (PetscDefined(USE_DEBUG)) { 356*bf025ffbSJacob Faibussowitsch const auto PetscDeviceCheckAllDestroyedAfterFinalize = []{ 357a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 358*bf025ffbSJacob 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); 359a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 360a4af0ceeSJacob Faibussowitsch }; 361*bf025ffbSJacob Faibussowitsch /* 362*bf025ffbSJacob Faibussowitsch you might be thinking, why on earth are you registered yet another finalizer in a 363*bf025ffbSJacob Faibussowitsch function already called during PetscRegisterFinalizeAll()? If this seems stupid it's 364*bf025ffbSJacob Faibussowitsch because it is. 365*bf025ffbSJacob Faibussowitsch 366*bf025ffbSJacob Faibussowitsch The crux of the problem is that the initializer (and therefore the ~finalizer~) of 367*bf025ffbSJacob Faibussowitsch PetscDeviceContext is guaranteed to run after PetscDevice's. So if the global context had 368*bf025ffbSJacob Faibussowitsch a default PetscDevice attached, that PetscDevice will have a reference count >0 and hence 369*bf025ffbSJacob Faibussowitsch won't be destroyed yet. So we need to repeat the check that all devices have been 370*bf025ffbSJacob Faibussowitsch destroyed again ~after~ the global context is destroyed. In summary: 371*bf025ffbSJacob Faibussowitsch 372*bf025ffbSJacob Faibussowitsch 1. This finalizer runs and destroys all devices, except it may not because the global 373*bf025ffbSJacob Faibussowitsch context may still hold a reference! 374*bf025ffbSJacob Faibussowitsch 2. The global context finalizer runs and does the final reference count decrement 375*bf025ffbSJacob Faibussowitsch required, which actually destroys the held device. 376*bf025ffbSJacob Faibussowitsch 3. Our newly added finalizer runs and checks that all is well. 377a4af0ceeSJacob Faibussowitsch */ 378a4af0ceeSJacob Faibussowitsch ierr = PetscRegisterFinalize(PetscDeviceCheckAllDestroyedAfterFinalize);CHKERRQ(ierr); 379a4af0ceeSJacob Faibussowitsch } 380a4af0ceeSJacob Faibussowitsch for (auto &&device : defaultDevices) {ierr = PetscDeviceDestroy(&device);CHKERRQ(ierr);} 381a4af0ceeSJacob Faibussowitsch CHKERRCXX(initializedDevice.fill(false)); 382030f984aSJacob Faibussowitsch PetscFunctionReturn(0); 383030f984aSJacob Faibussowitsch } 384030f984aSJacob Faibussowitsch 385cf3a2253SJacob Faibussowitsch /* 386cf3a2253SJacob Faibussowitsch Begins the init proceeedings for the entire PetscDevice stack. there are 3 stages of 387cf3a2253SJacob Faibussowitsch initialization types: 388cf3a2253SJacob Faibussowitsch 389a4af0ceeSJacob Faibussowitsch 1. defaultInitType - how does PetscDevice as a whole expect to initialize? 390a4af0ceeSJacob Faibussowitsch 2. subTypeDefaultInitType - how does each PetscDevice implementation expect to initialize? 391a4af0ceeSJacob Faibussowitsch e.g. you may want to blanket disable PetscDevice init (and disable say Kokkos init), but 392a4af0ceeSJacob Faibussowitsch have all CUDA devices still initialize. 393a4af0ceeSJacob Faibussowitsch 394a4af0ceeSJacob Faibussowitsch All told the following happens: 395cf3a2253SJacob Faibussowitsch 396a4af0ceeSJacob Faibussowitsch 0. defaultInitType -> LAZY 397a4af0ceeSJacob Faibussowitsch 1. Check for log_view/log_summary, if yes defaultInitType -> EAGER 398a4af0ceeSJacob Faibussowitsch 2. PetscDevice initializes each sub type with deviceDefaultInitType. 399a4af0ceeSJacob Faibussowitsch 2.1 Each enabled PetscDevice sub-type then does the above disable or view check in addition 400a4af0ceeSJacob Faibussowitsch to checking for specific device init. if view or specific device init 401a4af0ceeSJacob Faibussowitsch subTypeDefaultInitType -> EAGER. disabled once again overrides all. 402a4af0ceeSJacob Faibussowitsch */ 403a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceInitializeFromOptions_Internal(MPI_Comm comm) 404030f984aSJacob Faibussowitsch { 405a4af0ceeSJacob Faibussowitsch PetscBool flg,defaultView = PETSC_FALSE,initializeDeviceContextEagerly = PETSC_FALSE; 406a4af0ceeSJacob Faibussowitsch PetscInt defaultDevice = PETSC_DECIDE; 407a4af0ceeSJacob Faibussowitsch PetscDeviceType deviceContextInitDevice = PETSC_DEVICE_DEFAULT; 408a4af0ceeSJacob Faibussowitsch PetscDeviceInitType defaultInitType; 409a4af0ceeSJacob Faibussowitsch PetscErrorCode ierr; 410a4af0ceeSJacob Faibussowitsch 411a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 412a4af0ceeSJacob Faibussowitsch if (PetscDefined(USE_DEBUG)) { 413a4af0ceeSJacob Faibussowitsch int result; 414a4af0ceeSJacob Faibussowitsch 415a4af0ceeSJacob Faibussowitsch ierr = MPI_Comm_compare(comm,PETSC_COMM_WORLD,&result);CHKERRMPI(ierr); 416a4af0ceeSJacob Faibussowitsch /* in order to accurately assign ranks to gpus we need to get the MPI_Comm_rank of the 417a4af0ceeSJacob Faibussowitsch * global space */ 418a4af0ceeSJacob Faibussowitsch if (PetscUnlikely(result != MPI_IDENT)) { 419a4af0ceeSJacob Faibussowitsch char name[MPI_MAX_OBJECT_NAME] = {}; 420a4af0ceeSJacob Faibussowitsch int len; /* unused */ 421a4af0ceeSJacob Faibussowitsch 422a4af0ceeSJacob Faibussowitsch ierr = MPI_Comm_get_name(comm,name,&len);CHKERRMPI(ierr); 42398921bdaSJacob Faibussowitsch SETERRQ(comm,PETSC_ERR_MPI,"Default devices being initialized on MPI_Comm '%s' not PETSC_COMM_WORLD",name); 424a4af0ceeSJacob Faibussowitsch } 425a4af0ceeSJacob Faibussowitsch } 426a4af0ceeSJacob Faibussowitsch comm = PETSC_COMM_WORLD; /* from this point on we assume we're on PETSC_COMM_WORLD */ 427a4af0ceeSJacob Faibussowitsch ierr = PetscRegisterFinalize(PetscDeviceFinalize_Private);CHKERRQ(ierr); 428a4af0ceeSJacob Faibussowitsch ierr = PetscOptionsHasName(PETSC_NULLPTR,PETSC_NULLPTR,"-log_view",&flg);CHKERRQ(ierr); 429a4af0ceeSJacob Faibussowitsch if (!flg) { 430a4af0ceeSJacob Faibussowitsch ierr = PetscOptionsHasName(PETSC_NULLPTR,PETSC_NULLPTR,"-log_summary",&flg);CHKERRQ(ierr); 431a4af0ceeSJacob Faibussowitsch } 432a4af0ceeSJacob Faibussowitsch { 433a4af0ceeSJacob Faibussowitsch PetscInt initIdx = flg ? PETSC_DEVICE_INIT_EAGER : PETSC_DEVICE_INIT_LAZY; 434a4af0ceeSJacob Faibussowitsch 435a4af0ceeSJacob Faibussowitsch ierr = PetscOptionsBegin(comm,PETSC_NULLPTR,"PetscDevice Options","Sys");CHKERRQ(ierr); 436a4af0ceeSJacob Faibussowitsch ierr = PetscOptionsEList("-device_enable","How (or whether) to initialize PetscDevices","PetscDeviceInitializeFromOptions_Internal()",PetscDeviceInitTypes,3,PetscDeviceInitTypes[initIdx],&initIdx,PETSC_NULLPTR);CHKERRQ(ierr); 43717f48955SJacob 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); 438a4af0ceeSJacob Faibussowitsch ierr = PetscOptionsBool("-device_view","Display device information and assignments (forces eager initialization)",PETSC_NULLPTR,defaultView,&defaultView,&flg);CHKERRQ(ierr); 439a4af0ceeSJacob Faibussowitsch ierr = PetscOptionsEnd();CHKERRQ(ierr); 440a4af0ceeSJacob Faibussowitsch if (initIdx == PETSC_DEVICE_INIT_NONE) { 441a4af0ceeSJacob Faibussowitsch /* disabled all device initialization if devices are globally disabled */ 442*bf025ffbSJacob 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"); 443a4af0ceeSJacob Faibussowitsch defaultView = PETSC_FALSE; 444a4af0ceeSJacob Faibussowitsch } else { 445a4af0ceeSJacob Faibussowitsch defaultView = static_cast<decltype(defaultView)>(defaultView && flg); 446a4af0ceeSJacob Faibussowitsch if (defaultView) initIdx = PETSC_DEVICE_INIT_EAGER; 447a4af0ceeSJacob Faibussowitsch } 448a4af0ceeSJacob Faibussowitsch defaultInitType = static_cast<decltype(defaultInitType)>(initIdx); 449a4af0ceeSJacob Faibussowitsch } 450a4af0ceeSJacob Faibussowitsch static_assert((PETSC_DEVICE_INVALID == 0) && (PETSC_DEVICE_MAX < std::numeric_limits<int>::max()),""); 451a4af0ceeSJacob Faibussowitsch for (int i = 1; i < PETSC_DEVICE_MAX; ++i) { 452a4af0ceeSJacob Faibussowitsch const auto deviceType = static_cast<PetscDeviceType>(i); 453a4af0ceeSJacob Faibussowitsch auto initType = defaultInitType; 454a4af0ceeSJacob Faibussowitsch 455a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceInitializeTypeFromOptions_Private(comm,deviceType,defaultDevice,defaultView,&initType);CHKERRQ(ierr); 456a4af0ceeSJacob Faibussowitsch if (PetscDeviceConfiguredFor_Internal(deviceType) && (initType == PETSC_DEVICE_INIT_EAGER)) { 457a4af0ceeSJacob Faibussowitsch initializeDeviceContextEagerly = PETSC_TRUE; 458a4af0ceeSJacob Faibussowitsch deviceContextInitDevice = deviceType; 459a4af0ceeSJacob Faibussowitsch } 460a4af0ceeSJacob Faibussowitsch } 461a4af0ceeSJacob Faibussowitsch if (initializeDeviceContextEagerly) { 462a4af0ceeSJacob Faibussowitsch PetscDeviceContext dctx; 463a4af0ceeSJacob Faibussowitsch 464cf3a2253SJacob Faibussowitsch /* 465cf3a2253SJacob Faibussowitsch somewhat inefficient here as the device context is potentially fully set up twice (once 466cf3a2253SJacob Faibussowitsch when retrieved then the second time if setfromoptions makes changes) 467cf3a2253SJacob Faibussowitsch */ 4687d3de750SJacob Faibussowitsch ierr = PetscInfo(PETSC_NULLPTR,"Eagerly initializing PetscDeviceContext with %s device\n",PetscDeviceTypes[deviceContextInitDevice]);CHKERRQ(ierr); 469a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceContextSetRootDeviceType_Internal(deviceContextInitDevice);CHKERRQ(ierr); 470a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceContextGetCurrentContext(&dctx);CHKERRQ(ierr); 471a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceContextSetFromOptions(comm,"root_",dctx);CHKERRQ(ierr); 472a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceContextSetUp(dctx);CHKERRQ(ierr); 473a4af0ceeSJacob Faibussowitsch } 474a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 475a4af0ceeSJacob Faibussowitsch } 476a4af0ceeSJacob Faibussowitsch 477a4af0ceeSJacob Faibussowitsch /* Get the default PetscDevice for a particular type and constructs them if lazily initialized. */ 478a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceGetDefaultForType_Internal(PetscDeviceType type, PetscDevice *device) 479a4af0ceeSJacob Faibussowitsch { 480a4af0ceeSJacob Faibussowitsch PetscErrorCode ierr; 481a4af0ceeSJacob Faibussowitsch 482a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 483a4af0ceeSJacob Faibussowitsch PetscValidPointer(device,2); 484a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceInitialize(type);CHKERRQ(ierr); 485a4af0ceeSJacob Faibussowitsch *device = defaultDevices[type]; 486a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 487030f984aSJacob Faibussowitsch } 488