1030f984aSJacob Faibussowitsch #include "cupmdevice.hpp" /* I "petscdevice.h" */ 2*17f48955SJacob Faibussowitsch #include <petsc/private/petscadvancedmacros.h> 3030f984aSJacob Faibussowitsch 4*17f48955SJacob Faibussowitsch using namespace Petsc::Device; 5030f984aSJacob Faibussowitsch 6a4af0ceeSJacob Faibussowitsch /* note to anyone adding more classes, the name must be ALL_CAPS_SHORT_NAME + Device exactly to 7a4af0ceeSJacob Faibussowitsch * be picked up by the switch-case macros below. */ 8030f984aSJacob Faibussowitsch #if PetscDefined(HAVE_CUDA) 9*17f48955SJacob Faibussowitsch static CUPM::Device<CUPM::DeviceType::CUDA> CUDADevice(PetscDeviceContextCreate_CUDA); 10030f984aSJacob Faibussowitsch #endif 11030f984aSJacob Faibussowitsch #if PetscDefined(HAVE_HIP) 12*17f48955SJacob Faibussowitsch static CUPM::Device<CUPM::DeviceType::HIP> HIPDevice(PetscDeviceContextCreate_HIP); 13030f984aSJacob Faibussowitsch #endif 14a2158755SJunchao Zhang #if PetscDefined(HAVE_SYCL) 15a2158755SJunchao Zhang #include "sycldevice.hpp" 16*17f48955SJacob Faibussowitsch static SYCL::Device SYCLDevice(PetscDeviceContextCreate_SYCL); 17a2158755SJunchao Zhang #endif 18030f984aSJacob Faibussowitsch 19*17f48955SJacob Faibussowitsch static_assert(Petsc::util::integral_value(PETSC_DEVICE_INVALID) == 0,""); 20*17f48955SJacob Faibussowitsch static_assert(Petsc::util::integral_value(PETSC_DEVICE_CUDA) == 1,""); 21*17f48955SJacob Faibussowitsch static_assert(Petsc::util::integral_value(PETSC_DEVICE_HIP) == 2,""); 22*17f48955SJacob Faibussowitsch static_assert(Petsc::util::integral_value(PETSC_DEVICE_SYCL) == 3,""); 23*17f48955SJacob Faibussowitsch static_assert(Petsc::util::integral_value(PETSC_DEVICE_MAX) == 4,""); 24a4af0ceeSJacob Faibussowitsch const char *const PetscDeviceTypes[] = { 25a4af0ceeSJacob Faibussowitsch "invalid", 26a4af0ceeSJacob Faibussowitsch "cuda", 27a4af0ceeSJacob Faibussowitsch "hip", 28a2158755SJunchao Zhang "sycl", 29a4af0ceeSJacob Faibussowitsch "max", 30a4af0ceeSJacob Faibussowitsch "PetscDeviceType", 31a4af0ceeSJacob Faibussowitsch "PETSC_DEVICE_", 32a4af0ceeSJacob Faibussowitsch PETSC_NULLPTR 33a4af0ceeSJacob Faibussowitsch }; 34a4af0ceeSJacob Faibussowitsch 35*17f48955SJacob Faibussowitsch static_assert(Petsc::util::integral_value(PETSC_DEVICE_INIT_NONE) == 0,""); 36*17f48955SJacob Faibussowitsch static_assert(Petsc::util::integral_value(PETSC_DEVICE_INIT_LAZY) == 1,""); 37*17f48955SJacob Faibussowitsch static_assert(Petsc::util::integral_value(PETSC_DEVICE_INIT_EAGER) == 2,""); 38a4af0ceeSJacob Faibussowitsch const char *const PetscDeviceInitTypes[] = { 39a4af0ceeSJacob Faibussowitsch "none", 40a4af0ceeSJacob Faibussowitsch "lazy", 41a4af0ceeSJacob Faibussowitsch "eager", 42a4af0ceeSJacob Faibussowitsch "PetscDeviceInitType", 43a4af0ceeSJacob Faibussowitsch "PETSC_DEVICE_INIT_", 44a4af0ceeSJacob Faibussowitsch PETSC_NULLPTR 45a4af0ceeSJacob Faibussowitsch }; 46a4af0ceeSJacob Faibussowitsch static_assert( 47a4af0ceeSJacob Faibussowitsch sizeof(PetscDeviceInitTypes)/sizeof(*PetscDeviceInitTypes) == 6, 48a4af0ceeSJacob Faibussowitsch "Must change CUPMDevice<T>::initialize number of enum values in -device_enable_cupm to match!" 49a4af0ceeSJacob Faibussowitsch ); 50a4af0ceeSJacob Faibussowitsch 51*17f48955SJacob Faibussowitsch #define PETSC_DEVICE_CASE(IMPLS,func,...) \ 52*17f48955SJacob Faibussowitsch case PetscConcat_(PETSC_DEVICE_,IMPLS): { \ 53*17f48955SJacob Faibussowitsch auto ierr_ = PetscConcat_(IMPLS,Device).func(__VA_ARGS__);CHKERRQ(ierr_); \ 54*17f48955SJacob Faibussowitsch } break 55a4af0ceeSJacob Faibussowitsch 56*17f48955SJacob Faibussowitsch /* Suppose you have: 57*17f48955SJacob Faibussowitsch * 58*17f48955SJacob Faibussowitsch * CUDADevice.myFunction(arg1,arg2) 59*17f48955SJacob Faibussowitsch * 60*17f48955SJacob Faibussowitsch * that you would like to conditionally define and call in a switch-case: 61*17f48955SJacob Faibussowitsch * 62*17f48955SJacob Faibussowitsch * switch(PetscDeviceType) { 63*17f48955SJacob Faibussowitsch * #if PetscDefined(HAVE_CUDA) 64*17f48955SJacob Faibussowitsch * case PETSC_DEVICE_CUDA: { 65*17f48955SJacob Faibussowitsch * auto ierr = CUDADevice.myFunction(arg1,arg2);CHKERRQ(ierr); 66*17f48955SJacob Faibussowitsch * } break; 67*17f48955SJacob Faibussowitsch * #endif 68*17f48955SJacob Faibussowitsch * } 69*17f48955SJacob Faibussowitsch * 70*17f48955SJacob Faibussowitsch * then calling this macro: 71*17f48955SJacob Faibussowitsch * 72*17f48955SJacob Faibussowitsch * PETSC_DEVICE_CASE_IF_PETSC_DEFINED(CUDA,myFunction,arg1,arg2) 73*17f48955SJacob Faibussowitsch * 74*17f48955SJacob Faibussowitsch * will expand to the following case statement: 75*17f48955SJacob Faibussowitsch * 76*17f48955SJacob Faibussowitsch * case PETSC_DEVICE_CUDA: { 77*17f48955SJacob Faibussowitsch * auto ierr = CUDADevice.myFunction(arg1,arg2);CHKERRQ(ierr); 78*17f48955SJacob Faibussowitsch * } break 79*17f48955SJacob Faibussowitsch * 80*17f48955SJacob Faibussowitsch * if PetscDefined(HAVE_CUDA) evaluates to 1, and expand to nothing otherwise 81*17f48955SJacob Faibussowitsch */ 82*17f48955SJacob Faibussowitsch #define PETSC_DEVICE_CASE_IF_PETSC_DEFINED(IMPLS,func,...) \ 83*17f48955SJacob Faibussowitsch PetscIfPetscDefined(PetscConcat_(HAVE_,IMPLS),PETSC_DEVICE_CASE,PetscExpandToNothing)(IMPLS,func,__VA_ARGS__) 84030f984aSJacob Faibussowitsch 85030f984aSJacob Faibussowitsch /*@C 86a4af0ceeSJacob Faibussowitsch PetscDeviceCreate - Get a new handle for a particular device type 87030f984aSJacob Faibussowitsch 88030f984aSJacob Faibussowitsch Not Collective, Possibly Synchronous 89030f984aSJacob Faibussowitsch 90030f984aSJacob Faibussowitsch Input Parameter: 91a4af0ceeSJacob Faibussowitsch . type - The type of PetscDevice 92a4af0ceeSJacob Faibussowitsch . devid - The numeric ID# of the device (pass PETSC_DECIDE to assign automatically) 93030f984aSJacob Faibussowitsch 94030f984aSJacob Faibussowitsch Output Parameter: 95030f984aSJacob Faibussowitsch . device - The PetscDevice 96030f984aSJacob Faibussowitsch 97030f984aSJacob Faibussowitsch Notes: 98a4af0ceeSJacob Faibussowitsch This routine may initialize PetscDevice. If this is the case, this will most likely cause 99a4af0ceeSJacob Faibussowitsch some sort of device synchronization. 100a4af0ceeSJacob Faibussowitsch 101a4af0ceeSJacob Faibussowitsch devid is what you might pass to cudaSetDevice() for example. 102030f984aSJacob Faibussowitsch 103030f984aSJacob Faibussowitsch Level: beginner 104030f984aSJacob Faibussowitsch 105a4af0ceeSJacob Faibussowitsch .seealso: PetscDevice, PetscDeviceInitType, PetscDeviceInitialize(), 106a4af0ceeSJacob Faibussowitsch PetscDeviceInitialized(), PetscDeviceConfigure(), PetscDeviceView(), PetscDeviceDestroy() 107030f984aSJacob Faibussowitsch @*/ 108a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceCreate(PetscDeviceType type, PetscInt devid, PetscDevice *device) 109030f984aSJacob Faibussowitsch { 110030f984aSJacob Faibussowitsch static PetscInt PetscDeviceCounter = 0; 111030f984aSJacob Faibussowitsch PetscDevice dev; 112030f984aSJacob Faibussowitsch PetscErrorCode ierr; 113030f984aSJacob Faibussowitsch 114030f984aSJacob Faibussowitsch PetscFunctionBegin; 115a4af0ceeSJacob Faibussowitsch PetscValidDeviceType(type,1); 116a4af0ceeSJacob Faibussowitsch PetscValidPointer(device,3); 117a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceInitializePackage();CHKERRQ(ierr); 118030f984aSJacob Faibussowitsch ierr = PetscNew(&dev);CHKERRQ(ierr); 119030f984aSJacob Faibussowitsch dev->id = PetscDeviceCounter++; 120a4af0ceeSJacob Faibussowitsch dev->type = type; 121a4af0ceeSJacob Faibussowitsch dev->refcnt = 1; 122a4af0ceeSJacob Faibussowitsch /* if you are adding a device, you also need to add it's initialization in 123*17f48955SJacob Faibussowitsch * PetscDeviceInitializeTypeFromOptions_Private() below */ 124a4af0ceeSJacob Faibussowitsch switch (type) { 125a4af0ceeSJacob Faibussowitsch PETSC_DEVICE_CASE_IF_PETSC_DEFINED(CUDA,getDevice,dev,devid); 126a4af0ceeSJacob Faibussowitsch PETSC_DEVICE_CASE_IF_PETSC_DEFINED(HIP,getDevice,dev,devid); 127a2158755SJunchao Zhang PETSC_DEVICE_CASE_IF_PETSC_DEFINED(SYCL,getDevice,dev,devid); 128030f984aSJacob Faibussowitsch default: 129*17f48955SJacob Faibussowitsch /* in case the above macros expand to nothing this silences any unused variable warnings */ 130*17f48955SJacob Faibussowitsch (void)(devid); 131*17f48955SJacob Faibussowitsch SETERRQ1(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]); 132030f984aSJacob Faibussowitsch } 133030f984aSJacob Faibussowitsch *device = dev; 134030f984aSJacob Faibussowitsch PetscFunctionReturn(0); 135030f984aSJacob Faibussowitsch } 136030f984aSJacob Faibussowitsch 137030f984aSJacob Faibussowitsch /*@C 138030f984aSJacob Faibussowitsch PetscDeviceDestroy - Free a PetscDevice 139030f984aSJacob Faibussowitsch 140030f984aSJacob Faibussowitsch Not Collective, Asynchronous 141030f984aSJacob Faibussowitsch 142030f984aSJacob Faibussowitsch Input Parameter: 143030f984aSJacob Faibussowitsch . device - The PetscDevice 144030f984aSJacob Faibussowitsch 145030f984aSJacob Faibussowitsch Level: beginner 146030f984aSJacob Faibussowitsch 147a4af0ceeSJacob Faibussowitsch .seealso: PetscDevice, PetscDeviceCreate(), PetscDeviceConfigure(), PetscDeviceView() 148030f984aSJacob Faibussowitsch @*/ 149030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceDestroy(PetscDevice *device) 150030f984aSJacob Faibussowitsch { 151030f984aSJacob Faibussowitsch PetscErrorCode ierr; 152030f984aSJacob Faibussowitsch 153a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 154a4af0ceeSJacob Faibussowitsch if (!*device) PetscFunctionReturn(0); 155a4af0ceeSJacob Faibussowitsch PetscValidDevice(*device,1); 156a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceDereference_Internal(*device);CHKERRQ(ierr); 157a4af0ceeSJacob Faibussowitsch if ((*device)->refcnt) { 158a4af0ceeSJacob Faibussowitsch *device = PETSC_NULLPTR; 159a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 160030f984aSJacob Faibussowitsch } 161a4af0ceeSJacob Faibussowitsch ierr = PetscFree((*device)->data);CHKERRQ(ierr); 162a4af0ceeSJacob Faibussowitsch ierr = PetscFree(*device);CHKERRQ(ierr); 163030f984aSJacob Faibussowitsch PetscFunctionReturn(0); 164030f984aSJacob Faibussowitsch } 165030f984aSJacob Faibussowitsch 166a4af0ceeSJacob Faibussowitsch /*@C 167a4af0ceeSJacob Faibussowitsch PetscDeviceConfigure - Configure a particular PetscDevice 168030f984aSJacob Faibussowitsch 169a4af0ceeSJacob Faibussowitsch Not Collective, Asynchronous 170a4af0ceeSJacob Faibussowitsch 171a4af0ceeSJacob Faibussowitsch Input Parameter: 172a4af0ceeSJacob Faibussowitsch . device - The PetscDevice to configure 173a4af0ceeSJacob Faibussowitsch 174a4af0ceeSJacob Faibussowitsch Notes: 175a4af0ceeSJacob Faibussowitsch The user should not assume that this is a cheap operation 176a4af0ceeSJacob Faibussowitsch 177a4af0ceeSJacob Faibussowitsch Level: beginner 178a4af0ceeSJacob Faibussowitsch 179a4af0ceeSJacob Faibussowitsch .seealso: PetscDevice, PetscDeviceCreate(), PetscDeviceView(), PetscDeviceDestroy() 180a4af0ceeSJacob Faibussowitsch @*/ 181a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceConfigure(PetscDevice device) 182030f984aSJacob Faibussowitsch { 183030f984aSJacob Faibussowitsch PetscErrorCode ierr; 184030f984aSJacob Faibussowitsch 185030f984aSJacob Faibussowitsch PetscFunctionBegin; 186a4af0ceeSJacob Faibussowitsch PetscValidDevice(device,1); 187a4af0ceeSJacob Faibussowitsch if (PetscDefined(USE_DEBUG)) { 188a4af0ceeSJacob Faibussowitsch /* if no available configuration is available, this cascades all the way down to default 189*17f48955SJacob Faibussowitsch * and error */ 190a4af0ceeSJacob Faibussowitsch switch (device->type) { 191a4af0ceeSJacob Faibussowitsch case PETSC_DEVICE_CUDA: if (PetscDefined(HAVE_CUDA)) break; 192a4af0ceeSJacob Faibussowitsch case PETSC_DEVICE_HIP: if (PetscDefined(HAVE_HIP)) break; 193a2158755SJunchao Zhang case PETSC_DEVICE_SYCL: if (PetscDefined(HAVE_SYCL)) break; 194a4af0ceeSJacob Faibussowitsch default: 195*17f48955SJacob Faibussowitsch SETERRQ1(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]); 196a4af0ceeSJacob Faibussowitsch } 197a4af0ceeSJacob Faibussowitsch } 198a4af0ceeSJacob Faibussowitsch ierr = (*device->ops->configure)(device);CHKERRQ(ierr); 199a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 200a4af0ceeSJacob Faibussowitsch } 201a4af0ceeSJacob Faibussowitsch 202a4af0ceeSJacob Faibussowitsch /*@C 203a4af0ceeSJacob Faibussowitsch PetscDeviceView - View a PetscDevice 204a4af0ceeSJacob Faibussowitsch 205a4af0ceeSJacob Faibussowitsch Collective on viewer, Asynchronous 206a4af0ceeSJacob Faibussowitsch 207a4af0ceeSJacob Faibussowitsch Input Parameter: 208050c0c3dSJacob Faibussowitsch + device - The PetscDevice to view 209a4af0ceeSJacob Faibussowitsch - viewer - The PetscViewer to view the device with (NULL for PETSC_VIEWER_STDOUT_WORLD) 210a4af0ceeSJacob Faibussowitsch 211a4af0ceeSJacob Faibussowitsch Level: beginner 212a4af0ceeSJacob Faibussowitsch 213a4af0ceeSJacob Faibussowitsch .seealso: PetscDevice, PetscDeviceCreate(), PetscDeviceConfigure(), PetscDeviceDestroy() 214a4af0ceeSJacob Faibussowitsch @*/ 215a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceView(PetscDevice device, PetscViewer viewer) 216a4af0ceeSJacob Faibussowitsch { 217a4af0ceeSJacob Faibussowitsch PetscErrorCode ierr; 218a4af0ceeSJacob Faibussowitsch 219a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 220a4af0ceeSJacob Faibussowitsch PetscValidDevice(device,1); 221a4af0ceeSJacob Faibussowitsch if (!viewer) {ierr = PetscViewerASCIIGetStdout(PETSC_COMM_WORLD,&viewer);CHKERRQ(ierr);} 222a4af0ceeSJacob Faibussowitsch PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2); 223a4af0ceeSJacob Faibussowitsch ierr = (*device->ops->view)(device,viewer);CHKERRQ(ierr); 224a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 225a4af0ceeSJacob Faibussowitsch } 226a4af0ceeSJacob Faibussowitsch 227a4af0ceeSJacob Faibussowitsch static std::array<bool,PETSC_DEVICE_MAX> initializedDevice = {}; 228a4af0ceeSJacob Faibussowitsch static std::array<PetscDevice,PETSC_DEVICE_MAX> defaultDevices = {}; 229a4af0ceeSJacob Faibussowitsch static_assert(initializedDevice.size() == defaultDevices.size(),""); 230a4af0ceeSJacob Faibussowitsch 231a4af0ceeSJacob Faibussowitsch /*@C 232a4af0ceeSJacob Faibussowitsch PetscDeviceInitialize - Initialize PetscDevice 233a4af0ceeSJacob Faibussowitsch 234a4af0ceeSJacob Faibussowitsch Not Collective, Possibly Synchronous 235a4af0ceeSJacob Faibussowitsch 236a4af0ceeSJacob Faibussowitsch Input Parameter: 237a4af0ceeSJacob Faibussowitsch . type - The PetscDeviceType to initialize 238a4af0ceeSJacob Faibussowitsch 239a4af0ceeSJacob Faibussowitsch Notes: 240a4af0ceeSJacob Faibussowitsch Eagerly initializes the corresponding PetscDeviceType if needed. 241a4af0ceeSJacob Faibussowitsch 242a4af0ceeSJacob Faibussowitsch Level: beginner 243a4af0ceeSJacob Faibussowitsch 244a4af0ceeSJacob Faibussowitsch .seealso: PetscDevice, PetscDeviceInitType, PetscDeviceInitialized(), PetscDeviceCreate(), PetscDeviceDestroy() 245a4af0ceeSJacob Faibussowitsch @*/ 246a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceInitialize(PetscDeviceType type) 247a4af0ceeSJacob Faibussowitsch { 248a4af0ceeSJacob Faibussowitsch PetscErrorCode ierr; 249a4af0ceeSJacob Faibussowitsch 250a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 251a4af0ceeSJacob Faibussowitsch PetscValidDeviceType(type,1); 252a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceInitializeDefaultDevice_Internal(type,PETSC_DECIDE);CHKERRQ(ierr); 253a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 254a4af0ceeSJacob Faibussowitsch } 255a4af0ceeSJacob Faibussowitsch 256a4af0ceeSJacob Faibussowitsch /*@C 257a4af0ceeSJacob Faibussowitsch PetscDeviceInitialized - Determines whether PetscDevice is initialized for a particular 258a4af0ceeSJacob Faibussowitsch PetscDeviceType 259a4af0ceeSJacob Faibussowitsch 260a4af0ceeSJacob Faibussowitsch Not Collective, Asynchronous 261a4af0ceeSJacob Faibussowitsch 262a4af0ceeSJacob Faibussowitsch Input Parameter: 263a4af0ceeSJacob Faibussowitsch . type - The PetscDeviceType to check 264a4af0ceeSJacob Faibussowitsch 265a4af0ceeSJacob Faibussowitsch Output Parameter: 266a4af0ceeSJacob Faibussowitsch . [return value] - PETSC_TRUE if type is initialized, PETSC_FALSE otherwise 267a4af0ceeSJacob Faibussowitsch 268a4af0ceeSJacob Faibussowitsch Notes: 269a4af0ceeSJacob Faibussowitsch If one has not configured PETSc for a particular PetscDeviceType then this routine will 270a4af0ceeSJacob Faibussowitsch return PETSC_FALSE for that PetscDeviceType. 271a4af0ceeSJacob Faibussowitsch 272a4af0ceeSJacob Faibussowitsch Level: beginner 273a4af0ceeSJacob Faibussowitsch 274a4af0ceeSJacob Faibussowitsch .seealso: PetscDevice, PetscDeviceInitType, PetscDeviceInitialize(), PetscDeviceCreate(), PetscDeviceDestroy() 275a4af0ceeSJacob Faibussowitsch @*/ 276a4af0ceeSJacob Faibussowitsch PetscBool PetscDeviceInitialized(PetscDeviceType type) 277a4af0ceeSJacob Faibussowitsch { 278a4af0ceeSJacob Faibussowitsch return static_cast<PetscBool>(PetscDeviceConfiguredFor_Internal(type) && initializedDevice[type]); 279a4af0ceeSJacob Faibussowitsch } 280a4af0ceeSJacob Faibussowitsch 281a4af0ceeSJacob Faibussowitsch /* Actual intialization function; any functions claiming to initialize PetscDevice or 282a4af0ceeSJacob Faibussowitsch * PetscDeviceContext will have to run through this one */ 283a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceInitializeDefaultDevice_Internal(PetscDeviceType type, PetscInt defaultDeviceId) 284a4af0ceeSJacob Faibussowitsch { 285a4af0ceeSJacob Faibussowitsch PetscErrorCode ierr; 286a4af0ceeSJacob Faibussowitsch 287a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 288a4af0ceeSJacob Faibussowitsch PetscValidDeviceType(type,1); 289a4af0ceeSJacob Faibussowitsch if (PetscLikely(PetscDeviceInitialized(type))) PetscFunctionReturn(0); 290a4af0ceeSJacob Faibussowitsch if (PetscUnlikelyDebug(defaultDevices[type])) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_MEM,"Trying to overwrite existing default device of type %s",PetscDeviceTypes[type]); 291a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceCreate(type,defaultDeviceId,&defaultDevices[type]);CHKERRQ(ierr); 292a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceConfigure(defaultDevices[type]);CHKERRQ(ierr); 293a4af0ceeSJacob Faibussowitsch initializedDevice[type] = true; 294a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 295a4af0ceeSJacob Faibussowitsch } 296a4af0ceeSJacob Faibussowitsch 297a4af0ceeSJacob Faibussowitsch static PetscErrorCode PetscDeviceInitializeTypeFromOptions_Private(MPI_Comm comm, PetscDeviceType type, PetscInt defaultDeviceId, PetscBool defaultView, PetscDeviceInitType *defaultInitType) 298a4af0ceeSJacob Faibussowitsch { 299a4af0ceeSJacob Faibussowitsch PetscErrorCode ierr; 300a4af0ceeSJacob Faibussowitsch 301a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 302a4af0ceeSJacob Faibussowitsch if (!PetscDeviceConfiguredFor_Internal(type)) { 303a4af0ceeSJacob Faibussowitsch ierr = PetscInfo1(PETSC_NULLPTR,"PetscDeviceType %s not supported\n",PetscDeviceTypes[type]);CHKERRQ(ierr); 304a4af0ceeSJacob Faibussowitsch defaultDevices[type] = PETSC_NULLPTR; 305a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 306a4af0ceeSJacob Faibussowitsch } 307a4af0ceeSJacob Faibussowitsch ierr = PetscInfo1(PETSC_NULLPTR,"PetscDeviceType %s supported, initializing\n",PetscDeviceTypes[type]);CHKERRQ(ierr); 308a4af0ceeSJacob Faibussowitsch /* ugly switch needed to pick the right global variable... could maybe do this as a union? */ 309a4af0ceeSJacob Faibussowitsch switch (type) { 310a4af0ceeSJacob Faibussowitsch PETSC_DEVICE_CASE_IF_PETSC_DEFINED(CUDA,initialize,comm,&defaultDeviceId,defaultInitType); 311a4af0ceeSJacob Faibussowitsch PETSC_DEVICE_CASE_IF_PETSC_DEFINED(HIP,initialize,comm,&defaultDeviceId,defaultInitType); 312a2158755SJunchao Zhang PETSC_DEVICE_CASE_IF_PETSC_DEFINED(SYCL,initialize,comm,&defaultDeviceId,defaultInitType); 313a4af0ceeSJacob Faibussowitsch default: 314*17f48955SJacob Faibussowitsch SETERRQ1(comm,PETSC_ERR_PLIB,"PETSc was seemingly configured for PetscDeviceType %s but we've fallen through all cases in a switch",PetscDeviceTypes[type]); 315a4af0ceeSJacob Faibussowitsch } 316a4af0ceeSJacob Faibussowitsch /* defaultInitType and defaultDeviceId now represent what the individual TYPES have decided 317a4af0ceeSJacob Faibussowitsch * to initialize as */ 318a4af0ceeSJacob Faibussowitsch if (*defaultInitType == PETSC_DEVICE_INIT_EAGER) { 319*17f48955SJacob Faibussowitsch ierr = PetscInfo1(PETSC_NULLPTR,"Eagerly initializing %s PetscDevice\n",PetscDeviceTypes[type]);CHKERRQ(ierr); 320a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceInitializeDefaultDevice_Internal(type,defaultDeviceId);CHKERRQ(ierr); 321a4af0ceeSJacob Faibussowitsch if (defaultView) { 322a4af0ceeSJacob Faibussowitsch PetscViewer vwr; 323a4af0ceeSJacob Faibussowitsch 324a4af0ceeSJacob Faibussowitsch ierr = PetscViewerASCIIGetStdout(comm,&vwr);CHKERRQ(ierr); 325a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceView(defaultDevices[type],vwr);CHKERRQ(ierr); 326a4af0ceeSJacob Faibussowitsch } 327030f984aSJacob Faibussowitsch } 328030f984aSJacob Faibussowitsch PetscFunctionReturn(0); 329030f984aSJacob Faibussowitsch } 330030f984aSJacob Faibussowitsch 331030f984aSJacob Faibussowitsch /* called from PetscFinalize() do not call yourself! */ 332a4af0ceeSJacob Faibussowitsch static PetscErrorCode PetscDeviceFinalize_Private(void) 333030f984aSJacob Faibussowitsch { 334030f984aSJacob Faibussowitsch PetscErrorCode ierr; 335030f984aSJacob Faibussowitsch 336030f984aSJacob Faibussowitsch PetscFunctionBegin; 337a4af0ceeSJacob Faibussowitsch if (PetscDefined(USE_DEBUG)) { 338bde483f2SJacob Faibussowitsch const auto PetscDeviceCheckAllDestroyedAfterFinalize = [](){ 339a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 340*17f48955SJacob Faibussowitsch for (auto&& device : defaultDevices) { 3413ca90d2dSJacob Faibussowitsch if (PetscUnlikely(device)) SETERRQ2(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); 342a4af0ceeSJacob Faibussowitsch } 343a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 344a4af0ceeSJacob Faibussowitsch }; 345a4af0ceeSJacob Faibussowitsch /* you might be thinking, why on earth are you registered yet another finalizer in a 346a4af0ceeSJacob Faibussowitsch * function already called during PetscRegisterFinalizeAll()? If this seems stupid it's 347a4af0ceeSJacob Faibussowitsch * because it is. 348a4af0ceeSJacob Faibussowitsch * 349a4af0ceeSJacob Faibussowitsch * The crux of the problem is that the initializer (and therefore the ~finalizer~) of 350*17f48955SJacob Faibussowitsch * PetscDeviceContext is guaranteed to run after PetscDevice's. So if the global context 351*17f48955SJacob Faibussowitsch * had a default PetscDevice attached, that PetscDevice will have a reference count >0 and 352*17f48955SJacob Faibussowitsch * hence won't be destroyed yet. So we need to repeat the check that all devices have been 353*17f48955SJacob Faibussowitsch * destroyed again ~after~ the global context is destroyed. In summary: 354a4af0ceeSJacob Faibussowitsch * 355a4af0ceeSJacob Faibussowitsch * 1. This finalizer runs and destroys all devices, except it may not because the global 356a4af0ceeSJacob Faibussowitsch * context may still hold a reference! 357*17f48955SJacob Faibussowitsch * 2. The global context finalizer runs and does the final reference count decrement 358*17f48955SJacob Faibussowitsch * required, which actually destroys the held device. 359a4af0ceeSJacob Faibussowitsch * 3. Our newly added finalizer runs and checks that all is well. 360a4af0ceeSJacob Faibussowitsch */ 361a4af0ceeSJacob Faibussowitsch ierr = PetscRegisterFinalize(PetscDeviceCheckAllDestroyedAfterFinalize);CHKERRQ(ierr); 362a4af0ceeSJacob Faibussowitsch } 363a4af0ceeSJacob Faibussowitsch for (auto &&device : defaultDevices) {ierr = PetscDeviceDestroy(&device);CHKERRQ(ierr);} 364a4af0ceeSJacob Faibussowitsch CHKERRCXX(initializedDevice.fill(false)); 365030f984aSJacob Faibussowitsch PetscFunctionReturn(0); 366030f984aSJacob Faibussowitsch } 367030f984aSJacob Faibussowitsch 368a4af0ceeSJacob Faibussowitsch /* begins the init proceeedings for the entire PetscDevice stack. there are 3 stages of 369a4af0ceeSJacob Faibussowitsch * initialization types: 370a4af0ceeSJacob Faibussowitsch 1. defaultInitType - how does PetscDevice as a whole expect to initialize? 371a4af0ceeSJacob Faibussowitsch 2. subTypeDefaultInitType - how does each PetscDevice implementation expect to initialize? 372a4af0ceeSJacob Faibussowitsch e.g. you may want to blanket disable PetscDevice init (and disable say Kokkos init), but 373a4af0ceeSJacob Faibussowitsch have all CUDA devices still initialize. 374a4af0ceeSJacob Faibussowitsch 375a4af0ceeSJacob Faibussowitsch All told the following happens: 376a4af0ceeSJacob Faibussowitsch 0. defaultInitType -> LAZY 377a4af0ceeSJacob Faibussowitsch 1. Check for log_view/log_summary, if yes defaultInitType -> EAGER 378a4af0ceeSJacob Faibussowitsch 2. PetscDevice initializes each sub type with deviceDefaultInitType. 379a4af0ceeSJacob Faibussowitsch 2.1 Each enabled PetscDevice sub-type then does the above disable or view check in addition 380a4af0ceeSJacob Faibussowitsch to checking for specific device init. if view or specific device init 381a4af0ceeSJacob Faibussowitsch subTypeDefaultInitType -> EAGER. disabled once again overrides all. 382a4af0ceeSJacob Faibussowitsch */ 383a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceInitializeFromOptions_Internal(MPI_Comm comm) 384030f984aSJacob Faibussowitsch { 385a4af0ceeSJacob Faibussowitsch PetscBool flg,defaultView = PETSC_FALSE,initializeDeviceContextEagerly = PETSC_FALSE; 386a4af0ceeSJacob Faibussowitsch PetscInt defaultDevice = PETSC_DECIDE; 387a4af0ceeSJacob Faibussowitsch PetscDeviceType deviceContextInitDevice = PETSC_DEVICE_DEFAULT; 388a4af0ceeSJacob Faibussowitsch PetscDeviceInitType defaultInitType; 389a4af0ceeSJacob Faibussowitsch PetscErrorCode ierr; 390a4af0ceeSJacob Faibussowitsch 391a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 392a4af0ceeSJacob Faibussowitsch if (PetscDefined(USE_DEBUG)) { 393a4af0ceeSJacob Faibussowitsch int result; 394a4af0ceeSJacob Faibussowitsch 395a4af0ceeSJacob Faibussowitsch ierr = MPI_Comm_compare(comm,PETSC_COMM_WORLD,&result);CHKERRMPI(ierr); 396a4af0ceeSJacob Faibussowitsch /* in order to accurately assign ranks to gpus we need to get the MPI_Comm_rank of the 397a4af0ceeSJacob Faibussowitsch * global space */ 398a4af0ceeSJacob Faibussowitsch if (PetscUnlikely(result != MPI_IDENT)) { 399a4af0ceeSJacob Faibussowitsch char name[MPI_MAX_OBJECT_NAME] = {}; 400a4af0ceeSJacob Faibussowitsch int len; /* unused */ 401a4af0ceeSJacob Faibussowitsch 402a4af0ceeSJacob Faibussowitsch ierr = MPI_Comm_get_name(comm,name,&len);CHKERRMPI(ierr); 403a4af0ceeSJacob Faibussowitsch SETERRQ1(comm,PETSC_ERR_MPI,"Default devices being initialized on MPI_Comm '%s' not PETSC_COMM_WORLD",name); 404a4af0ceeSJacob Faibussowitsch } 405a4af0ceeSJacob Faibussowitsch } 406a4af0ceeSJacob Faibussowitsch comm = PETSC_COMM_WORLD; /* from this point on we assume we're on PETSC_COMM_WORLD */ 407a4af0ceeSJacob Faibussowitsch ierr = PetscRegisterFinalize(PetscDeviceFinalize_Private);CHKERRQ(ierr); 408a4af0ceeSJacob Faibussowitsch ierr = PetscOptionsHasName(PETSC_NULLPTR,PETSC_NULLPTR,"-log_view",&flg);CHKERRQ(ierr); 409a4af0ceeSJacob Faibussowitsch if (!flg) { 410a4af0ceeSJacob Faibussowitsch ierr = PetscOptionsHasName(PETSC_NULLPTR,PETSC_NULLPTR,"-log_summary",&flg);CHKERRQ(ierr); 411a4af0ceeSJacob Faibussowitsch } 412a4af0ceeSJacob Faibussowitsch { 413a4af0ceeSJacob Faibussowitsch PetscInt initIdx = flg ? PETSC_DEVICE_INIT_EAGER : PETSC_DEVICE_INIT_LAZY; 414a4af0ceeSJacob Faibussowitsch 415a4af0ceeSJacob Faibussowitsch ierr = PetscOptionsBegin(comm,PETSC_NULLPTR,"PetscDevice Options","Sys");CHKERRQ(ierr); 416a4af0ceeSJacob Faibussowitsch ierr = PetscOptionsEList("-device_enable","How (or whether) to initialize PetscDevices","PetscDeviceInitializeFromOptions_Internal()",PetscDeviceInitTypes,3,PetscDeviceInitTypes[initIdx],&initIdx,PETSC_NULLPTR);CHKERRQ(ierr); 417*17f48955SJacob 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); 418a4af0ceeSJacob Faibussowitsch ierr = PetscOptionsBool("-device_view","Display device information and assignments (forces eager initialization)",PETSC_NULLPTR,defaultView,&defaultView,&flg);CHKERRQ(ierr); 419a4af0ceeSJacob Faibussowitsch ierr = PetscOptionsEnd();CHKERRQ(ierr); 420a4af0ceeSJacob Faibussowitsch if (initIdx == PETSC_DEVICE_INIT_NONE) { 421a4af0ceeSJacob Faibussowitsch /* disabled all device initialization if devices are globally disabled */ 422a4af0ceeSJacob 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"); 423a4af0ceeSJacob Faibussowitsch defaultView = PETSC_FALSE; 424a4af0ceeSJacob Faibussowitsch } else { 425a4af0ceeSJacob Faibussowitsch defaultView = static_cast<decltype(defaultView)>(defaultView && flg); 426a4af0ceeSJacob Faibussowitsch if (defaultView) initIdx = PETSC_DEVICE_INIT_EAGER; 427a4af0ceeSJacob Faibussowitsch } 428a4af0ceeSJacob Faibussowitsch defaultInitType = static_cast<decltype(defaultInitType)>(initIdx); 429a4af0ceeSJacob Faibussowitsch } 430a4af0ceeSJacob Faibussowitsch static_assert((PETSC_DEVICE_INVALID == 0) && (PETSC_DEVICE_MAX < std::numeric_limits<int>::max()),""); 431a4af0ceeSJacob Faibussowitsch for (int i = 1; i < PETSC_DEVICE_MAX; ++i) { 432a4af0ceeSJacob Faibussowitsch const auto deviceType = static_cast<PetscDeviceType>(i); 433a4af0ceeSJacob Faibussowitsch auto initType = defaultInitType; 434a4af0ceeSJacob Faibussowitsch 435a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceInitializeTypeFromOptions_Private(comm,deviceType,defaultDevice,defaultView,&initType);CHKERRQ(ierr); 436a4af0ceeSJacob Faibussowitsch if (PetscDeviceConfiguredFor_Internal(deviceType) && (initType == PETSC_DEVICE_INIT_EAGER)) { 437a4af0ceeSJacob Faibussowitsch initializeDeviceContextEagerly = PETSC_TRUE; 438a4af0ceeSJacob Faibussowitsch deviceContextInitDevice = deviceType; 439a4af0ceeSJacob Faibussowitsch } 440a4af0ceeSJacob Faibussowitsch } 441a4af0ceeSJacob Faibussowitsch if (initializeDeviceContextEagerly) { 442a4af0ceeSJacob Faibussowitsch PetscDeviceContext dctx; 443a4af0ceeSJacob Faibussowitsch 444a4af0ceeSJacob Faibussowitsch /* somewhat inefficient here as the device context is potentially fully set up twice (once 445a4af0ceeSJacob Faibussowitsch * when retrieved then the second time if setfromoptions makes changes) */ 446a4af0ceeSJacob Faibussowitsch ierr = PetscInfo1(PETSC_NULLPTR,"Eagerly initializing PetscDeviceContext with %s device\n",PetscDeviceTypes[deviceContextInitDevice]);CHKERRQ(ierr); 447a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceContextSetRootDeviceType_Internal(deviceContextInitDevice);CHKERRQ(ierr); 448a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceContextGetCurrentContext(&dctx);CHKERRQ(ierr); 449a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceContextSetFromOptions(comm,"root_",dctx);CHKERRQ(ierr); 450a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceContextSetUp(dctx);CHKERRQ(ierr); 451a4af0ceeSJacob Faibussowitsch } 452a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 453a4af0ceeSJacob Faibussowitsch } 454a4af0ceeSJacob Faibussowitsch 455a4af0ceeSJacob Faibussowitsch /* Get the default PetscDevice for a particular type and constructs them if lazily initialized. */ 456a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceGetDefaultForType_Internal(PetscDeviceType type, PetscDevice *device) 457a4af0ceeSJacob Faibussowitsch { 458a4af0ceeSJacob Faibussowitsch PetscErrorCode ierr; 459a4af0ceeSJacob Faibussowitsch 460a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 461a4af0ceeSJacob Faibussowitsch PetscValidPointer(device,2); 462a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceInitialize(type);CHKERRQ(ierr); 463a4af0ceeSJacob Faibussowitsch *device = defaultDevices[type]; 464a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 465030f984aSJacob Faibussowitsch } 466