1030f984aSJacob Faibussowitsch #include "cupmdevice.hpp" /* I "petscdevice.h" */ 2030f984aSJacob Faibussowitsch 3030f984aSJacob Faibussowitsch using namespace Petsc; 4030f984aSJacob Faibussowitsch 5a4af0ceeSJacob Faibussowitsch /* note to anyone adding more classes, the name must be ALL_CAPS_SHORT_NAME + Device exactly to 6a4af0ceeSJacob Faibussowitsch * be picked up by the switch-case macros below. */ 7030f984aSJacob Faibussowitsch #if PetscDefined(HAVE_CUDA) 8a4af0ceeSJacob Faibussowitsch static CUPMDevice<CUPMDeviceType::CUDA> CUDADevice(PetscDeviceContextCreate_CUDA); 9030f984aSJacob Faibussowitsch #endif 10030f984aSJacob Faibussowitsch #if PetscDefined(HAVE_HIP) 11a4af0ceeSJacob Faibussowitsch static CUPMDevice<CUPMDeviceType::HIP> HIPDevice(PetscDeviceContextCreate_HIP); 12030f984aSJacob Faibussowitsch #endif 13*a2158755SJunchao Zhang #if PetscDefined(HAVE_SYCL) 14*a2158755SJunchao Zhang #include "sycldevice.hpp" 15*a2158755SJunchao Zhang static SyclDevice SYCLDevice(PetscDeviceContextCreate_SYCL); 16*a2158755SJunchao Zhang #endif 17030f984aSJacob Faibussowitsch 18a4af0ceeSJacob Faibussowitsch const char *const PetscDeviceTypes[] = { 19a4af0ceeSJacob Faibussowitsch "invalid", 20a4af0ceeSJacob Faibussowitsch "cuda", 21a4af0ceeSJacob Faibussowitsch "hip", 22*a2158755SJunchao Zhang "sycl", 23a4af0ceeSJacob Faibussowitsch "max", 24a4af0ceeSJacob Faibussowitsch "PetscDeviceType", 25a4af0ceeSJacob Faibussowitsch "PETSC_DEVICE_", 26a4af0ceeSJacob Faibussowitsch PETSC_NULLPTR 27a4af0ceeSJacob Faibussowitsch }; 28a4af0ceeSJacob Faibussowitsch 29a4af0ceeSJacob Faibussowitsch const char *const PetscDeviceInitTypes[] = { 30a4af0ceeSJacob Faibussowitsch "none", 31a4af0ceeSJacob Faibussowitsch "lazy", 32a4af0ceeSJacob Faibussowitsch "eager", 33a4af0ceeSJacob Faibussowitsch "PetscDeviceInitType", 34a4af0ceeSJacob Faibussowitsch "PETSC_DEVICE_INIT_", 35a4af0ceeSJacob Faibussowitsch PETSC_NULLPTR 36a4af0ceeSJacob Faibussowitsch }; 37a4af0ceeSJacob Faibussowitsch static_assert( 38a4af0ceeSJacob Faibussowitsch sizeof(PetscDeviceInitTypes)/sizeof(*PetscDeviceInitTypes) == 6, 39a4af0ceeSJacob Faibussowitsch "Must change CUPMDevice<T>::initialize number of enum values in -device_enable_cupm to match!" 40a4af0ceeSJacob Faibussowitsch ); 41a4af0ceeSJacob Faibussowitsch 42a4af0ceeSJacob Faibussowitsch #define PETSC_DEVICE_DEFAULT_CASE(comm,type) \ 43a4af0ceeSJacob Faibussowitsch SETERRQ1((comm),PETSC_ERR_PLIB, \ 44a4af0ceeSJacob Faibussowitsch "PETSc was seemingly configured for PetscDeviceType %s but " \ 45a4af0ceeSJacob Faibussowitsch "we've fallen through all cases in a switch", \ 46a4af0ceeSJacob Faibussowitsch PetscDeviceTypes[type]) 47a4af0ceeSJacob Faibussowitsch 48a4af0ceeSJacob Faibussowitsch #define CAT_(a,...) a ## __VA_ARGS__ 49a4af0ceeSJacob Faibussowitsch #define CAT(a,...) CAT_(a,__VA_ARGS__) 50a4af0ceeSJacob Faibussowitsch 51a4af0ceeSJacob Faibussowitsch #define PETSC_DEVICE_CASE_IF_PETSC_DEFINED__0(IMPLS,func,...) 52a4af0ceeSJacob Faibussowitsch #define PETSC_DEVICE_CASE_IF_PETSC_DEFINED__1(IMPLS,func,...) \ 53a4af0ceeSJacob Faibussowitsch case CAT(PETSC_DEVICE_,IMPLS): \ 54a4af0ceeSJacob Faibussowitsch { \ 55a4af0ceeSJacob Faibussowitsch auto ierr = CAT(IMPLS,Device).func(__VA_ARGS__);CHKERRQ(ierr); \ 56a4af0ceeSJacob Faibussowitsch break; \ 57a4af0ceeSJacob Faibussowitsch } 58a4af0ceeSJacob Faibussowitsch 59a4af0ceeSJacob Faibussowitsch #define PETSC_DEVICE_CASE_IF_PETSC_DEFINED_(IMPLS,...) \ 60a4af0ceeSJacob Faibussowitsch CAT(PETSC_DEVICE_CASE_IF_PETSC_DEFINED__,PetscDefined(CAT(HAVE_,IMPLS)))(IMPLS,__VA_ARGS__) 61a4af0ceeSJacob Faibussowitsch 62a4af0ceeSJacob Faibussowitsch #define PETSC_DEVICE_CASE_IF_PETSC_DEFINED(IMPLS,...) \ 63a4af0ceeSJacob Faibussowitsch PETSC_DEVICE_CASE_IF_PETSC_DEFINED_(IMPLS,__VA_ARGS__) 64a4af0ceeSJacob Faibussowitsch 65a4af0ceeSJacob Faibussowitsch #define PETSC_DEVICE_UNUSED_IF_NO_DEVICE(var) (void)(var) 66030f984aSJacob Faibussowitsch 67030f984aSJacob Faibussowitsch /*@C 68a4af0ceeSJacob Faibussowitsch PetscDeviceCreate - Get a new handle for a particular device type 69030f984aSJacob Faibussowitsch 70030f984aSJacob Faibussowitsch Not Collective, Possibly Synchronous 71030f984aSJacob Faibussowitsch 72030f984aSJacob Faibussowitsch Input Parameter: 73a4af0ceeSJacob Faibussowitsch . type - The type of PetscDevice 74a4af0ceeSJacob Faibussowitsch . devid - The numeric ID# of the device (pass PETSC_DECIDE to assign automatically) 75030f984aSJacob Faibussowitsch 76030f984aSJacob Faibussowitsch Output Parameter: 77030f984aSJacob Faibussowitsch . device - The PetscDevice 78030f984aSJacob Faibussowitsch 79030f984aSJacob Faibussowitsch Notes: 80a4af0ceeSJacob Faibussowitsch This routine may initialize PetscDevice. If this is the case, this will most likely cause 81a4af0ceeSJacob Faibussowitsch some sort of device synchronization. 82a4af0ceeSJacob Faibussowitsch 83a4af0ceeSJacob Faibussowitsch devid is what you might pass to cudaSetDevice() for example. 84030f984aSJacob Faibussowitsch 85030f984aSJacob Faibussowitsch Level: beginner 86030f984aSJacob Faibussowitsch 87a4af0ceeSJacob Faibussowitsch .seealso: PetscDevice, PetscDeviceInitType, PetscDeviceInitialize(), 88a4af0ceeSJacob Faibussowitsch PetscDeviceInitialized(), PetscDeviceConfigure(), PetscDeviceView(), PetscDeviceDestroy() 89030f984aSJacob Faibussowitsch @*/ 90a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceCreate(PetscDeviceType type, PetscInt devid, PetscDevice *device) 91030f984aSJacob Faibussowitsch { 92030f984aSJacob Faibussowitsch static PetscInt PetscDeviceCounter = 0; 93030f984aSJacob Faibussowitsch PetscDevice dev; 94030f984aSJacob Faibussowitsch PetscErrorCode ierr; 95030f984aSJacob Faibussowitsch 96030f984aSJacob Faibussowitsch PetscFunctionBegin; 97a4af0ceeSJacob Faibussowitsch PetscValidDeviceType(type,1); 98a4af0ceeSJacob Faibussowitsch PetscValidPointer(device,3); 99a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceInitializePackage();CHKERRQ(ierr); 100030f984aSJacob Faibussowitsch ierr = PetscNew(&dev);CHKERRQ(ierr); 101030f984aSJacob Faibussowitsch dev->id = PetscDeviceCounter++; 102a4af0ceeSJacob Faibussowitsch dev->type = type; 103a4af0ceeSJacob Faibussowitsch dev->refcnt = 1; 104a4af0ceeSJacob Faibussowitsch /* if you are adding a device, you also need to add it's initialization in 105a4af0ceeSJacob Faibussowitsch PetscDeviceInitializeTypeFromOptions_Private() below */ 106a4af0ceeSJacob Faibussowitsch switch (type) { 107a4af0ceeSJacob Faibussowitsch PETSC_DEVICE_CASE_IF_PETSC_DEFINED(CUDA,getDevice,dev,devid); 108a4af0ceeSJacob Faibussowitsch PETSC_DEVICE_CASE_IF_PETSC_DEFINED(HIP,getDevice,dev,devid); 109*a2158755SJunchao Zhang PETSC_DEVICE_CASE_IF_PETSC_DEFINED(SYCL,getDevice,dev,devid); 110030f984aSJacob Faibussowitsch default: 111a4af0ceeSJacob Faibussowitsch PETSC_DEVICE_UNUSED_IF_NO_DEVICE(devid); 112a4af0ceeSJacob Faibussowitsch PETSC_DEVICE_DEFAULT_CASE(PETSC_COMM_SELF,type); 113030f984aSJacob Faibussowitsch } 114030f984aSJacob Faibussowitsch *device = dev; 115030f984aSJacob Faibussowitsch PetscFunctionReturn(0); 116030f984aSJacob Faibussowitsch } 117030f984aSJacob Faibussowitsch 118030f984aSJacob Faibussowitsch /*@C 119030f984aSJacob Faibussowitsch PetscDeviceDestroy - Free a PetscDevice 120030f984aSJacob Faibussowitsch 121030f984aSJacob Faibussowitsch Not Collective, Asynchronous 122030f984aSJacob Faibussowitsch 123030f984aSJacob Faibussowitsch Input Parameter: 124030f984aSJacob Faibussowitsch . device - The PetscDevice 125030f984aSJacob Faibussowitsch 126030f984aSJacob Faibussowitsch Level: beginner 127030f984aSJacob Faibussowitsch 128a4af0ceeSJacob Faibussowitsch .seealso: PetscDevice, PetscDeviceCreate(), PetscDeviceConfigure(), PetscDeviceView() 129030f984aSJacob Faibussowitsch @*/ 130030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceDestroy(PetscDevice *device) 131030f984aSJacob Faibussowitsch { 132030f984aSJacob Faibussowitsch PetscErrorCode ierr; 133030f984aSJacob Faibussowitsch 134a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 135a4af0ceeSJacob Faibussowitsch if (!*device) PetscFunctionReturn(0); 136a4af0ceeSJacob Faibussowitsch PetscValidDevice(*device,1); 137a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceDereference_Internal(*device);CHKERRQ(ierr); 138a4af0ceeSJacob Faibussowitsch if ((*device)->refcnt) { 139a4af0ceeSJacob Faibussowitsch *device = PETSC_NULLPTR; 140a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 141030f984aSJacob Faibussowitsch } 142a4af0ceeSJacob Faibussowitsch ierr = PetscFree((*device)->data);CHKERRQ(ierr); 143a4af0ceeSJacob Faibussowitsch ierr = PetscFree(*device);CHKERRQ(ierr); 144030f984aSJacob Faibussowitsch PetscFunctionReturn(0); 145030f984aSJacob Faibussowitsch } 146030f984aSJacob Faibussowitsch 147a4af0ceeSJacob Faibussowitsch /*@C 148a4af0ceeSJacob Faibussowitsch PetscDeviceConfigure - Configure a particular PetscDevice 149030f984aSJacob Faibussowitsch 150a4af0ceeSJacob Faibussowitsch Not Collective, Asynchronous 151a4af0ceeSJacob Faibussowitsch 152a4af0ceeSJacob Faibussowitsch Input Parameter: 153a4af0ceeSJacob Faibussowitsch . device - The PetscDevice to configure 154a4af0ceeSJacob Faibussowitsch 155a4af0ceeSJacob Faibussowitsch Notes: 156a4af0ceeSJacob Faibussowitsch The user should not assume that this is a cheap operation 157a4af0ceeSJacob Faibussowitsch 158a4af0ceeSJacob Faibussowitsch Level: beginner 159a4af0ceeSJacob Faibussowitsch 160a4af0ceeSJacob Faibussowitsch .seealso: PetscDevice, PetscDeviceCreate(), PetscDeviceView(), PetscDeviceDestroy() 161a4af0ceeSJacob Faibussowitsch @*/ 162a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceConfigure(PetscDevice device) 163030f984aSJacob Faibussowitsch { 164030f984aSJacob Faibussowitsch PetscErrorCode ierr; 165030f984aSJacob Faibussowitsch 166030f984aSJacob Faibussowitsch PetscFunctionBegin; 167a4af0ceeSJacob Faibussowitsch PetscValidDevice(device,1); 168a4af0ceeSJacob Faibussowitsch if (PetscDefined(USE_DEBUG)) { 169a4af0ceeSJacob Faibussowitsch /* if no available configuration is available, this cascades all the way down to default 170a4af0ceeSJacob Faibussowitsch and error */ 171a4af0ceeSJacob Faibussowitsch switch (device->type) { 172a4af0ceeSJacob Faibussowitsch case PETSC_DEVICE_CUDA: if (PetscDefined(HAVE_CUDA)) break; 173a4af0ceeSJacob Faibussowitsch case PETSC_DEVICE_HIP: if (PetscDefined(HAVE_HIP)) break; 174*a2158755SJunchao Zhang case PETSC_DEVICE_SYCL: if (PetscDefined(HAVE_SYCL)) break; 175a4af0ceeSJacob Faibussowitsch default: 176a4af0ceeSJacob Faibussowitsch PETSC_DEVICE_DEFAULT_CASE(PETSC_COMM_SELF,device->type); 177a4af0ceeSJacob Faibussowitsch break; 178a4af0ceeSJacob Faibussowitsch } 179a4af0ceeSJacob Faibussowitsch } 180a4af0ceeSJacob Faibussowitsch ierr = (*device->ops->configure)(device);CHKERRQ(ierr); 181a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 182a4af0ceeSJacob Faibussowitsch } 183a4af0ceeSJacob Faibussowitsch 184a4af0ceeSJacob Faibussowitsch /*@C 185a4af0ceeSJacob Faibussowitsch PetscDeviceView - View a PetscDevice 186a4af0ceeSJacob Faibussowitsch 187a4af0ceeSJacob Faibussowitsch Collective on viewer, Asynchronous 188a4af0ceeSJacob Faibussowitsch 189a4af0ceeSJacob Faibussowitsch Input Parameter: 190050c0c3dSJacob Faibussowitsch + device - The PetscDevice to view 191a4af0ceeSJacob Faibussowitsch - viewer - The PetscViewer to view the device with (NULL for PETSC_VIEWER_STDOUT_WORLD) 192a4af0ceeSJacob Faibussowitsch 193a4af0ceeSJacob Faibussowitsch Level: beginner 194a4af0ceeSJacob Faibussowitsch 195a4af0ceeSJacob Faibussowitsch .seealso: PetscDevice, PetscDeviceCreate(), PetscDeviceConfigure(), PetscDeviceDestroy() 196a4af0ceeSJacob Faibussowitsch @*/ 197a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceView(PetscDevice device, PetscViewer viewer) 198a4af0ceeSJacob Faibussowitsch { 199a4af0ceeSJacob Faibussowitsch PetscErrorCode ierr; 200a4af0ceeSJacob Faibussowitsch 201a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 202a4af0ceeSJacob Faibussowitsch PetscValidDevice(device,1); 203a4af0ceeSJacob Faibussowitsch if (!viewer) {ierr = PetscViewerASCIIGetStdout(PETSC_COMM_WORLD,&viewer);CHKERRQ(ierr);} 204a4af0ceeSJacob Faibussowitsch PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2); 205a4af0ceeSJacob Faibussowitsch ierr = (*device->ops->view)(device,viewer);CHKERRQ(ierr); 206a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 207a4af0ceeSJacob Faibussowitsch } 208a4af0ceeSJacob Faibussowitsch 209a4af0ceeSJacob Faibussowitsch static std::array<bool,PETSC_DEVICE_MAX> initializedDevice = {}; 210a4af0ceeSJacob Faibussowitsch static std::array<PetscDevice,PETSC_DEVICE_MAX> defaultDevices = {}; 211a4af0ceeSJacob Faibussowitsch static_assert(initializedDevice.size() == defaultDevices.size(),""); 212a4af0ceeSJacob Faibussowitsch 213a4af0ceeSJacob Faibussowitsch /*@C 214a4af0ceeSJacob Faibussowitsch PetscDeviceInitialize - Initialize PetscDevice 215a4af0ceeSJacob Faibussowitsch 216a4af0ceeSJacob Faibussowitsch Not Collective, Possibly Synchronous 217a4af0ceeSJacob Faibussowitsch 218a4af0ceeSJacob Faibussowitsch Input Parameter: 219a4af0ceeSJacob Faibussowitsch . type - The PetscDeviceType to initialize 220a4af0ceeSJacob Faibussowitsch 221a4af0ceeSJacob Faibussowitsch Notes: 222a4af0ceeSJacob Faibussowitsch Eagerly initializes the corresponding PetscDeviceType if needed. 223a4af0ceeSJacob Faibussowitsch 224a4af0ceeSJacob Faibussowitsch Level: beginner 225a4af0ceeSJacob Faibussowitsch 226a4af0ceeSJacob Faibussowitsch .seealso: PetscDevice, PetscDeviceInitType, PetscDeviceInitialized(), PetscDeviceCreate(), PetscDeviceDestroy() 227a4af0ceeSJacob Faibussowitsch @*/ 228a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceInitialize(PetscDeviceType type) 229a4af0ceeSJacob Faibussowitsch { 230a4af0ceeSJacob Faibussowitsch PetscErrorCode ierr; 231a4af0ceeSJacob Faibussowitsch 232a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 233a4af0ceeSJacob Faibussowitsch PetscValidDeviceType(type,1); 234a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceInitializeDefaultDevice_Internal(type,PETSC_DECIDE);CHKERRQ(ierr); 235a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 236a4af0ceeSJacob Faibussowitsch } 237a4af0ceeSJacob Faibussowitsch 238a4af0ceeSJacob Faibussowitsch /*@C 239a4af0ceeSJacob Faibussowitsch PetscDeviceInitialized - Determines whether PetscDevice is initialized for a particular 240a4af0ceeSJacob Faibussowitsch PetscDeviceType 241a4af0ceeSJacob Faibussowitsch 242a4af0ceeSJacob Faibussowitsch Not Collective, Asynchronous 243a4af0ceeSJacob Faibussowitsch 244a4af0ceeSJacob Faibussowitsch Input Parameter: 245a4af0ceeSJacob Faibussowitsch . type - The PetscDeviceType to check 246a4af0ceeSJacob Faibussowitsch 247a4af0ceeSJacob Faibussowitsch Output Parameter: 248a4af0ceeSJacob Faibussowitsch . [return value] - PETSC_TRUE if type is initialized, PETSC_FALSE otherwise 249a4af0ceeSJacob Faibussowitsch 250a4af0ceeSJacob Faibussowitsch Notes: 251a4af0ceeSJacob Faibussowitsch If one has not configured PETSc for a particular PetscDeviceType then this routine will 252a4af0ceeSJacob Faibussowitsch return PETSC_FALSE for that PetscDeviceType. 253a4af0ceeSJacob Faibussowitsch 254a4af0ceeSJacob Faibussowitsch Level: beginner 255a4af0ceeSJacob Faibussowitsch 256a4af0ceeSJacob Faibussowitsch .seealso: PetscDevice, PetscDeviceInitType, PetscDeviceInitialize(), PetscDeviceCreate(), PetscDeviceDestroy() 257a4af0ceeSJacob Faibussowitsch @*/ 258a4af0ceeSJacob Faibussowitsch PetscBool PetscDeviceInitialized(PetscDeviceType type) 259a4af0ceeSJacob Faibussowitsch { 260a4af0ceeSJacob Faibussowitsch return static_cast<PetscBool>(PetscDeviceConfiguredFor_Internal(type) && initializedDevice[type]); 261a4af0ceeSJacob Faibussowitsch } 262a4af0ceeSJacob Faibussowitsch 263a4af0ceeSJacob Faibussowitsch /* Actual intialization function; any functions claiming to initialize PetscDevice or 264a4af0ceeSJacob Faibussowitsch * PetscDeviceContext will have to run through this one */ 265a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceInitializeDefaultDevice_Internal(PetscDeviceType type, PetscInt defaultDeviceId) 266a4af0ceeSJacob Faibussowitsch { 267a4af0ceeSJacob Faibussowitsch PetscErrorCode ierr; 268a4af0ceeSJacob Faibussowitsch 269a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 270a4af0ceeSJacob Faibussowitsch PetscValidDeviceType(type,1); 271a4af0ceeSJacob Faibussowitsch if (PetscLikely(PetscDeviceInitialized(type))) PetscFunctionReturn(0); 272a4af0ceeSJacob Faibussowitsch if (PetscUnlikelyDebug(defaultDevices[type])) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_MEM,"Trying to overwrite existing default device of type %s",PetscDeviceTypes[type]); 273a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceCreate(type,defaultDeviceId,&defaultDevices[type]);CHKERRQ(ierr); 274a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceConfigure(defaultDevices[type]);CHKERRQ(ierr); 275030f984aSJacob Faibussowitsch /* the default devices are all automatically "referenced" at least once, otherwise the 276a4af0ceeSJacob Faibussowitsch * reference counting is off for them. We could alternatively increase the reference count 277a4af0ceeSJacob Faibussowitsch * when they are retrieved but that is a lot more brittle; what's to stop someone from doing 278a4af0ceeSJacob Faibussowitsch * the following? 279030f984aSJacob Faibussowitsch 280030f984aSJacob Faibussowitsch for (int i = 0; i < 10000; ++i) auto device = PetscDeviceDefault_Internal(); 281030f984aSJacob Faibussowitsch */ 282a4af0ceeSJacob Faibussowitsch initializedDevice[type] = true; 283a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 284a4af0ceeSJacob Faibussowitsch } 285a4af0ceeSJacob Faibussowitsch 286a4af0ceeSJacob Faibussowitsch static PetscErrorCode PetscDeviceInitializeTypeFromOptions_Private(MPI_Comm comm, PetscDeviceType type, PetscInt defaultDeviceId, PetscBool defaultView, PetscDeviceInitType *defaultInitType) 287a4af0ceeSJacob Faibussowitsch { 288a4af0ceeSJacob Faibussowitsch PetscErrorCode ierr; 289a4af0ceeSJacob Faibussowitsch 290a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 291a4af0ceeSJacob Faibussowitsch if (!PetscDeviceConfiguredFor_Internal(type)) { 292a4af0ceeSJacob Faibussowitsch ierr = PetscInfo1(PETSC_NULLPTR,"PetscDeviceType %s not supported\n",PetscDeviceTypes[type]);CHKERRQ(ierr); 293a4af0ceeSJacob Faibussowitsch defaultDevices[type] = PETSC_NULLPTR; 294a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 295a4af0ceeSJacob Faibussowitsch } 296a4af0ceeSJacob Faibussowitsch ierr = PetscInfo1(PETSC_NULLPTR,"PetscDeviceType %s supported, initializing\n",PetscDeviceTypes[type]);CHKERRQ(ierr); 297a4af0ceeSJacob Faibussowitsch /* ugly switch needed to pick the right global variable... could maybe do this as a union? */ 298a4af0ceeSJacob Faibussowitsch switch (type) { 299a4af0ceeSJacob Faibussowitsch PETSC_DEVICE_CASE_IF_PETSC_DEFINED(CUDA,initialize,comm,&defaultDeviceId,defaultInitType); 300a4af0ceeSJacob Faibussowitsch PETSC_DEVICE_CASE_IF_PETSC_DEFINED(HIP,initialize,comm,&defaultDeviceId,defaultInitType); 301*a2158755SJunchao Zhang PETSC_DEVICE_CASE_IF_PETSC_DEFINED(SYCL,initialize,comm,&defaultDeviceId,defaultInitType); 302a4af0ceeSJacob Faibussowitsch default: 303a4af0ceeSJacob Faibussowitsch PETSC_DEVICE_DEFAULT_CASE(comm,type); 304a4af0ceeSJacob Faibussowitsch break; 305a4af0ceeSJacob Faibussowitsch } 306a4af0ceeSJacob Faibussowitsch /* defaultInitType and defaultDeviceId now represent what the individual TYPES have decided 307a4af0ceeSJacob Faibussowitsch * to initialize as */ 308a4af0ceeSJacob Faibussowitsch if (*defaultInitType == PETSC_DEVICE_INIT_EAGER) { 309a4af0ceeSJacob Faibussowitsch ierr = PetscInfo1(PETSC_NULLPTR,"Greedily initializing %s PetscDevice\n",PetscDeviceTypes[type]);CHKERRQ(ierr); 310a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceInitializeDefaultDevice_Internal(type,defaultDeviceId);CHKERRQ(ierr); 311a4af0ceeSJacob Faibussowitsch if (defaultView) { 312a4af0ceeSJacob Faibussowitsch PetscViewer vwr; 313a4af0ceeSJacob Faibussowitsch 314a4af0ceeSJacob Faibussowitsch ierr = PetscViewerASCIIGetStdout(comm,&vwr);CHKERRQ(ierr); 315a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceView(defaultDevices[type],vwr);CHKERRQ(ierr); 316a4af0ceeSJacob Faibussowitsch } 317030f984aSJacob Faibussowitsch } 318030f984aSJacob Faibussowitsch PetscFunctionReturn(0); 319030f984aSJacob Faibussowitsch } 320030f984aSJacob Faibussowitsch 321030f984aSJacob Faibussowitsch /* called from PetscFinalize() do not call yourself! */ 322a4af0ceeSJacob Faibussowitsch static PetscErrorCode PetscDeviceFinalize_Private(void) 323030f984aSJacob Faibussowitsch { 324030f984aSJacob Faibussowitsch PetscErrorCode ierr; 325030f984aSJacob Faibussowitsch 326030f984aSJacob Faibussowitsch PetscFunctionBegin; 327a4af0ceeSJacob Faibussowitsch if (PetscDefined(USE_DEBUG)) { 328050c0c3dSJacob Faibussowitsch PETSC_CONSTEXPR_17 auto PetscDeviceCheckAllDestroyedAfterFinalize = [](){ 329a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 330a4af0ceeSJacob Faibussowitsch for (const auto &device : defaultDevices) { 3313ca90d2dSJacob 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); 332a4af0ceeSJacob Faibussowitsch } 333a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 334a4af0ceeSJacob Faibussowitsch }; 335a4af0ceeSJacob Faibussowitsch /* you might be thinking, why on earth are you registered yet another finalizer in a 336a4af0ceeSJacob Faibussowitsch * function already called during PetscRegisterFinalizeAll()? If this seems stupid it's 337a4af0ceeSJacob Faibussowitsch * because it is. 338a4af0ceeSJacob Faibussowitsch * 339a4af0ceeSJacob Faibussowitsch * The crux of the problem is that the initializer (and therefore the ~finalizer~) of 340a4af0ceeSJacob Faibussowitsch * PetscDeviceContext is guaranteed to run after this finalizer. So if the global context 341a4af0ceeSJacob Faibussowitsch * had a default PetscDevice attached it will hold a reference this routine won't destroy 342a4af0ceeSJacob Faibussowitsch * it. So we need to check that all devices have been destroyed after the global context is 343a4af0ceeSJacob Faibussowitsch * destroyed. In summary: 344a4af0ceeSJacob Faibussowitsch * 345a4af0ceeSJacob Faibussowitsch * 1. This finalizer runs and destroys all devices, except it may not because the global 346a4af0ceeSJacob Faibussowitsch * context may still hold a reference! 347a4af0ceeSJacob Faibussowitsch * 2. The global context finalizer runs and in turn actually destroys the referenced 348a4af0ceeSJacob Faibussowitsch * device. 349a4af0ceeSJacob Faibussowitsch * 3. Our newly added finalizer runs and checks that all is well. 350a4af0ceeSJacob Faibussowitsch */ 351a4af0ceeSJacob Faibussowitsch ierr = PetscRegisterFinalize(PetscDeviceCheckAllDestroyedAfterFinalize);CHKERRQ(ierr); 352a4af0ceeSJacob Faibussowitsch } 353a4af0ceeSJacob Faibussowitsch for (auto &&device : defaultDevices) {ierr = PetscDeviceDestroy(&device);CHKERRQ(ierr);} 354a4af0ceeSJacob Faibussowitsch CHKERRCXX(initializedDevice.fill(false)); 355030f984aSJacob Faibussowitsch PetscFunctionReturn(0); 356030f984aSJacob Faibussowitsch } 357030f984aSJacob Faibussowitsch 358a4af0ceeSJacob Faibussowitsch /* begins the init proceeedings for the entire PetscDevice stack. there are 3 stages of 359a4af0ceeSJacob Faibussowitsch * initialization types: 360a4af0ceeSJacob Faibussowitsch 1. defaultInitType - how does PetscDevice as a whole expect to initialize? 361a4af0ceeSJacob Faibussowitsch 2. subTypeDefaultInitType - how does each PetscDevice implementation expect to initialize? 362a4af0ceeSJacob Faibussowitsch e.g. you may want to blanket disable PetscDevice init (and disable say Kokkos init), but 363a4af0ceeSJacob Faibussowitsch have all CUDA devices still initialize. 364a4af0ceeSJacob Faibussowitsch 365a4af0ceeSJacob Faibussowitsch All told the following happens: 366a4af0ceeSJacob Faibussowitsch 0. defaultInitType -> LAZY 367a4af0ceeSJacob Faibussowitsch 1. Check for log_view/log_summary, if yes defaultInitType -> EAGER 368a4af0ceeSJacob Faibussowitsch 2. PetscDevice initializes each sub type with deviceDefaultInitType. 369a4af0ceeSJacob Faibussowitsch 2.1 Each enabled PetscDevice sub-type then does the above disable or view check in addition 370a4af0ceeSJacob Faibussowitsch to checking for specific device init. if view or specific device init 371a4af0ceeSJacob Faibussowitsch subTypeDefaultInitType -> EAGER. disabled once again overrides all. 372a4af0ceeSJacob Faibussowitsch */ 373a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceInitializeFromOptions_Internal(MPI_Comm comm) 374030f984aSJacob Faibussowitsch { 375a4af0ceeSJacob Faibussowitsch PetscBool flg,defaultView = PETSC_FALSE,initializeDeviceContextEagerly = PETSC_FALSE; 376a4af0ceeSJacob Faibussowitsch PetscInt defaultDevice = PETSC_DECIDE; 377a4af0ceeSJacob Faibussowitsch PetscDeviceType deviceContextInitDevice = PETSC_DEVICE_DEFAULT; 378a4af0ceeSJacob Faibussowitsch PetscDeviceInitType defaultInitType; 379a4af0ceeSJacob Faibussowitsch PetscErrorCode ierr; 380a4af0ceeSJacob Faibussowitsch 381a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 382a4af0ceeSJacob Faibussowitsch if (PetscDefined(USE_DEBUG)) { 383a4af0ceeSJacob Faibussowitsch int result; 384a4af0ceeSJacob Faibussowitsch 385a4af0ceeSJacob Faibussowitsch ierr = MPI_Comm_compare(comm,PETSC_COMM_WORLD,&result);CHKERRMPI(ierr); 386a4af0ceeSJacob Faibussowitsch /* in order to accurately assign ranks to gpus we need to get the MPI_Comm_rank of the 387a4af0ceeSJacob Faibussowitsch * global space */ 388a4af0ceeSJacob Faibussowitsch if (PetscUnlikely(result != MPI_IDENT)) { 389a4af0ceeSJacob Faibussowitsch char name[MPI_MAX_OBJECT_NAME] = {}; 390a4af0ceeSJacob Faibussowitsch int len; /* unused */ 391a4af0ceeSJacob Faibussowitsch 392a4af0ceeSJacob Faibussowitsch ierr = MPI_Comm_get_name(comm,name,&len);CHKERRMPI(ierr); 393a4af0ceeSJacob Faibussowitsch SETERRQ1(comm,PETSC_ERR_MPI,"Default devices being initialized on MPI_Comm '%s' not PETSC_COMM_WORLD",name); 394a4af0ceeSJacob Faibussowitsch } 395a4af0ceeSJacob Faibussowitsch } 396a4af0ceeSJacob Faibussowitsch comm = PETSC_COMM_WORLD; /* from this point on we assume we're on PETSC_COMM_WORLD */ 397a4af0ceeSJacob Faibussowitsch ierr = PetscRegisterFinalize(PetscDeviceFinalize_Private);CHKERRQ(ierr); 398a4af0ceeSJacob Faibussowitsch ierr = PetscOptionsHasName(PETSC_NULLPTR,PETSC_NULLPTR,"-log_view",&flg);CHKERRQ(ierr); 399a4af0ceeSJacob Faibussowitsch if (!flg) { 400a4af0ceeSJacob Faibussowitsch ierr = PetscOptionsHasName(PETSC_NULLPTR,PETSC_NULLPTR,"-log_summary",&flg);CHKERRQ(ierr); 401a4af0ceeSJacob Faibussowitsch } 402a4af0ceeSJacob Faibussowitsch { 403a4af0ceeSJacob Faibussowitsch PetscInt initIdx = flg ? PETSC_DEVICE_INIT_EAGER : PETSC_DEVICE_INIT_LAZY; 404a4af0ceeSJacob Faibussowitsch 405a4af0ceeSJacob Faibussowitsch ierr = PetscOptionsBegin(comm,PETSC_NULLPTR,"PetscDevice Options","Sys");CHKERRQ(ierr); 406a4af0ceeSJacob Faibussowitsch ierr = PetscOptionsEList("-device_enable","How (or whether) to initialize PetscDevices","PetscDeviceInitializeFromOptions_Internal()",PetscDeviceInitTypes,3,PetscDeviceInitTypes[initIdx],&initIdx,PETSC_NULLPTR);CHKERRQ(ierr); 407a4af0ceeSJacob 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); 408a4af0ceeSJacob Faibussowitsch ierr = PetscOptionsBool("-device_view","Display device information and assignments (forces eager initialization)",PETSC_NULLPTR,defaultView,&defaultView,&flg);CHKERRQ(ierr); 409a4af0ceeSJacob Faibussowitsch ierr = PetscOptionsEnd();CHKERRQ(ierr); 410a4af0ceeSJacob Faibussowitsch if (initIdx == PETSC_DEVICE_INIT_NONE) { 411a4af0ceeSJacob Faibussowitsch /* disabled all device initialization if devices are globally disabled */ 412a4af0ceeSJacob 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"); 413a4af0ceeSJacob Faibussowitsch defaultView = PETSC_FALSE; 414a4af0ceeSJacob Faibussowitsch } else { 415a4af0ceeSJacob Faibussowitsch defaultView = static_cast<decltype(defaultView)>(defaultView && flg); 416a4af0ceeSJacob Faibussowitsch if (defaultView) initIdx = PETSC_DEVICE_INIT_EAGER; 417a4af0ceeSJacob Faibussowitsch } 418a4af0ceeSJacob Faibussowitsch defaultInitType = static_cast<decltype(defaultInitType)>(initIdx); 419a4af0ceeSJacob Faibussowitsch } 420a4af0ceeSJacob Faibussowitsch static_assert((PETSC_DEVICE_INVALID == 0) && (PETSC_DEVICE_MAX < std::numeric_limits<int>::max()),""); 421a4af0ceeSJacob Faibussowitsch for (int i = 1; i < PETSC_DEVICE_MAX; ++i) { 422a4af0ceeSJacob Faibussowitsch const auto deviceType = static_cast<PetscDeviceType>(i); 423a4af0ceeSJacob Faibussowitsch auto initType = defaultInitType; 424a4af0ceeSJacob Faibussowitsch 425a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceInitializeTypeFromOptions_Private(comm,deviceType,defaultDevice,defaultView,&initType);CHKERRQ(ierr); 426a4af0ceeSJacob Faibussowitsch if (PetscDeviceConfiguredFor_Internal(deviceType) && (initType == PETSC_DEVICE_INIT_EAGER)) { 427a4af0ceeSJacob Faibussowitsch initializeDeviceContextEagerly = PETSC_TRUE; 428a4af0ceeSJacob Faibussowitsch deviceContextInitDevice = deviceType; 429a4af0ceeSJacob Faibussowitsch } 430a4af0ceeSJacob Faibussowitsch } 431a4af0ceeSJacob Faibussowitsch if (initializeDeviceContextEagerly) { 432a4af0ceeSJacob Faibussowitsch PetscDeviceContext dctx; 433a4af0ceeSJacob Faibussowitsch 434a4af0ceeSJacob Faibussowitsch /* somewhat inefficient here as the device context is potentially fully set up twice (once 435a4af0ceeSJacob Faibussowitsch * when retrieved then the second time if setfromoptions makes changes) */ 436a4af0ceeSJacob Faibussowitsch ierr = PetscInfo1(PETSC_NULLPTR,"Eagerly initializing PetscDeviceContext with %s device\n",PetscDeviceTypes[deviceContextInitDevice]);CHKERRQ(ierr); 437a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceContextSetRootDeviceType_Internal(deviceContextInitDevice);CHKERRQ(ierr); 438a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceContextGetCurrentContext(&dctx);CHKERRQ(ierr); 439a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceContextSetFromOptions(comm,"root_",dctx);CHKERRQ(ierr); 440a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceContextSetUp(dctx);CHKERRQ(ierr); 441a4af0ceeSJacob Faibussowitsch } 442a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 443a4af0ceeSJacob Faibussowitsch } 444a4af0ceeSJacob Faibussowitsch 445a4af0ceeSJacob Faibussowitsch /* Get the default PetscDevice for a particular type and constructs them if lazily initialized. */ 446a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceGetDefaultForType_Internal(PetscDeviceType type, PetscDevice *device) 447a4af0ceeSJacob Faibussowitsch { 448a4af0ceeSJacob Faibussowitsch PetscErrorCode ierr; 449a4af0ceeSJacob Faibussowitsch 450a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 451a4af0ceeSJacob Faibussowitsch PetscValidPointer(device,2); 452a4af0ceeSJacob Faibussowitsch ierr = PetscDeviceInitialize(type);CHKERRQ(ierr); 453a4af0ceeSJacob Faibussowitsch *device = defaultDevices[type]; 454a4af0ceeSJacob Faibussowitsch PetscFunctionReturn(0); 455030f984aSJacob Faibussowitsch } 456