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