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); 136*98921bdaSJacob 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: 202*98921bdaSJacob 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*98921bdaSJacob Faibussowitsch if (PetscUnlikelyDebug(defaultDevices[type])) SETERRQ(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 306a4af0ceeSJacob Faibussowitsch static PetscErrorCode PetscDeviceInitializeTypeFromOptions_Private(MPI_Comm comm, PetscDeviceType type, PetscInt defaultDeviceId, PetscBool defaultView, PetscDeviceInitType *defaultInitType) 307a4af0ceeSJacob Faibussowitsch { 308a4af0ceeSJacob Faibussowitsch PetscErrorCode ierr; 309a4af0ceeSJacob Faibussowitsch 310a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 311a4af0ceeSJacob Faibussowitsch if (!PetscDeviceConfiguredFor_Internal(type)) { 312a4af0ceeSJacob Faibussowitsch ierr = PetscInfo1(PETSC_NULLPTR,"PetscDeviceType %s not supported\n",PetscDeviceTypes[type]);CHKERRQ(ierr); 313a4af0ceeSJacob Faibussowitsch defaultDevices[type] = PETSC_NULLPTR; 314a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 315a4af0ceeSJacob Faibussowitsch } 316a4af0ceeSJacob Faibussowitsch ierr = PetscInfo1(PETSC_NULLPTR,"PetscDeviceType %s supported, initializing\n",PetscDeviceTypes[type]);CHKERRQ(ierr); 317a4af0ceeSJacob Faibussowitsch /* ugly switch needed to pick the right global variable... could maybe do this as a union? */ 318a4af0ceeSJacob Faibussowitsch switch (type) { 319a4af0ceeSJacob Faibussowitsch PETSC_DEVICE_CASE_IF_PETSC_DEFINED(CUDA,initialize,comm,&defaultDeviceId,defaultInitType); 320a4af0ceeSJacob Faibussowitsch PETSC_DEVICE_CASE_IF_PETSC_DEFINED(HIP,initialize,comm,&defaultDeviceId,defaultInitType); 321a2158755SJunchao Zhang PETSC_DEVICE_CASE_IF_PETSC_DEFINED(SYCL,initialize,comm,&defaultDeviceId,defaultInitType); 322a4af0ceeSJacob Faibussowitsch default: 323*98921bdaSJacob 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]); 324a4af0ceeSJacob Faibussowitsch } 325cf3a2253SJacob Faibussowitsch /* 326cf3a2253SJacob Faibussowitsch defaultInitType and defaultDeviceId now represent what the individual TYPES have decided to 327cf3a2253SJacob Faibussowitsch initialize as 328cf3a2253SJacob Faibussowitsch */ 329a4af0ceeSJacob Faibussowitsch if (*defaultInitType == PETSC_DEVICE_INIT_EAGER) { 33017f48955SJacob Faibussowitsch ierr = PetscInfo1(PETSC_NULLPTR,"Eagerly initializing %s PetscDevice\n",PetscDeviceTypes[type]);CHKERRQ(ierr); 331a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceInitializeDefaultDevice_Internal(type,defaultDeviceId);CHKERRQ(ierr); 332a4af0ceeSJacob Faibussowitsch if (defaultView) { 333a4af0ceeSJacob Faibussowitsch PetscViewer vwr; 334a4af0ceeSJacob Faibussowitsch 335a4af0ceeSJacob Faibussowitsch ierr = PetscViewerASCIIGetStdout(comm,&vwr);CHKERRQ(ierr); 336a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceView(defaultDevices[type],vwr);CHKERRQ(ierr); 337a4af0ceeSJacob Faibussowitsch } 338030f984aSJacob Faibussowitsch } 339030f984aSJacob Faibussowitsch PetscFunctionReturn(0); 340030f984aSJacob Faibussowitsch } 341030f984aSJacob Faibussowitsch 342030f984aSJacob Faibussowitsch /* called from PetscFinalize() do not call yourself! */ 343a4af0ceeSJacob Faibussowitsch static PetscErrorCode PetscDeviceFinalize_Private(void) 344030f984aSJacob Faibussowitsch { 345030f984aSJacob Faibussowitsch PetscErrorCode ierr; 346030f984aSJacob Faibussowitsch 347030f984aSJacob Faibussowitsch PetscFunctionBegin; 348a4af0ceeSJacob Faibussowitsch if (PetscDefined(USE_DEBUG)) { 349bde483f2SJacob Faibussowitsch const auto PetscDeviceCheckAllDestroyedAfterFinalize = [](){ 350a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 35117f48955SJacob Faibussowitsch for (auto&& device : defaultDevices) { 352*98921bdaSJacob Faibussowitsch if (PetscUnlikely(device)) SETERRQ(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); 353a4af0ceeSJacob Faibussowitsch } 354a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 355a4af0ceeSJacob Faibussowitsch }; 356a4af0ceeSJacob Faibussowitsch /* you might be thinking, why on earth are you registered yet another finalizer in a 357a4af0ceeSJacob Faibussowitsch * function already called during PetscRegisterFinalizeAll()? If this seems stupid it's 358a4af0ceeSJacob Faibussowitsch * because it is. 359a4af0ceeSJacob Faibussowitsch * 360a4af0ceeSJacob Faibussowitsch * The crux of the problem is that the initializer (and therefore the ~finalizer~) of 36117f48955SJacob Faibussowitsch * PetscDeviceContext is guaranteed to run after PetscDevice's. So if the global context 36217f48955SJacob Faibussowitsch * had a default PetscDevice attached, that PetscDevice will have a reference count >0 and 36317f48955SJacob Faibussowitsch * hence won't be destroyed yet. So we need to repeat the check that all devices have been 36417f48955SJacob Faibussowitsch * destroyed again ~after~ the global context is destroyed. In summary: 365a4af0ceeSJacob Faibussowitsch * 366a4af0ceeSJacob Faibussowitsch * 1. This finalizer runs and destroys all devices, except it may not because the global 367a4af0ceeSJacob Faibussowitsch * context may still hold a reference! 36817f48955SJacob Faibussowitsch * 2. The global context finalizer runs and does the final reference count decrement 36917f48955SJacob Faibussowitsch * required, which actually destroys the held device. 370a4af0ceeSJacob Faibussowitsch * 3. Our newly added finalizer runs and checks that all is well. 371a4af0ceeSJacob Faibussowitsch */ 372a4af0ceeSJacob Faibussowitsch ierr = PetscRegisterFinalize(PetscDeviceCheckAllDestroyedAfterFinalize);CHKERRQ(ierr); 373a4af0ceeSJacob Faibussowitsch } 374a4af0ceeSJacob Faibussowitsch for (auto &&device : defaultDevices) {ierr = PetscDeviceDestroy(&device);CHKERRQ(ierr);} 375a4af0ceeSJacob Faibussowitsch CHKERRCXX(initializedDevice.fill(false)); 376030f984aSJacob Faibussowitsch PetscFunctionReturn(0); 377030f984aSJacob Faibussowitsch } 378030f984aSJacob Faibussowitsch 379cf3a2253SJacob Faibussowitsch /* 380cf3a2253SJacob Faibussowitsch Begins the init proceeedings for the entire PetscDevice stack. there are 3 stages of 381cf3a2253SJacob Faibussowitsch initialization types: 382cf3a2253SJacob Faibussowitsch 383a4af0ceeSJacob Faibussowitsch 1. defaultInitType - how does PetscDevice as a whole expect to initialize? 384a4af0ceeSJacob Faibussowitsch 2. subTypeDefaultInitType - how does each PetscDevice implementation expect to initialize? 385a4af0ceeSJacob Faibussowitsch e.g. you may want to blanket disable PetscDevice init (and disable say Kokkos init), but 386a4af0ceeSJacob Faibussowitsch have all CUDA devices still initialize. 387a4af0ceeSJacob Faibussowitsch 388a4af0ceeSJacob Faibussowitsch All told the following happens: 389cf3a2253SJacob Faibussowitsch 390a4af0ceeSJacob Faibussowitsch 0. defaultInitType -> LAZY 391a4af0ceeSJacob Faibussowitsch 1. Check for log_view/log_summary, if yes defaultInitType -> EAGER 392a4af0ceeSJacob Faibussowitsch 2. PetscDevice initializes each sub type with deviceDefaultInitType. 393a4af0ceeSJacob Faibussowitsch 2.1 Each enabled PetscDevice sub-type then does the above disable or view check in addition 394a4af0ceeSJacob Faibussowitsch to checking for specific device init. if view or specific device init 395a4af0ceeSJacob Faibussowitsch subTypeDefaultInitType -> EAGER. disabled once again overrides all. 396a4af0ceeSJacob Faibussowitsch */ 397a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceInitializeFromOptions_Internal(MPI_Comm comm) 398030f984aSJacob Faibussowitsch { 399a4af0ceeSJacob Faibussowitsch PetscBool flg,defaultView = PETSC_FALSE,initializeDeviceContextEagerly = PETSC_FALSE; 400a4af0ceeSJacob Faibussowitsch PetscInt defaultDevice = PETSC_DECIDE; 401a4af0ceeSJacob Faibussowitsch PetscDeviceType deviceContextInitDevice = PETSC_DEVICE_DEFAULT; 402a4af0ceeSJacob Faibussowitsch PetscDeviceInitType defaultInitType; 403a4af0ceeSJacob Faibussowitsch PetscErrorCode ierr; 404a4af0ceeSJacob Faibussowitsch 405a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 406a4af0ceeSJacob Faibussowitsch if (PetscDefined(USE_DEBUG)) { 407a4af0ceeSJacob Faibussowitsch int result; 408a4af0ceeSJacob Faibussowitsch 409a4af0ceeSJacob Faibussowitsch ierr = MPI_Comm_compare(comm,PETSC_COMM_WORLD,&result);CHKERRMPI(ierr); 410a4af0ceeSJacob Faibussowitsch /* in order to accurately assign ranks to gpus we need to get the MPI_Comm_rank of the 411a4af0ceeSJacob Faibussowitsch * global space */ 412a4af0ceeSJacob Faibussowitsch if (PetscUnlikely(result != MPI_IDENT)) { 413a4af0ceeSJacob Faibussowitsch char name[MPI_MAX_OBJECT_NAME] = {}; 414a4af0ceeSJacob Faibussowitsch int len; /* unused */ 415a4af0ceeSJacob Faibussowitsch 416a4af0ceeSJacob Faibussowitsch ierr = MPI_Comm_get_name(comm,name,&len);CHKERRMPI(ierr); 417*98921bdaSJacob Faibussowitsch SETERRQ(comm,PETSC_ERR_MPI,"Default devices being initialized on MPI_Comm '%s' not PETSC_COMM_WORLD",name); 418a4af0ceeSJacob Faibussowitsch } 419a4af0ceeSJacob Faibussowitsch } 420a4af0ceeSJacob Faibussowitsch comm = PETSC_COMM_WORLD; /* from this point on we assume we're on PETSC_COMM_WORLD */ 421a4af0ceeSJacob Faibussowitsch ierr = PetscRegisterFinalize(PetscDeviceFinalize_Private);CHKERRQ(ierr); 422a4af0ceeSJacob Faibussowitsch ierr = PetscOptionsHasName(PETSC_NULLPTR,PETSC_NULLPTR,"-log_view",&flg);CHKERRQ(ierr); 423a4af0ceeSJacob Faibussowitsch if (!flg) { 424a4af0ceeSJacob Faibussowitsch ierr = PetscOptionsHasName(PETSC_NULLPTR,PETSC_NULLPTR,"-log_summary",&flg);CHKERRQ(ierr); 425a4af0ceeSJacob Faibussowitsch } 426a4af0ceeSJacob Faibussowitsch { 427a4af0ceeSJacob Faibussowitsch PetscInt initIdx = flg ? PETSC_DEVICE_INIT_EAGER : PETSC_DEVICE_INIT_LAZY; 428a4af0ceeSJacob Faibussowitsch 429a4af0ceeSJacob Faibussowitsch ierr = PetscOptionsBegin(comm,PETSC_NULLPTR,"PetscDevice Options","Sys");CHKERRQ(ierr); 430a4af0ceeSJacob Faibussowitsch ierr = PetscOptionsEList("-device_enable","How (or whether) to initialize PetscDevices","PetscDeviceInitializeFromOptions_Internal()",PetscDeviceInitTypes,3,PetscDeviceInitTypes[initIdx],&initIdx,PETSC_NULLPTR);CHKERRQ(ierr); 43117f48955SJacob 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); 432a4af0ceeSJacob Faibussowitsch ierr = PetscOptionsBool("-device_view","Display device information and assignments (forces eager initialization)",PETSC_NULLPTR,defaultView,&defaultView,&flg);CHKERRQ(ierr); 433a4af0ceeSJacob Faibussowitsch ierr = PetscOptionsEnd();CHKERRQ(ierr); 434a4af0ceeSJacob Faibussowitsch if (initIdx == PETSC_DEVICE_INIT_NONE) { 435a4af0ceeSJacob Faibussowitsch /* disabled all device initialization if devices are globally disabled */ 436a4af0ceeSJacob Faibussowitsch if (PetscUnlikely(defaultDevice != PETSC_DECIDE)) SETERRQ(comm,PETSC_ERR_USER_INPUT,"You have disabled devices but also specified a particular device to use, these options are mutually exlusive"); 437a4af0ceeSJacob Faibussowitsch defaultView = PETSC_FALSE; 438a4af0ceeSJacob Faibussowitsch } else { 439a4af0ceeSJacob Faibussowitsch defaultView = static_cast<decltype(defaultView)>(defaultView && flg); 440a4af0ceeSJacob Faibussowitsch if (defaultView) initIdx = PETSC_DEVICE_INIT_EAGER; 441a4af0ceeSJacob Faibussowitsch } 442a4af0ceeSJacob Faibussowitsch defaultInitType = static_cast<decltype(defaultInitType)>(initIdx); 443a4af0ceeSJacob Faibussowitsch } 444a4af0ceeSJacob Faibussowitsch static_assert((PETSC_DEVICE_INVALID == 0) && (PETSC_DEVICE_MAX < std::numeric_limits<int>::max()),""); 445a4af0ceeSJacob Faibussowitsch for (int i = 1; i < PETSC_DEVICE_MAX; ++i) { 446a4af0ceeSJacob Faibussowitsch const auto deviceType = static_cast<PetscDeviceType>(i); 447a4af0ceeSJacob Faibussowitsch auto initType = defaultInitType; 448a4af0ceeSJacob Faibussowitsch 449a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceInitializeTypeFromOptions_Private(comm,deviceType,defaultDevice,defaultView,&initType);CHKERRQ(ierr); 450a4af0ceeSJacob Faibussowitsch if (PetscDeviceConfiguredFor_Internal(deviceType) && (initType == PETSC_DEVICE_INIT_EAGER)) { 451a4af0ceeSJacob Faibussowitsch initializeDeviceContextEagerly = PETSC_TRUE; 452a4af0ceeSJacob Faibussowitsch deviceContextInitDevice = deviceType; 453a4af0ceeSJacob Faibussowitsch } 454a4af0ceeSJacob Faibussowitsch } 455a4af0ceeSJacob Faibussowitsch if (initializeDeviceContextEagerly) { 456a4af0ceeSJacob Faibussowitsch PetscDeviceContext dctx; 457a4af0ceeSJacob Faibussowitsch 458cf3a2253SJacob Faibussowitsch /* 459cf3a2253SJacob Faibussowitsch somewhat inefficient here as the device context is potentially fully set up twice (once 460cf3a2253SJacob Faibussowitsch when retrieved then the second time if setfromoptions makes changes) 461cf3a2253SJacob Faibussowitsch */ 462a4af0ceeSJacob Faibussowitsch ierr = PetscInfo1(PETSC_NULLPTR,"Eagerly initializing PetscDeviceContext with %s device\n",PetscDeviceTypes[deviceContextInitDevice]);CHKERRQ(ierr); 463a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceContextSetRootDeviceType_Internal(deviceContextInitDevice);CHKERRQ(ierr); 464a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceContextGetCurrentContext(&dctx);CHKERRQ(ierr); 465a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceContextSetFromOptions(comm,"root_",dctx);CHKERRQ(ierr); 466a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceContextSetUp(dctx);CHKERRQ(ierr); 467a4af0ceeSJacob Faibussowitsch } 468a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 469a4af0ceeSJacob Faibussowitsch } 470a4af0ceeSJacob Faibussowitsch 471a4af0ceeSJacob Faibussowitsch /* Get the default PetscDevice for a particular type and constructs them if lazily initialized. */ 472a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceGetDefaultForType_Internal(PetscDeviceType type, PetscDevice *device) 473a4af0ceeSJacob Faibussowitsch { 474a4af0ceeSJacob Faibussowitsch PetscErrorCode ierr; 475a4af0ceeSJacob Faibussowitsch 476a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 477a4af0ceeSJacob Faibussowitsch PetscValidPointer(device,2); 478a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceInitialize(type);CHKERRQ(ierr); 479a4af0ceeSJacob Faibussowitsch *device = defaultDevices[type]; 480a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 481030f984aSJacob Faibussowitsch } 482