xref: /petsc/src/sys/objects/device/impls/cupm/cupmcontext.hpp (revision 98921bda46e76d7aaed9e0138c5ff9d0ce93f355)
117f48955SJacob Faibussowitsch #ifndef PETSCDEVICECONTEXTCUPM_HPP
2030f984aSJacob Faibussowitsch #define PETSCDEVICECONTEXTCUPM_HPP
3030f984aSJacob Faibussowitsch 
4a4af0ceeSJacob Faibussowitsch #include <petsc/private/deviceimpl.h>
517f48955SJacob Faibussowitsch #include <petsc/private/cupmblasinterface.hpp>
6030f984aSJacob Faibussowitsch 
7a4af0ceeSJacob Faibussowitsch #include <array>
8a4af0ceeSJacob Faibussowitsch 
9a4af0ceeSJacob Faibussowitsch namespace Petsc
10a4af0ceeSJacob Faibussowitsch {
11a4af0ceeSJacob Faibussowitsch 
1217f48955SJacob Faibussowitsch namespace Device
1317f48955SJacob Faibussowitsch {
1417f48955SJacob Faibussowitsch 
1517f48955SJacob Faibussowitsch namespace CUPM
1617f48955SJacob Faibussowitsch {
1717f48955SJacob Faibussowitsch 
1817f48955SJacob Faibussowitsch namespace Impl
1917f48955SJacob Faibussowitsch {
2017f48955SJacob Faibussowitsch 
21a4af0ceeSJacob Faibussowitsch namespace detail
22a4af0ceeSJacob Faibussowitsch {
23a4af0ceeSJacob Faibussowitsch 
24a4af0ceeSJacob Faibussowitsch // for tag-based dispatch of handle retrieval
2517f48955SJacob Faibussowitsch template <typename T> struct HandleTag { using type = T; };
26a4af0ceeSJacob Faibussowitsch 
27a4af0ceeSJacob Faibussowitsch } // namespace detail
28030f984aSJacob Faibussowitsch 
29030f984aSJacob Faibussowitsch // Forward declare
3017f48955SJacob Faibussowitsch template <DeviceType T> class PETSC_VISIBILITY_INTERNAL DeviceContext;
31030f984aSJacob Faibussowitsch 
3217f48955SJacob Faibussowitsch template <DeviceType T>
3317f48955SJacob Faibussowitsch class DeviceContext : Impl::BlasInterface<T>
34030f984aSJacob Faibussowitsch {
3517f48955SJacob Faibussowitsch public:
3617f48955SJacob Faibussowitsch   PETSC_CUPMBLAS_INHERIT_INTERFACE_TYPEDEFS_USING(cupmBlasInterface_t,T);
3717f48955SJacob Faibussowitsch 
3817f48955SJacob Faibussowitsch private:
3917f48955SJacob Faibussowitsch   template <typename H> using HandleTag = typename detail::HandleTag<H>;
4017f48955SJacob Faibussowitsch   using stream_tag = HandleTag<cupmStream_t>;
4117f48955SJacob Faibussowitsch   using blas_tag   = HandleTag<cupmBlasHandle_t>;
4217f48955SJacob Faibussowitsch   using solver_tag = HandleTag<cupmSolverHandle_t>;
43a4af0ceeSJacob Faibussowitsch 
44030f984aSJacob Faibussowitsch public:
45030f984aSJacob Faibussowitsch   // This is the canonical PETSc "impls" struct that normally resides in a standalone impls
46030f984aSJacob Faibussowitsch   // header, but since we are using the power of templates it must be declared part of
47030f984aSJacob Faibussowitsch   // this class to have easy access the same typedefs. Technically one can make a
48030f984aSJacob Faibussowitsch   // templated struct outside the class but it's more code for the same result.
49030f984aSJacob Faibussowitsch   struct PetscDeviceContext_IMPLS
50030f984aSJacob Faibussowitsch   {
51030f984aSJacob Faibussowitsch     cupmStream_t       stream;
52030f984aSJacob Faibussowitsch     cupmEvent_t        event;
53a4af0ceeSJacob Faibussowitsch     cupmEvent_t        begin; // timer-only
54a4af0ceeSJacob Faibussowitsch     cupmEvent_t        end;   // timer-only
55a4af0ceeSJacob Faibussowitsch #if PetscDefined(USE_DEBUG)
56a4af0ceeSJacob Faibussowitsch     PetscBool          timerInUse;
57a4af0ceeSJacob Faibussowitsch #endif
58030f984aSJacob Faibussowitsch     cupmBlasHandle_t   blas;
59030f984aSJacob Faibussowitsch     cupmSolverHandle_t solver;
60a4af0ceeSJacob Faibussowitsch 
6117f48955SJacob Faibussowitsch     PETSC_NODISCARD auto get(stream_tag) const -> decltype(this->stream) { return this->stream; }
6217f48955SJacob Faibussowitsch     PETSC_NODISCARD auto get(blas_tag)   const -> decltype(this->blas)   { return this->blas;   }
6317f48955SJacob Faibussowitsch     PETSC_NODISCARD auto get(solver_tag) const -> decltype(this->solver) { return this->solver; }
64030f984aSJacob Faibussowitsch   };
65030f984aSJacob Faibussowitsch 
66030f984aSJacob Faibussowitsch private:
6717f48955SJacob Faibussowitsch   static bool initialized_;
6817f48955SJacob Faibussowitsch   static std::array<cupmBlasHandle_t,PETSC_DEVICE_MAX_DEVICES>   blashandles_;
6917f48955SJacob Faibussowitsch   static std::array<cupmSolverHandle_t,PETSC_DEVICE_MAX_DEVICES> solverhandles_;
70030f984aSJacob Faibussowitsch 
7117f48955SJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(constexpr PetscDeviceContext_IMPLS* impls_cast_(PetscDeviceContext ptr))
72a4af0ceeSJacob Faibussowitsch   {
73a4af0ceeSJacob Faibussowitsch     return static_cast<PetscDeviceContext_IMPLS*>(ptr->data);
74a4af0ceeSJacob Faibussowitsch   }
75a4af0ceeSJacob Faibussowitsch 
7617f48955SJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode initialize_handle_(cupmBlasHandle_t &handle))
77030f984aSJacob Faibussowitsch   {
78030f984aSJacob Faibussowitsch     PetscFunctionBegin;
7917f48955SJacob Faibussowitsch     if (handle) PetscFunctionReturn(0);
8017f48955SJacob Faibussowitsch     for (auto i = 0; i < 3; ++i) {
8117f48955SJacob Faibussowitsch       auto cberr = cupmBlasCreate(&handle);
8217f48955SJacob Faibussowitsch       if (PetscLikely(cberr == CUPMBLAS_STATUS_SUCCESS)) break;
8317f48955SJacob Faibussowitsch       if (PetscUnlikely(cberr != CUPMBLAS_STATUS_ALLOC_FAILED) && (cberr != CUPMBLAS_STATUS_NOT_INITIALIZED)) CHKERRCUPMBLAS(cberr);
8417f48955SJacob Faibussowitsch       if (i != 2) {
8517f48955SJacob Faibussowitsch         auto ierr = PetscSleep(3);CHKERRQ(ierr);
8617f48955SJacob Faibussowitsch         continue;
87a4af0ceeSJacob Faibussowitsch       }
88*98921bdaSJacob Faibussowitsch       if (PetscUnlikely(cberr != CUPMBLAS_STATUS_SUCCESS)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_GPU_RESOURCE,"Unable to initialize %s",cupmBlasName());
89a4af0ceeSJacob Faibussowitsch     }
90030f984aSJacob Faibussowitsch     PetscFunctionReturn(0);
91030f984aSJacob Faibussowitsch   }
92030f984aSJacob Faibussowitsch 
9317f48955SJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode set_handle_stream_(cupmBlasHandle_t &handle, cupmStream_t &stream))
9417f48955SJacob Faibussowitsch   {
9517f48955SJacob Faibussowitsch     cupmStream_t    cupmStream;
9617f48955SJacob Faibussowitsch     cupmBlasError_t cberr;
9717f48955SJacob Faibussowitsch 
9817f48955SJacob Faibussowitsch     PetscFunctionBegin;
9917f48955SJacob Faibussowitsch     cberr = cupmBlasGetStream(handle,&cupmStream);CHKERRCUPMBLAS(cberr);
10017f48955SJacob Faibussowitsch     if (cupmStream != stream) {cberr = cupmBlasSetStream(handle,stream);CHKERRCUPMBLAS(cberr);}
10117f48955SJacob Faibussowitsch     PetscFunctionReturn(0);
10217f48955SJacob Faibussowitsch   }
10317f48955SJacob Faibussowitsch 
10417f48955SJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode finalize_())
10517f48955SJacob Faibussowitsch   {
10617f48955SJacob Faibussowitsch     PetscFunctionBegin;
10717f48955SJacob Faibussowitsch     for (auto&& handle : blashandles_) {
10817f48955SJacob Faibussowitsch       if (handle) {
10917f48955SJacob Faibussowitsch         auto cberr = cupmBlasDestroy(handle);CHKERRCUPMBLAS(cberr);
11017f48955SJacob Faibussowitsch         handle     = nullptr;
11117f48955SJacob Faibussowitsch       }
11217f48955SJacob Faibussowitsch     }
11317f48955SJacob Faibussowitsch     for (auto&& handle : solverhandles_) {
11417f48955SJacob Faibussowitsch       if (handle) {
11517f48955SJacob Faibussowitsch         auto ierr = cupmBlasInterface_t::DestroyHandle(handle);CHKERRQ(ierr);
11617f48955SJacob Faibussowitsch         handle    = nullptr;
11717f48955SJacob Faibussowitsch       }
11817f48955SJacob Faibussowitsch     }
11917f48955SJacob Faibussowitsch     initialized_ = false;
12017f48955SJacob Faibussowitsch     PetscFunctionReturn(0);
12117f48955SJacob Faibussowitsch   }
12217f48955SJacob Faibussowitsch 
12317f48955SJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode initialize_(PetscInt id, PetscDeviceContext_IMPLS *dci))
124030f984aSJacob Faibussowitsch   {
125030f984aSJacob Faibussowitsch     PetscErrorCode ierr;
126030f984aSJacob Faibussowitsch 
127030f984aSJacob Faibussowitsch     PetscFunctionBegin;
128a4af0ceeSJacob Faibussowitsch     ierr = PetscDeviceCheckDeviceCount_Internal(id);CHKERRQ(ierr);
12917f48955SJacob Faibussowitsch     if (!initialized_) {
13017f48955SJacob Faibussowitsch       initialized_ = true;
13117f48955SJacob Faibussowitsch       ierr = PetscRegisterFinalize(finalize_);CHKERRQ(ierr);
132030f984aSJacob Faibussowitsch     }
133a4af0ceeSJacob Faibussowitsch     // use the blashandle as a canary
13417f48955SJacob Faibussowitsch     if (!blashandles_[id]) {
13517f48955SJacob Faibussowitsch       ierr = initialize_handle_(blashandles_[id]);CHKERRQ(ierr);
13617f48955SJacob Faibussowitsch       ierr = cupmBlasInterface_t::InitializeHandle(solverhandles_[id]);CHKERRQ(ierr);
137030f984aSJacob Faibussowitsch     }
13817f48955SJacob Faibussowitsch     ierr = set_handle_stream_(blashandles_[id],dci->stream);CHKERRQ(ierr);
13917f48955SJacob Faibussowitsch     ierr = cupmBlasInterface_t::SetHandleStream(solverhandles_[id],dci->stream);CHKERRQ(ierr);
14017f48955SJacob Faibussowitsch     dci->blas   = blashandles_[id];
14117f48955SJacob Faibussowitsch     dci->solver = solverhandles_[id];
142030f984aSJacob Faibussowitsch     PetscFunctionReturn(0);
143030f984aSJacob Faibussowitsch   }
144030f984aSJacob Faibussowitsch 
145030f984aSJacob Faibussowitsch public:
146a4af0ceeSJacob Faibussowitsch   const struct _DeviceContextOps ops = {
147a4af0ceeSJacob Faibussowitsch     destroy,
148a4af0ceeSJacob Faibussowitsch     changeStreamType,
149a4af0ceeSJacob Faibussowitsch     setUp,
150a4af0ceeSJacob Faibussowitsch     query,
151a4af0ceeSJacob Faibussowitsch     waitForContext,
152a4af0ceeSJacob Faibussowitsch     synchronize,
15317f48955SJacob Faibussowitsch     getHandle<blas_tag>,
15417f48955SJacob Faibussowitsch     getHandle<solver_tag>,
15517f48955SJacob Faibussowitsch     getHandle<stream_tag>,
156a4af0ceeSJacob Faibussowitsch     beginTimer,
15717f48955SJacob Faibussowitsch     endTimer,
158a4af0ceeSJacob Faibussowitsch   };
159030f984aSJacob Faibussowitsch 
160030f984aSJacob Faibussowitsch   // All of these functions MUST be static in order to be callable from C, otherwise they
161030f984aSJacob Faibussowitsch   // get the implicit 'this' pointer tacked on
16217f48955SJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode destroy(PetscDeviceContext));
16317f48955SJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode changeStreamType(PetscDeviceContext,PetscStreamType));
16417f48955SJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode setUp(PetscDeviceContext));
16517f48955SJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode query(PetscDeviceContext,PetscBool*));
16617f48955SJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode waitForContext(PetscDeviceContext,PetscDeviceContext));
16717f48955SJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode synchronize(PetscDeviceContext));
168a4af0ceeSJacob Faibussowitsch   template <typename Handle_t>
16917f48955SJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode getHandle(PetscDeviceContext,void*));
17017f48955SJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode beginTimer(PetscDeviceContext));
17117f48955SJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode endTimer(PetscDeviceContext,PetscLogDouble*));
172030f984aSJacob Faibussowitsch };
173030f984aSJacob Faibussowitsch 
17417f48955SJacob Faibussowitsch template <DeviceType T>
17517f48955SJacob Faibussowitsch PETSC_CXX_COMPAT_DEFN(PetscErrorCode DeviceContext<T>::destroy(PetscDeviceContext dctx))
176030f984aSJacob Faibussowitsch {
177030f984aSJacob Faibussowitsch   cupmError_t    cerr;
178030f984aSJacob Faibussowitsch   PetscErrorCode ierr;
17917f48955SJacob Faibussowitsch   auto           dci = impls_cast_(dctx);
180030f984aSJacob Faibussowitsch 
181030f984aSJacob Faibussowitsch   PetscFunctionBegin;
182030f984aSJacob Faibussowitsch   if (dci->stream) {cerr = cupmStreamDestroy(dci->stream);CHKERRCUPM(cerr);}
18317f48955SJacob Faibussowitsch   if (dci->event)  {cerr = cupmEventDestroy(dci->event);CHKERRCUPM(cerr);  }
18417f48955SJacob Faibussowitsch   if (dci->begin)  {cerr = cupmEventDestroy(dci->begin);CHKERRCUPM(cerr);  }
18517f48955SJacob Faibussowitsch   if (dci->end)    {cerr = cupmEventDestroy(dci->end);CHKERRCUPM(cerr);    }
186030f984aSJacob Faibussowitsch   ierr = PetscFree(dctx->data);CHKERRQ(ierr);
187030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
188030f984aSJacob Faibussowitsch }
189030f984aSJacob Faibussowitsch 
19017f48955SJacob Faibussowitsch template <DeviceType T>
19117f48955SJacob Faibussowitsch PETSC_CXX_COMPAT_DEFN(PetscErrorCode DeviceContext<T>::changeStreamType(PetscDeviceContext dctx, PETSC_UNUSED PetscStreamType stype))
192030f984aSJacob Faibussowitsch {
19317f48955SJacob Faibussowitsch   auto dci = impls_cast_(dctx);
194030f984aSJacob Faibussowitsch 
195030f984aSJacob Faibussowitsch   PetscFunctionBegin;
196030f984aSJacob Faibussowitsch   if (dci->stream) {
19717f48955SJacob Faibussowitsch     auto cerr = cupmStreamDestroy(dci->stream);CHKERRCUPM(cerr);
198030f984aSJacob Faibussowitsch     dci->stream = nullptr;
199030f984aSJacob Faibussowitsch   }
200030f984aSJacob Faibussowitsch   // set these to null so they aren't usable until setup is called again
201030f984aSJacob Faibussowitsch   dci->blas   = nullptr;
202030f984aSJacob Faibussowitsch   dci->solver = nullptr;
203030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
204030f984aSJacob Faibussowitsch }
205030f984aSJacob Faibussowitsch 
20617f48955SJacob Faibussowitsch template <DeviceType T>
20717f48955SJacob Faibussowitsch PETSC_CXX_COMPAT_DEFN(PetscErrorCode DeviceContext<T>::setUp(PetscDeviceContext dctx))
208030f984aSJacob Faibussowitsch {
209030f984aSJacob Faibussowitsch   PetscErrorCode ierr;
210030f984aSJacob Faibussowitsch   cupmError_t    cerr;
21117f48955SJacob Faibussowitsch   auto           dci = impls_cast_(dctx);
212030f984aSJacob Faibussowitsch 
213030f984aSJacob Faibussowitsch   PetscFunctionBegin;
21417f48955SJacob Faibussowitsch   if (dci->stream) {
21517f48955SJacob Faibussowitsch     cerr = cupmStreamDestroy(dci->stream);CHKERRCUPM(cerr);
21617f48955SJacob Faibussowitsch     dci->stream = nullptr;
21717f48955SJacob Faibussowitsch   }
218030f984aSJacob Faibussowitsch   switch (dctx->streamType) {
219030f984aSJacob Faibussowitsch   case PETSC_STREAM_GLOBAL_BLOCKING:
220030f984aSJacob Faibussowitsch     // don't create a stream for global blocking
221030f984aSJacob Faibussowitsch     break;
222030f984aSJacob Faibussowitsch   case PETSC_STREAM_DEFAULT_BLOCKING:
223030f984aSJacob Faibussowitsch     cerr = cupmStreamCreate(&dci->stream);CHKERRCUPM(cerr);
224030f984aSJacob Faibussowitsch     break;
225030f984aSJacob Faibussowitsch   case PETSC_STREAM_GLOBAL_NONBLOCKING:
226030f984aSJacob Faibussowitsch     cerr = cupmStreamCreateWithFlags(&dci->stream,cupmStreamNonBlocking);CHKERRCUPM(cerr);
227030f984aSJacob Faibussowitsch     break;
228030f984aSJacob Faibussowitsch   default:
229*98921bdaSJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_CORRUPT,"Invalid PetscStreamType %s",PetscStreamTypes[util::integral_value(dctx->streamType)]);
230030f984aSJacob Faibussowitsch     break;
231030f984aSJacob Faibussowitsch   }
23217f48955SJacob Faibussowitsch   if (!dci->event) {cerr = cupmEventCreate(&dci->event);CHKERRCUPM(cerr);}
233a4af0ceeSJacob Faibussowitsch #if PetscDefined(USE_DEBUG)
234a4af0ceeSJacob Faibussowitsch   dci->timerInUse = PETSC_FALSE;
235a4af0ceeSJacob Faibussowitsch #endif
23617f48955SJacob Faibussowitsch   ierr = initialize_(dctx->device->deviceId,dci);CHKERRQ(ierr);
237030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
238030f984aSJacob Faibussowitsch }
239030f984aSJacob Faibussowitsch 
24017f48955SJacob Faibussowitsch template <DeviceType T>
24117f48955SJacob Faibussowitsch PETSC_CXX_COMPAT_DEFN(PetscErrorCode DeviceContext<T>::query(PetscDeviceContext dctx, PetscBool *idle))
242030f984aSJacob Faibussowitsch {
243030f984aSJacob Faibussowitsch   cupmError_t cerr;
244030f984aSJacob Faibussowitsch 
245030f984aSJacob Faibussowitsch   PetscFunctionBegin;
24617f48955SJacob Faibussowitsch   cerr = cupmStreamQuery(impls_cast_(dctx)->stream);
247a4af0ceeSJacob Faibussowitsch   if (cerr == cupmSuccess) *idle = PETSC_TRUE;
248a4af0ceeSJacob Faibussowitsch   else {
249030f984aSJacob Faibussowitsch     // somethings gone wrong
250a4af0ceeSJacob Faibussowitsch     if (PetscUnlikely(cerr != cupmErrorNotReady)) CHKERRCUPM(cerr);
251a4af0ceeSJacob Faibussowitsch     *idle = PETSC_FALSE;
252030f984aSJacob Faibussowitsch   }
253030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
254030f984aSJacob Faibussowitsch }
255030f984aSJacob Faibussowitsch 
25617f48955SJacob Faibussowitsch template <DeviceType T>
25717f48955SJacob Faibussowitsch PETSC_CXX_COMPAT_DEFN(PetscErrorCode DeviceContext<T>::waitForContext(PetscDeviceContext dctxa, PetscDeviceContext dctxb))
258030f984aSJacob Faibussowitsch {
259030f984aSJacob Faibussowitsch   cupmError_t cerr;
26017f48955SJacob Faibussowitsch   auto        dcib = impls_cast_(dctxb);
261030f984aSJacob Faibussowitsch 
262030f984aSJacob Faibussowitsch   PetscFunctionBegin;
263030f984aSJacob Faibussowitsch   cerr = cupmEventRecord(dcib->event,dcib->stream);CHKERRCUPM(cerr);
26417f48955SJacob Faibussowitsch   cerr = cupmStreamWaitEvent(impls_cast_(dctxa)->stream,dcib->event,0);CHKERRCUPM(cerr);
265030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
266030f984aSJacob Faibussowitsch }
267030f984aSJacob Faibussowitsch 
26817f48955SJacob Faibussowitsch template <DeviceType T>
26917f48955SJacob Faibussowitsch PETSC_CXX_COMPAT_DEFN(PetscErrorCode DeviceContext<T>::synchronize(PetscDeviceContext dctx))
270030f984aSJacob Faibussowitsch {
271030f984aSJacob Faibussowitsch   cupmError_t cerr;
27217f48955SJacob Faibussowitsch   auto        dci = impls_cast_(dctx);
273030f984aSJacob Faibussowitsch 
274030f984aSJacob Faibussowitsch   PetscFunctionBegin;
275030f984aSJacob Faibussowitsch   // in case anything was queued on the event
276030f984aSJacob Faibussowitsch   cerr = cupmStreamWaitEvent(dci->stream,dci->event,0);CHKERRCUPM(cerr);
277030f984aSJacob Faibussowitsch   cerr = cupmStreamSynchronize(dci->stream);CHKERRCUPM(cerr);
278030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
279030f984aSJacob Faibussowitsch }
280030f984aSJacob Faibussowitsch 
28117f48955SJacob Faibussowitsch template <DeviceType T>
28217f48955SJacob Faibussowitsch template <typename handle_t>
28317f48955SJacob Faibussowitsch PETSC_CXX_COMPAT_DEFN(PetscErrorCode DeviceContext<T>::getHandle(PetscDeviceContext dctx, void *handle))
284a4af0ceeSJacob Faibussowitsch {
285a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
28617f48955SJacob Faibussowitsch   *static_cast<typename handle_t::type*>(handle) = impls_cast_(dctx)->get(handle_t());
287a4af0ceeSJacob Faibussowitsch   PetscFunctionReturn(0);
288a4af0ceeSJacob Faibussowitsch }
289a4af0ceeSJacob Faibussowitsch 
29017f48955SJacob Faibussowitsch template <DeviceType T>
29117f48955SJacob Faibussowitsch PETSC_CXX_COMPAT_DEFN(PetscErrorCode DeviceContext<T>::beginTimer(PetscDeviceContext dctx))
292a4af0ceeSJacob Faibussowitsch {
29317f48955SJacob Faibussowitsch   auto        dci = impls_cast_(dctx);
294a4af0ceeSJacob Faibussowitsch   cupmError_t cerr;
295a4af0ceeSJacob Faibussowitsch 
296a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
297a4af0ceeSJacob Faibussowitsch #if PetscDefined(USE_DEBUG)
298a4af0ceeSJacob Faibussowitsch   if (PetscUnlikely(dci->timerInUse)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Forgot to call PetscLogGpuTimeEnd()?");
299a4af0ceeSJacob Faibussowitsch   dci->timerInUse = PETSC_TRUE;
300a4af0ceeSJacob Faibussowitsch #endif
30117f48955SJacob Faibussowitsch   if (!dci->begin) {
30217f48955SJacob Faibussowitsch     cerr = cupmEventCreate(&dci->begin);CHKERRCUPM(cerr);
30317f48955SJacob Faibussowitsch     cerr = cupmEventCreate(&dci->end);CHKERRCUPM(cerr);
30417f48955SJacob Faibussowitsch   }
305a4af0ceeSJacob Faibussowitsch   cerr = cupmEventRecord(dci->begin,dci->stream);CHKERRCUPM(cerr);
306a4af0ceeSJacob Faibussowitsch   PetscFunctionReturn(0);
307a4af0ceeSJacob Faibussowitsch }
308a4af0ceeSJacob Faibussowitsch 
30917f48955SJacob Faibussowitsch template <DeviceType T>
31017f48955SJacob Faibussowitsch PETSC_CXX_COMPAT_DEFN(PetscErrorCode DeviceContext<T>::endTimer(PetscDeviceContext dctx, PetscLogDouble *elapsed))
311a4af0ceeSJacob Faibussowitsch {
312a4af0ceeSJacob Faibussowitsch   cupmError_t cerr;
313a4af0ceeSJacob Faibussowitsch   float       gtime;
31417f48955SJacob Faibussowitsch   auto        dci = impls_cast_(dctx);
315a4af0ceeSJacob Faibussowitsch 
316a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
317a4af0ceeSJacob Faibussowitsch #if PetscDefined(USE_DEBUG)
318a4af0ceeSJacob Faibussowitsch   if (PetscUnlikely(!dci->timerInUse)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Forgot to call PetscLogGpuTimeBegin()?");
319a4af0ceeSJacob Faibussowitsch   dci->timerInUse = PETSC_FALSE;
320a4af0ceeSJacob Faibussowitsch #endif
321a4af0ceeSJacob Faibussowitsch   cerr = cupmEventRecord(dci->end,dci->stream);CHKERRCUPM(cerr);
322a4af0ceeSJacob Faibussowitsch   cerr = cupmEventSynchronize(dci->end);CHKERRCUPM(cerr);
323a4af0ceeSJacob Faibussowitsch   cerr = cupmEventElapsedTime(&gtime,dci->begin,dci->end);CHKERRCUPM(cerr);
32417f48955SJacob Faibussowitsch   *elapsed = static_cast<util::remove_pointer_t<decltype(elapsed)>>(gtime);
325a4af0ceeSJacob Faibussowitsch   PetscFunctionReturn(0);
326a4af0ceeSJacob Faibussowitsch }
327a4af0ceeSJacob Faibussowitsch 
328030f984aSJacob Faibussowitsch // initialize the static member variables
32917f48955SJacob Faibussowitsch template <DeviceType T> bool DeviceContext<T>::initialized_ = false;
330030f984aSJacob Faibussowitsch 
33117f48955SJacob Faibussowitsch template <DeviceType T>
33217f48955SJacob Faibussowitsch std::array<typename DeviceContext<T>::cupmBlasHandle_t,PETSC_DEVICE_MAX_DEVICES>   DeviceContext<T>::blashandles_ = {};
333030f984aSJacob Faibussowitsch 
33417f48955SJacob Faibussowitsch template <DeviceType T>
33517f48955SJacob Faibussowitsch std::array<typename DeviceContext<T>::cupmSolverHandle_t,PETSC_DEVICE_MAX_DEVICES> DeviceContext<T>::solverhandles_ = {};
33617f48955SJacob Faibussowitsch 
33717f48955SJacob Faibussowitsch } // namespace Impl
338030f984aSJacob Faibussowitsch 
339a4af0ceeSJacob Faibussowitsch // shorten this one up a bit (and instantiate the templates)
34017f48955SJacob Faibussowitsch using CUPMContextCuda = Impl::DeviceContext<DeviceType::CUDA>;
34117f48955SJacob Faibussowitsch using CUPMContextHip  = Impl::DeviceContext<DeviceType::HIP>;
342030f984aSJacob Faibussowitsch 
343030f984aSJacob Faibussowitsch // shorthand for what is an EXTREMELY long name
34417f48955SJacob Faibussowitsch #define PetscDeviceContext_(IMPLS) Petsc::Device::CUPM::Impl::DeviceContext<Petsc::Device::CUPM::DeviceType::IMPLS>::PetscDeviceContext_IMPLS
345030f984aSJacob Faibussowitsch 
34617f48955SJacob Faibussowitsch } // namespace CUPM
34717f48955SJacob Faibussowitsch 
34817f48955SJacob Faibussowitsch } // namespace Device
34917f48955SJacob Faibussowitsch 
35017f48955SJacob Faibussowitsch } // namespace Petsc
351030f984aSJacob Faibussowitsch 
352a4af0ceeSJacob Faibussowitsch #endif // PETSCDEVICECONTEXTCUDA_HPP
353