xref: /petsc/src/sys/objects/device/interface/device.cxx (revision 91e63d38360eb9bc922f79d792328cc4769c01ac)
1030f984aSJacob Faibussowitsch #include "cupmdevice.hpp" /* I "petscdevice.h" */
217f48955SJacob Faibussowitsch #include <petsc/private/petscadvancedmacros.h>
3030f984aSJacob Faibussowitsch 
417f48955SJacob Faibussowitsch using namespace Petsc::Device;
5030f984aSJacob Faibussowitsch 
6cf3a2253SJacob Faibussowitsch /*
7cf3a2253SJacob Faibussowitsch   note to anyone adding more classes, the name must be ALL_CAPS_SHORT_NAME + Device exactly to
8cf3a2253SJacob Faibussowitsch   be picked up by the switch-case macros below
9cf3a2253SJacob Faibussowitsch */
10030f984aSJacob Faibussowitsch #if PetscDefined(HAVE_CUDA)
1117f48955SJacob Faibussowitsch static CUPM::Device<CUPM::DeviceType::CUDA> CUDADevice(PetscDeviceContextCreate_CUDA);
12030f984aSJacob Faibussowitsch #endif
13030f984aSJacob Faibussowitsch #if PetscDefined(HAVE_HIP)
1417f48955SJacob Faibussowitsch static CUPM::Device<CUPM::DeviceType::HIP>  HIPDevice(PetscDeviceContextCreate_HIP);
15030f984aSJacob Faibussowitsch #endif
16a2158755SJunchao Zhang #if PetscDefined(HAVE_SYCL)
17a2158755SJunchao Zhang #include "sycldevice.hpp"
1817f48955SJacob Faibussowitsch static SYCL::Device                         SYCLDevice(PetscDeviceContextCreate_SYCL);
19a2158755SJunchao Zhang #endif
20030f984aSJacob Faibussowitsch 
2117f48955SJacob Faibussowitsch static_assert(Petsc::util::integral_value(PETSC_DEVICE_INVALID) == 0,"");
2217f48955SJacob Faibussowitsch static_assert(Petsc::util::integral_value(PETSC_DEVICE_CUDA)    == 1,"");
2317f48955SJacob Faibussowitsch static_assert(Petsc::util::integral_value(PETSC_DEVICE_HIP)     == 2,"");
2417f48955SJacob Faibussowitsch static_assert(Petsc::util::integral_value(PETSC_DEVICE_SYCL)    == 3,"");
2517f48955SJacob Faibussowitsch static_assert(Petsc::util::integral_value(PETSC_DEVICE_MAX)     == 4,"");
26a4af0ceeSJacob Faibussowitsch const char *const PetscDeviceTypes[] = {
27a4af0ceeSJacob Faibussowitsch   "invalid",
28a4af0ceeSJacob Faibussowitsch   "cuda",
29a4af0ceeSJacob Faibussowitsch   "hip",
30a2158755SJunchao Zhang   "sycl",
31a4af0ceeSJacob Faibussowitsch   "max",
32a4af0ceeSJacob Faibussowitsch   "PetscDeviceType",
33a4af0ceeSJacob Faibussowitsch   "PETSC_DEVICE_",
34a4af0ceeSJacob Faibussowitsch   PETSC_NULLPTR
35a4af0ceeSJacob Faibussowitsch };
36a4af0ceeSJacob Faibussowitsch 
3717f48955SJacob Faibussowitsch static_assert(Petsc::util::integral_value(PETSC_DEVICE_INIT_NONE)  == 0,"");
3817f48955SJacob Faibussowitsch static_assert(Petsc::util::integral_value(PETSC_DEVICE_INIT_LAZY)  == 1,"");
3917f48955SJacob Faibussowitsch static_assert(Petsc::util::integral_value(PETSC_DEVICE_INIT_EAGER) == 2,"");
40a4af0ceeSJacob Faibussowitsch const char *const PetscDeviceInitTypes[] = {
41a4af0ceeSJacob Faibussowitsch   "none",
42a4af0ceeSJacob Faibussowitsch   "lazy",
43a4af0ceeSJacob Faibussowitsch   "eager",
44a4af0ceeSJacob Faibussowitsch   "PetscDeviceInitType",
45a4af0ceeSJacob Faibussowitsch   "PETSC_DEVICE_INIT_",
46a4af0ceeSJacob Faibussowitsch   PETSC_NULLPTR
47a4af0ceeSJacob Faibussowitsch };
48a4af0ceeSJacob Faibussowitsch static_assert(
49a4af0ceeSJacob Faibussowitsch   sizeof(PetscDeviceInitTypes)/sizeof(*PetscDeviceInitTypes) == 6,
50a4af0ceeSJacob Faibussowitsch   "Must change CUPMDevice<T>::initialize number of enum values in -device_enable_cupm to match!"
51a4af0ceeSJacob Faibussowitsch );
52a4af0ceeSJacob Faibussowitsch 
5317f48955SJacob Faibussowitsch #define PETSC_DEVICE_CASE(IMPLS,func,...)                                     \
5417f48955SJacob Faibussowitsch   case PetscConcat_(PETSC_DEVICE_,IMPLS): {                                   \
5517f48955SJacob Faibussowitsch     auto ierr_ = PetscConcat_(IMPLS,Device).func(__VA_ARGS__);CHKERRQ(ierr_); \
5617f48955SJacob Faibussowitsch   } break
57a4af0ceeSJacob Faibussowitsch 
58cf3a2253SJacob Faibussowitsch /*
59cf3a2253SJacob Faibussowitsch   Suppose you have:
60cf3a2253SJacob Faibussowitsch 
61cf3a2253SJacob Faibussowitsch   CUDADevice.myFunction(arg1,arg2)
62cf3a2253SJacob Faibussowitsch 
63cf3a2253SJacob Faibussowitsch   that you would like to conditionally define and call in a switch-case:
64cf3a2253SJacob Faibussowitsch 
65cf3a2253SJacob Faibussowitsch   switch(PetscDeviceType) {
66cf3a2253SJacob Faibussowitsch   #if PetscDefined(HAVE_CUDA)
67cf3a2253SJacob Faibussowitsch   case PETSC_DEVICE_CUDA: {
68cf3a2253SJacob Faibussowitsch     auto ierr = CUDADevice.myFunction(arg1,arg2);CHKERRQ(ierr);
69cf3a2253SJacob Faibussowitsch   } break;
70cf3a2253SJacob Faibussowitsch   #endif
71cf3a2253SJacob Faibussowitsch   }
72cf3a2253SJacob Faibussowitsch 
73cf3a2253SJacob Faibussowitsch   then calling this macro:
74cf3a2253SJacob Faibussowitsch 
75cf3a2253SJacob Faibussowitsch   PETSC_DEVICE_CASE_IF_PETSC_DEFINED(CUDA,myFunction,arg1,arg2)
76cf3a2253SJacob Faibussowitsch 
77cf3a2253SJacob Faibussowitsch   will expand to the following case statement:
78cf3a2253SJacob Faibussowitsch 
79cf3a2253SJacob Faibussowitsch   case PETSC_DEVICE_CUDA: {
80cf3a2253SJacob Faibussowitsch     auto ierr = CUDADevice.myFunction(arg1,arg2);CHKERRQ(ierr);
81cf3a2253SJacob Faibussowitsch   } break
82cf3a2253SJacob Faibussowitsch 
83cf3a2253SJacob Faibussowitsch   if PetscDefined(HAVE_CUDA) evaluates to 1, and expand to nothing otherwise
8417f48955SJacob Faibussowitsch */
8517f48955SJacob Faibussowitsch #define PETSC_DEVICE_CASE_IF_PETSC_DEFINED(IMPLS,func,...)                                     \
8617f48955SJacob Faibussowitsch   PetscIfPetscDefined(PetscConcat_(HAVE_,IMPLS),PETSC_DEVICE_CASE,PetscExpandToNothing)(IMPLS,func,__VA_ARGS__)
87030f984aSJacob Faibussowitsch 
88030f984aSJacob Faibussowitsch /*@C
89a4af0ceeSJacob Faibussowitsch   PetscDeviceCreate - Get a new handle for a particular device type
90030f984aSJacob Faibussowitsch 
91030f984aSJacob Faibussowitsch   Not Collective, Possibly Synchronous
92030f984aSJacob Faibussowitsch 
93f1a722f8SMatthew G. Knepley   Input Parameters:
94f1a722f8SMatthew G. Knepley + type  - The type of PetscDevice
95f1a722f8SMatthew G. Knepley - devid - The numeric ID# of the device (pass PETSC_DECIDE to assign automatically)
96030f984aSJacob Faibussowitsch 
97030f984aSJacob Faibussowitsch   Output Parameter:
98030f984aSJacob Faibussowitsch . device - The PetscDevice
99030f984aSJacob Faibussowitsch 
100030f984aSJacob Faibussowitsch   Notes:
101a4af0ceeSJacob Faibussowitsch   This routine may initialize PetscDevice. If this is the case, this will most likely cause
102a4af0ceeSJacob Faibussowitsch   some sort of device synchronization.
103a4af0ceeSJacob Faibussowitsch 
104a4af0ceeSJacob Faibussowitsch   devid is what you might pass to cudaSetDevice() for example.
105030f984aSJacob Faibussowitsch 
106030f984aSJacob Faibussowitsch   Level: beginner
107030f984aSJacob Faibussowitsch 
108a4af0ceeSJacob Faibussowitsch .seealso: PetscDevice, PetscDeviceInitType, PetscDeviceInitialize(),
109a4af0ceeSJacob Faibussowitsch PetscDeviceInitialized(), PetscDeviceConfigure(), PetscDeviceView(), PetscDeviceDestroy()
110030f984aSJacob Faibussowitsch @*/
111a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceCreate(PetscDeviceType type, PetscInt devid, PetscDevice *device)
112030f984aSJacob Faibussowitsch {
113030f984aSJacob Faibussowitsch   static PetscInt PetscDeviceCounter = 0;
114030f984aSJacob Faibussowitsch   PetscDevice     dev;
115030f984aSJacob Faibussowitsch   PetscErrorCode  ierr;
116030f984aSJacob Faibussowitsch 
117030f984aSJacob Faibussowitsch   PetscFunctionBegin;
118a4af0ceeSJacob Faibussowitsch   PetscValidDeviceType(type,1);
119a4af0ceeSJacob Faibussowitsch   PetscValidPointer(device,3);
120a4af0ceeSJacob Faibussowitsch   ierr = PetscDeviceInitializePackage();CHKERRQ(ierr);
121030f984aSJacob Faibussowitsch   ierr = PetscNew(&dev);CHKERRQ(ierr);
122030f984aSJacob Faibussowitsch   dev->id     = PetscDeviceCounter++;
123a4af0ceeSJacob Faibussowitsch   dev->type   = type;
124a4af0ceeSJacob Faibussowitsch   dev->refcnt = 1;
125cf3a2253SJacob Faibussowitsch   /*
126cf3a2253SJacob Faibussowitsch     if you are adding a device, you also need to add it's initialization in
127cf3a2253SJacob Faibussowitsch     PetscDeviceInitializeTypeFromOptions_Private() below
128cf3a2253SJacob Faibussowitsch   */
129a4af0ceeSJacob Faibussowitsch   switch (type) {
130a4af0ceeSJacob Faibussowitsch     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(CUDA,getDevice,dev,devid);
131a4af0ceeSJacob Faibussowitsch     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(HIP,getDevice,dev,devid);
132a2158755SJunchao Zhang     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(SYCL,getDevice,dev,devid);
133030f984aSJacob Faibussowitsch   default:
13417f48955SJacob Faibussowitsch     /* in case the above macros expand to nothing this silences any unused variable warnings */
13517f48955SJacob Faibussowitsch     (void)(devid);
13698921bdaSJacob Faibussowitsch     SETERRQ(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]);
137030f984aSJacob Faibussowitsch   }
138030f984aSJacob Faibussowitsch   *device = dev;
139030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
140030f984aSJacob Faibussowitsch }
141030f984aSJacob Faibussowitsch 
142030f984aSJacob Faibussowitsch /*@C
143030f984aSJacob Faibussowitsch   PetscDeviceDestroy - Free a PetscDevice
144030f984aSJacob Faibussowitsch 
145030f984aSJacob Faibussowitsch   Not Collective, Asynchronous
146030f984aSJacob Faibussowitsch 
147030f984aSJacob Faibussowitsch   Input Parameter:
148030f984aSJacob Faibussowitsch . device - The PetscDevice
149030f984aSJacob Faibussowitsch 
150030f984aSJacob Faibussowitsch   Level: beginner
151030f984aSJacob Faibussowitsch 
152a4af0ceeSJacob Faibussowitsch .seealso: PetscDevice, PetscDeviceCreate(), PetscDeviceConfigure(), PetscDeviceView()
153030f984aSJacob Faibussowitsch @*/
154030f984aSJacob Faibussowitsch PetscErrorCode PetscDeviceDestroy(PetscDevice *device)
155030f984aSJacob Faibussowitsch {
156030f984aSJacob Faibussowitsch   PetscErrorCode ierr;
157030f984aSJacob Faibussowitsch 
158a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
159a4af0ceeSJacob Faibussowitsch   if (!*device) PetscFunctionReturn(0);
160a4af0ceeSJacob Faibussowitsch   PetscValidDevice(*device,1);
161a4af0ceeSJacob Faibussowitsch   ierr = PetscDeviceDereference_Internal(*device);CHKERRQ(ierr);
162a4af0ceeSJacob Faibussowitsch   if ((*device)->refcnt) {
163a4af0ceeSJacob Faibussowitsch     *device = PETSC_NULLPTR;
164a4af0ceeSJacob Faibussowitsch     PetscFunctionReturn(0);
165030f984aSJacob Faibussowitsch   }
166a4af0ceeSJacob Faibussowitsch   ierr = PetscFree((*device)->data);CHKERRQ(ierr);
167a4af0ceeSJacob Faibussowitsch   ierr = PetscFree(*device);CHKERRQ(ierr);
168030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
169030f984aSJacob Faibussowitsch }
170030f984aSJacob Faibussowitsch 
171a4af0ceeSJacob Faibussowitsch /*@C
172a4af0ceeSJacob Faibussowitsch   PetscDeviceConfigure - Configure a particular PetscDevice
173030f984aSJacob Faibussowitsch 
174a4af0ceeSJacob Faibussowitsch   Not Collective, Asynchronous
175a4af0ceeSJacob Faibussowitsch 
176a4af0ceeSJacob Faibussowitsch   Input Parameter:
177a4af0ceeSJacob Faibussowitsch . device - The PetscDevice to configure
178a4af0ceeSJacob Faibussowitsch 
179a4af0ceeSJacob Faibussowitsch   Notes:
180a4af0ceeSJacob Faibussowitsch   The user should not assume that this is a cheap operation
181a4af0ceeSJacob Faibussowitsch 
182a4af0ceeSJacob Faibussowitsch   Level: beginner
183a4af0ceeSJacob Faibussowitsch 
184a4af0ceeSJacob Faibussowitsch .seealso: PetscDevice, PetscDeviceCreate(), PetscDeviceView(), PetscDeviceDestroy()
185a4af0ceeSJacob Faibussowitsch @*/
186a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceConfigure(PetscDevice device)
187030f984aSJacob Faibussowitsch {
188030f984aSJacob Faibussowitsch   PetscErrorCode ierr;
189030f984aSJacob Faibussowitsch 
190030f984aSJacob Faibussowitsch   PetscFunctionBegin;
191a4af0ceeSJacob Faibussowitsch   PetscValidDevice(device,1);
192a4af0ceeSJacob Faibussowitsch   if (PetscDefined(USE_DEBUG)) {
193cf3a2253SJacob Faibussowitsch     /*
194cf3a2253SJacob Faibussowitsch       if no available configuration is available, this cascades all the way down to default
195cf3a2253SJacob Faibussowitsch       and error
196cf3a2253SJacob Faibussowitsch     */
197a4af0ceeSJacob Faibussowitsch     switch (device->type) {
198a4af0ceeSJacob Faibussowitsch     case PETSC_DEVICE_CUDA: if (PetscDefined(HAVE_CUDA)) break;
199a4af0ceeSJacob Faibussowitsch     case PETSC_DEVICE_HIP:  if (PetscDefined(HAVE_HIP))  break;
200a2158755SJunchao Zhang     case PETSC_DEVICE_SYCL: if (PetscDefined(HAVE_SYCL)) break;
201a4af0ceeSJacob Faibussowitsch     default:
20298921bdaSJacob Faibussowitsch       SETERRQ(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]);
203a4af0ceeSJacob Faibussowitsch     }
204a4af0ceeSJacob Faibussowitsch   }
205a4af0ceeSJacob Faibussowitsch   ierr = (*device->ops->configure)(device);CHKERRQ(ierr);
206a4af0ceeSJacob Faibussowitsch   PetscFunctionReturn(0);
207a4af0ceeSJacob Faibussowitsch }
208a4af0ceeSJacob Faibussowitsch 
209a4af0ceeSJacob Faibussowitsch /*@C
210a4af0ceeSJacob Faibussowitsch   PetscDeviceView - View a PetscDevice
211a4af0ceeSJacob Faibussowitsch 
212a4af0ceeSJacob Faibussowitsch   Collective on viewer, Asynchronous
213a4af0ceeSJacob Faibussowitsch 
214*91e63d38SStefano Zampini   Input Parameters:
215050c0c3dSJacob Faibussowitsch + device - The PetscDevice to view
216a4af0ceeSJacob Faibussowitsch - viewer - The PetscViewer to view the device with (NULL for PETSC_VIEWER_STDOUT_WORLD)
217a4af0ceeSJacob Faibussowitsch 
218a4af0ceeSJacob Faibussowitsch   Level: beginner
219a4af0ceeSJacob Faibussowitsch 
220a4af0ceeSJacob Faibussowitsch .seealso: PetscDevice, PetscDeviceCreate(), PetscDeviceConfigure(), PetscDeviceDestroy()
221a4af0ceeSJacob Faibussowitsch @*/
222a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceView(PetscDevice device, PetscViewer viewer)
223a4af0ceeSJacob Faibussowitsch {
224a4af0ceeSJacob Faibussowitsch   PetscErrorCode ierr;
225a4af0ceeSJacob Faibussowitsch 
226a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
227a4af0ceeSJacob Faibussowitsch   PetscValidDevice(device,1);
228a4af0ceeSJacob Faibussowitsch   if (!viewer) {ierr = PetscViewerASCIIGetStdout(PETSC_COMM_WORLD,&viewer);CHKERRQ(ierr);}
229a4af0ceeSJacob Faibussowitsch   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
230a4af0ceeSJacob Faibussowitsch   ierr = (*device->ops->view)(device,viewer);CHKERRQ(ierr);
231a4af0ceeSJacob Faibussowitsch   PetscFunctionReturn(0);
232a4af0ceeSJacob Faibussowitsch }
233a4af0ceeSJacob Faibussowitsch 
234*91e63d38SStefano Zampini /*@C
235*91e63d38SStefano Zampini   PetscDeviceGetDeviceId - Get the device id
236*91e63d38SStefano Zampini 
237*91e63d38SStefano Zampini   Not collective
238*91e63d38SStefano Zampini 
239*91e63d38SStefano Zampini   Input Parameter:
240*91e63d38SStefano Zampini . device - The PetscDevice
241*91e63d38SStefano Zampini 
242*91e63d38SStefano Zampini   Output Parameter:
243*91e63d38SStefano Zampini . id - The device id
244*91e63d38SStefano Zampini 
245*91e63d38SStefano Zampini   Level: beginner
246*91e63d38SStefano Zampini 
247*91e63d38SStefano Zampini .seealso: PetscDevice, PetscDeviceCreate(), PetscDeviceConfigure(), PetscDeviceDestroy()
248*91e63d38SStefano Zampini @*/
249*91e63d38SStefano Zampini PetscErrorCode PetscDeviceGetDeviceId(PetscDevice device, PetscInt *id)
250*91e63d38SStefano Zampini {
251*91e63d38SStefano Zampini   PetscFunctionBegin;
252*91e63d38SStefano Zampini   PetscValidDevice(device,1);
253*91e63d38SStefano Zampini   PetscValidIntPointer(id,2);
254*91e63d38SStefano Zampini   *id = device->deviceId;
255*91e63d38SStefano Zampini   PetscFunctionReturn(0);
256*91e63d38SStefano Zampini }
257*91e63d38SStefano Zampini 
258a4af0ceeSJacob Faibussowitsch static std::array<bool,PETSC_DEVICE_MAX>        initializedDevice = {};
259a4af0ceeSJacob Faibussowitsch static std::array<PetscDevice,PETSC_DEVICE_MAX> defaultDevices    = {};
260a4af0ceeSJacob Faibussowitsch static_assert(initializedDevice.size() == defaultDevices.size(),"");
261a4af0ceeSJacob Faibussowitsch 
262a4af0ceeSJacob Faibussowitsch /*@C
263a4af0ceeSJacob Faibussowitsch   PetscDeviceInitialize - Initialize PetscDevice
264a4af0ceeSJacob Faibussowitsch 
265a4af0ceeSJacob Faibussowitsch   Not Collective, Possibly Synchronous
266a4af0ceeSJacob Faibussowitsch 
267a4af0ceeSJacob Faibussowitsch   Input Parameter:
268a4af0ceeSJacob Faibussowitsch . type - The PetscDeviceType to initialize
269a4af0ceeSJacob Faibussowitsch 
270a4af0ceeSJacob Faibussowitsch   Notes:
271a4af0ceeSJacob Faibussowitsch   Eagerly initializes the corresponding PetscDeviceType if needed.
272a4af0ceeSJacob Faibussowitsch 
273a4af0ceeSJacob Faibussowitsch   Level: beginner
274a4af0ceeSJacob Faibussowitsch 
275a4af0ceeSJacob Faibussowitsch .seealso: PetscDevice, PetscDeviceInitType, PetscDeviceInitialized(), PetscDeviceCreate(), PetscDeviceDestroy()
276a4af0ceeSJacob Faibussowitsch @*/
277a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceInitialize(PetscDeviceType type)
278a4af0ceeSJacob Faibussowitsch {
279a4af0ceeSJacob Faibussowitsch   PetscErrorCode ierr;
280a4af0ceeSJacob Faibussowitsch 
281a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
282a4af0ceeSJacob Faibussowitsch   PetscValidDeviceType(type,1);
283a4af0ceeSJacob Faibussowitsch   ierr = PetscDeviceInitializeDefaultDevice_Internal(type,PETSC_DECIDE);CHKERRQ(ierr);
284a4af0ceeSJacob Faibussowitsch   PetscFunctionReturn(0);
285a4af0ceeSJacob Faibussowitsch }
286a4af0ceeSJacob Faibussowitsch 
287a4af0ceeSJacob Faibussowitsch /*@C
288a4af0ceeSJacob Faibussowitsch   PetscDeviceInitialized - Determines whether PetscDevice is initialized for a particular
289a4af0ceeSJacob Faibussowitsch   PetscDeviceType
290a4af0ceeSJacob Faibussowitsch 
291a4af0ceeSJacob Faibussowitsch   Not Collective, Asynchronous
292a4af0ceeSJacob Faibussowitsch 
293a4af0ceeSJacob Faibussowitsch   Input Parameter:
294a4af0ceeSJacob Faibussowitsch . type - The PetscDeviceType to check
295a4af0ceeSJacob Faibussowitsch 
296a4af0ceeSJacob Faibussowitsch   Output Parameter:
297a4af0ceeSJacob Faibussowitsch . [return value] - PETSC_TRUE if type is initialized, PETSC_FALSE otherwise
298a4af0ceeSJacob Faibussowitsch 
299a4af0ceeSJacob Faibussowitsch   Notes:
300a4af0ceeSJacob Faibussowitsch   If one has not configured PETSc for a particular PetscDeviceType then this routine will
301a4af0ceeSJacob Faibussowitsch   return PETSC_FALSE for that PetscDeviceType.
302a4af0ceeSJacob Faibussowitsch 
303a4af0ceeSJacob Faibussowitsch   Level: beginner
304a4af0ceeSJacob Faibussowitsch 
305a4af0ceeSJacob Faibussowitsch .seealso: PetscDevice, PetscDeviceInitType, PetscDeviceInitialize(), PetscDeviceCreate(), PetscDeviceDestroy()
306a4af0ceeSJacob Faibussowitsch @*/
307a4af0ceeSJacob Faibussowitsch PetscBool PetscDeviceInitialized(PetscDeviceType type)
308a4af0ceeSJacob Faibussowitsch {
309a4af0ceeSJacob Faibussowitsch   return static_cast<PetscBool>(PetscDeviceConfiguredFor_Internal(type) && initializedDevice[type]);
310a4af0ceeSJacob Faibussowitsch }
311a4af0ceeSJacob Faibussowitsch 
312cf3a2253SJacob Faibussowitsch /*
313cf3a2253SJacob Faibussowitsch   Actual intialization function; any functions claiming to initialize PetscDevice or
314cf3a2253SJacob Faibussowitsch   PetscDeviceContext will have to run through this one
315cf3a2253SJacob Faibussowitsch */
316a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceInitializeDefaultDevice_Internal(PetscDeviceType type, PetscInt defaultDeviceId)
317a4af0ceeSJacob Faibussowitsch {
318a4af0ceeSJacob Faibussowitsch   PetscErrorCode ierr;
319a4af0ceeSJacob Faibussowitsch 
320a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
321a4af0ceeSJacob Faibussowitsch   PetscValidDeviceType(type,1);
322a4af0ceeSJacob Faibussowitsch   if (PetscLikely(PetscDeviceInitialized(type))) PetscFunctionReturn(0);
323bf025ffbSJacob Faibussowitsch   PetscAssert(!defaultDevices[type],PETSC_COMM_SELF,PETSC_ERR_MEM,"Trying to overwrite existing default device of type %s",PetscDeviceTypes[type]);
324a4af0ceeSJacob Faibussowitsch   ierr = PetscDeviceCreate(type,defaultDeviceId,&defaultDevices[type]);CHKERRQ(ierr);
325a4af0ceeSJacob Faibussowitsch   ierr = PetscDeviceConfigure(defaultDevices[type]);CHKERRQ(ierr);
326a4af0ceeSJacob Faibussowitsch   initializedDevice[type] = true;
327a4af0ceeSJacob Faibussowitsch   PetscFunctionReturn(0);
328a4af0ceeSJacob Faibussowitsch }
329a4af0ceeSJacob Faibussowitsch 
330ce244043SStefano Zampini #if PetscDefined(USE_LOG)
331ce244043SStefano Zampini PETSC_INTERN PetscErrorCode PetscLogInitialize(void);
332ce244043SStefano Zampini #else
333ce244043SStefano Zampini #define PetscLogInitialize() 0
334ce244043SStefano Zampini #endif
335ce244043SStefano Zampini 
336a4af0ceeSJacob Faibussowitsch static PetscErrorCode PetscDeviceInitializeTypeFromOptions_Private(MPI_Comm comm, PetscDeviceType type, PetscInt defaultDeviceId, PetscBool defaultView, PetscDeviceInitType *defaultInitType)
337a4af0ceeSJacob Faibussowitsch {
338a4af0ceeSJacob Faibussowitsch   PetscErrorCode ierr;
339a4af0ceeSJacob Faibussowitsch 
340a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
341a4af0ceeSJacob Faibussowitsch   if (!PetscDeviceConfiguredFor_Internal(type)) {
3427d3de750SJacob Faibussowitsch     ierr = PetscInfo(PETSC_NULLPTR,"PetscDeviceType %s not supported\n",PetscDeviceTypes[type]);CHKERRQ(ierr);
343a4af0ceeSJacob Faibussowitsch     defaultDevices[type] = PETSC_NULLPTR;
344a4af0ceeSJacob Faibussowitsch     PetscFunctionReturn(0);
345a4af0ceeSJacob Faibussowitsch   }
3467d3de750SJacob Faibussowitsch   ierr = PetscInfo(PETSC_NULLPTR,"PetscDeviceType %s supported, initializing\n",PetscDeviceTypes[type]);CHKERRQ(ierr);
347a4af0ceeSJacob Faibussowitsch   /* ugly switch needed to pick the right global variable... could maybe do this as a union? */
348a4af0ceeSJacob Faibussowitsch   switch (type) {
349a4af0ceeSJacob Faibussowitsch     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(CUDA,initialize,comm,&defaultDeviceId,defaultInitType);
350a4af0ceeSJacob Faibussowitsch     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(HIP,initialize,comm,&defaultDeviceId,defaultInitType);
351a2158755SJunchao Zhang     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(SYCL,initialize,comm,&defaultDeviceId,defaultInitType);
352a4af0ceeSJacob Faibussowitsch   default:
35398921bdaSJacob Faibussowitsch     SETERRQ(comm,PETSC_ERR_PLIB,"PETSc was seemingly configured for PetscDeviceType %s but we've fallen through all cases in a switch",PetscDeviceTypes[type]);
354a4af0ceeSJacob Faibussowitsch   }
355cf3a2253SJacob Faibussowitsch   /*
356cf3a2253SJacob Faibussowitsch     defaultInitType and defaultDeviceId now represent what the individual TYPES have decided to
357cf3a2253SJacob Faibussowitsch     initialize as
358cf3a2253SJacob Faibussowitsch   */
359a4af0ceeSJacob Faibussowitsch   if (*defaultInitType == PETSC_DEVICE_INIT_EAGER) {
3607d3de750SJacob Faibussowitsch     ierr = PetscInfo(PETSC_NULLPTR,"Eagerly initializing %s PetscDevice\n",PetscDeviceTypes[type]);CHKERRQ(ierr);
361a4af0ceeSJacob Faibussowitsch     ierr = PetscDeviceInitializeDefaultDevice_Internal(type,defaultDeviceId);CHKERRQ(ierr);
362a4af0ceeSJacob Faibussowitsch     if (defaultView) {
363a4af0ceeSJacob Faibussowitsch       PetscViewer vwr;
364a4af0ceeSJacob Faibussowitsch 
365ce244043SStefano Zampini       ierr = PetscLogInitialize();CHKERRQ(ierr);
366a4af0ceeSJacob Faibussowitsch       ierr = PetscViewerASCIIGetStdout(comm,&vwr);CHKERRQ(ierr);
367a4af0ceeSJacob Faibussowitsch       ierr = PetscDeviceView(defaultDevices[type],vwr);CHKERRQ(ierr);
368a4af0ceeSJacob Faibussowitsch     }
369030f984aSJacob Faibussowitsch   }
370030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
371030f984aSJacob Faibussowitsch }
372030f984aSJacob Faibussowitsch 
373030f984aSJacob Faibussowitsch /* called from PetscFinalize() do not call yourself! */
374a4af0ceeSJacob Faibussowitsch static PetscErrorCode PetscDeviceFinalize_Private(void)
375030f984aSJacob Faibussowitsch {
376030f984aSJacob Faibussowitsch   PetscErrorCode ierr;
377030f984aSJacob Faibussowitsch 
378030f984aSJacob Faibussowitsch   PetscFunctionBegin;
379a4af0ceeSJacob Faibussowitsch   if (PetscDefined(USE_DEBUG)) {
380bf025ffbSJacob Faibussowitsch     const auto PetscDeviceCheckAllDestroyedAfterFinalize = []{
381a4af0ceeSJacob Faibussowitsch       PetscFunctionBegin;
382bf025ffbSJacob Faibussowitsch       for (auto&& device : defaultDevices) PetscCheck(!device,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);
383a4af0ceeSJacob Faibussowitsch       PetscFunctionReturn(0);
384a4af0ceeSJacob Faibussowitsch     };
385bf025ffbSJacob Faibussowitsch     /*
386bf025ffbSJacob Faibussowitsch       you might be thinking, why on earth are you registered yet another finalizer in a
387bf025ffbSJacob Faibussowitsch       function already called during PetscRegisterFinalizeAll()? If this seems stupid it's
388bf025ffbSJacob Faibussowitsch       because it is.
389bf025ffbSJacob Faibussowitsch 
390bf025ffbSJacob Faibussowitsch       The crux of the problem is that the initializer (and therefore the ~finalizer~) of
391bf025ffbSJacob Faibussowitsch       PetscDeviceContext is guaranteed to run after PetscDevice's. So if the global context had
392bf025ffbSJacob Faibussowitsch       a default PetscDevice attached, that PetscDevice will have a reference count >0 and hence
393bf025ffbSJacob Faibussowitsch       won't be destroyed yet. So we need to repeat the check that all devices have been
394bf025ffbSJacob Faibussowitsch       destroyed again ~after~ the global context is destroyed. In summary:
395bf025ffbSJacob Faibussowitsch 
396bf025ffbSJacob Faibussowitsch       1. This finalizer runs and destroys all devices, except it may not because the global
397bf025ffbSJacob Faibussowitsch          context may still hold a reference!
398bf025ffbSJacob Faibussowitsch       2. The global context finalizer runs and does the final reference count decrement
399bf025ffbSJacob Faibussowitsch          required, which actually destroys the held device.
400bf025ffbSJacob Faibussowitsch       3. Our newly added finalizer runs and checks that all is well.
401a4af0ceeSJacob Faibussowitsch     */
402a4af0ceeSJacob Faibussowitsch     ierr = PetscRegisterFinalize(PetscDeviceCheckAllDestroyedAfterFinalize);CHKERRQ(ierr);
403a4af0ceeSJacob Faibussowitsch   }
404a4af0ceeSJacob Faibussowitsch   for (auto &&device : defaultDevices) {ierr = PetscDeviceDestroy(&device);CHKERRQ(ierr);}
405a4af0ceeSJacob Faibussowitsch   CHKERRCXX(initializedDevice.fill(false));
406030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
407030f984aSJacob Faibussowitsch }
408030f984aSJacob Faibussowitsch 
409cf3a2253SJacob Faibussowitsch /*
410cf3a2253SJacob Faibussowitsch   Begins the init proceeedings for the entire PetscDevice stack. there are 3 stages of
411cf3a2253SJacob Faibussowitsch   initialization types:
412cf3a2253SJacob Faibussowitsch 
413a4af0ceeSJacob Faibussowitsch   1. defaultInitType - how does PetscDevice as a whole expect to initialize?
414a4af0ceeSJacob Faibussowitsch   2. subTypeDefaultInitType - how does each PetscDevice implementation expect to initialize?
415a4af0ceeSJacob Faibussowitsch      e.g. you may want to blanket disable PetscDevice init (and disable say Kokkos init), but
416a4af0ceeSJacob Faibussowitsch      have all CUDA devices still initialize.
417a4af0ceeSJacob Faibussowitsch 
418a4af0ceeSJacob Faibussowitsch   All told the following happens:
419cf3a2253SJacob Faibussowitsch 
420a4af0ceeSJacob Faibussowitsch   0. defaultInitType -> LAZY
421a4af0ceeSJacob Faibussowitsch   1. Check for log_view/log_summary, if yes defaultInitType -> EAGER
422a4af0ceeSJacob Faibussowitsch   2. PetscDevice initializes each sub type with deviceDefaultInitType.
423a4af0ceeSJacob Faibussowitsch   2.1 Each enabled PetscDevice sub-type then does the above disable or view check in addition
424a4af0ceeSJacob Faibussowitsch       to checking for specific device init. if view or specific device init
425a4af0ceeSJacob Faibussowitsch       subTypeDefaultInitType -> EAGER. disabled once again overrides all.
426a4af0ceeSJacob Faibussowitsch */
427a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceInitializeFromOptions_Internal(MPI_Comm comm)
428030f984aSJacob Faibussowitsch {
429a4af0ceeSJacob Faibussowitsch   PetscBool           flg,defaultView = PETSC_FALSE,initializeDeviceContextEagerly = PETSC_FALSE;
430a4af0ceeSJacob Faibussowitsch   PetscInt            defaultDevice   = PETSC_DECIDE;
431a4af0ceeSJacob Faibussowitsch   PetscDeviceType     deviceContextInitDevice = PETSC_DEVICE_DEFAULT;
432a4af0ceeSJacob Faibussowitsch   PetscDeviceInitType defaultInitType;
433a4af0ceeSJacob Faibussowitsch   PetscErrorCode      ierr;
434a4af0ceeSJacob Faibussowitsch 
435a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
436a4af0ceeSJacob Faibussowitsch   if (PetscDefined(USE_DEBUG)) {
437a4af0ceeSJacob Faibussowitsch     int result;
438a4af0ceeSJacob Faibussowitsch 
439a4af0ceeSJacob Faibussowitsch     ierr = MPI_Comm_compare(comm,PETSC_COMM_WORLD,&result);CHKERRMPI(ierr);
440a4af0ceeSJacob Faibussowitsch     /* in order to accurately assign ranks to gpus we need to get the MPI_Comm_rank of the
441a4af0ceeSJacob Faibussowitsch      * global space */
442a4af0ceeSJacob Faibussowitsch     if (PetscUnlikely(result != MPI_IDENT)) {
443a4af0ceeSJacob Faibussowitsch       char name[MPI_MAX_OBJECT_NAME] = {};
444a4af0ceeSJacob Faibussowitsch       int  len; /* unused */
445a4af0ceeSJacob Faibussowitsch 
446a4af0ceeSJacob Faibussowitsch       ierr = MPI_Comm_get_name(comm,name,&len);CHKERRMPI(ierr);
44798921bdaSJacob Faibussowitsch       SETERRQ(comm,PETSC_ERR_MPI,"Default devices being initialized on MPI_Comm '%s' not PETSC_COMM_WORLD",name);
448a4af0ceeSJacob Faibussowitsch     }
449a4af0ceeSJacob Faibussowitsch   }
450a4af0ceeSJacob Faibussowitsch   comm = PETSC_COMM_WORLD; /* from this point on we assume we're on PETSC_COMM_WORLD */
451a4af0ceeSJacob Faibussowitsch   ierr = PetscRegisterFinalize(PetscDeviceFinalize_Private);CHKERRQ(ierr);
452a4af0ceeSJacob Faibussowitsch   ierr = PetscOptionsHasName(PETSC_NULLPTR,PETSC_NULLPTR,"-log_view",&flg);CHKERRQ(ierr);
453a4af0ceeSJacob Faibussowitsch   if (!flg) {
454a4af0ceeSJacob Faibussowitsch     ierr = PetscOptionsHasName(PETSC_NULLPTR,PETSC_NULLPTR,"-log_summary",&flg);CHKERRQ(ierr);
455a4af0ceeSJacob Faibussowitsch   }
456a4af0ceeSJacob Faibussowitsch   {
457a4af0ceeSJacob Faibussowitsch     PetscInt initIdx = flg ? PETSC_DEVICE_INIT_EAGER : PETSC_DEVICE_INIT_LAZY;
458a4af0ceeSJacob Faibussowitsch 
459a4af0ceeSJacob Faibussowitsch     ierr = PetscOptionsBegin(comm,PETSC_NULLPTR,"PetscDevice Options","Sys");CHKERRQ(ierr);
460a4af0ceeSJacob Faibussowitsch     ierr = PetscOptionsEList("-device_enable","How (or whether) to initialize PetscDevices","PetscDeviceInitializeFromOptions_Internal()",PetscDeviceInitTypes,3,PetscDeviceInitTypes[initIdx],&initIdx,PETSC_NULLPTR);CHKERRQ(ierr);
46117f48955SJacob 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);
462a4af0ceeSJacob Faibussowitsch     ierr = PetscOptionsBool("-device_view","Display device information and assignments (forces eager initialization)",PETSC_NULLPTR,defaultView,&defaultView,&flg);CHKERRQ(ierr);
463a4af0ceeSJacob Faibussowitsch     ierr = PetscOptionsEnd();CHKERRQ(ierr);
464a4af0ceeSJacob Faibussowitsch     if (initIdx == PETSC_DEVICE_INIT_NONE) {
465a4af0ceeSJacob Faibussowitsch       /* disabled all device initialization if devices are globally disabled */
466bf025ffbSJacob Faibussowitsch       PetscCheck(defaultDevice == PETSC_DECIDE,comm,PETSC_ERR_USER_INPUT,"You have disabled devices but also specified a particular device to use, these options are mutually exlusive");
467a4af0ceeSJacob Faibussowitsch       defaultView = PETSC_FALSE;
468a4af0ceeSJacob Faibussowitsch     } else {
469a4af0ceeSJacob Faibussowitsch       defaultView = static_cast<decltype(defaultView)>(defaultView && flg);
470a4af0ceeSJacob Faibussowitsch       if (defaultView) initIdx = PETSC_DEVICE_INIT_EAGER;
471a4af0ceeSJacob Faibussowitsch     }
472a4af0ceeSJacob Faibussowitsch     defaultInitType = static_cast<decltype(defaultInitType)>(initIdx);
473a4af0ceeSJacob Faibussowitsch   }
474a4af0ceeSJacob Faibussowitsch   static_assert((PETSC_DEVICE_INVALID == 0) && (PETSC_DEVICE_MAX < std::numeric_limits<int>::max()),"");
475a4af0ceeSJacob Faibussowitsch   for (int i = 1; i < PETSC_DEVICE_MAX; ++i) {
476a4af0ceeSJacob Faibussowitsch     const auto deviceType = static_cast<PetscDeviceType>(i);
477a4af0ceeSJacob Faibussowitsch     auto initType         = defaultInitType;
478a4af0ceeSJacob Faibussowitsch 
479a4af0ceeSJacob Faibussowitsch     ierr = PetscDeviceInitializeTypeFromOptions_Private(comm,deviceType,defaultDevice,defaultView,&initType);CHKERRQ(ierr);
480a4af0ceeSJacob Faibussowitsch     if (PetscDeviceConfiguredFor_Internal(deviceType) && (initType == PETSC_DEVICE_INIT_EAGER)) {
481a4af0ceeSJacob Faibussowitsch       initializeDeviceContextEagerly = PETSC_TRUE;
482a4af0ceeSJacob Faibussowitsch       deviceContextInitDevice        = deviceType;
483a4af0ceeSJacob Faibussowitsch     }
484a4af0ceeSJacob Faibussowitsch   }
485a4af0ceeSJacob Faibussowitsch   if (initializeDeviceContextEagerly) {
486a4af0ceeSJacob Faibussowitsch     PetscDeviceContext dctx;
487a4af0ceeSJacob Faibussowitsch 
488cf3a2253SJacob Faibussowitsch     /*
489cf3a2253SJacob Faibussowitsch       somewhat inefficient here as the device context is potentially fully set up twice (once
490cf3a2253SJacob Faibussowitsch       when retrieved then the second time if setfromoptions makes changes)
491cf3a2253SJacob Faibussowitsch     */
4927d3de750SJacob Faibussowitsch     ierr = PetscInfo(PETSC_NULLPTR,"Eagerly initializing PetscDeviceContext with %s device\n",PetscDeviceTypes[deviceContextInitDevice]);CHKERRQ(ierr);
493a4af0ceeSJacob Faibussowitsch     ierr = PetscDeviceContextSetRootDeviceType_Internal(deviceContextInitDevice);CHKERRQ(ierr);
494a4af0ceeSJacob Faibussowitsch     ierr = PetscDeviceContextGetCurrentContext(&dctx);CHKERRQ(ierr);
495a4af0ceeSJacob Faibussowitsch     ierr = PetscDeviceContextSetFromOptions(comm,"root_",dctx);CHKERRQ(ierr);
496a4af0ceeSJacob Faibussowitsch     ierr = PetscDeviceContextSetUp(dctx);CHKERRQ(ierr);
497a4af0ceeSJacob Faibussowitsch   }
498a4af0ceeSJacob Faibussowitsch   PetscFunctionReturn(0);
499a4af0ceeSJacob Faibussowitsch }
500a4af0ceeSJacob Faibussowitsch 
501a4af0ceeSJacob Faibussowitsch /* Get the default PetscDevice for a particular type and constructs them if lazily initialized. */
502a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceGetDefaultForType_Internal(PetscDeviceType type, PetscDevice *device)
503a4af0ceeSJacob Faibussowitsch {
504a4af0ceeSJacob Faibussowitsch   PetscErrorCode ierr;
505a4af0ceeSJacob Faibussowitsch 
506a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
507a4af0ceeSJacob Faibussowitsch   PetscValidPointer(device,2);
508a4af0ceeSJacob Faibussowitsch   ierr = PetscDeviceInitialize(type);CHKERRQ(ierr);
509a4af0ceeSJacob Faibussowitsch   *device = defaultDevices[type];
510a4af0ceeSJacob Faibussowitsch   PetscFunctionReturn(0);
511030f984aSJacob Faibussowitsch }
512