xref: /petsc/src/sys/objects/device/interface/device.cxx (revision ce244043d4f2ea338c5210fafae4d782e9f13e7e)
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 
93030f984aSJacob Faibussowitsch   Input Parameter:
94a4af0ceeSJacob Faibussowitsch . type  - The type of PetscDevice
95a4af0ceeSJacob Faibussowitsch . 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 
214a4af0ceeSJacob Faibussowitsch   Input Parameter:
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 
234a4af0ceeSJacob Faibussowitsch static std::array<bool,PETSC_DEVICE_MAX>        initializedDevice = {};
235a4af0ceeSJacob Faibussowitsch static std::array<PetscDevice,PETSC_DEVICE_MAX> defaultDevices    = {};
236a4af0ceeSJacob Faibussowitsch static_assert(initializedDevice.size() == defaultDevices.size(),"");
237a4af0ceeSJacob Faibussowitsch 
238a4af0ceeSJacob Faibussowitsch /*@C
239a4af0ceeSJacob Faibussowitsch   PetscDeviceInitialize - Initialize PetscDevice
240a4af0ceeSJacob Faibussowitsch 
241a4af0ceeSJacob Faibussowitsch   Not Collective, Possibly Synchronous
242a4af0ceeSJacob Faibussowitsch 
243a4af0ceeSJacob Faibussowitsch   Input Parameter:
244a4af0ceeSJacob Faibussowitsch . type - The PetscDeviceType to initialize
245a4af0ceeSJacob Faibussowitsch 
246a4af0ceeSJacob Faibussowitsch   Notes:
247a4af0ceeSJacob Faibussowitsch   Eagerly initializes the corresponding PetscDeviceType if needed.
248a4af0ceeSJacob Faibussowitsch 
249a4af0ceeSJacob Faibussowitsch   Level: beginner
250a4af0ceeSJacob Faibussowitsch 
251a4af0ceeSJacob Faibussowitsch .seealso: PetscDevice, PetscDeviceInitType, PetscDeviceInitialized(), PetscDeviceCreate(), PetscDeviceDestroy()
252a4af0ceeSJacob Faibussowitsch @*/
253a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceInitialize(PetscDeviceType type)
254a4af0ceeSJacob Faibussowitsch {
255a4af0ceeSJacob Faibussowitsch   PetscErrorCode ierr;
256a4af0ceeSJacob Faibussowitsch 
257a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
258a4af0ceeSJacob Faibussowitsch   PetscValidDeviceType(type,1);
259a4af0ceeSJacob Faibussowitsch   ierr = PetscDeviceInitializeDefaultDevice_Internal(type,PETSC_DECIDE);CHKERRQ(ierr);
260a4af0ceeSJacob Faibussowitsch   PetscFunctionReturn(0);
261a4af0ceeSJacob Faibussowitsch }
262a4af0ceeSJacob Faibussowitsch 
263a4af0ceeSJacob Faibussowitsch /*@C
264a4af0ceeSJacob Faibussowitsch   PetscDeviceInitialized - Determines whether PetscDevice is initialized for a particular
265a4af0ceeSJacob Faibussowitsch   PetscDeviceType
266a4af0ceeSJacob Faibussowitsch 
267a4af0ceeSJacob Faibussowitsch   Not Collective, Asynchronous
268a4af0ceeSJacob Faibussowitsch 
269a4af0ceeSJacob Faibussowitsch   Input Parameter:
270a4af0ceeSJacob Faibussowitsch . type - The PetscDeviceType to check
271a4af0ceeSJacob Faibussowitsch 
272a4af0ceeSJacob Faibussowitsch   Output Parameter:
273a4af0ceeSJacob Faibussowitsch . [return value] - PETSC_TRUE if type is initialized, PETSC_FALSE otherwise
274a4af0ceeSJacob Faibussowitsch 
275a4af0ceeSJacob Faibussowitsch   Notes:
276a4af0ceeSJacob Faibussowitsch   If one has not configured PETSc for a particular PetscDeviceType then this routine will
277a4af0ceeSJacob Faibussowitsch   return PETSC_FALSE for that PetscDeviceType.
278a4af0ceeSJacob Faibussowitsch 
279a4af0ceeSJacob Faibussowitsch   Level: beginner
280a4af0ceeSJacob Faibussowitsch 
281a4af0ceeSJacob Faibussowitsch .seealso: PetscDevice, PetscDeviceInitType, PetscDeviceInitialize(), PetscDeviceCreate(), PetscDeviceDestroy()
282a4af0ceeSJacob Faibussowitsch @*/
283a4af0ceeSJacob Faibussowitsch PetscBool PetscDeviceInitialized(PetscDeviceType type)
284a4af0ceeSJacob Faibussowitsch {
285a4af0ceeSJacob Faibussowitsch   return static_cast<PetscBool>(PetscDeviceConfiguredFor_Internal(type) && initializedDevice[type]);
286a4af0ceeSJacob Faibussowitsch }
287a4af0ceeSJacob Faibussowitsch 
288cf3a2253SJacob Faibussowitsch /*
289cf3a2253SJacob Faibussowitsch   Actual intialization function; any functions claiming to initialize PetscDevice or
290cf3a2253SJacob Faibussowitsch   PetscDeviceContext will have to run through this one
291cf3a2253SJacob Faibussowitsch */
292a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceInitializeDefaultDevice_Internal(PetscDeviceType type, PetscInt defaultDeviceId)
293a4af0ceeSJacob Faibussowitsch {
294a4af0ceeSJacob Faibussowitsch   PetscErrorCode ierr;
295a4af0ceeSJacob Faibussowitsch 
296a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
297a4af0ceeSJacob Faibussowitsch   PetscValidDeviceType(type,1);
298a4af0ceeSJacob Faibussowitsch   if (PetscLikely(PetscDeviceInitialized(type))) PetscFunctionReturn(0);
2992c71b3e2SJacob Faibussowitsch   PetscAssertFalse(defaultDevices[type],PETSC_COMM_SELF,PETSC_ERR_MEM,"Trying to overwrite existing default device of type %s",PetscDeviceTypes[type]);
300a4af0ceeSJacob Faibussowitsch   ierr = PetscDeviceCreate(type,defaultDeviceId,&defaultDevices[type]);CHKERRQ(ierr);
301a4af0ceeSJacob Faibussowitsch   ierr = PetscDeviceConfigure(defaultDevices[type]);CHKERRQ(ierr);
302a4af0ceeSJacob Faibussowitsch   initializedDevice[type] = true;
303a4af0ceeSJacob Faibussowitsch   PetscFunctionReturn(0);
304a4af0ceeSJacob Faibussowitsch }
305a4af0ceeSJacob Faibussowitsch 
306*ce244043SStefano Zampini #if PetscDefined(USE_LOG)
307*ce244043SStefano Zampini PETSC_INTERN PetscErrorCode PetscLogInitialize(void);
308*ce244043SStefano Zampini #else
309*ce244043SStefano Zampini #define PetscLogInitialize() 0
310*ce244043SStefano Zampini #endif
311*ce244043SStefano Zampini 
312a4af0ceeSJacob Faibussowitsch static PetscErrorCode PetscDeviceInitializeTypeFromOptions_Private(MPI_Comm comm, PetscDeviceType type, PetscInt defaultDeviceId, PetscBool defaultView, PetscDeviceInitType *defaultInitType)
313a4af0ceeSJacob Faibussowitsch {
314a4af0ceeSJacob Faibussowitsch   PetscErrorCode ierr;
315a4af0ceeSJacob Faibussowitsch 
316a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
317a4af0ceeSJacob Faibussowitsch   if (!PetscDeviceConfiguredFor_Internal(type)) {
3187d3de750SJacob Faibussowitsch     ierr = PetscInfo(PETSC_NULLPTR,"PetscDeviceType %s not supported\n",PetscDeviceTypes[type]);CHKERRQ(ierr);
319a4af0ceeSJacob Faibussowitsch     defaultDevices[type] = PETSC_NULLPTR;
320a4af0ceeSJacob Faibussowitsch     PetscFunctionReturn(0);
321a4af0ceeSJacob Faibussowitsch   }
3227d3de750SJacob Faibussowitsch   ierr = PetscInfo(PETSC_NULLPTR,"PetscDeviceType %s supported, initializing\n",PetscDeviceTypes[type]);CHKERRQ(ierr);
323a4af0ceeSJacob Faibussowitsch   /* ugly switch needed to pick the right global variable... could maybe do this as a union? */
324a4af0ceeSJacob Faibussowitsch   switch (type) {
325a4af0ceeSJacob Faibussowitsch     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(CUDA,initialize,comm,&defaultDeviceId,defaultInitType);
326a4af0ceeSJacob Faibussowitsch     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(HIP,initialize,comm,&defaultDeviceId,defaultInitType);
327a2158755SJunchao Zhang     PETSC_DEVICE_CASE_IF_PETSC_DEFINED(SYCL,initialize,comm,&defaultDeviceId,defaultInitType);
328a4af0ceeSJacob Faibussowitsch   default:
32998921bdaSJacob 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]);
330a4af0ceeSJacob Faibussowitsch   }
331cf3a2253SJacob Faibussowitsch   /*
332cf3a2253SJacob Faibussowitsch     defaultInitType and defaultDeviceId now represent what the individual TYPES have decided to
333cf3a2253SJacob Faibussowitsch     initialize as
334cf3a2253SJacob Faibussowitsch   */
335a4af0ceeSJacob Faibussowitsch   if (*defaultInitType == PETSC_DEVICE_INIT_EAGER) {
3367d3de750SJacob Faibussowitsch     ierr = PetscInfo(PETSC_NULLPTR,"Eagerly initializing %s PetscDevice\n",PetscDeviceTypes[type]);CHKERRQ(ierr);
337a4af0ceeSJacob Faibussowitsch     ierr = PetscDeviceInitializeDefaultDevice_Internal(type,defaultDeviceId);CHKERRQ(ierr);
338a4af0ceeSJacob Faibussowitsch     if (defaultView) {
339a4af0ceeSJacob Faibussowitsch       PetscViewer vwr;
340a4af0ceeSJacob Faibussowitsch 
341*ce244043SStefano Zampini       ierr = PetscLogInitialize();CHKERRQ(ierr);
342a4af0ceeSJacob Faibussowitsch       ierr = PetscViewerASCIIGetStdout(comm,&vwr);CHKERRQ(ierr);
343a4af0ceeSJacob Faibussowitsch       ierr = PetscDeviceView(defaultDevices[type],vwr);CHKERRQ(ierr);
344a4af0ceeSJacob Faibussowitsch     }
345030f984aSJacob Faibussowitsch   }
346030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
347030f984aSJacob Faibussowitsch }
348030f984aSJacob Faibussowitsch 
349030f984aSJacob Faibussowitsch /* called from PetscFinalize() do not call yourself! */
350a4af0ceeSJacob Faibussowitsch static PetscErrorCode PetscDeviceFinalize_Private(void)
351030f984aSJacob Faibussowitsch {
352030f984aSJacob Faibussowitsch   PetscErrorCode ierr;
353030f984aSJacob Faibussowitsch 
354030f984aSJacob Faibussowitsch   PetscFunctionBegin;
355a4af0ceeSJacob Faibussowitsch   if (PetscDefined(USE_DEBUG)) {
356bde483f2SJacob Faibussowitsch     const auto PetscDeviceCheckAllDestroyedAfterFinalize = [](){
357a4af0ceeSJacob Faibussowitsch       PetscFunctionBegin;
35817f48955SJacob Faibussowitsch       for (auto&& device : defaultDevices) {
3592c71b3e2SJacob Faibussowitsch         PetscCheckFalse(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);
360a4af0ceeSJacob Faibussowitsch       }
361a4af0ceeSJacob Faibussowitsch       PetscFunctionReturn(0);
362a4af0ceeSJacob Faibussowitsch     };
363a4af0ceeSJacob Faibussowitsch     /* you might be thinking, why on earth are you registered yet another finalizer in a
364a4af0ceeSJacob Faibussowitsch      * function already called during PetscRegisterFinalizeAll()? If this seems stupid it's
365a4af0ceeSJacob Faibussowitsch      * because it is.
366a4af0ceeSJacob Faibussowitsch      *
367a4af0ceeSJacob Faibussowitsch      * The crux of the problem is that the initializer (and therefore the ~finalizer~) of
36817f48955SJacob Faibussowitsch      * PetscDeviceContext is guaranteed to run after PetscDevice's. So if the global context
36917f48955SJacob Faibussowitsch      * had a default PetscDevice attached, that PetscDevice will have a reference count >0 and
37017f48955SJacob Faibussowitsch      * hence won't be destroyed yet. So we need to repeat the check that all devices have been
37117f48955SJacob Faibussowitsch      * destroyed again ~after~ the global context is destroyed. In summary:
372a4af0ceeSJacob Faibussowitsch      *
373a4af0ceeSJacob Faibussowitsch      * 1. This finalizer runs and destroys all devices, except it may not because the global
374a4af0ceeSJacob Faibussowitsch      *    context may still hold a reference!
37517f48955SJacob Faibussowitsch      * 2. The global context finalizer runs and does the final reference count decrement
37617f48955SJacob Faibussowitsch      *    required, which actually destroys the held device.
377a4af0ceeSJacob Faibussowitsch      * 3. Our newly added finalizer runs and checks that all is well.
378a4af0ceeSJacob Faibussowitsch      */
379a4af0ceeSJacob Faibussowitsch     ierr = PetscRegisterFinalize(PetscDeviceCheckAllDestroyedAfterFinalize);CHKERRQ(ierr);
380a4af0ceeSJacob Faibussowitsch   }
381a4af0ceeSJacob Faibussowitsch   for (auto &&device : defaultDevices) {ierr = PetscDeviceDestroy(&device);CHKERRQ(ierr);}
382a4af0ceeSJacob Faibussowitsch   CHKERRCXX(initializedDevice.fill(false));
383030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
384030f984aSJacob Faibussowitsch }
385030f984aSJacob Faibussowitsch 
386cf3a2253SJacob Faibussowitsch /*
387cf3a2253SJacob Faibussowitsch   Begins the init proceeedings for the entire PetscDevice stack. there are 3 stages of
388cf3a2253SJacob Faibussowitsch   initialization types:
389cf3a2253SJacob Faibussowitsch 
390a4af0ceeSJacob Faibussowitsch   1. defaultInitType - how does PetscDevice as a whole expect to initialize?
391a4af0ceeSJacob Faibussowitsch   2. subTypeDefaultInitType - how does each PetscDevice implementation expect to initialize?
392a4af0ceeSJacob Faibussowitsch      e.g. you may want to blanket disable PetscDevice init (and disable say Kokkos init), but
393a4af0ceeSJacob Faibussowitsch      have all CUDA devices still initialize.
394a4af0ceeSJacob Faibussowitsch 
395a4af0ceeSJacob Faibussowitsch   All told the following happens:
396cf3a2253SJacob Faibussowitsch 
397a4af0ceeSJacob Faibussowitsch   0. defaultInitType -> LAZY
398a4af0ceeSJacob Faibussowitsch   1. Check for log_view/log_summary, if yes defaultInitType -> EAGER
399a4af0ceeSJacob Faibussowitsch   2. PetscDevice initializes each sub type with deviceDefaultInitType.
400a4af0ceeSJacob Faibussowitsch   2.1 Each enabled PetscDevice sub-type then does the above disable or view check in addition
401a4af0ceeSJacob Faibussowitsch       to checking for specific device init. if view or specific device init
402a4af0ceeSJacob Faibussowitsch       subTypeDefaultInitType -> EAGER. disabled once again overrides all.
403a4af0ceeSJacob Faibussowitsch */
404a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceInitializeFromOptions_Internal(MPI_Comm comm)
405030f984aSJacob Faibussowitsch {
406a4af0ceeSJacob Faibussowitsch   PetscBool           flg,defaultView = PETSC_FALSE,initializeDeviceContextEagerly = PETSC_FALSE;
407a4af0ceeSJacob Faibussowitsch   PetscInt            defaultDevice   = PETSC_DECIDE;
408a4af0ceeSJacob Faibussowitsch   PetscDeviceType     deviceContextInitDevice = PETSC_DEVICE_DEFAULT;
409a4af0ceeSJacob Faibussowitsch   PetscDeviceInitType defaultInitType;
410a4af0ceeSJacob Faibussowitsch   PetscErrorCode      ierr;
411a4af0ceeSJacob Faibussowitsch 
412a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
413a4af0ceeSJacob Faibussowitsch   if (PetscDefined(USE_DEBUG)) {
414a4af0ceeSJacob Faibussowitsch     int result;
415a4af0ceeSJacob Faibussowitsch 
416a4af0ceeSJacob Faibussowitsch     ierr = MPI_Comm_compare(comm,PETSC_COMM_WORLD,&result);CHKERRMPI(ierr);
417a4af0ceeSJacob Faibussowitsch     /* in order to accurately assign ranks to gpus we need to get the MPI_Comm_rank of the
418a4af0ceeSJacob Faibussowitsch      * global space */
419a4af0ceeSJacob Faibussowitsch     if (PetscUnlikely(result != MPI_IDENT)) {
420a4af0ceeSJacob Faibussowitsch       char name[MPI_MAX_OBJECT_NAME] = {};
421a4af0ceeSJacob Faibussowitsch       int  len; /* unused */
422a4af0ceeSJacob Faibussowitsch 
423a4af0ceeSJacob Faibussowitsch       ierr = MPI_Comm_get_name(comm,name,&len);CHKERRMPI(ierr);
42498921bdaSJacob Faibussowitsch       SETERRQ(comm,PETSC_ERR_MPI,"Default devices being initialized on MPI_Comm '%s' not PETSC_COMM_WORLD",name);
425a4af0ceeSJacob Faibussowitsch     }
426a4af0ceeSJacob Faibussowitsch   }
427a4af0ceeSJacob Faibussowitsch   comm = PETSC_COMM_WORLD; /* from this point on we assume we're on PETSC_COMM_WORLD */
428a4af0ceeSJacob Faibussowitsch   ierr = PetscRegisterFinalize(PetscDeviceFinalize_Private);CHKERRQ(ierr);
429a4af0ceeSJacob Faibussowitsch   ierr = PetscOptionsHasName(PETSC_NULLPTR,PETSC_NULLPTR,"-log_view",&flg);CHKERRQ(ierr);
430a4af0ceeSJacob Faibussowitsch   if (!flg) {
431a4af0ceeSJacob Faibussowitsch     ierr = PetscOptionsHasName(PETSC_NULLPTR,PETSC_NULLPTR,"-log_summary",&flg);CHKERRQ(ierr);
432a4af0ceeSJacob Faibussowitsch   }
433a4af0ceeSJacob Faibussowitsch   {
434a4af0ceeSJacob Faibussowitsch     PetscInt initIdx = flg ? PETSC_DEVICE_INIT_EAGER : PETSC_DEVICE_INIT_LAZY;
435a4af0ceeSJacob Faibussowitsch 
436a4af0ceeSJacob Faibussowitsch     ierr = PetscOptionsBegin(comm,PETSC_NULLPTR,"PetscDevice Options","Sys");CHKERRQ(ierr);
437a4af0ceeSJacob Faibussowitsch     ierr = PetscOptionsEList("-device_enable","How (or whether) to initialize PetscDevices","PetscDeviceInitializeFromOptions_Internal()",PetscDeviceInitTypes,3,PetscDeviceInitTypes[initIdx],&initIdx,PETSC_NULLPTR);CHKERRQ(ierr);
43817f48955SJacob 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);
439a4af0ceeSJacob Faibussowitsch     ierr = PetscOptionsBool("-device_view","Display device information and assignments (forces eager initialization)",PETSC_NULLPTR,defaultView,&defaultView,&flg);CHKERRQ(ierr);
440a4af0ceeSJacob Faibussowitsch     ierr = PetscOptionsEnd();CHKERRQ(ierr);
441a4af0ceeSJacob Faibussowitsch     if (initIdx == PETSC_DEVICE_INIT_NONE) {
442a4af0ceeSJacob Faibussowitsch       /* disabled all device initialization if devices are globally disabled */
4432c71b3e2SJacob Faibussowitsch       PetscCheckFalse(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");
444a4af0ceeSJacob Faibussowitsch       defaultView = PETSC_FALSE;
445a4af0ceeSJacob Faibussowitsch     } else {
446a4af0ceeSJacob Faibussowitsch       defaultView = static_cast<decltype(defaultView)>(defaultView && flg);
447a4af0ceeSJacob Faibussowitsch       if (defaultView) initIdx = PETSC_DEVICE_INIT_EAGER;
448a4af0ceeSJacob Faibussowitsch     }
449a4af0ceeSJacob Faibussowitsch     defaultInitType = static_cast<decltype(defaultInitType)>(initIdx);
450a4af0ceeSJacob Faibussowitsch   }
451a4af0ceeSJacob Faibussowitsch   static_assert((PETSC_DEVICE_INVALID == 0) && (PETSC_DEVICE_MAX < std::numeric_limits<int>::max()),"");
452a4af0ceeSJacob Faibussowitsch   for (int i = 1; i < PETSC_DEVICE_MAX; ++i) {
453a4af0ceeSJacob Faibussowitsch     const auto deviceType = static_cast<PetscDeviceType>(i);
454a4af0ceeSJacob Faibussowitsch     auto initType         = defaultInitType;
455a4af0ceeSJacob Faibussowitsch 
456a4af0ceeSJacob Faibussowitsch     ierr = PetscDeviceInitializeTypeFromOptions_Private(comm,deviceType,defaultDevice,defaultView,&initType);CHKERRQ(ierr);
457a4af0ceeSJacob Faibussowitsch     if (PetscDeviceConfiguredFor_Internal(deviceType) && (initType == PETSC_DEVICE_INIT_EAGER)) {
458a4af0ceeSJacob Faibussowitsch       initializeDeviceContextEagerly = PETSC_TRUE;
459a4af0ceeSJacob Faibussowitsch       deviceContextInitDevice        = deviceType;
460a4af0ceeSJacob Faibussowitsch     }
461a4af0ceeSJacob Faibussowitsch   }
462a4af0ceeSJacob Faibussowitsch   if (initializeDeviceContextEagerly) {
463a4af0ceeSJacob Faibussowitsch     PetscDeviceContext dctx;
464a4af0ceeSJacob Faibussowitsch 
465cf3a2253SJacob Faibussowitsch     /*
466cf3a2253SJacob Faibussowitsch       somewhat inefficient here as the device context is potentially fully set up twice (once
467cf3a2253SJacob Faibussowitsch       when retrieved then the second time if setfromoptions makes changes)
468cf3a2253SJacob Faibussowitsch     */
4697d3de750SJacob Faibussowitsch     ierr = PetscInfo(PETSC_NULLPTR,"Eagerly initializing PetscDeviceContext with %s device\n",PetscDeviceTypes[deviceContextInitDevice]);CHKERRQ(ierr);
470a4af0ceeSJacob Faibussowitsch     ierr = PetscDeviceContextSetRootDeviceType_Internal(deviceContextInitDevice);CHKERRQ(ierr);
471a4af0ceeSJacob Faibussowitsch     ierr = PetscDeviceContextGetCurrentContext(&dctx);CHKERRQ(ierr);
472a4af0ceeSJacob Faibussowitsch     ierr = PetscDeviceContextSetFromOptions(comm,"root_",dctx);CHKERRQ(ierr);
473a4af0ceeSJacob Faibussowitsch     ierr = PetscDeviceContextSetUp(dctx);CHKERRQ(ierr);
474a4af0ceeSJacob Faibussowitsch   }
475a4af0ceeSJacob Faibussowitsch   PetscFunctionReturn(0);
476a4af0ceeSJacob Faibussowitsch }
477a4af0ceeSJacob Faibussowitsch 
478a4af0ceeSJacob Faibussowitsch /* Get the default PetscDevice for a particular type and constructs them if lazily initialized. */
479a4af0ceeSJacob Faibussowitsch PetscErrorCode PetscDeviceGetDefaultForType_Internal(PetscDeviceType type, PetscDevice *device)
480a4af0ceeSJacob Faibussowitsch {
481a4af0ceeSJacob Faibussowitsch   PetscErrorCode ierr;
482a4af0ceeSJacob Faibussowitsch 
483a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
484a4af0ceeSJacob Faibussowitsch   PetscValidPointer(device,2);
485a4af0ceeSJacob Faibussowitsch   ierr = PetscDeviceInitialize(type);CHKERRQ(ierr);
486a4af0ceeSJacob Faibussowitsch   *device = defaultDevices[type];
487a4af0ceeSJacob Faibussowitsch   PetscFunctionReturn(0);
488030f984aSJacob Faibussowitsch }
489