xref: /petsc/src/sys/objects/device/impls/cupm/cupmcontext.hpp (revision 7a101e5e7ba9859de4c800924a501d6ea3cd325c)
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>
6*7a101e5eSJacob Faibussowitsch #include <petsc/private/logimpl.h>
7030f984aSJacob Faibussowitsch 
8a4af0ceeSJacob Faibussowitsch #include <array>
9a4af0ceeSJacob Faibussowitsch 
10a4af0ceeSJacob Faibussowitsch namespace Petsc
11a4af0ceeSJacob Faibussowitsch {
12a4af0ceeSJacob Faibussowitsch 
1317f48955SJacob Faibussowitsch namespace Device
1417f48955SJacob Faibussowitsch {
1517f48955SJacob Faibussowitsch 
1617f48955SJacob Faibussowitsch namespace CUPM
1717f48955SJacob Faibussowitsch {
1817f48955SJacob Faibussowitsch 
1917f48955SJacob Faibussowitsch namespace Impl
2017f48955SJacob Faibussowitsch {
2117f48955SJacob Faibussowitsch 
22030f984aSJacob Faibussowitsch // Forward declare
2317f48955SJacob Faibussowitsch template <DeviceType T> class PETSC_VISIBILITY_INTERNAL DeviceContext;
24030f984aSJacob Faibussowitsch 
2517f48955SJacob Faibussowitsch template <DeviceType T>
2617f48955SJacob Faibussowitsch class DeviceContext : Impl::BlasInterface<T>
27030f984aSJacob Faibussowitsch {
2817f48955SJacob Faibussowitsch public:
2917f48955SJacob Faibussowitsch   PETSC_CUPMBLAS_INHERIT_INTERFACE_TYPEDEFS_USING(cupmBlasInterface_t,T);
3017f48955SJacob Faibussowitsch 
3117f48955SJacob Faibussowitsch private:
32*7a101e5eSJacob Faibussowitsch   // for tag-based dispatch of handle retrieval
33*7a101e5eSJacob Faibussowitsch   template <typename H,std::size_t> struct HandleTag { using type = H; };
34*7a101e5eSJacob Faibussowitsch   using stream_tag = HandleTag<cupmStream_t,0>;
35*7a101e5eSJacob Faibussowitsch   using blas_tag   = HandleTag<cupmBlasHandle_t,1>;
36*7a101e5eSJacob Faibussowitsch   using solver_tag = HandleTag<cupmSolverHandle_t,2>;
37a4af0ceeSJacob Faibussowitsch 
38030f984aSJacob Faibussowitsch public:
39030f984aSJacob Faibussowitsch   // This is the canonical PETSc "impls" struct that normally resides in a standalone impls
40030f984aSJacob Faibussowitsch   // header, but since we are using the power of templates it must be declared part of
41030f984aSJacob Faibussowitsch   // this class to have easy access the same typedefs. Technically one can make a
42030f984aSJacob Faibussowitsch   // templated struct outside the class but it's more code for the same result.
43030f984aSJacob Faibussowitsch   struct PetscDeviceContext_IMPLS
44030f984aSJacob Faibussowitsch   {
45030f984aSJacob Faibussowitsch     cupmStream_t       stream;
46030f984aSJacob Faibussowitsch     cupmEvent_t        event;
47a4af0ceeSJacob Faibussowitsch     cupmEvent_t        begin; // timer-only
48a4af0ceeSJacob Faibussowitsch     cupmEvent_t        end;   // timer-only
49a4af0ceeSJacob Faibussowitsch #if PetscDefined(USE_DEBUG)
50a4af0ceeSJacob Faibussowitsch     PetscBool          timerInUse;
51a4af0ceeSJacob Faibussowitsch #endif
52030f984aSJacob Faibussowitsch     cupmBlasHandle_t   blas;
53030f984aSJacob Faibussowitsch     cupmSolverHandle_t solver;
54a4af0ceeSJacob Faibussowitsch 
5517f48955SJacob Faibussowitsch     PETSC_NODISCARD auto get(stream_tag) const -> decltype(this->stream) { return this->stream; }
5617f48955SJacob Faibussowitsch     PETSC_NODISCARD auto get(blas_tag)   const -> decltype(this->blas)   { return this->blas;   }
5717f48955SJacob Faibussowitsch     PETSC_NODISCARD auto get(solver_tag) const -> decltype(this->solver) { return this->solver; }
58030f984aSJacob Faibussowitsch   };
59030f984aSJacob Faibussowitsch 
60030f984aSJacob Faibussowitsch private:
6117f48955SJacob Faibussowitsch   static bool initialized_;
6217f48955SJacob Faibussowitsch   static std::array<cupmBlasHandle_t,PETSC_DEVICE_MAX_DEVICES>   blashandles_;
6317f48955SJacob Faibussowitsch   static std::array<cupmSolverHandle_t,PETSC_DEVICE_MAX_DEVICES> solverhandles_;
64030f984aSJacob Faibussowitsch 
6517f48955SJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(constexpr PetscDeviceContext_IMPLS* impls_cast_(PetscDeviceContext ptr))
66a4af0ceeSJacob Faibussowitsch   {
67a4af0ceeSJacob Faibussowitsch     return static_cast<PetscDeviceContext_IMPLS*>(ptr->data);
68a4af0ceeSJacob Faibussowitsch   }
69a4af0ceeSJacob Faibussowitsch 
70*7a101e5eSJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(constexpr PetscLogEvent CUPMBLAS_HANDLE_CREATE())
71030f984aSJacob Faibussowitsch   {
72*7a101e5eSJacob Faibussowitsch     return T == DeviceType::CUDA ? CUBLAS_HANDLE_CREATE : HIPBLAS_HANDLE_CREATE;
73*7a101e5eSJacob Faibussowitsch   }
74*7a101e5eSJacob Faibussowitsch 
75*7a101e5eSJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(constexpr PetscLogEvent CUPMSOLVER_HANDLE_CREATE())
76*7a101e5eSJacob Faibussowitsch   {
77*7a101e5eSJacob Faibussowitsch     return T == DeviceType::CUDA ? CUSOLVER_HANDLE_CREATE : HIPSOLVER_HANDLE_CREATE;
78*7a101e5eSJacob Faibussowitsch   }
79*7a101e5eSJacob Faibussowitsch 
80*7a101e5eSJacob Faibussowitsch   // this exists purely to satisfy the compiler so the tag-based dispatch works for the other
81*7a101e5eSJacob Faibussowitsch   // handles
82*7a101e5eSJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode initialize_handle_(stream_tag,PetscDeviceContext)) { return 0; }
83*7a101e5eSJacob Faibussowitsch 
84*7a101e5eSJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode create_handle_(cupmBlasHandle_t &handle))
85*7a101e5eSJacob Faibussowitsch   {
86*7a101e5eSJacob Faibussowitsch     PetscLogEvent event;
87*7a101e5eSJacob Faibussowitsch 
88030f984aSJacob Faibussowitsch     PetscFunctionBegin;
89*7a101e5eSJacob Faibussowitsch     if (PetscLikely(handle)) PetscFunctionReturn(0);
90*7a101e5eSJacob Faibussowitsch     PetscCall(PetscLogPauseCurrentEvent_Internal(&event));
91*7a101e5eSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(CUPMBLAS_HANDLE_CREATE(),0,0,0,0));
9217f48955SJacob Faibussowitsch     for (auto i = 0; i < 3; ++i) {
9317f48955SJacob Faibussowitsch       auto cberr = cupmBlasCreate(&handle);
9417f48955SJacob Faibussowitsch       if (PetscLikely(cberr == CUPMBLAS_STATUS_SUCCESS)) break;
959566063dSJacob Faibussowitsch       if (PetscUnlikely(cberr != CUPMBLAS_STATUS_ALLOC_FAILED) && (cberr != CUPMBLAS_STATUS_NOT_INITIALIZED)) PetscCallCUPMBLAS(cberr);
9617f48955SJacob Faibussowitsch       if (i != 2) {
979566063dSJacob Faibussowitsch         PetscCall(PetscSleep(3));
9817f48955SJacob Faibussowitsch         continue;
99a4af0ceeSJacob Faibussowitsch       }
1005f80ce2aSJacob Faibussowitsch       PetscCheck(cberr == CUPMBLAS_STATUS_SUCCESS,PETSC_COMM_SELF,PETSC_ERR_GPU_RESOURCE,"Unable to initialize %s",cupmBlasName());
101a4af0ceeSJacob Faibussowitsch     }
102*7a101e5eSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(CUPMBLAS_HANDLE_CREATE(),0,0,0,0));
103*7a101e5eSJacob Faibussowitsch     PetscCall(PetscLogEventResume_Internal(event));
104030f984aSJacob Faibussowitsch     PetscFunctionReturn(0);
105030f984aSJacob Faibussowitsch   }
106030f984aSJacob Faibussowitsch 
107*7a101e5eSJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode initialize_handle_(blas_tag, PetscDeviceContext dctx))
10817f48955SJacob Faibussowitsch   {
109*7a101e5eSJacob Faibussowitsch     const auto dci = impls_cast_(dctx);
110*7a101e5eSJacob Faibussowitsch     auto& handle = blashandles_[dctx->device->deviceId];
11117f48955SJacob Faibussowitsch 
11217f48955SJacob Faibussowitsch     PetscFunctionBegin;
113*7a101e5eSJacob Faibussowitsch     PetscCall(create_handle_(handle));
114*7a101e5eSJacob Faibussowitsch     PetscCallCUPMBLAS(cupmBlasSetStream(handle,dci->stream));
115*7a101e5eSJacob Faibussowitsch     dci->blas = handle;
116*7a101e5eSJacob Faibussowitsch     PetscFunctionReturn(0);
117*7a101e5eSJacob Faibussowitsch   }
118*7a101e5eSJacob Faibussowitsch 
119*7a101e5eSJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode create_handle_(cupmSolverHandle_t &handle))
120*7a101e5eSJacob Faibussowitsch   {
121*7a101e5eSJacob Faibussowitsch     PetscLogEvent event;
122*7a101e5eSJacob Faibussowitsch 
123*7a101e5eSJacob Faibussowitsch     PetscFunctionBegin;
124*7a101e5eSJacob Faibussowitsch     PetscCall(PetscLogPauseCurrentEvent_Internal(&event));
125*7a101e5eSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(CUPMSOLVER_HANDLE_CREATE(),0,0,0,0));
126*7a101e5eSJacob Faibussowitsch     PetscCall(cupmBlasInterface_t::InitializeHandle(handle));
127*7a101e5eSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(CUPMSOLVER_HANDLE_CREATE(),0,0,0,0));
128*7a101e5eSJacob Faibussowitsch     PetscCall(PetscLogEventResume_Internal(event));
129*7a101e5eSJacob Faibussowitsch     PetscFunctionReturn(0);
130*7a101e5eSJacob Faibussowitsch   }
131*7a101e5eSJacob Faibussowitsch 
132*7a101e5eSJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode initialize_handle_(solver_tag, PetscDeviceContext dctx))
133*7a101e5eSJacob Faibussowitsch   {
134*7a101e5eSJacob Faibussowitsch     const auto dci    = impls_cast_(dctx);
135*7a101e5eSJacob Faibussowitsch     auto&      handle = solverhandles_[dctx->device->deviceId];
136*7a101e5eSJacob Faibussowitsch 
137*7a101e5eSJacob Faibussowitsch     PetscFunctionBegin;
138*7a101e5eSJacob Faibussowitsch     PetscCall(create_handle_(handle));
139*7a101e5eSJacob Faibussowitsch     PetscCall(cupmBlasInterface_t::SetHandleStream(handle,dci->stream));
140*7a101e5eSJacob Faibussowitsch     dci->solver = handle;
14117f48955SJacob Faibussowitsch     PetscFunctionReturn(0);
14217f48955SJacob Faibussowitsch   }
14317f48955SJacob Faibussowitsch 
14417f48955SJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode finalize_())
14517f48955SJacob Faibussowitsch   {
14617f48955SJacob Faibussowitsch     PetscFunctionBegin;
14717f48955SJacob Faibussowitsch     for (auto&& handle : blashandles_) {
14817f48955SJacob Faibussowitsch       if (handle) {
1499566063dSJacob Faibussowitsch         PetscCallCUPMBLAS(cupmBlasDestroy(handle));
15017f48955SJacob Faibussowitsch         handle     = nullptr;
15117f48955SJacob Faibussowitsch       }
15217f48955SJacob Faibussowitsch     }
15317f48955SJacob Faibussowitsch     for (auto&& handle : solverhandles_) {
15417f48955SJacob Faibussowitsch       if (handle) {
1559566063dSJacob Faibussowitsch         PetscCall(cupmBlasInterface_t::DestroyHandle(handle));
15617f48955SJacob Faibussowitsch         handle    = nullptr;
15717f48955SJacob Faibussowitsch       }
15817f48955SJacob Faibussowitsch     }
15917f48955SJacob Faibussowitsch     initialized_ = false;
16017f48955SJacob Faibussowitsch     PetscFunctionReturn(0);
16117f48955SJacob Faibussowitsch   }
16217f48955SJacob Faibussowitsch 
163030f984aSJacob Faibussowitsch public:
164a4af0ceeSJacob Faibussowitsch   const struct _DeviceContextOps ops = {
165a4af0ceeSJacob Faibussowitsch     destroy,
166a4af0ceeSJacob Faibussowitsch     changeStreamType,
167a4af0ceeSJacob Faibussowitsch     setUp,
168a4af0ceeSJacob Faibussowitsch     query,
169a4af0ceeSJacob Faibussowitsch     waitForContext,
170a4af0ceeSJacob Faibussowitsch     synchronize,
17117f48955SJacob Faibussowitsch     getHandle<blas_tag>,
17217f48955SJacob Faibussowitsch     getHandle<solver_tag>,
17317f48955SJacob Faibussowitsch     getHandle<stream_tag>,
174a4af0ceeSJacob Faibussowitsch     beginTimer,
17517f48955SJacob Faibussowitsch     endTimer,
176a4af0ceeSJacob Faibussowitsch   };
177030f984aSJacob Faibussowitsch 
178030f984aSJacob Faibussowitsch   // All of these functions MUST be static in order to be callable from C, otherwise they
179030f984aSJacob Faibussowitsch   // get the implicit 'this' pointer tacked on
18017f48955SJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode destroy(PetscDeviceContext));
18117f48955SJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode changeStreamType(PetscDeviceContext,PetscStreamType));
18217f48955SJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode setUp(PetscDeviceContext));
18317f48955SJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode query(PetscDeviceContext,PetscBool*));
18417f48955SJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode waitForContext(PetscDeviceContext,PetscDeviceContext));
18517f48955SJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode synchronize(PetscDeviceContext));
186a4af0ceeSJacob Faibussowitsch   template <typename Handle_t>
18717f48955SJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode getHandle(PetscDeviceContext,void*));
18817f48955SJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode beginTimer(PetscDeviceContext));
18917f48955SJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode endTimer(PetscDeviceContext,PetscLogDouble*));
190*7a101e5eSJacob Faibussowitsch 
191*7a101e5eSJacob Faibussowitsch   // not a PetscDeviceContext method, this registers the class
192*7a101e5eSJacob Faibussowitsch   PETSC_CXX_COMPAT_DECL(PetscErrorCode initialize());
193030f984aSJacob Faibussowitsch };
194030f984aSJacob Faibussowitsch 
19517f48955SJacob Faibussowitsch template <DeviceType T>
196*7a101e5eSJacob Faibussowitsch PETSC_CXX_COMPAT_DEFN(PetscErrorCode DeviceContext<T>::initialize())
197*7a101e5eSJacob Faibussowitsch {
198*7a101e5eSJacob Faibussowitsch   PetscFunctionBegin;
199*7a101e5eSJacob Faibussowitsch   if (PetscUnlikely(!initialized_)) {
200*7a101e5eSJacob Faibussowitsch     initialized_ = true;
201*7a101e5eSJacob Faibussowitsch     PetscCall(PetscRegisterFinalize(finalize_));
202*7a101e5eSJacob Faibussowitsch   }
203*7a101e5eSJacob Faibussowitsch   PetscFunctionReturn(0);
204*7a101e5eSJacob Faibussowitsch }
205*7a101e5eSJacob Faibussowitsch 
206*7a101e5eSJacob Faibussowitsch template <DeviceType T>
20717f48955SJacob Faibussowitsch PETSC_CXX_COMPAT_DEFN(PetscErrorCode DeviceContext<T>::destroy(PetscDeviceContext dctx))
208030f984aSJacob Faibussowitsch {
209*7a101e5eSJacob Faibussowitsch   const auto dci = impls_cast_(dctx);
210030f984aSJacob Faibussowitsch 
211030f984aSJacob Faibussowitsch   PetscFunctionBegin;
2129566063dSJacob Faibussowitsch   if (dci->stream) PetscCallCUPM(cupmStreamDestroy(dci->stream));
2139566063dSJacob Faibussowitsch   if (dci->event)  PetscCallCUPM(cupmEventDestroy(dci->event));
2149566063dSJacob Faibussowitsch   if (dci->begin)  PetscCallCUPM(cupmEventDestroy(dci->begin));
2159566063dSJacob Faibussowitsch   if (dci->end)    PetscCallCUPM(cupmEventDestroy(dci->end));
2169566063dSJacob Faibussowitsch   PetscCall(PetscFree(dctx->data));
217030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
218030f984aSJacob Faibussowitsch }
219030f984aSJacob Faibussowitsch 
22017f48955SJacob Faibussowitsch template <DeviceType T>
22117f48955SJacob Faibussowitsch PETSC_CXX_COMPAT_DEFN(PetscErrorCode DeviceContext<T>::changeStreamType(PetscDeviceContext dctx, PETSC_UNUSED PetscStreamType stype))
222030f984aSJacob Faibussowitsch {
223*7a101e5eSJacob Faibussowitsch   const auto dci = impls_cast_(dctx);
224030f984aSJacob Faibussowitsch 
225030f984aSJacob Faibussowitsch   PetscFunctionBegin;
226*7a101e5eSJacob Faibussowitsch   if (auto& stream = dci->stream) {
227*7a101e5eSJacob Faibussowitsch     PetscCallCUPM(cupmStreamDestroy(stream));
228*7a101e5eSJacob Faibussowitsch     stream = nullptr;
229030f984aSJacob Faibussowitsch   }
230030f984aSJacob Faibussowitsch   // set these to null so they aren't usable until setup is called again
231030f984aSJacob Faibussowitsch   dci->blas   = nullptr;
232030f984aSJacob Faibussowitsch   dci->solver = nullptr;
233030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
234030f984aSJacob Faibussowitsch }
235030f984aSJacob Faibussowitsch 
23617f48955SJacob Faibussowitsch template <DeviceType T>
23717f48955SJacob Faibussowitsch PETSC_CXX_COMPAT_DEFN(PetscErrorCode DeviceContext<T>::setUp(PetscDeviceContext dctx))
238030f984aSJacob Faibussowitsch {
239*7a101e5eSJacob Faibussowitsch   const auto dci    = impls_cast_(dctx);
240*7a101e5eSJacob Faibussowitsch   auto&      stream = dci->stream;
241030f984aSJacob Faibussowitsch 
242030f984aSJacob Faibussowitsch   PetscFunctionBegin;
243*7a101e5eSJacob Faibussowitsch   if (stream) {
244*7a101e5eSJacob Faibussowitsch     PetscCallCUPM(cupmStreamDestroy(stream));
245*7a101e5eSJacob Faibussowitsch     stream = nullptr;
24617f48955SJacob Faibussowitsch   }
247*7a101e5eSJacob Faibussowitsch   switch (const auto stype = dctx->streamType) {
248030f984aSJacob Faibussowitsch   case PETSC_STREAM_GLOBAL_BLOCKING:
249030f984aSJacob Faibussowitsch     // don't create a stream for global blocking
250030f984aSJacob Faibussowitsch     break;
251030f984aSJacob Faibussowitsch   case PETSC_STREAM_DEFAULT_BLOCKING:
252*7a101e5eSJacob Faibussowitsch     PetscCallCUPM(cupmStreamCreate(&stream));
253030f984aSJacob Faibussowitsch     break;
254030f984aSJacob Faibussowitsch   case PETSC_STREAM_GLOBAL_NONBLOCKING:
255*7a101e5eSJacob Faibussowitsch     PetscCallCUPM(cupmStreamCreateWithFlags(&stream,cupmStreamNonBlocking));
256030f984aSJacob Faibussowitsch     break;
257030f984aSJacob Faibussowitsch   default:
258*7a101e5eSJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_CORRUPT,"Invalid PetscStreamType %s",PetscStreamTypes[util::integral_value(stype)]);
259030f984aSJacob Faibussowitsch     break;
260030f984aSJacob Faibussowitsch   }
2619566063dSJacob Faibussowitsch   if (!dci->event) PetscCallCUPM(cupmEventCreate(&dci->event));
262a4af0ceeSJacob Faibussowitsch #if PetscDefined(USE_DEBUG)
263a4af0ceeSJacob Faibussowitsch   dci->timerInUse = PETSC_FALSE;
264a4af0ceeSJacob Faibussowitsch #endif
265030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
266030f984aSJacob Faibussowitsch }
267030f984aSJacob Faibussowitsch 
26817f48955SJacob Faibussowitsch template <DeviceType T>
26917f48955SJacob Faibussowitsch PETSC_CXX_COMPAT_DEFN(PetscErrorCode DeviceContext<T>::query(PetscDeviceContext dctx, PetscBool *idle))
270030f984aSJacob Faibussowitsch {
271030f984aSJacob Faibussowitsch   cupmError_t cerr;
272030f984aSJacob Faibussowitsch 
273030f984aSJacob Faibussowitsch   PetscFunctionBegin;
27417f48955SJacob Faibussowitsch   cerr = cupmStreamQuery(impls_cast_(dctx)->stream);
275a4af0ceeSJacob Faibussowitsch   if (cerr == cupmSuccess) *idle = PETSC_TRUE;
276a4af0ceeSJacob Faibussowitsch   else {
277030f984aSJacob Faibussowitsch     // somethings gone wrong
2789566063dSJacob Faibussowitsch     if (PetscUnlikely(cerr != cupmErrorNotReady)) PetscCallCUPM(cerr);
279a4af0ceeSJacob Faibussowitsch     *idle = PETSC_FALSE;
280030f984aSJacob Faibussowitsch   }
281030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
282030f984aSJacob Faibussowitsch }
283030f984aSJacob Faibussowitsch 
28417f48955SJacob Faibussowitsch template <DeviceType T>
28517f48955SJacob Faibussowitsch PETSC_CXX_COMPAT_DEFN(PetscErrorCode DeviceContext<T>::waitForContext(PetscDeviceContext dctxa, PetscDeviceContext dctxb))
286030f984aSJacob Faibussowitsch {
28717f48955SJacob Faibussowitsch   auto        dcib = impls_cast_(dctxb);
288030f984aSJacob Faibussowitsch 
289030f984aSJacob Faibussowitsch   PetscFunctionBegin;
2909566063dSJacob Faibussowitsch   PetscCallCUPM(cupmEventRecord(dcib->event,dcib->stream));
2919566063dSJacob Faibussowitsch   PetscCallCUPM(cupmStreamWaitEvent(impls_cast_(dctxa)->stream,dcib->event,0));
292030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
293030f984aSJacob Faibussowitsch }
294030f984aSJacob Faibussowitsch 
29517f48955SJacob Faibussowitsch template <DeviceType T>
29617f48955SJacob Faibussowitsch PETSC_CXX_COMPAT_DEFN(PetscErrorCode DeviceContext<T>::synchronize(PetscDeviceContext dctx))
297030f984aSJacob Faibussowitsch {
29817f48955SJacob Faibussowitsch   auto        dci = impls_cast_(dctx);
299030f984aSJacob Faibussowitsch 
300030f984aSJacob Faibussowitsch   PetscFunctionBegin;
301030f984aSJacob Faibussowitsch   // in case anything was queued on the event
3029566063dSJacob Faibussowitsch   PetscCallCUPM(cupmStreamWaitEvent(dci->stream,dci->event,0));
3039566063dSJacob Faibussowitsch   PetscCallCUPM(cupmStreamSynchronize(dci->stream));
304030f984aSJacob Faibussowitsch   PetscFunctionReturn(0);
305030f984aSJacob Faibussowitsch }
306030f984aSJacob Faibussowitsch 
30717f48955SJacob Faibussowitsch template <DeviceType T>
30817f48955SJacob Faibussowitsch template <typename handle_t>
30917f48955SJacob Faibussowitsch PETSC_CXX_COMPAT_DEFN(PetscErrorCode DeviceContext<T>::getHandle(PetscDeviceContext dctx, void *handle))
310a4af0ceeSJacob Faibussowitsch {
311a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
312*7a101e5eSJacob Faibussowitsch   PetscCall(initialize_handle_(handle_t{},dctx));
313*7a101e5eSJacob Faibussowitsch   *static_cast<typename handle_t::type*>(handle) = impls_cast_(dctx)->get(handle_t{});
314a4af0ceeSJacob Faibussowitsch   PetscFunctionReturn(0);
315a4af0ceeSJacob Faibussowitsch }
316a4af0ceeSJacob Faibussowitsch 
31717f48955SJacob Faibussowitsch template <DeviceType T>
31817f48955SJacob Faibussowitsch PETSC_CXX_COMPAT_DEFN(PetscErrorCode DeviceContext<T>::beginTimer(PetscDeviceContext dctx))
319a4af0ceeSJacob Faibussowitsch {
32017f48955SJacob Faibussowitsch   auto        dci = impls_cast_(dctx);
321a4af0ceeSJacob Faibussowitsch 
322a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
323a4af0ceeSJacob Faibussowitsch #if PetscDefined(USE_DEBUG)
3245f80ce2aSJacob Faibussowitsch   PetscCheck(!dci->timerInUse,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Forgot to call PetscLogGpuTimeEnd()?");
325a4af0ceeSJacob Faibussowitsch   dci->timerInUse = PETSC_TRUE;
326a4af0ceeSJacob Faibussowitsch #endif
32717f48955SJacob Faibussowitsch   if (!dci->begin) {
3289566063dSJacob Faibussowitsch     PetscCallCUPM(cupmEventCreate(&dci->begin));
3299566063dSJacob Faibussowitsch     PetscCallCUPM(cupmEventCreate(&dci->end));
33017f48955SJacob Faibussowitsch   }
3319566063dSJacob Faibussowitsch   PetscCallCUPM(cupmEventRecord(dci->begin,dci->stream));
332a4af0ceeSJacob Faibussowitsch   PetscFunctionReturn(0);
333a4af0ceeSJacob Faibussowitsch }
334a4af0ceeSJacob Faibussowitsch 
33517f48955SJacob Faibussowitsch template <DeviceType T>
33617f48955SJacob Faibussowitsch PETSC_CXX_COMPAT_DEFN(PetscErrorCode DeviceContext<T>::endTimer(PetscDeviceContext dctx, PetscLogDouble *elapsed))
337a4af0ceeSJacob Faibussowitsch {
338a4af0ceeSJacob Faibussowitsch   float       gtime;
33917f48955SJacob Faibussowitsch   auto        dci = impls_cast_(dctx);
340a4af0ceeSJacob Faibussowitsch 
341a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
342a4af0ceeSJacob Faibussowitsch #if PetscDefined(USE_DEBUG)
3435f80ce2aSJacob Faibussowitsch   PetscCheck(dci->timerInUse,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Forgot to call PetscLogGpuTimeBegin()?");
344a4af0ceeSJacob Faibussowitsch   dci->timerInUse = PETSC_FALSE;
345a4af0ceeSJacob Faibussowitsch #endif
3469566063dSJacob Faibussowitsch   PetscCallCUPM(cupmEventRecord(dci->end,dci->stream));
3479566063dSJacob Faibussowitsch   PetscCallCUPM(cupmEventSynchronize(dci->end));
3489566063dSJacob Faibussowitsch   PetscCallCUPM(cupmEventElapsedTime(&gtime,dci->begin,dci->end));
34917f48955SJacob Faibussowitsch   *elapsed = static_cast<util::remove_pointer_t<decltype(elapsed)>>(gtime);
350a4af0ceeSJacob Faibussowitsch   PetscFunctionReturn(0);
351a4af0ceeSJacob Faibussowitsch }
352a4af0ceeSJacob Faibussowitsch 
353030f984aSJacob Faibussowitsch // initialize the static member variables
35417f48955SJacob Faibussowitsch template <DeviceType T> bool DeviceContext<T>::initialized_ = false;
355030f984aSJacob Faibussowitsch 
35617f48955SJacob Faibussowitsch template <DeviceType T>
35717f48955SJacob Faibussowitsch std::array<typename DeviceContext<T>::cupmBlasHandle_t,PETSC_DEVICE_MAX_DEVICES>   DeviceContext<T>::blashandles_ = {};
358030f984aSJacob Faibussowitsch 
35917f48955SJacob Faibussowitsch template <DeviceType T>
36017f48955SJacob Faibussowitsch std::array<typename DeviceContext<T>::cupmSolverHandle_t,PETSC_DEVICE_MAX_DEVICES> DeviceContext<T>::solverhandles_ = {};
36117f48955SJacob Faibussowitsch 
36217f48955SJacob Faibussowitsch } // namespace Impl
363030f984aSJacob Faibussowitsch 
364a4af0ceeSJacob Faibussowitsch // shorten this one up a bit (and instantiate the templates)
36517f48955SJacob Faibussowitsch using CUPMContextCuda = Impl::DeviceContext<DeviceType::CUDA>;
36617f48955SJacob Faibussowitsch using CUPMContextHip  = Impl::DeviceContext<DeviceType::HIP>;
367030f984aSJacob Faibussowitsch 
368030f984aSJacob Faibussowitsch // shorthand for what is an EXTREMELY long name
36917f48955SJacob Faibussowitsch #define PetscDeviceContext_(IMPLS) Petsc::Device::CUPM::Impl::DeviceContext<Petsc::Device::CUPM::DeviceType::IMPLS>::PetscDeviceContext_IMPLS
370030f984aSJacob Faibussowitsch 
37117f48955SJacob Faibussowitsch } // namespace CUPM
37217f48955SJacob Faibussowitsch 
37317f48955SJacob Faibussowitsch } // namespace Device
37417f48955SJacob Faibussowitsch 
37517f48955SJacob Faibussowitsch } // namespace Petsc
376030f984aSJacob Faibussowitsch 
377a4af0ceeSJacob Faibussowitsch #endif // PETSCDEVICECONTEXTCUDA_HPP
378