xref: /petsc/src/sys/objects/device/impls/cupm/cupmcontext.hpp (revision 17f48955e3445b92d4f06cdd133e9c1d2d0ea0c8) !
1*17f48955SJacob Faibussowitsch #ifndef PETSCDEVICECONTEXTCUPM_HPP
2030f984aSJacob Faibussowitsch #define PETSCDEVICECONTEXTCUPM_HPP
3030f984aSJacob Faibussowitsch 
4a4af0ceeSJacob Faibussowitsch #include <petsc/private/deviceimpl.h>
5*17f48955SJacob Faibussowitsch #include <petsc/private/cupmblasinterface.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 
11a4af0ceeSJacob Faibussowitsch #include <array>
12a4af0ceeSJacob Faibussowitsch 
13a4af0ceeSJacob Faibussowitsch namespace Petsc
14a4af0ceeSJacob Faibussowitsch {
15a4af0ceeSJacob Faibussowitsch 
16*17f48955SJacob Faibussowitsch namespace Device
17*17f48955SJacob Faibussowitsch {
18*17f48955SJacob Faibussowitsch 
19*17f48955SJacob Faibussowitsch namespace CUPM
20*17f48955SJacob Faibussowitsch {
21*17f48955SJacob Faibussowitsch 
22*17f48955SJacob Faibussowitsch namespace Impl
23*17f48955SJacob Faibussowitsch {
24*17f48955SJacob Faibussowitsch 
25a4af0ceeSJacob Faibussowitsch namespace detail
26a4af0ceeSJacob Faibussowitsch {
27a4af0ceeSJacob Faibussowitsch 
28a4af0ceeSJacob Faibussowitsch // for tag-based dispatch of handle retrieval
29*17f48955SJacob Faibussowitsch template <typename T> struct HandleTag { using type = T; };
30a4af0ceeSJacob Faibussowitsch 
31a4af0ceeSJacob Faibussowitsch } // namespace detail
32030f984aSJacob Faibussowitsch 
33030f984aSJacob Faibussowitsch // Forward declare
34*17f48955SJacob Faibussowitsch template <DeviceType T> class PETSC_VISIBILITY_INTERNAL DeviceContext;
35030f984aSJacob Faibussowitsch 
36*17f48955SJacob Faibussowitsch template <DeviceType T>
37*17f48955SJacob Faibussowitsch class DeviceContext : Impl::BlasInterface<T>
38030f984aSJacob Faibussowitsch {
39*17f48955SJacob Faibussowitsch public:
40*17f48955SJacob Faibussowitsch   PETSC_CUPMBLAS_INHERIT_INTERFACE_TYPEDEFS_USING(cupmBlasInterface_t,T);
41*17f48955SJacob Faibussowitsch 
42*17f48955SJacob Faibussowitsch private:
43*17f48955SJacob Faibussowitsch   template <typename H> using HandleTag = typename detail::HandleTag<H>;
44*17f48955SJacob Faibussowitsch   using stream_tag = HandleTag<cupmStream_t>;
45*17f48955SJacob Faibussowitsch   using blas_tag   = HandleTag<cupmBlasHandle_t>;
46*17f48955SJacob Faibussowitsch   using solver_tag = HandleTag<cupmSolverHandle_t>;
47a4af0ceeSJacob Faibussowitsch 
48030f984aSJacob Faibussowitsch public:
49030f984aSJacob Faibussowitsch   // This is the canonical PETSc "impls" struct that normally resides in a standalone impls
50030f984aSJacob Faibussowitsch   // header, but since we are using the power of templates it must be declared part of
51030f984aSJacob Faibussowitsch   // this class to have easy access the same typedefs. Technically one can make a
52030f984aSJacob Faibussowitsch   // templated struct outside the class but it's more code for the same result.
53030f984aSJacob Faibussowitsch   struct PetscDeviceContext_IMPLS
54030f984aSJacob Faibussowitsch   {
55030f984aSJacob Faibussowitsch     cupmStream_t       stream;
56030f984aSJacob Faibussowitsch     cupmEvent_t        event;
57a4af0ceeSJacob Faibussowitsch     cupmEvent_t        begin; // timer-only
58a4af0ceeSJacob Faibussowitsch     cupmEvent_t        end;   // timer-only
59a4af0ceeSJacob Faibussowitsch #if PetscDefined(USE_DEBUG)
60a4af0ceeSJacob Faibussowitsch     PetscBool          timerInUse;
61a4af0ceeSJacob Faibussowitsch #endif
62030f984aSJacob Faibussowitsch     cupmBlasHandle_t   blas;
63030f984aSJacob Faibussowitsch     cupmSolverHandle_t solver;
64a4af0ceeSJacob Faibussowitsch 
65*17f48955SJacob Faibussowitsch     PETSC_NODISCARD auto get(stream_tag) const -> decltype(this->stream) { return this->stream; }
66*17f48955SJacob Faibussowitsch     PETSC_NODISCARD auto get(blas_tag)   const -> decltype(this->blas)   { return this->blas;   }
67*17f48955SJacob Faibussowitsch     PETSC_NODISCARD auto get(solver_tag) const -> decltype(this->solver) { return this->solver; }
68030f984aSJacob Faibussowitsch   };
69030f984aSJacob Faibussowitsch 
70030f984aSJacob Faibussowitsch private:
71*17f48955SJacob Faibussowitsch   static bool initialized_;
72*17f48955SJacob Faibussowitsch   static std::array<cupmBlasHandle_t,PETSC_DEVICE_MAX_DEVICES>   blashandles_;
73*17f48955SJacob Faibussowitsch   static std::array<cupmSolverHandle_t,PETSC_DEVICE_MAX_DEVICES> solverhandles_;
74030f984aSJacob Faibussowitsch 
75*17f48955SJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(constexpr PetscDeviceContext_IMPLS* impls_cast_(PetscDeviceContext ptr))
76a4af0ceeSJacob Faibussowitsch   {
77a4af0ceeSJacob Faibussowitsch     return static_cast<PetscDeviceContext_IMPLS*>(ptr->data);
78a4af0ceeSJacob Faibussowitsch   }
79a4af0ceeSJacob Faibussowitsch 
80*17f48955SJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode initialize_handle_(cupmBlasHandle_t &handle))
81030f984aSJacob Faibussowitsch   {
82030f984aSJacob Faibussowitsch     PetscFunctionBegin;
83*17f48955SJacob Faibussowitsch     if (handle) PetscFunctionReturn(0);
84*17f48955SJacob Faibussowitsch     for (auto i = 0; i < 3; ++i) {
85*17f48955SJacob Faibussowitsch       auto cberr = cupmBlasCreate(&handle);
86*17f48955SJacob Faibussowitsch       if (PetscLikely(cberr == CUPMBLAS_STATUS_SUCCESS)) break;
87*17f48955SJacob Faibussowitsch       if (PetscUnlikely(cberr != CUPMBLAS_STATUS_ALLOC_FAILED) && (cberr != CUPMBLAS_STATUS_NOT_INITIALIZED)) CHKERRCUPMBLAS(cberr);
88*17f48955SJacob Faibussowitsch       if (i != 2) {
89*17f48955SJacob Faibussowitsch         auto ierr = PetscSleep(3);CHKERRQ(ierr);
90*17f48955SJacob Faibussowitsch         continue;
91a4af0ceeSJacob Faibussowitsch       }
92*17f48955SJacob Faibussowitsch       if (PetscUnlikely(cberr != CUPMBLAS_STATUS_SUCCESS)) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_GPU_RESOURCE,"Unable to initialize %s",cupmBlasName());
93a4af0ceeSJacob Faibussowitsch     }
94030f984aSJacob Faibussowitsch     PetscFunctionReturn(0);
95030f984aSJacob Faibussowitsch   }
96030f984aSJacob Faibussowitsch 
97*17f48955SJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode set_handle_stream_(cupmBlasHandle_t &handle, cupmStream_t &stream))
98*17f48955SJacob Faibussowitsch   {
99*17f48955SJacob Faibussowitsch     cupmStream_t    cupmStream;
100*17f48955SJacob Faibussowitsch     cupmBlasError_t cberr;
101*17f48955SJacob Faibussowitsch 
102*17f48955SJacob Faibussowitsch     PetscFunctionBegin;
103*17f48955SJacob Faibussowitsch     cberr = cupmBlasGetStream(handle,&cupmStream);CHKERRCUPMBLAS(cberr);
104*17f48955SJacob Faibussowitsch     if (cupmStream != stream) {cberr = cupmBlasSetStream(handle,stream);CHKERRCUPMBLAS(cberr);}
105*17f48955SJacob Faibussowitsch     PetscFunctionReturn(0);
106*17f48955SJacob Faibussowitsch   }
107*17f48955SJacob Faibussowitsch 
108*17f48955SJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode finalize_())
109*17f48955SJacob Faibussowitsch   {
110*17f48955SJacob Faibussowitsch     PetscFunctionBegin;
111*17f48955SJacob Faibussowitsch     for (auto&& handle : blashandles_) {
112*17f48955SJacob Faibussowitsch       if (handle) {
113*17f48955SJacob Faibussowitsch         auto cberr = cupmBlasDestroy(handle);CHKERRCUPMBLAS(cberr);
114*17f48955SJacob Faibussowitsch         handle     = nullptr;
115*17f48955SJacob Faibussowitsch       }
116*17f48955SJacob Faibussowitsch     }
117*17f48955SJacob Faibussowitsch     for (auto&& handle : solverhandles_) {
118*17f48955SJacob Faibussowitsch       if (handle) {
119*17f48955SJacob Faibussowitsch         auto ierr = cupmBlasInterface_t::DestroyHandle(handle);CHKERRQ(ierr);
120*17f48955SJacob Faibussowitsch         handle    = nullptr;
121*17f48955SJacob Faibussowitsch       }
122*17f48955SJacob Faibussowitsch     }
123*17f48955SJacob Faibussowitsch     initialized_ = false;
124*17f48955SJacob Faibussowitsch     PetscFunctionReturn(0);
125*17f48955SJacob Faibussowitsch   }
126*17f48955SJacob Faibussowitsch 
127*17f48955SJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode initialize_(PetscInt id, PetscDeviceContext_IMPLS *dci))
128030f984aSJacob Faibussowitsch   {
129030f984aSJacob Faibussowitsch     PetscErrorCode ierr;
130030f984aSJacob Faibussowitsch 
131030f984aSJacob Faibussowitsch     PetscFunctionBegin;
132a4af0ceeSJacob Faibussowitsch     ierr = PetscDeviceCheckDeviceCount_Internal(id);CHKERRQ(ierr);
133*17f48955SJacob Faibussowitsch     if (!initialized_) {
134*17f48955SJacob Faibussowitsch       initialized_ = true;
135*17f48955SJacob Faibussowitsch       ierr = PetscRegisterFinalize(finalize_);CHKERRQ(ierr);
136030f984aSJacob Faibussowitsch     }
137a4af0ceeSJacob Faibussowitsch     // use the blashandle as a canary
138*17f48955SJacob Faibussowitsch     if (!blashandles_[id]) {
139*17f48955SJacob Faibussowitsch       ierr = initialize_handle_(blashandles_[id]);CHKERRQ(ierr);
140*17f48955SJacob Faibussowitsch       ierr = cupmBlasInterface_t::InitializeHandle(solverhandles_[id]);CHKERRQ(ierr);
141030f984aSJacob Faibussowitsch     }
142*17f48955SJacob Faibussowitsch     ierr = set_handle_stream_(blashandles_[id],dci->stream);CHKERRQ(ierr);
143*17f48955SJacob Faibussowitsch     ierr = cupmBlasInterface_t::SetHandleStream(solverhandles_[id],dci->stream);CHKERRQ(ierr);
144*17f48955SJacob Faibussowitsch     dci->blas   = blashandles_[id];
145*17f48955SJacob Faibussowitsch     dci->solver = solverhandles_[id];
146030f984aSJacob Faibussowitsch     PetscFunctionReturn(0);
147030f984aSJacob Faibussowitsch   }
148030f984aSJacob Faibussowitsch 
149030f984aSJacob Faibussowitsch public:
150a4af0ceeSJacob Faibussowitsch   const struct _DeviceContextOps ops = {
151a4af0ceeSJacob Faibussowitsch     destroy,
152a4af0ceeSJacob Faibussowitsch     changeStreamType,
153a4af0ceeSJacob Faibussowitsch     setUp,
154a4af0ceeSJacob Faibussowitsch     query,
155a4af0ceeSJacob Faibussowitsch     waitForContext,
156a4af0ceeSJacob Faibussowitsch     synchronize,
157*17f48955SJacob Faibussowitsch     getHandle<blas_tag>,
158*17f48955SJacob Faibussowitsch     getHandle<solver_tag>,
159*17f48955SJacob Faibussowitsch     getHandle<stream_tag>,
160a4af0ceeSJacob Faibussowitsch     beginTimer,
161*17f48955SJacob Faibussowitsch     endTimer,
162a4af0ceeSJacob Faibussowitsch   };
163030f984aSJacob Faibussowitsch 
164030f984aSJacob Faibussowitsch   // All of these functions MUST be static in order to be callable from C, otherwise they
165030f984aSJacob Faibussowitsch   // get the implicit 'this' pointer tacked on
166*17f48955SJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode destroy(PetscDeviceContext));
167*17f48955SJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode changeStreamType(PetscDeviceContext,PetscStreamType));
168*17f48955SJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode setUp(PetscDeviceContext));
169*17f48955SJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode query(PetscDeviceContext,PetscBool*));
170*17f48955SJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode waitForContext(PetscDeviceContext,PetscDeviceContext));
171*17f48955SJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode synchronize(PetscDeviceContext));
172a4af0ceeSJacob Faibussowitsch   template <typename Handle_t>
173*17f48955SJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode getHandle(PetscDeviceContext,void*));
174*17f48955SJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode beginTimer(PetscDeviceContext));
175*17f48955SJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode endTimer(PetscDeviceContext,PetscLogDouble*));
176030f984aSJacob Faibussowitsch };
177030f984aSJacob Faibussowitsch 
178*17f48955SJacob Faibussowitsch template <DeviceType T>
179*17f48955SJacob Faibussowitsch PETSC_CXX_COMPAT_DEFN(PetscErrorCode DeviceContext<T>::destroy(PetscDeviceContext dctx))
180030f984aSJacob Faibussowitsch {
181030f984aSJacob Faibussowitsch   cupmError_t    cerr;
182030f984aSJacob Faibussowitsch   PetscErrorCode ierr;
183*17f48955SJacob Faibussowitsch   auto           dci = impls_cast_(dctx);
184030f984aSJacob Faibussowitsch 
185030f984aSJacob Faibussowitsch   PetscFunctionBegin;
186030f984aSJacob Faibussowitsch   if (dci->stream) {cerr = cupmStreamDestroy(dci->stream);CHKERRCUPM(cerr);}
187*17f48955SJacob Faibussowitsch   if (dci->event)  {cerr = cupmEventDestroy(dci->event);CHKERRCUPM(cerr);  }
188*17f48955SJacob Faibussowitsch   if (dci->begin)  {cerr = cupmEventDestroy(dci->begin);CHKERRCUPM(cerr);  }
189*17f48955SJacob Faibussowitsch   if (dci->end)    {cerr = cupmEventDestroy(dci->end);CHKERRCUPM(cerr);    }
190030f984aSJacob Faibussowitsch   ierr = PetscFree(dctx->data);CHKERRQ(ierr);
191030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
192030f984aSJacob Faibussowitsch }
193030f984aSJacob Faibussowitsch 
194*17f48955SJacob Faibussowitsch template <DeviceType T>
195*17f48955SJacob Faibussowitsch PETSC_CXX_COMPAT_DEFN(PetscErrorCode DeviceContext<T>::changeStreamType(PetscDeviceContext dctx, PETSC_UNUSED PetscStreamType stype))
196030f984aSJacob Faibussowitsch {
197*17f48955SJacob Faibussowitsch   auto dci = impls_cast_(dctx);
198030f984aSJacob Faibussowitsch 
199030f984aSJacob Faibussowitsch   PetscFunctionBegin;
200030f984aSJacob Faibussowitsch   if (dci->stream) {
201*17f48955SJacob Faibussowitsch     auto cerr = cupmStreamDestroy(dci->stream);CHKERRCUPM(cerr);
202030f984aSJacob Faibussowitsch     dci->stream = nullptr;
203030f984aSJacob Faibussowitsch   }
204030f984aSJacob Faibussowitsch   // set these to null so they aren't usable until setup is called again
205030f984aSJacob Faibussowitsch   dci->blas   = nullptr;
206030f984aSJacob Faibussowitsch   dci->solver = nullptr;
207030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
208030f984aSJacob Faibussowitsch }
209030f984aSJacob Faibussowitsch 
210*17f48955SJacob Faibussowitsch template <DeviceType T>
211*17f48955SJacob Faibussowitsch PETSC_CXX_COMPAT_DEFN(PetscErrorCode DeviceContext<T>::setUp(PetscDeviceContext dctx))
212030f984aSJacob Faibussowitsch {
213030f984aSJacob Faibussowitsch   PetscErrorCode ierr;
214030f984aSJacob Faibussowitsch   cupmError_t    cerr;
215*17f48955SJacob Faibussowitsch   auto           dci = impls_cast_(dctx);
216030f984aSJacob Faibussowitsch 
217030f984aSJacob Faibussowitsch   PetscFunctionBegin;
218*17f48955SJacob Faibussowitsch   if (dci->stream) {
219*17f48955SJacob Faibussowitsch     cerr = cupmStreamDestroy(dci->stream);CHKERRCUPM(cerr);
220*17f48955SJacob Faibussowitsch     dci->stream = nullptr;
221*17f48955SJacob Faibussowitsch   }
222030f984aSJacob Faibussowitsch   switch (dctx->streamType) {
223030f984aSJacob Faibussowitsch   case PETSC_STREAM_GLOBAL_BLOCKING:
224030f984aSJacob Faibussowitsch     // don't create a stream for global blocking
225030f984aSJacob Faibussowitsch     break;
226030f984aSJacob Faibussowitsch   case PETSC_STREAM_DEFAULT_BLOCKING:
227030f984aSJacob Faibussowitsch     cerr = cupmStreamCreate(&dci->stream);CHKERRCUPM(cerr);
228030f984aSJacob Faibussowitsch     break;
229030f984aSJacob Faibussowitsch   case PETSC_STREAM_GLOBAL_NONBLOCKING:
230030f984aSJacob Faibussowitsch     cerr = cupmStreamCreateWithFlags(&dci->stream,cupmStreamNonBlocking);CHKERRCUPM(cerr);
231030f984aSJacob Faibussowitsch     break;
232030f984aSJacob Faibussowitsch   default:
233*17f48955SJacob Faibussowitsch     SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_CORRUPT,"Invalid PetscStreamType %s",PetscStreamTypes[util::integral_value(dctx->streamType)]);
234030f984aSJacob Faibussowitsch     break;
235030f984aSJacob Faibussowitsch   }
236*17f48955SJacob Faibussowitsch   if (!dci->event) {cerr = cupmEventCreate(&dci->event);CHKERRCUPM(cerr);}
237a4af0ceeSJacob Faibussowitsch #if PetscDefined(USE_DEBUG)
238a4af0ceeSJacob Faibussowitsch   dci->timerInUse = PETSC_FALSE;
239a4af0ceeSJacob Faibussowitsch #endif
240*17f48955SJacob Faibussowitsch   ierr = initialize_(dctx->device->deviceId,dci);CHKERRQ(ierr);
241030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
242030f984aSJacob Faibussowitsch }
243030f984aSJacob Faibussowitsch 
244*17f48955SJacob Faibussowitsch template <DeviceType T>
245*17f48955SJacob Faibussowitsch PETSC_CXX_COMPAT_DEFN(PetscErrorCode DeviceContext<T>::query(PetscDeviceContext dctx, PetscBool *idle))
246030f984aSJacob Faibussowitsch {
247030f984aSJacob Faibussowitsch   cupmError_t cerr;
248030f984aSJacob Faibussowitsch 
249030f984aSJacob Faibussowitsch   PetscFunctionBegin;
250*17f48955SJacob Faibussowitsch   cerr = cupmStreamQuery(impls_cast_(dctx)->stream);
251a4af0ceeSJacob Faibussowitsch   if (cerr == cupmSuccess) *idle = PETSC_TRUE;
252a4af0ceeSJacob Faibussowitsch   else {
253030f984aSJacob Faibussowitsch     // somethings gone wrong
254a4af0ceeSJacob Faibussowitsch     if (PetscUnlikely(cerr != cupmErrorNotReady)) CHKERRCUPM(cerr);
255a4af0ceeSJacob Faibussowitsch     *idle = PETSC_FALSE;
256030f984aSJacob Faibussowitsch   }
257030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
258030f984aSJacob Faibussowitsch }
259030f984aSJacob Faibussowitsch 
260*17f48955SJacob Faibussowitsch template <DeviceType T>
261*17f48955SJacob Faibussowitsch PETSC_CXX_COMPAT_DEFN(PetscErrorCode DeviceContext<T>::waitForContext(PetscDeviceContext dctxa, PetscDeviceContext dctxb))
262030f984aSJacob Faibussowitsch {
263030f984aSJacob Faibussowitsch   cupmError_t cerr;
264*17f48955SJacob Faibussowitsch   auto        dcib = impls_cast_(dctxb);
265030f984aSJacob Faibussowitsch 
266030f984aSJacob Faibussowitsch   PetscFunctionBegin;
267030f984aSJacob Faibussowitsch   cerr = cupmEventRecord(dcib->event,dcib->stream);CHKERRCUPM(cerr);
268*17f48955SJacob Faibussowitsch   cerr = cupmStreamWaitEvent(impls_cast_(dctxa)->stream,dcib->event,0);CHKERRCUPM(cerr);
269030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
270030f984aSJacob Faibussowitsch }
271030f984aSJacob Faibussowitsch 
272*17f48955SJacob Faibussowitsch template <DeviceType T>
273*17f48955SJacob Faibussowitsch PETSC_CXX_COMPAT_DEFN(PetscErrorCode DeviceContext<T>::synchronize(PetscDeviceContext dctx))
274030f984aSJacob Faibussowitsch {
275030f984aSJacob Faibussowitsch   cupmError_t cerr;
276*17f48955SJacob Faibussowitsch   auto        dci = impls_cast_(dctx);
277030f984aSJacob Faibussowitsch 
278030f984aSJacob Faibussowitsch   PetscFunctionBegin;
279030f984aSJacob Faibussowitsch   // in case anything was queued on the event
280030f984aSJacob Faibussowitsch   cerr = cupmStreamWaitEvent(dci->stream,dci->event,0);CHKERRCUPM(cerr);
281030f984aSJacob Faibussowitsch   cerr = cupmStreamSynchronize(dci->stream);CHKERRCUPM(cerr);
282030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
283030f984aSJacob Faibussowitsch }
284030f984aSJacob Faibussowitsch 
285*17f48955SJacob Faibussowitsch template <DeviceType T>
286*17f48955SJacob Faibussowitsch template <typename handle_t>
287*17f48955SJacob Faibussowitsch PETSC_CXX_COMPAT_DEFN(PetscErrorCode DeviceContext<T>::getHandle(PetscDeviceContext dctx, void *handle))
288a4af0ceeSJacob Faibussowitsch {
289a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
290*17f48955SJacob Faibussowitsch   *static_cast<typename handle_t::type*>(handle) = impls_cast_(dctx)->get(handle_t());
291a4af0ceeSJacob Faibussowitsch   PetscFunctionReturn(0);
292a4af0ceeSJacob Faibussowitsch }
293a4af0ceeSJacob Faibussowitsch 
294*17f48955SJacob Faibussowitsch template <DeviceType T>
295*17f48955SJacob Faibussowitsch PETSC_CXX_COMPAT_DEFN(PetscErrorCode DeviceContext<T>::beginTimer(PetscDeviceContext dctx))
296a4af0ceeSJacob Faibussowitsch {
297*17f48955SJacob Faibussowitsch   auto        dci = impls_cast_(dctx);
298a4af0ceeSJacob Faibussowitsch   cupmError_t cerr;
299a4af0ceeSJacob Faibussowitsch 
300a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
301a4af0ceeSJacob Faibussowitsch #if PetscDefined(USE_DEBUG)
302a4af0ceeSJacob Faibussowitsch   if (PetscUnlikely(dci->timerInUse)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Forgot to call PetscLogGpuTimeEnd()?");
303a4af0ceeSJacob Faibussowitsch   dci->timerInUse = PETSC_TRUE;
304a4af0ceeSJacob Faibussowitsch #endif
305*17f48955SJacob Faibussowitsch   if (!dci->begin) {
306*17f48955SJacob Faibussowitsch     cerr = cupmEventCreate(&dci->begin);CHKERRCUPM(cerr);
307*17f48955SJacob Faibussowitsch     cerr = cupmEventCreate(&dci->end);CHKERRCUPM(cerr);
308*17f48955SJacob Faibussowitsch   }
309a4af0ceeSJacob Faibussowitsch   cerr = cupmEventRecord(dci->begin,dci->stream);CHKERRCUPM(cerr);
310a4af0ceeSJacob Faibussowitsch   PetscFunctionReturn(0);
311a4af0ceeSJacob Faibussowitsch }
312a4af0ceeSJacob Faibussowitsch 
313*17f48955SJacob Faibussowitsch template <DeviceType T>
314*17f48955SJacob Faibussowitsch PETSC_CXX_COMPAT_DEFN(PetscErrorCode DeviceContext<T>::endTimer(PetscDeviceContext dctx, PetscLogDouble *elapsed))
315a4af0ceeSJacob Faibussowitsch {
316a4af0ceeSJacob Faibussowitsch   cupmError_t cerr;
317a4af0ceeSJacob Faibussowitsch   float       gtime;
318*17f48955SJacob Faibussowitsch   auto        dci = impls_cast_(dctx);
319a4af0ceeSJacob Faibussowitsch 
320a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
321a4af0ceeSJacob Faibussowitsch #if PetscDefined(USE_DEBUG)
322a4af0ceeSJacob Faibussowitsch   if (PetscUnlikely(!dci->timerInUse)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Forgot to call PetscLogGpuTimeBegin()?");
323a4af0ceeSJacob Faibussowitsch   dci->timerInUse = PETSC_FALSE;
324a4af0ceeSJacob Faibussowitsch #endif
325a4af0ceeSJacob Faibussowitsch   cerr = cupmEventRecord(dci->end,dci->stream);CHKERRCUPM(cerr);
326a4af0ceeSJacob Faibussowitsch   cerr = cupmEventSynchronize(dci->end);CHKERRCUPM(cerr);
327a4af0ceeSJacob Faibussowitsch   cerr = cupmEventElapsedTime(&gtime,dci->begin,dci->end);CHKERRCUPM(cerr);
328*17f48955SJacob Faibussowitsch   *elapsed = static_cast<util::remove_pointer_t<decltype(elapsed)>>(gtime);
329a4af0ceeSJacob Faibussowitsch   PetscFunctionReturn(0);
330a4af0ceeSJacob Faibussowitsch }
331a4af0ceeSJacob Faibussowitsch 
332030f984aSJacob Faibussowitsch // initialize the static member variables
333*17f48955SJacob Faibussowitsch template <DeviceType T> bool DeviceContext<T>::initialized_ = false;
334030f984aSJacob Faibussowitsch 
335*17f48955SJacob Faibussowitsch template <DeviceType T>
336*17f48955SJacob Faibussowitsch std::array<typename DeviceContext<T>::cupmBlasHandle_t,PETSC_DEVICE_MAX_DEVICES>   DeviceContext<T>::blashandles_ = {};
337030f984aSJacob Faibussowitsch 
338*17f48955SJacob Faibussowitsch template <DeviceType T>
339*17f48955SJacob Faibussowitsch std::array<typename DeviceContext<T>::cupmSolverHandle_t,PETSC_DEVICE_MAX_DEVICES> DeviceContext<T>::solverhandles_ = {};
340*17f48955SJacob Faibussowitsch 
341*17f48955SJacob Faibussowitsch } // namespace Impl
342030f984aSJacob Faibussowitsch 
343a4af0ceeSJacob Faibussowitsch // shorten this one up a bit (and instantiate the templates)
344*17f48955SJacob Faibussowitsch using CUPMContextCuda = Impl::DeviceContext<DeviceType::CUDA>;
345*17f48955SJacob Faibussowitsch using CUPMContextHip  = Impl::DeviceContext<DeviceType::HIP>;
346030f984aSJacob Faibussowitsch 
347030f984aSJacob Faibussowitsch // shorthand for what is an EXTREMELY long name
348*17f48955SJacob Faibussowitsch #define PetscDeviceContext_(IMPLS) Petsc::Device::CUPM::Impl::DeviceContext<Petsc::Device::CUPM::DeviceType::IMPLS>::PetscDeviceContext_IMPLS
349030f984aSJacob Faibussowitsch 
350*17f48955SJacob Faibussowitsch } // namespace CUPM
351*17f48955SJacob Faibussowitsch 
352*17f48955SJacob Faibussowitsch } // namespace Device
353*17f48955SJacob Faibussowitsch 
354*17f48955SJacob Faibussowitsch } // namespace Petsc
355030f984aSJacob Faibussowitsch 
356a4af0ceeSJacob Faibussowitsch #endif // PETSCDEVICECONTEXTCUDA_HPP
357