xref: /petsc/src/sys/objects/device/interface/device.cxx (revision a215875508625ca78920da261755e35d40bb5865)
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