xref: /petsc/src/sys/objects/device/impls/cupm/cupmcontext.hpp (revision a4af0ceea8a251db97ee0dc5c0d52d4adf50264a) !
1030f984aSJacob Faibussowitsch #if !defined(PETSCDEVICECONTEXTCUPM_HPP)
2030f984aSJacob Faibussowitsch #define PETSCDEVICECONTEXTCUPM_HPP
3030f984aSJacob Faibussowitsch 
4*a4af0ceeSJacob Faibussowitsch #include <petsc/private/deviceimpl.h>
5030f984aSJacob Faibussowitsch #include <petsc/private/cupminterface.hpp>
6030f984aSJacob Faibussowitsch 
7030f984aSJacob Faibussowitsch #if !defined(PETSC_HAVE_CXX_DIALECT_CXX11)
8030f984aSJacob Faibussowitsch #error PetscDeviceContext backends for CUDA and HIP requires C++11
9030f984aSJacob Faibussowitsch #endif
10030f984aSJacob Faibussowitsch 
11*a4af0ceeSJacob Faibussowitsch #include <array>
12*a4af0ceeSJacob Faibussowitsch 
13*a4af0ceeSJacob Faibussowitsch namespace Petsc
14*a4af0ceeSJacob Faibussowitsch {
15*a4af0ceeSJacob Faibussowitsch 
16*a4af0ceeSJacob Faibussowitsch namespace detail
17*a4af0ceeSJacob Faibussowitsch {
18*a4af0ceeSJacob Faibussowitsch 
19*a4af0ceeSJacob Faibussowitsch // for tag-based dispatch of handle retrieval
20*a4af0ceeSJacob Faibussowitsch template <typename HT> struct HandleTag { };
21*a4af0ceeSJacob Faibussowitsch 
22*a4af0ceeSJacob Faibussowitsch } // namespace detail
23030f984aSJacob Faibussowitsch 
24030f984aSJacob Faibussowitsch // Forward declare
25*a4af0ceeSJacob Faibussowitsch template <CUPMDeviceType T> class CUPMContext;
26030f984aSJacob Faibussowitsch 
27*a4af0ceeSJacob Faibussowitsch template <CUPMDeviceType T>
28030f984aSJacob Faibussowitsch class CUPMContext : CUPMInterface<T>
29030f984aSJacob Faibussowitsch {
30*a4af0ceeSJacob Faibussowitsch   template <typename H>
31*a4af0ceeSJacob Faibussowitsch   using HandleTag = typename detail::HandleTag<H>;
32*a4af0ceeSJacob Faibussowitsch 
33030f984aSJacob Faibussowitsch public:
341b6e0089SPierre Jolivet   PETSC_INHERIT_CUPM_INTERFACE_TYPEDEFS_USING(cupmInterface_t,T)
35030f984aSJacob Faibussowitsch 
36030f984aSJacob Faibussowitsch   // This is the canonical PETSc "impls" struct that normally resides in a standalone impls
37030f984aSJacob Faibussowitsch   // header, but since we are using the power of templates it must be declared part of
38030f984aSJacob Faibussowitsch   // this class to have easy access the same typedefs. Technically one can make a
39030f984aSJacob Faibussowitsch   // templated struct outside the class but it's more code for the same result.
40030f984aSJacob Faibussowitsch   struct PetscDeviceContext_IMPLS
41030f984aSJacob Faibussowitsch   {
42030f984aSJacob Faibussowitsch     cupmStream_t       stream;
43030f984aSJacob Faibussowitsch     cupmEvent_t        event;
44*a4af0ceeSJacob Faibussowitsch     cupmEvent_t        begin; // timer-only
45*a4af0ceeSJacob Faibussowitsch     cupmEvent_t        end;   // timer-only
46*a4af0ceeSJacob Faibussowitsch #if PetscDefined(USE_DEBUG)
47*a4af0ceeSJacob Faibussowitsch     PetscBool          timerInUse;
48*a4af0ceeSJacob Faibussowitsch #endif
49030f984aSJacob Faibussowitsch     cupmBlasHandle_t   blas;
50030f984aSJacob Faibussowitsch     cupmSolverHandle_t solver;
51*a4af0ceeSJacob Faibussowitsch 
52*a4af0ceeSJacob Faibussowitsch     PETSC_NODISCARD cupmBlasHandle_t   handle(HandleTag<cupmBlasHandle_t>)   { return blas;   }
53*a4af0ceeSJacob Faibussowitsch     PETSC_NODISCARD cupmSolverHandle_t handle(HandleTag<cupmSolverHandle_t>) { return solver; }
54030f984aSJacob Faibussowitsch   };
55030f984aSJacob Faibussowitsch 
56030f984aSJacob Faibussowitsch private:
57*a4af0ceeSJacob Faibussowitsch   static bool _initialized;
58*a4af0ceeSJacob Faibussowitsch   static std::array<cupmBlasHandle_t,PETSC_DEVICE_MAX_DEVICES>   _blashandles;
59*a4af0ceeSJacob Faibussowitsch   static std::array<cupmSolverHandle_t,PETSC_DEVICE_MAX_DEVICES> _solverhandles;
60030f984aSJacob Faibussowitsch 
61*a4af0ceeSJacob Faibussowitsch   PETSC_NODISCARD static constexpr PetscDeviceContext_IMPLS* __impls_cast(PetscDeviceContext ptr) noexcept
62*a4af0ceeSJacob Faibussowitsch   {
63*a4af0ceeSJacob Faibussowitsch     return static_cast<PetscDeviceContext_IMPLS*>(ptr->data);
64*a4af0ceeSJacob Faibussowitsch   }
65*a4af0ceeSJacob Faibussowitsch 
66*a4af0ceeSJacob Faibussowitsch   PETSC_NODISCARD static PetscErrorCode __finalize() noexcept
67030f984aSJacob Faibussowitsch   {
68030f984aSJacob Faibussowitsch     PetscErrorCode ierr;
69030f984aSJacob Faibussowitsch 
70030f984aSJacob Faibussowitsch     PetscFunctionBegin;
71*a4af0ceeSJacob Faibussowitsch     for (auto&& handle : _blashandles) {
72*a4af0ceeSJacob Faibussowitsch       if (handle) {ierr = cupmInterface_t::DestroyHandle(handle);CHKERRQ(ierr);}
73*a4af0ceeSJacob Faibussowitsch     }
74*a4af0ceeSJacob Faibussowitsch     for (auto&& handle : _solverhandles) {
75*a4af0ceeSJacob Faibussowitsch       if (handle) {ierr = cupmInterface_t::DestroyHandle(handle);CHKERRQ(ierr);}
76*a4af0ceeSJacob Faibussowitsch     }
77*a4af0ceeSJacob Faibussowitsch     _initialized = false;
78030f984aSJacob Faibussowitsch     PetscFunctionReturn(0);
79030f984aSJacob Faibussowitsch   }
80030f984aSJacob Faibussowitsch 
81*a4af0ceeSJacob Faibussowitsch   PETSC_NODISCARD static PetscErrorCode __initialize(PetscInt id, PetscDeviceContext_IMPLS *dci) noexcept
82030f984aSJacob Faibussowitsch   {
83030f984aSJacob Faibussowitsch     PetscErrorCode ierr;
84030f984aSJacob Faibussowitsch 
85030f984aSJacob Faibussowitsch     PetscFunctionBegin;
86*a4af0ceeSJacob Faibussowitsch     ierr = PetscDeviceCheckDeviceCount_Internal(id);CHKERRQ(ierr);
87*a4af0ceeSJacob Faibussowitsch     if (!_initialized) {
88*a4af0ceeSJacob Faibussowitsch       _initialized = true;
89*a4af0ceeSJacob Faibussowitsch       ierr = PetscRegisterFinalize(__finalize);CHKERRQ(ierr);
90030f984aSJacob Faibussowitsch     }
91*a4af0ceeSJacob Faibussowitsch     // use the blashandle as a canary
92*a4af0ceeSJacob Faibussowitsch     if (!_blashandles[id]) {
93*a4af0ceeSJacob Faibussowitsch       ierr = cupmInterface_t::InitializeHandle(_blashandles[id]);CHKERRQ(ierr);
94*a4af0ceeSJacob Faibussowitsch       ierr = cupmInterface_t::InitializeHandle(_solverhandles[id]);CHKERRQ(ierr);
95030f984aSJacob Faibussowitsch     }
96*a4af0ceeSJacob Faibussowitsch     ierr = cupmInterface_t::SetHandleStream(_blashandles[id],dci->stream);CHKERRQ(ierr);
97*a4af0ceeSJacob Faibussowitsch     ierr = cupmInterface_t::SetHandleStream(_solverhandles[id],dci->stream);CHKERRQ(ierr);
98*a4af0ceeSJacob Faibussowitsch     dci->blas   = _blashandles[id];
99*a4af0ceeSJacob Faibussowitsch     dci->solver = _solverhandles[id];
100030f984aSJacob Faibussowitsch     PetscFunctionReturn(0);
101030f984aSJacob Faibussowitsch   }
102030f984aSJacob Faibussowitsch 
103030f984aSJacob Faibussowitsch public:
104*a4af0ceeSJacob Faibussowitsch   const struct _DeviceContextOps ops = {
105*a4af0ceeSJacob Faibussowitsch     destroy,
106*a4af0ceeSJacob Faibussowitsch     changeStreamType,
107*a4af0ceeSJacob Faibussowitsch     setUp,
108*a4af0ceeSJacob Faibussowitsch     query,
109*a4af0ceeSJacob Faibussowitsch     waitForContext,
110*a4af0ceeSJacob Faibussowitsch     synchronize,
111*a4af0ceeSJacob Faibussowitsch     getHandle<cupmBlasHandle_t>,
112*a4af0ceeSJacob Faibussowitsch     getHandle<cupmSolverHandle_t>,
113*a4af0ceeSJacob Faibussowitsch     beginTimer,
114*a4af0ceeSJacob Faibussowitsch     endTimer
115*a4af0ceeSJacob Faibussowitsch   };
116030f984aSJacob Faibussowitsch 
117030f984aSJacob Faibussowitsch   // default constructor
118030f984aSJacob Faibussowitsch   constexpr CUPMContext() noexcept = default;
119030f984aSJacob Faibussowitsch 
120030f984aSJacob Faibussowitsch   // All of these functions MUST be static in order to be callable from C, otherwise they
121030f984aSJacob Faibussowitsch   // get the implicit 'this' pointer tacked on
122030f984aSJacob Faibussowitsch   PETSC_NODISCARD static PetscErrorCode destroy(PetscDeviceContext) noexcept;
123030f984aSJacob Faibussowitsch   PETSC_NODISCARD static PetscErrorCode changeStreamType(PetscDeviceContext,PetscStreamType) noexcept;
124030f984aSJacob Faibussowitsch   PETSC_NODISCARD static PetscErrorCode setUp(PetscDeviceContext) noexcept;
125030f984aSJacob Faibussowitsch   PETSC_NODISCARD static PetscErrorCode query(PetscDeviceContext,PetscBool*) noexcept;
126030f984aSJacob Faibussowitsch   PETSC_NODISCARD static PetscErrorCode waitForContext(PetscDeviceContext,PetscDeviceContext) noexcept;
127030f984aSJacob Faibussowitsch   PETSC_NODISCARD static PetscErrorCode synchronize(PetscDeviceContext) noexcept;
128*a4af0ceeSJacob Faibussowitsch   template <typename Handle_t>
129*a4af0ceeSJacob Faibussowitsch   PETSC_NODISCARD static PetscErrorCode getHandle(PetscDeviceContext,void*) noexcept;
130*a4af0ceeSJacob Faibussowitsch   PETSC_NODISCARD static PetscErrorCode beginTimer(PetscDeviceContext) noexcept;
131*a4af0ceeSJacob Faibussowitsch   PETSC_NODISCARD static PetscErrorCode endTimer(PetscDeviceContext,PetscLogDouble*) noexcept;
132030f984aSJacob Faibussowitsch };
133030f984aSJacob Faibussowitsch 
134*a4af0ceeSJacob Faibussowitsch template <CUPMDeviceType T>
135030f984aSJacob Faibussowitsch inline PetscErrorCode CUPMContext<T>::destroy(PetscDeviceContext dctx) noexcept
136030f984aSJacob Faibussowitsch {
137030f984aSJacob Faibussowitsch   cupmError_t    cerr;
138030f984aSJacob Faibussowitsch   PetscErrorCode ierr;
139*a4af0ceeSJacob Faibussowitsch   auto           dci = __impls_cast(dctx);
140030f984aSJacob Faibussowitsch 
141030f984aSJacob Faibussowitsch   PetscFunctionBegin;
142030f984aSJacob Faibussowitsch   if (dci->stream) {cerr = cupmStreamDestroy(dci->stream);CHKERRCUPM(cerr);}
143*a4af0ceeSJacob Faibussowitsch   if (dci->event)  {
144*a4af0ceeSJacob Faibussowitsch     cerr = cupmEventDestroy(dci->event);CHKERRCUPM(cerr);
145*a4af0ceeSJacob Faibussowitsch     cerr = cupmEventDestroy(dci->begin);CHKERRCUPM(cerr);
146*a4af0ceeSJacob Faibussowitsch     cerr = cupmEventDestroy(dci->end);CHKERRCUPM(cerr);
147*a4af0ceeSJacob Faibussowitsch   }
148030f984aSJacob Faibussowitsch   ierr = PetscFree(dctx->data);CHKERRQ(ierr);
149030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
150030f984aSJacob Faibussowitsch }
151030f984aSJacob Faibussowitsch 
152*a4af0ceeSJacob Faibussowitsch template <CUPMDeviceType T>
153*a4af0ceeSJacob Faibussowitsch inline PetscErrorCode CUPMContext<T>::changeStreamType(PetscDeviceContext dctx, PETSC_UNUSED PetscStreamType stype) noexcept
154030f984aSJacob Faibussowitsch {
155*a4af0ceeSJacob Faibussowitsch   auto dci = __impls_cast(dctx);
156030f984aSJacob Faibussowitsch 
157030f984aSJacob Faibussowitsch   PetscFunctionBegin;
158030f984aSJacob Faibussowitsch   if (dci->stream) {
159030f984aSJacob Faibussowitsch     cupmError_t cerr;
160030f984aSJacob Faibussowitsch 
161030f984aSJacob Faibussowitsch     cerr = cupmStreamDestroy(dci->stream);CHKERRCUPM(cerr);
162030f984aSJacob Faibussowitsch     dci->stream = nullptr;
163030f984aSJacob Faibussowitsch   }
164030f984aSJacob Faibussowitsch   // set these to null so they aren't usable until setup is called again
165030f984aSJacob Faibussowitsch   dci->blas   = nullptr;
166030f984aSJacob Faibussowitsch   dci->solver = nullptr;
167030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
168030f984aSJacob Faibussowitsch }
169030f984aSJacob Faibussowitsch 
170*a4af0ceeSJacob Faibussowitsch template <CUPMDeviceType T>
171030f984aSJacob Faibussowitsch inline PetscErrorCode CUPMContext<T>::setUp(PetscDeviceContext dctx) noexcept
172030f984aSJacob Faibussowitsch {
173030f984aSJacob Faibussowitsch   PetscErrorCode ierr;
174030f984aSJacob Faibussowitsch   cupmError_t    cerr;
175*a4af0ceeSJacob Faibussowitsch   auto           dci = __impls_cast(dctx);
176030f984aSJacob Faibussowitsch 
177030f984aSJacob Faibussowitsch   PetscFunctionBegin;
178030f984aSJacob Faibussowitsch   if (dci->stream) {cerr = cupmStreamDestroy(dci->stream);CHKERRCUPM(cerr);}
179030f984aSJacob Faibussowitsch   switch (dctx->streamType) {
180030f984aSJacob Faibussowitsch   case PETSC_STREAM_GLOBAL_BLOCKING:
181030f984aSJacob Faibussowitsch     // don't create a stream for global blocking
182030f984aSJacob Faibussowitsch     dci->stream = nullptr;
183030f984aSJacob Faibussowitsch     break;
184030f984aSJacob Faibussowitsch   case PETSC_STREAM_DEFAULT_BLOCKING:
185030f984aSJacob Faibussowitsch     cerr = cupmStreamCreate(&dci->stream);CHKERRCUPM(cerr);
186030f984aSJacob Faibussowitsch     break;
187030f984aSJacob Faibussowitsch   case PETSC_STREAM_GLOBAL_NONBLOCKING:
188030f984aSJacob Faibussowitsch     cerr = cupmStreamCreateWithFlags(&dci->stream,cupmStreamNonBlocking);CHKERRCUPM(cerr);
189030f984aSJacob Faibussowitsch     break;
190030f984aSJacob Faibussowitsch   default:
191*a4af0ceeSJacob Faibussowitsch     SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_CORRUPT,"Invalid PetscStreamType %s",PetscStreamTypes[static_cast<int>(dctx->streamType)]);
192030f984aSJacob Faibussowitsch     break;
193030f984aSJacob Faibussowitsch   }
194*a4af0ceeSJacob Faibussowitsch   if (!dci->event) {
195*a4af0ceeSJacob Faibussowitsch     cerr = cupmEventCreate(&dci->event);CHKERRCUPM(cerr);
196*a4af0ceeSJacob Faibussowitsch     cerr = cupmEventCreate(&dci->begin);CHKERRCUPM(cerr);
197*a4af0ceeSJacob Faibussowitsch     cerr = cupmEventCreate(&dci->end);CHKERRCUPM(cerr);
198*a4af0ceeSJacob Faibussowitsch   }
199*a4af0ceeSJacob Faibussowitsch #if PetscDefined(USE_DEBUG)
200*a4af0ceeSJacob Faibussowitsch   dci->timerInUse = PETSC_FALSE;
201*a4af0ceeSJacob Faibussowitsch #endif
202*a4af0ceeSJacob Faibussowitsch   ierr = __initialize(dctx->device->deviceId,dci);CHKERRQ(ierr);
203030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
204030f984aSJacob Faibussowitsch }
205030f984aSJacob Faibussowitsch 
206*a4af0ceeSJacob Faibussowitsch template <CUPMDeviceType T>
207030f984aSJacob Faibussowitsch inline PetscErrorCode CUPMContext<T>::query(PetscDeviceContext dctx, PetscBool *idle) noexcept
208030f984aSJacob Faibussowitsch {
209030f984aSJacob Faibussowitsch   cupmError_t cerr;
210030f984aSJacob Faibussowitsch 
211030f984aSJacob Faibussowitsch   PetscFunctionBegin;
212*a4af0ceeSJacob Faibussowitsch   cerr = cupmStreamQuery(__impls_cast(dctx)->stream);
213*a4af0ceeSJacob Faibussowitsch   if (cerr == cupmSuccess) *idle = PETSC_TRUE;
214*a4af0ceeSJacob Faibussowitsch   else {
215030f984aSJacob Faibussowitsch     // somethings gone wrong
216*a4af0ceeSJacob Faibussowitsch     if (PetscUnlikely(cerr != cupmErrorNotReady)) CHKERRCUPM(cerr);
217*a4af0ceeSJacob Faibussowitsch     *idle = PETSC_FALSE;
218030f984aSJacob Faibussowitsch   }
219030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
220030f984aSJacob Faibussowitsch }
221030f984aSJacob Faibussowitsch 
222*a4af0ceeSJacob Faibussowitsch template <CUPMDeviceType T>
223030f984aSJacob Faibussowitsch inline PetscErrorCode CUPMContext<T>::waitForContext(PetscDeviceContext dctxa, PetscDeviceContext dctxb) noexcept
224030f984aSJacob Faibussowitsch {
225030f984aSJacob Faibussowitsch   cupmError_t cerr;
226*a4af0ceeSJacob Faibussowitsch   auto        dcia = __impls_cast(dctxa),dcib = __impls_cast(dctxb);
227030f984aSJacob Faibussowitsch 
228030f984aSJacob Faibussowitsch   PetscFunctionBegin;
229030f984aSJacob Faibussowitsch   cerr = cupmEventRecord(dcib->event,dcib->stream);CHKERRCUPM(cerr);
230030f984aSJacob Faibussowitsch   cerr = cupmStreamWaitEvent(dcia->stream,dcib->event,0);CHKERRCUPM(cerr);
231030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
232030f984aSJacob Faibussowitsch }
233030f984aSJacob Faibussowitsch 
234*a4af0ceeSJacob Faibussowitsch template <CUPMDeviceType T>
235030f984aSJacob Faibussowitsch inline PetscErrorCode CUPMContext<T>::synchronize(PetscDeviceContext dctx) noexcept
236030f984aSJacob Faibussowitsch {
237030f984aSJacob Faibussowitsch   cupmError_t cerr;
238*a4af0ceeSJacob Faibussowitsch   auto        dci = __impls_cast(dctx);
239030f984aSJacob Faibussowitsch 
240030f984aSJacob Faibussowitsch   PetscFunctionBegin;
241030f984aSJacob Faibussowitsch   // in case anything was queued on the event
242030f984aSJacob Faibussowitsch   cerr = cupmStreamWaitEvent(dci->stream,dci->event,0);CHKERRCUPM(cerr);
243030f984aSJacob Faibussowitsch   cerr = cupmStreamSynchronize(dci->stream);CHKERRCUPM(cerr);
244030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
245030f984aSJacob Faibussowitsch }
246030f984aSJacob Faibussowitsch 
247*a4af0ceeSJacob Faibussowitsch template <CUPMDeviceType T>
248*a4af0ceeSJacob Faibussowitsch template <typename Handle_T>
249*a4af0ceeSJacob Faibussowitsch inline PetscErrorCode CUPMContext<T>::getHandle(PetscDeviceContext dctx, void *handle) noexcept
250*a4af0ceeSJacob Faibussowitsch {
251*a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
252*a4af0ceeSJacob Faibussowitsch   *static_cast<Handle_T*>(handle) = __impls_cast(dctx)->handle(HandleTag<Handle_T>());
253*a4af0ceeSJacob Faibussowitsch   PetscFunctionReturn(0);
254*a4af0ceeSJacob Faibussowitsch }
255*a4af0ceeSJacob Faibussowitsch 
256*a4af0ceeSJacob Faibussowitsch template <CUPMDeviceType T>
257*a4af0ceeSJacob Faibussowitsch inline PetscErrorCode CUPMContext<T>::beginTimer(PetscDeviceContext dctx) noexcept
258*a4af0ceeSJacob Faibussowitsch {
259*a4af0ceeSJacob Faibussowitsch   auto        dci = __impls_cast(dctx);
260*a4af0ceeSJacob Faibussowitsch   cupmError_t cerr;
261*a4af0ceeSJacob Faibussowitsch 
262*a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
263*a4af0ceeSJacob Faibussowitsch #if PetscDefined(USE_DEBUG)
264*a4af0ceeSJacob Faibussowitsch   if (PetscUnlikely(dci->timerInUse)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Forgot to call PetscLogGpuTimeEnd()?");
265*a4af0ceeSJacob Faibussowitsch   dci->timerInUse = PETSC_TRUE;
266*a4af0ceeSJacob Faibussowitsch #endif
267*a4af0ceeSJacob Faibussowitsch   cerr = cupmEventRecord(dci->begin,dci->stream);CHKERRCUPM(cerr);
268*a4af0ceeSJacob Faibussowitsch   PetscFunctionReturn(0);
269*a4af0ceeSJacob Faibussowitsch }
270*a4af0ceeSJacob Faibussowitsch 
271*a4af0ceeSJacob Faibussowitsch template <CUPMDeviceType T>
272*a4af0ceeSJacob Faibussowitsch inline PetscErrorCode CUPMContext<T>::endTimer(PetscDeviceContext dctx, PetscLogDouble *elapsed) noexcept
273*a4af0ceeSJacob Faibussowitsch {
274*a4af0ceeSJacob Faibussowitsch   cupmError_t cerr;
275*a4af0ceeSJacob Faibussowitsch   float       gtime;
276*a4af0ceeSJacob Faibussowitsch   auto        dci = __impls_cast(dctx);
277*a4af0ceeSJacob Faibussowitsch 
278*a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
279*a4af0ceeSJacob Faibussowitsch #if PetscDefined(USE_DEBUG)
280*a4af0ceeSJacob Faibussowitsch   if (PetscUnlikely(!dci->timerInUse)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Forgot to call PetscLogGpuTimeBegin()?");
281*a4af0ceeSJacob Faibussowitsch   dci->timerInUse = PETSC_FALSE;
282*a4af0ceeSJacob Faibussowitsch #endif
283*a4af0ceeSJacob Faibussowitsch   cerr = cupmEventRecord(dci->end,dci->stream);CHKERRCUPM(cerr);
284*a4af0ceeSJacob Faibussowitsch   cerr = cupmEventSynchronize(dci->end);CHKERRCUPM(cerr);
285*a4af0ceeSJacob Faibussowitsch   cerr = cupmEventElapsedTime(&gtime,dci->begin,dci->end);CHKERRCUPM(cerr);
286*a4af0ceeSJacob Faibussowitsch   *elapsed = static_cast<PetscLogDouble>(gtime);
287*a4af0ceeSJacob Faibussowitsch   PetscFunctionReturn(0);
288*a4af0ceeSJacob Faibussowitsch }
289*a4af0ceeSJacob Faibussowitsch 
290030f984aSJacob Faibussowitsch // initialize the static member variables
291*a4af0ceeSJacob Faibussowitsch template <CUPMDeviceType T> bool CUPMContext<T>::_initialized = false;
292030f984aSJacob Faibussowitsch 
293*a4af0ceeSJacob Faibussowitsch template <CUPMDeviceType T>
294*a4af0ceeSJacob Faibussowitsch std::array<typename CUPMContext<T>::cupmBlasHandle_t,PETSC_DEVICE_MAX_DEVICES>   CUPMContext<T>::_blashandles = {};
295030f984aSJacob Faibussowitsch 
296*a4af0ceeSJacob Faibussowitsch template <CUPMDeviceType T>
297*a4af0ceeSJacob Faibussowitsch std::array<typename CUPMContext<T>::cupmSolverHandle_t,PETSC_DEVICE_MAX_DEVICES> CUPMContext<T>::_solverhandles = {};
298030f984aSJacob Faibussowitsch 
299*a4af0ceeSJacob Faibussowitsch // shorten this one up a bit (and instantiate the templates)
300*a4af0ceeSJacob Faibussowitsch using CUPMContextCuda = CUPMContext<CUPMDeviceType::CUDA>;
301*a4af0ceeSJacob Faibussowitsch using CUPMContextHip  = CUPMContext<CUPMDeviceType::HIP>;
302030f984aSJacob Faibussowitsch 
303030f984aSJacob Faibussowitsch } // namespace Petsc
304030f984aSJacob Faibussowitsch 
305030f984aSJacob Faibussowitsch // shorthand for what is an EXTREMELY long name
306*a4af0ceeSJacob Faibussowitsch #define PetscDeviceContext_(IMPLS) Petsc::CUPMContext<Petsc::CUPMDeviceType::IMPLS>::PetscDeviceContext_IMPLS
307030f984aSJacob Faibussowitsch 
308030f984aSJacob Faibussowitsch // shorthand for casting dctx->data to the appropriate object to access the handles
309*a4af0ceeSJacob Faibussowitsch #define PDC_IMPLS_STATIC_CAST(IMPLS,obj) static_cast<PetscDeviceContext_(IMPLS) *>((obj)->data)
310030f984aSJacob Faibussowitsch 
311*a4af0ceeSJacob Faibussowitsch #endif // PETSCDEVICECONTEXTCUDA_HPP
312