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); 2992c71b3e2SJacob Faibussowitsch PetscAssertFalse(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 306*ce244043SStefano Zampini #if PetscDefined(USE_LOG) 307*ce244043SStefano Zampini PETSC_INTERN PetscErrorCode PetscLogInitialize(void); 308*ce244043SStefano Zampini #else 309*ce244043SStefano Zampini #define PetscLogInitialize() 0 310*ce244043SStefano Zampini #endif 311*ce244043SStefano 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 341*ce244043SStefano 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)) { 356bde483f2SJacob Faibussowitsch const auto PetscDeviceCheckAllDestroyedAfterFinalize = [](){ 357a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 35817f48955SJacob Faibussowitsch for (auto&& device : defaultDevices) { 3592c71b3e2SJacob Faibussowitsch PetscCheckFalse(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); 360a4af0ceeSJacob Faibussowitsch } 361a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 362a4af0ceeSJacob Faibussowitsch }; 363a4af0ceeSJacob Faibussowitsch /* you might be thinking, why on earth are you registered yet another finalizer in a 364a4af0ceeSJacob Faibussowitsch * function already called during PetscRegisterFinalizeAll()? If this seems stupid it's 365a4af0ceeSJacob Faibussowitsch * because it is. 366a4af0ceeSJacob Faibussowitsch * 367a4af0ceeSJacob Faibussowitsch * The crux of the problem is that the initializer (and therefore the ~finalizer~) of 36817f48955SJacob Faibussowitsch * PetscDeviceContext is guaranteed to run after PetscDevice's. So if the global context 36917f48955SJacob Faibussowitsch * had a default PetscDevice attached, that PetscDevice will have a reference count >0 and 37017f48955SJacob Faibussowitsch * hence won't be destroyed yet. So we need to repeat the check that all devices have been 37117f48955SJacob Faibussowitsch * destroyed again ~after~ the global context is destroyed. In summary: 372a4af0ceeSJacob Faibussowitsch * 373a4af0ceeSJacob Faibussowitsch * 1. This finalizer runs and destroys all devices, except it may not because the global 374a4af0ceeSJacob Faibussowitsch * context may still hold a reference! 37517f48955SJacob Faibussowitsch * 2. The global context finalizer runs and does the final reference count decrement 37617f48955SJacob Faibussowitsch * required, which actually destroys the held device. 377a4af0ceeSJacob Faibussowitsch * 3. Our newly added finalizer runs and checks that all is well. 378a4af0ceeSJacob Faibussowitsch */ 379a4af0ceeSJacob Faibussowitsch ierr = PetscRegisterFinalize(PetscDeviceCheckAllDestroyedAfterFinalize);CHKERRQ(ierr); 380a4af0ceeSJacob Faibussowitsch } 381a4af0ceeSJacob Faibussowitsch for (auto &&device : defaultDevices) {ierr = PetscDeviceDestroy(&device);CHKERRQ(ierr);} 382a4af0ceeSJacob Faibussowitsch CHKERRCXX(initializedDevice.fill(false)); 383030f984aSJacob Faibussowitsch PetscFunctionReturn(0); 384030f984aSJacob Faibussowitsch } 385030f984aSJacob Faibussowitsch 386cf3a2253SJacob Faibussowitsch /* 387cf3a2253SJacob Faibussowitsch Begins the init proceeedings for the entire PetscDevice stack. there are 3 stages of 388cf3a2253SJacob Faibussowitsch initialization types: 389cf3a2253SJacob Faibussowitsch 390a4af0ceeSJacob Faibussowitsch 1. defaultInitType - how does PetscDevice as a whole expect to initialize? 391a4af0ceeSJacob Faibussowitsch 2. subTypeDefaultInitType - how does each PetscDevice implementation expect to initialize? 392a4af0ceeSJacob Faibussowitsch e.g. you may want to blanket disable PetscDevice init (and disable say Kokkos init), but 393a4af0ceeSJacob Faibussowitsch have all CUDA devices still initialize. 394a4af0ceeSJacob Faibussowitsch 395a4af0ceeSJacob Faibussowitsch All told the following happens: 396cf3a2253SJacob Faibussowitsch 397a4af0ceeSJacob Faibussowitsch 0. defaultInitType -> LAZY 398a4af0ceeSJacob Faibussowitsch 1. Check for log_view/log_summary, if yes defaultInitType -> EAGER 399a4af0ceeSJacob Faibussowitsch 2. PetscDevice initializes each sub type with deviceDefaultInitType. 400a4af0ceeSJacob Faibussowitsch 2.1 Each enabled PetscDevice sub-type then does the above disable or view check in addition 401a4af0ceeSJacob Faibussowitsch to checking for specific device init. if view or specific device init 402a4af0ceeSJacob Faibussowitsch subTypeDefaultInitType -> EAGER. disabled once again overrides all. 403a4af0ceeSJacob Faibussowitsch */ 404a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceInitializeFromOptions_Internal(MPI_Comm comm) 405030f984aSJacob Faibussowitsch { 406a4af0ceeSJacob Faibussowitsch PetscBool flg,defaultView = PETSC_FALSE,initializeDeviceContextEagerly = PETSC_FALSE; 407a4af0ceeSJacob Faibussowitsch PetscInt defaultDevice = PETSC_DECIDE; 408a4af0ceeSJacob Faibussowitsch PetscDeviceType deviceContextInitDevice = PETSC_DEVICE_DEFAULT; 409a4af0ceeSJacob Faibussowitsch PetscDeviceInitType defaultInitType; 410a4af0ceeSJacob Faibussowitsch PetscErrorCode ierr; 411a4af0ceeSJacob Faibussowitsch 412a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 413a4af0ceeSJacob Faibussowitsch if (PetscDefined(USE_DEBUG)) { 414a4af0ceeSJacob Faibussowitsch int result; 415a4af0ceeSJacob Faibussowitsch 416a4af0ceeSJacob Faibussowitsch ierr = MPI_Comm_compare(comm,PETSC_COMM_WORLD,&result);CHKERRMPI(ierr); 417a4af0ceeSJacob Faibussowitsch /* in order to accurately assign ranks to gpus we need to get the MPI_Comm_rank of the 418a4af0ceeSJacob Faibussowitsch * global space */ 419a4af0ceeSJacob Faibussowitsch if (PetscUnlikely(result != MPI_IDENT)) { 420a4af0ceeSJacob Faibussowitsch char name[MPI_MAX_OBJECT_NAME] = {}; 421a4af0ceeSJacob Faibussowitsch int len; /* unused */ 422a4af0ceeSJacob Faibussowitsch 423a4af0ceeSJacob Faibussowitsch ierr = MPI_Comm_get_name(comm,name,&len);CHKERRMPI(ierr); 42498921bdaSJacob Faibussowitsch SETERRQ(comm,PETSC_ERR_MPI,"Default devices being initialized on MPI_Comm '%s' not PETSC_COMM_WORLD",name); 425a4af0ceeSJacob Faibussowitsch } 426a4af0ceeSJacob Faibussowitsch } 427a4af0ceeSJacob Faibussowitsch comm = PETSC_COMM_WORLD; /* from this point on we assume we're on PETSC_COMM_WORLD */ 428a4af0ceeSJacob Faibussowitsch ierr = PetscRegisterFinalize(PetscDeviceFinalize_Private);CHKERRQ(ierr); 429a4af0ceeSJacob Faibussowitsch ierr = PetscOptionsHasName(PETSC_NULLPTR,PETSC_NULLPTR,"-log_view",&flg);CHKERRQ(ierr); 430a4af0ceeSJacob Faibussowitsch if (!flg) { 431a4af0ceeSJacob Faibussowitsch ierr = PetscOptionsHasName(PETSC_NULLPTR,PETSC_NULLPTR,"-log_summary",&flg);CHKERRQ(ierr); 432a4af0ceeSJacob Faibussowitsch } 433a4af0ceeSJacob Faibussowitsch { 434a4af0ceeSJacob Faibussowitsch PetscInt initIdx = flg ? PETSC_DEVICE_INIT_EAGER : PETSC_DEVICE_INIT_LAZY; 435a4af0ceeSJacob Faibussowitsch 436a4af0ceeSJacob Faibussowitsch ierr = PetscOptionsBegin(comm,PETSC_NULLPTR,"PetscDevice Options","Sys");CHKERRQ(ierr); 437a4af0ceeSJacob Faibussowitsch ierr = PetscOptionsEList("-device_enable","How (or whether) to initialize PetscDevices","PetscDeviceInitializeFromOptions_Internal()",PetscDeviceInitTypes,3,PetscDeviceInitTypes[initIdx],&initIdx,PETSC_NULLPTR);CHKERRQ(ierr); 43817f48955SJacob 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); 439a4af0ceeSJacob Faibussowitsch ierr = PetscOptionsBool("-device_view","Display device information and assignments (forces eager initialization)",PETSC_NULLPTR,defaultView,&defaultView,&flg);CHKERRQ(ierr); 440a4af0ceeSJacob Faibussowitsch ierr = PetscOptionsEnd();CHKERRQ(ierr); 441a4af0ceeSJacob Faibussowitsch if (initIdx == PETSC_DEVICE_INIT_NONE) { 442a4af0ceeSJacob Faibussowitsch /* disabled all device initialization if devices are globally disabled */ 4432c71b3e2SJacob Faibussowitsch PetscCheckFalse(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"); 444a4af0ceeSJacob Faibussowitsch defaultView = PETSC_FALSE; 445a4af0ceeSJacob Faibussowitsch } else { 446a4af0ceeSJacob Faibussowitsch defaultView = static_cast<decltype(defaultView)>(defaultView && flg); 447a4af0ceeSJacob Faibussowitsch if (defaultView) initIdx = PETSC_DEVICE_INIT_EAGER; 448a4af0ceeSJacob Faibussowitsch } 449a4af0ceeSJacob Faibussowitsch defaultInitType = static_cast<decltype(defaultInitType)>(initIdx); 450a4af0ceeSJacob Faibussowitsch } 451a4af0ceeSJacob Faibussowitsch static_assert((PETSC_DEVICE_INVALID == 0) && (PETSC_DEVICE_MAX < std::numeric_limits<int>::max()),""); 452a4af0ceeSJacob Faibussowitsch for (int i = 1; i < PETSC_DEVICE_MAX; ++i) { 453a4af0ceeSJacob Faibussowitsch const auto deviceType = static_cast<PetscDeviceType>(i); 454a4af0ceeSJacob Faibussowitsch auto initType = defaultInitType; 455a4af0ceeSJacob Faibussowitsch 456a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceInitializeTypeFromOptions_Private(comm,deviceType,defaultDevice,defaultView,&initType);CHKERRQ(ierr); 457a4af0ceeSJacob Faibussowitsch if (PetscDeviceConfiguredFor_Internal(deviceType) && (initType == PETSC_DEVICE_INIT_EAGER)) { 458a4af0ceeSJacob Faibussowitsch initializeDeviceContextEagerly = PETSC_TRUE; 459a4af0ceeSJacob Faibussowitsch deviceContextInitDevice = deviceType; 460a4af0ceeSJacob Faibussowitsch } 461a4af0ceeSJacob Faibussowitsch } 462a4af0ceeSJacob Faibussowitsch if (initializeDeviceContextEagerly) { 463a4af0ceeSJacob Faibussowitsch PetscDeviceContext dctx; 464a4af0ceeSJacob Faibussowitsch 465cf3a2253SJacob Faibussowitsch /* 466cf3a2253SJacob Faibussowitsch somewhat inefficient here as the device context is potentially fully set up twice (once 467cf3a2253SJacob Faibussowitsch when retrieved then the second time if setfromoptions makes changes) 468cf3a2253SJacob Faibussowitsch */ 4697d3de750SJacob Faibussowitsch ierr = PetscInfo(PETSC_NULLPTR,"Eagerly initializing PetscDeviceContext with %s device\n",PetscDeviceTypes[deviceContextInitDevice]);CHKERRQ(ierr); 470a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceContextSetRootDeviceType_Internal(deviceContextInitDevice);CHKERRQ(ierr); 471a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceContextGetCurrentContext(&dctx);CHKERRQ(ierr); 472a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceContextSetFromOptions(comm,"root_",dctx);CHKERRQ(ierr); 473a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceContextSetUp(dctx);CHKERRQ(ierr); 474a4af0ceeSJacob Faibussowitsch } 475a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 476a4af0ceeSJacob Faibussowitsch } 477a4af0ceeSJacob Faibussowitsch 478a4af0ceeSJacob Faibussowitsch /* Get the default PetscDevice for a particular type and constructs them if lazily initialized. */ 479a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceGetDefaultForType_Internal(PetscDeviceType type, PetscDevice *device) 480a4af0ceeSJacob Faibussowitsch { 481a4af0ceeSJacob Faibussowitsch PetscErrorCode ierr; 482a4af0ceeSJacob Faibussowitsch 483a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 484a4af0ceeSJacob Faibussowitsch PetscValidPointer(device,2); 485a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceInitialize(type);CHKERRQ(ierr); 486a4af0ceeSJacob Faibussowitsch *device = defaultDevices[type]; 487a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 488030f984aSJacob Faibussowitsch } 489