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