xref: /petsc/src/sys/objects/device/impls/cupm/cupmcontext.hpp (revision 31d4707089da71ebcff1fd00fbb3a11b50a9f3d1)
117f48955SJacob Faibussowitsch #ifndef PETSCDEVICECONTEXTCUPM_HPP
2030f984aSJacob Faibussowitsch #define PETSCDEVICECONTEXTCUPM_HPP
3030f984aSJacob Faibussowitsch 
4a4af0ceeSJacob Faibussowitsch #include <petsc/private/deviceimpl.h>
596a4b4d9SJacob Faibussowitsch #include <petsc/private/cupmsolverinterface.hpp>
67a101e5eSJacob Faibussowitsch #include <petsc/private/logimpl.h>
7030f984aSJacob Faibussowitsch 
80e6b6b59SJacob Faibussowitsch #include <petsc/private/cpp/array.hpp>
9a4af0ceeSJacob Faibussowitsch 
100e6b6b59SJacob Faibussowitsch #include "../segmentedmempool.hpp"
110e6b6b59SJacob Faibussowitsch #include "cupmallocator.hpp"
120e6b6b59SJacob Faibussowitsch #include "cupmstream.hpp"
130e6b6b59SJacob Faibussowitsch #include "cupmevent.hpp"
140e6b6b59SJacob Faibussowitsch 
150e6b6b59SJacob Faibussowitsch #if defined(__cplusplus)
166797ed33SJacob Faibussowitsch 
17d71ae5a4SJacob Faibussowitsch namespace Petsc
18d71ae5a4SJacob Faibussowitsch {
19a4af0ceeSJacob Faibussowitsch 
20d71ae5a4SJacob Faibussowitsch namespace device
21d71ae5a4SJacob Faibussowitsch {
2217f48955SJacob Faibussowitsch 
23d71ae5a4SJacob Faibussowitsch namespace cupm
24d71ae5a4SJacob Faibussowitsch {
2517f48955SJacob Faibussowitsch 
26d71ae5a4SJacob Faibussowitsch namespace impl
27d71ae5a4SJacob Faibussowitsch {
28030f984aSJacob Faibussowitsch 
2917f48955SJacob Faibussowitsch template <DeviceType T>
3096a4b4d9SJacob Faibussowitsch class DeviceContext : SolverInterface<T> {
3117f48955SJacob Faibussowitsch public:
3296a4b4d9SJacob Faibussowitsch   PETSC_CUPMSOLVER_INHERIT_INTERFACE_TYPEDEFS_USING(T);
3317f48955SJacob Faibussowitsch 
3417f48955SJacob Faibussowitsch private:
359371c9d4SSatish Balay   template <typename H, std::size_t>
369371c9d4SSatish Balay   struct HandleTag {
379371c9d4SSatish Balay     using type = H;
389371c9d4SSatish Balay   };
390e6b6b59SJacob Faibussowitsch 
407a101e5eSJacob Faibussowitsch   using stream_tag = HandleTag<cupmStream_t, 0>;
417a101e5eSJacob Faibussowitsch   using blas_tag   = HandleTag<cupmBlasHandle_t, 1>;
427a101e5eSJacob Faibussowitsch   using solver_tag = HandleTag<cupmSolverHandle_t, 2>;
43a4af0ceeSJacob Faibussowitsch 
440e6b6b59SJacob Faibussowitsch   using stream_type = CUPMStream<T>;
450e6b6b59SJacob Faibussowitsch   using event_type  = CUPMEvent<T>;
460e6b6b59SJacob Faibussowitsch 
47030f984aSJacob Faibussowitsch public:
48030f984aSJacob Faibussowitsch   // This is the canonical PETSc "impls" struct that normally resides in a standalone impls
49030f984aSJacob Faibussowitsch   // header, but since we are using the power of templates it must be declared part of
50030f984aSJacob Faibussowitsch   // this class to have easy access the same typedefs. Technically one can make a
51030f984aSJacob Faibussowitsch   // templated struct outside the class but it's more code for the same result.
520e6b6b59SJacob Faibussowitsch   struct PetscDeviceContext_IMPLS : memory::PoolAllocated<PetscDeviceContext_IMPLS> {
530e6b6b59SJacob Faibussowitsch     stream_type stream{};
540e6b6b59SJacob Faibussowitsch     cupmEvent_t event{};
550e6b6b59SJacob Faibussowitsch     cupmEvent_t begin{}; // timer-only
560e6b6b59SJacob Faibussowitsch     cupmEvent_t end{};   // timer-only
57a4af0ceeSJacob Faibussowitsch   #if PetscDefined(USE_DEBUG)
580e6b6b59SJacob Faibussowitsch     PetscBool timerInUse{};
59a4af0ceeSJacob Faibussowitsch   #endif
600e6b6b59SJacob Faibussowitsch     cupmBlasHandle_t   blas{};
610e6b6b59SJacob Faibussowitsch     cupmSolverHandle_t solver{};
62a4af0ceeSJacob Faibussowitsch 
630e6b6b59SJacob Faibussowitsch     constexpr PetscDeviceContext_IMPLS() noexcept = default;
640e6b6b59SJacob Faibussowitsch 
65*31d47070SJunchao Zhang     PETSC_NODISCARD const cupmStream_t &get(stream_tag) const noexcept { return this->stream.get_stream(); }
660e6b6b59SJacob Faibussowitsch 
67*31d47070SJunchao Zhang     PETSC_NODISCARD const cupmBlasHandle_t &get(blas_tag) const noexcept { return this->blas; }
680e6b6b59SJacob Faibussowitsch 
69*31d47070SJunchao Zhang     PETSC_NODISCARD const cupmSolverHandle_t &get(solver_tag) const noexcept { return this->solver; }
70030f984aSJacob Faibussowitsch   };
71030f984aSJacob Faibussowitsch 
72030f984aSJacob Faibussowitsch private:
7317f48955SJacob Faibussowitsch   static bool initialized_;
746d54fb17SJacob Faibussowitsch 
7517f48955SJacob Faibussowitsch   static std::array<cupmBlasHandle_t, PETSC_DEVICE_MAX_DEVICES>   blashandles_;
7617f48955SJacob Faibussowitsch   static std::array<cupmSolverHandle_t, PETSC_DEVICE_MAX_DEVICES> solverhandles_;
77030f984aSJacob Faibussowitsch 
78d71ae5a4SJacob Faibussowitsch   PETSC_NODISCARD static constexpr PetscDeviceContext_IMPLS *impls_cast_(PetscDeviceContext ptr) noexcept { return static_cast<PetscDeviceContext_IMPLS *>(ptr->data); }
79a4af0ceeSJacob Faibussowitsch 
80d71ae5a4SJacob Faibussowitsch   PETSC_NODISCARD static constexpr CUPMEvent<T> *event_cast_(PetscEvent event) noexcept { return static_cast<CUPMEvent<T> *>(event->data); }
810e6b6b59SJacob Faibussowitsch 
82d71ae5a4SJacob Faibussowitsch   PETSC_NODISCARD static PetscLogEvent CUPMBLAS_HANDLE_CREATE() noexcept { return T == DeviceType::CUDA ? CUBLAS_HANDLE_CREATE : HIPBLAS_HANDLE_CREATE; }
837a101e5eSJacob Faibussowitsch 
84d71ae5a4SJacob Faibussowitsch   PETSC_NODISCARD static PetscLogEvent CUPMSOLVER_HANDLE_CREATE() noexcept { return T == DeviceType::CUDA ? CUSOLVER_HANDLE_CREATE : HIPSOLVER_HANDLE_CREATE; }
857a101e5eSJacob Faibussowitsch 
867a101e5eSJacob Faibussowitsch   // this exists purely to satisfy the compiler so the tag-based dispatch works for the other
877a101e5eSJacob Faibussowitsch   // handles
88089fb57cSJacob Faibussowitsch   static PetscErrorCode initialize_handle_(stream_tag, PetscDeviceContext) noexcept { return PETSC_SUCCESS; }
897a101e5eSJacob Faibussowitsch 
9096a4b4d9SJacob Faibussowitsch   static PetscErrorCode initialize_handle_(blas_tag, PetscDeviceContext dctx) noexcept
91d71ae5a4SJacob Faibussowitsch   {
9296a4b4d9SJacob Faibussowitsch     const auto dci    = impls_cast_(dctx);
9396a4b4d9SJacob Faibussowitsch     auto      &handle = blashandles_[dctx->device->deviceId];
947a101e5eSJacob Faibussowitsch 
95030f984aSJacob Faibussowitsch     PetscFunctionBegin;
9696a4b4d9SJacob Faibussowitsch     if (!handle) {
9796a4b4d9SJacob Faibussowitsch       PetscLogEvent event;
9896a4b4d9SJacob Faibussowitsch 
997a101e5eSJacob Faibussowitsch       PetscCall(PetscLogPauseCurrentEvent_Internal(&event));
1007a101e5eSJacob Faibussowitsch       PetscCall(PetscLogEventBegin(CUPMBLAS_HANDLE_CREATE(), 0, 0, 0, 0));
10117f48955SJacob Faibussowitsch       for (auto i = 0; i < 3; ++i) {
10296a4b4d9SJacob Faibussowitsch         const auto cberr = cupmBlasCreate(handle.ptr_to());
10317f48955SJacob Faibussowitsch         if (PetscLikely(cberr == CUPMBLAS_STATUS_SUCCESS)) break;
1049566063dSJacob Faibussowitsch         if (PetscUnlikely(cberr != CUPMBLAS_STATUS_ALLOC_FAILED) && (cberr != CUPMBLAS_STATUS_NOT_INITIALIZED)) PetscCallCUPMBLAS(cberr);
10517f48955SJacob Faibussowitsch         if (i != 2) {
1069566063dSJacob Faibussowitsch           PetscCall(PetscSleep(3));
10717f48955SJacob Faibussowitsch           continue;
108a4af0ceeSJacob Faibussowitsch         }
1095f80ce2aSJacob Faibussowitsch         PetscCheck(cberr == CUPMBLAS_STATUS_SUCCESS, PETSC_COMM_SELF, PETSC_ERR_GPU_RESOURCE, "Unable to initialize %s", cupmBlasName());
110a4af0ceeSJacob Faibussowitsch       }
1117a101e5eSJacob Faibussowitsch       PetscCall(PetscLogEventEnd(CUPMBLAS_HANDLE_CREATE(), 0, 0, 0, 0));
1127a101e5eSJacob Faibussowitsch       PetscCall(PetscLogEventResume_Internal(event));
113030f984aSJacob Faibussowitsch     }
1140e6b6b59SJacob Faibussowitsch     PetscCallCUPMBLAS(cupmBlasSetStream(handle, dci->stream.get_stream()));
1157a101e5eSJacob Faibussowitsch     dci->blas = handle;
1163ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
1177a101e5eSJacob Faibussowitsch   }
1187a101e5eSJacob Faibussowitsch 
119089fb57cSJacob Faibussowitsch   static PetscErrorCode initialize_handle_(solver_tag, PetscDeviceContext dctx) noexcept
120d71ae5a4SJacob Faibussowitsch   {
1216d54fb17SJacob Faibussowitsch     const auto dci    = impls_cast_(dctx);
1226d54fb17SJacob Faibussowitsch     auto      &handle = solverhandles_[dctx->device->deviceId];
1237a101e5eSJacob Faibussowitsch 
1247a101e5eSJacob Faibussowitsch     PetscFunctionBegin;
12596a4b4d9SJacob Faibussowitsch     if (!handle) {
12696a4b4d9SJacob Faibussowitsch       PetscLogEvent event;
12796a4b4d9SJacob Faibussowitsch 
1287a101e5eSJacob Faibussowitsch       PetscCall(PetscLogPauseCurrentEvent_Internal(&event));
1297a101e5eSJacob Faibussowitsch       PetscCall(PetscLogEventBegin(CUPMSOLVER_HANDLE_CREATE(), 0, 0, 0, 0));
13096a4b4d9SJacob Faibussowitsch       for (auto i = 0; i < 3; ++i) {
13196a4b4d9SJacob Faibussowitsch         const auto cerr = cupmSolverCreate(&handle);
13296a4b4d9SJacob Faibussowitsch         if (PetscLikely(cerr == CUPMSOLVER_STATUS_SUCCESS)) break;
13396a4b4d9SJacob Faibussowitsch         if ((cerr != CUPMSOLVER_STATUS_NOT_INITIALIZED) && (cerr != CUPMSOLVER_STATUS_ALLOC_FAILED)) PetscCallCUPMSOLVER(cerr);
13496a4b4d9SJacob Faibussowitsch         if (i < 2) {
13596a4b4d9SJacob Faibussowitsch           PetscCall(PetscSleep(3));
13696a4b4d9SJacob Faibussowitsch           continue;
13796a4b4d9SJacob Faibussowitsch         }
13896a4b4d9SJacob Faibussowitsch         PetscCheck(cerr == CUPMSOLVER_STATUS_SUCCESS, PETSC_COMM_SELF, PETSC_ERR_GPU_RESOURCE, "Unable to initialize %s", cupmSolverName());
13996a4b4d9SJacob Faibussowitsch       }
1407a101e5eSJacob Faibussowitsch       PetscCall(PetscLogEventEnd(CUPMSOLVER_HANDLE_CREATE(), 0, 0, 0, 0));
1417a101e5eSJacob Faibussowitsch       PetscCall(PetscLogEventResume_Internal(event));
14296a4b4d9SJacob Faibussowitsch     }
14396a4b4d9SJacob Faibussowitsch     PetscCallCUPMSOLVER(cupmSolverSetStream(handle, dci->stream.get_stream()));
1447a101e5eSJacob Faibussowitsch     dci->solver = handle;
1453ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
14617f48955SJacob Faibussowitsch   }
14717f48955SJacob Faibussowitsch 
148089fb57cSJacob Faibussowitsch   static PetscErrorCode check_current_device_(PetscDeviceContext dctxl, PetscDeviceContext dctxr) noexcept
149d71ae5a4SJacob Faibussowitsch   {
1500e6b6b59SJacob Faibussowitsch     const auto devidl = dctxl->device->deviceId, devidr = dctxr->device->deviceId;
1510e6b6b59SJacob Faibussowitsch 
1520e6b6b59SJacob Faibussowitsch     PetscFunctionBegin;
1530e6b6b59SJacob Faibussowitsch     PetscCheck(devidl == devidr, PETSC_COMM_SELF, PETSC_ERR_GPU, "Device contexts must be on the same device; dctx A (id %" PetscInt64_FMT " device id %" PetscInt_FMT ") dctx B (id %" PetscInt64_FMT " device id %" PetscInt_FMT ")",
1540e6b6b59SJacob Faibussowitsch                PetscObjectCast(dctxl)->id, devidl, PetscObjectCast(dctxr)->id, devidr);
1550e6b6b59SJacob Faibussowitsch     PetscCall(PetscDeviceCheckDeviceCount_Internal(devidl));
1560e6b6b59SJacob Faibussowitsch     PetscCall(PetscDeviceCheckDeviceCount_Internal(devidr));
1570e6b6b59SJacob Faibussowitsch     PetscCallCUPM(cupmSetDevice(static_cast<int>(devidl)));
1583ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
1590e6b6b59SJacob Faibussowitsch   }
1600e6b6b59SJacob Faibussowitsch 
161089fb57cSJacob Faibussowitsch   static PetscErrorCode check_current_device_(PetscDeviceContext dctx) noexcept { return check_current_device_(dctx, dctx); }
1620e6b6b59SJacob Faibussowitsch 
163089fb57cSJacob Faibussowitsch   static PetscErrorCode finalize_() noexcept
164d71ae5a4SJacob Faibussowitsch   {
16517f48955SJacob Faibussowitsch     PetscFunctionBegin;
16617f48955SJacob Faibussowitsch     for (auto &&handle : blashandles_) {
16717f48955SJacob Faibussowitsch       if (handle) {
1689566063dSJacob Faibussowitsch         PetscCallCUPMBLAS(cupmBlasDestroy(handle));
16917f48955SJacob Faibussowitsch         handle = nullptr;
17017f48955SJacob Faibussowitsch       }
17117f48955SJacob Faibussowitsch     }
1726d54fb17SJacob Faibussowitsch 
17317f48955SJacob Faibussowitsch     for (auto &&handle : solverhandles_) {
17417f48955SJacob Faibussowitsch       if (handle) {
17596a4b4d9SJacob Faibussowitsch         PetscCallCUPMSOLVER(cupmSolverDestroy(handle));
17617f48955SJacob Faibussowitsch         handle = nullptr;
17717f48955SJacob Faibussowitsch       }
17817f48955SJacob Faibussowitsch     }
17917f48955SJacob Faibussowitsch     initialized_ = false;
1803ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
18117f48955SJacob Faibussowitsch   }
18217f48955SJacob Faibussowitsch 
1830e6b6b59SJacob Faibussowitsch   template <typename Allocator, typename PoolType = ::Petsc::memory::SegmentedMemoryPool<typename Allocator::value_type, stream_type, Allocator, 256 * sizeof(PetscScalar)>>
184d71ae5a4SJacob Faibussowitsch   PETSC_NODISCARD static PoolType &default_pool_() noexcept
185d71ae5a4SJacob Faibussowitsch   {
1860e6b6b59SJacob Faibussowitsch     static PoolType pool;
1870e6b6b59SJacob Faibussowitsch     return pool;
1880e6b6b59SJacob Faibussowitsch   }
189030f984aSJacob Faibussowitsch 
190089fb57cSJacob Faibussowitsch   static PetscErrorCode check_memtype_(PetscMemType mtype, const char mess[]) noexcept
191d71ae5a4SJacob Faibussowitsch   {
1920e6b6b59SJacob Faibussowitsch     PetscFunctionBegin;
1930e6b6b59SJacob Faibussowitsch     PetscCheck(PetscMemTypeHost(mtype) || (mtype == PETSC_MEMTYPE_DEVICE) || (mtype == PETSC_MEMTYPE_CUPM()), PETSC_COMM_SELF, PETSC_ERR_SUP, "%s device context can only handle %s (pinned) host or device memory", cupmName(), mess);
1943ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
1950e6b6b59SJacob Faibussowitsch   }
1960e6b6b59SJacob Faibussowitsch 
1970e6b6b59SJacob Faibussowitsch public:
198030f984aSJacob Faibussowitsch   // All of these functions MUST be static in order to be callable from C, otherwise they
199030f984aSJacob Faibussowitsch   // get the implicit 'this' pointer tacked on
200089fb57cSJacob Faibussowitsch   static PetscErrorCode destroy(PetscDeviceContext) noexcept;
201089fb57cSJacob Faibussowitsch   static PetscErrorCode changeStreamType(PetscDeviceContext, PetscStreamType) noexcept;
202089fb57cSJacob Faibussowitsch   static PetscErrorCode setUp(PetscDeviceContext) noexcept;
203089fb57cSJacob Faibussowitsch   static PetscErrorCode query(PetscDeviceContext, PetscBool *) noexcept;
204089fb57cSJacob Faibussowitsch   static PetscErrorCode waitForContext(PetscDeviceContext, PetscDeviceContext) noexcept;
205089fb57cSJacob Faibussowitsch   static PetscErrorCode synchronize(PetscDeviceContext) noexcept;
206a4af0ceeSJacob Faibussowitsch   template <typename Handle_t>
207089fb57cSJacob Faibussowitsch   static PetscErrorCode getHandle(PetscDeviceContext, void *) noexcept;
208*31d47070SJunchao Zhang   template <typename Handle_t>
209*31d47070SJunchao Zhang   static PetscErrorCode getHandlePtr(PetscDeviceContext, void *) noexcept;
210089fb57cSJacob Faibussowitsch   static PetscErrorCode beginTimer(PetscDeviceContext) noexcept;
211089fb57cSJacob Faibussowitsch   static PetscErrorCode endTimer(PetscDeviceContext, PetscLogDouble *) noexcept;
212089fb57cSJacob Faibussowitsch   static PetscErrorCode memAlloc(PetscDeviceContext, PetscBool, PetscMemType, std::size_t, std::size_t, void **) noexcept;
213089fb57cSJacob Faibussowitsch   static PetscErrorCode memFree(PetscDeviceContext, PetscMemType, void **) noexcept;
214089fb57cSJacob Faibussowitsch   static PetscErrorCode memCopy(PetscDeviceContext, void *PETSC_RESTRICT, const void *PETSC_RESTRICT, std::size_t, PetscDeviceCopyMode) noexcept;
215089fb57cSJacob Faibussowitsch   static PetscErrorCode memSet(PetscDeviceContext, PetscMemType, void *, PetscInt, std::size_t) noexcept;
216089fb57cSJacob Faibussowitsch   static PetscErrorCode createEvent(PetscDeviceContext, PetscEvent) noexcept;
217089fb57cSJacob Faibussowitsch   static PetscErrorCode recordEvent(PetscDeviceContext, PetscEvent) noexcept;
218089fb57cSJacob Faibussowitsch   static PetscErrorCode waitForEvent(PetscDeviceContext, PetscEvent) noexcept;
2197a101e5eSJacob Faibussowitsch 
2207a101e5eSJacob Faibussowitsch   // not a PetscDeviceContext method, this registers the class
221089fb57cSJacob Faibussowitsch   static PetscErrorCode initialize(PetscDevice) noexcept;
2220e6b6b59SJacob Faibussowitsch 
2230e6b6b59SJacob Faibussowitsch   // clang-format off
2246ff55be4SJacob Faibussowitsch   static constexpr _DeviceContextOps ops = {
2256ff55be4SJacob Faibussowitsch     PetscDesignatedInitializer(destroy, destroy),
2266ff55be4SJacob Faibussowitsch     PetscDesignatedInitializer(changestreamtype, changeStreamType),
2276ff55be4SJacob Faibussowitsch     PetscDesignatedInitializer(setup, setUp),
2286ff55be4SJacob Faibussowitsch     PetscDesignatedInitializer(query, query),
2296ff55be4SJacob Faibussowitsch     PetscDesignatedInitializer(waitforcontext, waitForContext),
2306ff55be4SJacob Faibussowitsch     PetscDesignatedInitializer(synchronize, synchronize),
2316ff55be4SJacob Faibussowitsch     PetscDesignatedInitializer(getblashandle, getHandle<blas_tag>),
2326ff55be4SJacob Faibussowitsch     PetscDesignatedInitializer(getsolverhandle, getHandle<solver_tag>),
233*31d47070SJunchao Zhang     PetscDesignatedInitializer(getstreamhandle, getHandlePtr<stream_tag>),
2346ff55be4SJacob Faibussowitsch     PetscDesignatedInitializer(begintimer, beginTimer),
2356ff55be4SJacob Faibussowitsch     PetscDesignatedInitializer(endtimer, endTimer),
2366ff55be4SJacob Faibussowitsch     PetscDesignatedInitializer(memalloc, memAlloc),
2376ff55be4SJacob Faibussowitsch     PetscDesignatedInitializer(memfree, memFree),
2386ff55be4SJacob Faibussowitsch     PetscDesignatedInitializer(memcopy, memCopy),
2396ff55be4SJacob Faibussowitsch     PetscDesignatedInitializer(memset, memSet),
2406ff55be4SJacob Faibussowitsch     PetscDesignatedInitializer(createevent, createEvent),
2416ff55be4SJacob Faibussowitsch     PetscDesignatedInitializer(recordevent, recordEvent),
2426ff55be4SJacob Faibussowitsch     PetscDesignatedInitializer(waitforevent, waitForEvent)
2430e6b6b59SJacob Faibussowitsch   };
2440e6b6b59SJacob Faibussowitsch   // clang-format on
245030f984aSJacob Faibussowitsch };
246030f984aSJacob Faibussowitsch 
2470e6b6b59SJacob Faibussowitsch // not a PetscDeviceContext method, this initializes the CLASS
24817f48955SJacob Faibussowitsch template <DeviceType T>
2496d54fb17SJacob Faibussowitsch inline PetscErrorCode DeviceContext<T>::initialize(PetscDevice device) noexcept
250d71ae5a4SJacob Faibussowitsch {
2517a101e5eSJacob Faibussowitsch   PetscFunctionBegin;
2527a101e5eSJacob Faibussowitsch   if (PetscUnlikely(!initialized_)) {
2530e6b6b59SJacob Faibussowitsch     uint64_t      threshold = UINT64_MAX;
2546d54fb17SJacob Faibussowitsch     cupmMemPool_t mempool;
2550e6b6b59SJacob Faibussowitsch 
2567a101e5eSJacob Faibussowitsch     initialized_ = true;
2576d54fb17SJacob Faibussowitsch     PetscCallCUPM(cupmDeviceGetMemPool(&mempool, static_cast<int>(device->deviceId)));
2580e6b6b59SJacob Faibussowitsch     PetscCallCUPM(cupmMemPoolSetAttribute(mempool, cupmMemPoolAttrReleaseThreshold, &threshold));
2590e6b6b59SJacob Faibussowitsch     blashandles_.fill(nullptr);
2600e6b6b59SJacob Faibussowitsch     solverhandles_.fill(nullptr);
2617a101e5eSJacob Faibussowitsch     PetscCall(PetscRegisterFinalize(finalize_));
2627a101e5eSJacob Faibussowitsch   }
2633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2647a101e5eSJacob Faibussowitsch }
2657a101e5eSJacob Faibussowitsch 
2667a101e5eSJacob Faibussowitsch template <DeviceType T>
2676d54fb17SJacob Faibussowitsch inline PetscErrorCode DeviceContext<T>::destroy(PetscDeviceContext dctx) noexcept
268d71ae5a4SJacob Faibussowitsch {
269030f984aSJacob Faibussowitsch   PetscFunctionBegin;
2700e6b6b59SJacob Faibussowitsch   if (const auto dci = impls_cast_(dctx)) {
2710e6b6b59SJacob Faibussowitsch     PetscCall(dci->stream.destroy());
272146a86ebSJacob Faibussowitsch     if (dci->event) PetscCall(cupm_fast_event_pool<T>().deallocate(&dci->event));
2739566063dSJacob Faibussowitsch     if (dci->begin) PetscCallCUPM(cupmEventDestroy(dci->begin));
2749566063dSJacob Faibussowitsch     if (dci->end) PetscCallCUPM(cupmEventDestroy(dci->end));
2750e6b6b59SJacob Faibussowitsch     delete dci;
2760e6b6b59SJacob Faibussowitsch     dctx->data = nullptr;
2770e6b6b59SJacob Faibussowitsch   }
2783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
279030f984aSJacob Faibussowitsch }
280030f984aSJacob Faibussowitsch 
28117f48955SJacob Faibussowitsch template <DeviceType T>
2826d54fb17SJacob Faibussowitsch inline PetscErrorCode DeviceContext<T>::changeStreamType(PetscDeviceContext dctx, PETSC_UNUSED PetscStreamType stype) noexcept
283d71ae5a4SJacob Faibussowitsch {
2847a101e5eSJacob Faibussowitsch   const auto dci = impls_cast_(dctx);
285030f984aSJacob Faibussowitsch 
286030f984aSJacob Faibussowitsch   PetscFunctionBegin;
2870e6b6b59SJacob Faibussowitsch   PetscCall(dci->stream.destroy());
288030f984aSJacob Faibussowitsch   // set these to null so they aren't usable until setup is called again
289030f984aSJacob Faibussowitsch   dci->blas   = nullptr;
290030f984aSJacob Faibussowitsch   dci->solver = nullptr;
2913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
292030f984aSJacob Faibussowitsch }
293030f984aSJacob Faibussowitsch 
29417f48955SJacob Faibussowitsch template <DeviceType T>
2956d54fb17SJacob Faibussowitsch inline PetscErrorCode DeviceContext<T>::setUp(PetscDeviceContext dctx) noexcept
296d71ae5a4SJacob Faibussowitsch {
2977a101e5eSJacob Faibussowitsch   const auto dci   = impls_cast_(dctx);
2980e6b6b59SJacob Faibussowitsch   auto      &event = dci->event;
299030f984aSJacob Faibussowitsch 
300030f984aSJacob Faibussowitsch   PetscFunctionBegin;
3010e6b6b59SJacob Faibussowitsch   PetscCall(check_current_device_(dctx));
3020e6b6b59SJacob Faibussowitsch   PetscCall(dci->stream.change_type(dctx->streamType));
3030e6b6b59SJacob Faibussowitsch   if (!event) PetscCall(cupm_fast_event_pool<T>().allocate(&event));
304a4af0ceeSJacob Faibussowitsch   #if PetscDefined(USE_DEBUG)
305a4af0ceeSJacob Faibussowitsch   dci->timerInUse = PETSC_FALSE;
306a4af0ceeSJacob Faibussowitsch   #endif
3073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
308030f984aSJacob Faibussowitsch }
309030f984aSJacob Faibussowitsch 
31017f48955SJacob Faibussowitsch template <DeviceType T>
3116d54fb17SJacob Faibussowitsch inline PetscErrorCode DeviceContext<T>::query(PetscDeviceContext dctx, PetscBool *idle) noexcept
312d71ae5a4SJacob Faibussowitsch {
313030f984aSJacob Faibussowitsch   PetscFunctionBegin;
3140e6b6b59SJacob Faibussowitsch   PetscCall(check_current_device_(dctx));
3154b955ea4SJacob Faibussowitsch   switch (auto cerr = cupmStreamQuery(impls_cast_(dctx)->stream.get_stream())) {
316d71ae5a4SJacob Faibussowitsch   case cupmSuccess:
317d71ae5a4SJacob Faibussowitsch     *idle = PETSC_TRUE;
318d71ae5a4SJacob Faibussowitsch     break;
319d71ae5a4SJacob Faibussowitsch   case cupmErrorNotReady:
320d71ae5a4SJacob Faibussowitsch     *idle = PETSC_FALSE;
3214b955ea4SJacob Faibussowitsch     // reset the error
3224b955ea4SJacob Faibussowitsch     cerr = cupmGetLastError();
3234b955ea4SJacob Faibussowitsch     static_cast<void>(cerr);
324d71ae5a4SJacob Faibussowitsch     break;
325d71ae5a4SJacob Faibussowitsch   default:
326d71ae5a4SJacob Faibussowitsch     PetscCallCUPM(cerr);
327d71ae5a4SJacob Faibussowitsch     PetscUnreachable();
328030f984aSJacob Faibussowitsch   }
3293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
330030f984aSJacob Faibussowitsch }
331030f984aSJacob Faibussowitsch 
33217f48955SJacob Faibussowitsch template <DeviceType T>
3336d54fb17SJacob Faibussowitsch inline PetscErrorCode DeviceContext<T>::waitForContext(PetscDeviceContext dctxa, PetscDeviceContext dctxb) noexcept
334d71ae5a4SJacob Faibussowitsch {
3350e6b6b59SJacob Faibussowitsch   const auto dcib  = impls_cast_(dctxb);
3360e6b6b59SJacob Faibussowitsch   const auto event = dcib->event;
337030f984aSJacob Faibussowitsch 
338030f984aSJacob Faibussowitsch   PetscFunctionBegin;
3390e6b6b59SJacob Faibussowitsch   PetscCall(check_current_device_(dctxa, dctxb));
3400e6b6b59SJacob Faibussowitsch   PetscCallCUPM(cupmEventRecord(event, dcib->stream.get_stream()));
3410e6b6b59SJacob Faibussowitsch   PetscCallCUPM(cupmStreamWaitEvent(impls_cast_(dctxa)->stream.get_stream(), event, 0));
3423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
343030f984aSJacob Faibussowitsch }
344030f984aSJacob Faibussowitsch 
34517f48955SJacob Faibussowitsch template <DeviceType T>
3466d54fb17SJacob Faibussowitsch inline PetscErrorCode DeviceContext<T>::synchronize(PetscDeviceContext dctx) noexcept
347d71ae5a4SJacob Faibussowitsch {
3480e6b6b59SJacob Faibussowitsch   auto idle = PETSC_TRUE;
349030f984aSJacob Faibussowitsch 
350030f984aSJacob Faibussowitsch   PetscFunctionBegin;
3510e6b6b59SJacob Faibussowitsch   PetscCall(query(dctx, &idle));
3520e6b6b59SJacob Faibussowitsch   if (!idle) PetscCallCUPM(cupmStreamSynchronize(impls_cast_(dctx)->stream.get_stream()));
3533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
354030f984aSJacob Faibussowitsch }
355030f984aSJacob Faibussowitsch 
35617f48955SJacob Faibussowitsch template <DeviceType T>
35717f48955SJacob Faibussowitsch template <typename handle_t>
3586d54fb17SJacob Faibussowitsch inline PetscErrorCode DeviceContext<T>::getHandle(PetscDeviceContext dctx, void *handle) noexcept
359d71ae5a4SJacob Faibussowitsch {
360a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
3617a101e5eSJacob Faibussowitsch   PetscCall(initialize_handle_(handle_t{}, dctx));
3627a101e5eSJacob Faibussowitsch   *static_cast<typename handle_t::type *>(handle) = impls_cast_(dctx)->get(handle_t{});
3633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
364a4af0ceeSJacob Faibussowitsch }
365a4af0ceeSJacob Faibussowitsch 
36617f48955SJacob Faibussowitsch template <DeviceType T>
367*31d47070SJunchao Zhang template <typename handle_t>
368*31d47070SJunchao Zhang inline PetscErrorCode DeviceContext<T>::getHandlePtr(PetscDeviceContext dctx, void *handle) noexcept
369*31d47070SJunchao Zhang {
370*31d47070SJunchao Zhang   using handle_type = typename handle_t::type;
371*31d47070SJunchao Zhang 
372*31d47070SJunchao Zhang   PetscFunctionBegin;
373*31d47070SJunchao Zhang   PetscCall(initialize_handle_(handle_t{}, dctx));
374*31d47070SJunchao Zhang   *static_cast<handle_type **>(handle) = const_cast<handle_type *>(std::addressof(impls_cast_(dctx)->get(handle_t{})));
375*31d47070SJunchao Zhang   PetscFunctionReturn(PETSC_SUCCESS);
376*31d47070SJunchao Zhang }
377*31d47070SJunchao Zhang 
378*31d47070SJunchao Zhang template <DeviceType T>
3796d54fb17SJacob Faibussowitsch inline PetscErrorCode DeviceContext<T>::beginTimer(PetscDeviceContext dctx) noexcept
380d71ae5a4SJacob Faibussowitsch {
3810e6b6b59SJacob Faibussowitsch   const auto dci = impls_cast_(dctx);
382a4af0ceeSJacob Faibussowitsch 
383a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
3840e6b6b59SJacob Faibussowitsch   PetscCall(check_current_device_(dctx));
385a4af0ceeSJacob Faibussowitsch   #if PetscDefined(USE_DEBUG)
3865f80ce2aSJacob Faibussowitsch   PetscCheck(!dci->timerInUse, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Forgot to call PetscLogGpuTimeEnd()?");
387a4af0ceeSJacob Faibussowitsch   dci->timerInUse = PETSC_TRUE;
388a4af0ceeSJacob Faibussowitsch   #endif
38917f48955SJacob Faibussowitsch   if (!dci->begin) {
3900e6b6b59SJacob Faibussowitsch     PetscAssert(!dci->end, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Don't have a 'begin' event, but somehow have an end event");
3919566063dSJacob Faibussowitsch     PetscCallCUPM(cupmEventCreate(&dci->begin));
3929566063dSJacob Faibussowitsch     PetscCallCUPM(cupmEventCreate(&dci->end));
39317f48955SJacob Faibussowitsch   }
3940e6b6b59SJacob Faibussowitsch   PetscCallCUPM(cupmEventRecord(dci->begin, dci->stream.get_stream()));
3953ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
396a4af0ceeSJacob Faibussowitsch }
397a4af0ceeSJacob Faibussowitsch 
39817f48955SJacob Faibussowitsch template <DeviceType T>
3996d54fb17SJacob Faibussowitsch inline PetscErrorCode DeviceContext<T>::endTimer(PetscDeviceContext dctx, PetscLogDouble *elapsed) noexcept
400d71ae5a4SJacob Faibussowitsch {
401a4af0ceeSJacob Faibussowitsch   float      gtime;
4020e6b6b59SJacob Faibussowitsch   const auto dci = impls_cast_(dctx);
4030e6b6b59SJacob Faibussowitsch   const auto end = dci->end;
404a4af0ceeSJacob Faibussowitsch 
405a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
4060e6b6b59SJacob Faibussowitsch   PetscCall(check_current_device_(dctx));
407a4af0ceeSJacob Faibussowitsch   #if PetscDefined(USE_DEBUG)
4085f80ce2aSJacob Faibussowitsch   PetscCheck(dci->timerInUse, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Forgot to call PetscLogGpuTimeBegin()?");
409a4af0ceeSJacob Faibussowitsch   dci->timerInUse = PETSC_FALSE;
410a4af0ceeSJacob Faibussowitsch   #endif
4110e6b6b59SJacob Faibussowitsch   PetscCallCUPM(cupmEventRecord(end, dci->stream.get_stream()));
4120e6b6b59SJacob Faibussowitsch   PetscCallCUPM(cupmEventSynchronize(end));
4130e6b6b59SJacob Faibussowitsch   PetscCallCUPM(cupmEventElapsedTime(&gtime, dci->begin, end));
41417f48955SJacob Faibussowitsch   *elapsed = static_cast<util::remove_pointer_t<decltype(elapsed)>>(gtime);
4153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
416a4af0ceeSJacob Faibussowitsch }
417a4af0ceeSJacob Faibussowitsch 
4180e6b6b59SJacob Faibussowitsch template <DeviceType T>
4196d54fb17SJacob Faibussowitsch inline PetscErrorCode DeviceContext<T>::memAlloc(PetscDeviceContext dctx, PetscBool clear, PetscMemType mtype, std::size_t n, std::size_t alignment, void **dest) noexcept
420d71ae5a4SJacob Faibussowitsch {
4210e6b6b59SJacob Faibussowitsch   const auto &stream = impls_cast_(dctx)->stream;
4220e6b6b59SJacob Faibussowitsch 
4230e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
4240e6b6b59SJacob Faibussowitsch   PetscCall(check_current_device_(dctx));
4250e6b6b59SJacob Faibussowitsch   PetscCall(check_memtype_(mtype, "allocating"));
4260e6b6b59SJacob Faibussowitsch   if (PetscMemTypeHost(mtype)) {
4276797ed33SJacob Faibussowitsch     PetscCall(default_pool_<HostAllocator<T>>().allocate(n, reinterpret_cast<char **>(dest), &stream, alignment));
4280e6b6b59SJacob Faibussowitsch   } else {
4296797ed33SJacob Faibussowitsch     PetscCall(default_pool_<DeviceAllocator<T>>().allocate(n, reinterpret_cast<char **>(dest), &stream, alignment));
4300e6b6b59SJacob Faibussowitsch   }
4316797ed33SJacob Faibussowitsch   if (clear) PetscCallCUPM(cupmMemsetAsync(*dest, 0, n, stream.get_stream()));
4323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4330e6b6b59SJacob Faibussowitsch }
4340e6b6b59SJacob Faibussowitsch 
4350e6b6b59SJacob Faibussowitsch template <DeviceType T>
4366d54fb17SJacob Faibussowitsch inline PetscErrorCode DeviceContext<T>::memFree(PetscDeviceContext dctx, PetscMemType mtype, void **ptr) noexcept
437d71ae5a4SJacob Faibussowitsch {
4380e6b6b59SJacob Faibussowitsch   const auto &stream = impls_cast_(dctx)->stream;
4390e6b6b59SJacob Faibussowitsch 
4400e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
4410e6b6b59SJacob Faibussowitsch   PetscCall(check_current_device_(dctx));
4420e6b6b59SJacob Faibussowitsch   PetscCall(check_memtype_(mtype, "freeing"));
4433ba16761SJacob Faibussowitsch   if (!*ptr) PetscFunctionReturn(PETSC_SUCCESS);
4440e6b6b59SJacob Faibussowitsch   if (PetscMemTypeHost(mtype)) {
4450e6b6b59SJacob Faibussowitsch     PetscCall(default_pool_<HostAllocator<T>>().deallocate(reinterpret_cast<char **>(ptr), &stream));
4460e6b6b59SJacob Faibussowitsch     // if ptr exists still exists the pool didn't own it
4470e6b6b59SJacob Faibussowitsch     if (*ptr) {
4480e6b6b59SJacob Faibussowitsch       auto registered = PETSC_FALSE, managed = PETSC_FALSE;
4490e6b6b59SJacob Faibussowitsch 
4500e6b6b59SJacob Faibussowitsch       PetscCall(PetscCUPMGetMemType(*ptr, nullptr, &registered, &managed));
4510e6b6b59SJacob Faibussowitsch       if (registered) {
4520e6b6b59SJacob Faibussowitsch         PetscCallCUPM(cupmFreeHost(*ptr));
4530e6b6b59SJacob Faibussowitsch       } else if (managed) {
4540e6b6b59SJacob Faibussowitsch         PetscCallCUPM(cupmFreeAsync(*ptr, stream.get_stream()));
4550e6b6b59SJacob Faibussowitsch       }
4560e6b6b59SJacob Faibussowitsch     }
4570e6b6b59SJacob Faibussowitsch   } else {
4580e6b6b59SJacob Faibussowitsch     PetscCall(default_pool_<DeviceAllocator<T>>().deallocate(reinterpret_cast<char **>(ptr), &stream));
4596d54fb17SJacob Faibussowitsch     // if ptr still exists the pool didn't own it
4600e6b6b59SJacob Faibussowitsch     if (*ptr) PetscCallCUPM(cupmFreeAsync(*ptr, stream.get_stream()));
4610e6b6b59SJacob Faibussowitsch   }
4623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4630e6b6b59SJacob Faibussowitsch }
4640e6b6b59SJacob Faibussowitsch 
4650e6b6b59SJacob Faibussowitsch template <DeviceType T>
4666d54fb17SJacob Faibussowitsch inline PetscErrorCode DeviceContext<T>::memCopy(PetscDeviceContext dctx, void *PETSC_RESTRICT dest, const void *PETSC_RESTRICT src, std::size_t n, PetscDeviceCopyMode mode) noexcept
467d71ae5a4SJacob Faibussowitsch {
4680e6b6b59SJacob Faibussowitsch   const auto stream = impls_cast_(dctx)->stream.get_stream();
4690e6b6b59SJacob Faibussowitsch 
4700e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
4710e6b6b59SJacob Faibussowitsch   // can't use PetscCUPMMemcpyAsync here since we don't know sizeof(*src)...
4720e6b6b59SJacob Faibussowitsch   if (mode == PETSC_DEVICE_COPY_HTOH) {
4736d54fb17SJacob Faibussowitsch     const auto cerr = cupmStreamQuery(stream);
4746d54fb17SJacob Faibussowitsch 
4750e6b6b59SJacob Faibussowitsch     // yes this is faster
4766d54fb17SJacob Faibussowitsch     if (cerr == cupmSuccess) {
4770e6b6b59SJacob Faibussowitsch       PetscCall(PetscMemcpy(dest, src, n));
4783ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
4796d54fb17SJacob Faibussowitsch     } else if (cerr == cupmErrorNotReady) {
4806d54fb17SJacob Faibussowitsch       auto PETSC_UNUSED unused = cupmGetLastError();
4816d54fb17SJacob Faibussowitsch 
4826d54fb17SJacob Faibussowitsch       static_cast<void>(unused);
4836d54fb17SJacob Faibussowitsch     } else {
4846d54fb17SJacob Faibussowitsch       PetscCallCUPM(cerr);
4850e6b6b59SJacob Faibussowitsch     }
4860e6b6b59SJacob Faibussowitsch   }
4873ba16761SJacob Faibussowitsch   PetscCallCUPM(cupmMemcpyAsync(dest, src, n, PetscDeviceCopyModeToCUPMMemcpyKind(mode), stream));
4883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4890e6b6b59SJacob Faibussowitsch }
4900e6b6b59SJacob Faibussowitsch 
4910e6b6b59SJacob Faibussowitsch template <DeviceType T>
4926d54fb17SJacob Faibussowitsch inline PetscErrorCode DeviceContext<T>::memSet(PetscDeviceContext dctx, PetscMemType mtype, void *ptr, PetscInt v, std::size_t n) noexcept
493d71ae5a4SJacob Faibussowitsch {
4940e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
4950e6b6b59SJacob Faibussowitsch   PetscCall(check_current_device_(dctx));
4960e6b6b59SJacob Faibussowitsch   PetscCall(check_memtype_(mtype, "zeroing"));
4976797ed33SJacob Faibussowitsch   PetscCallCUPM(cupmMemsetAsync(ptr, static_cast<int>(v), n, impls_cast_(dctx)->stream.get_stream()));
4983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4990e6b6b59SJacob Faibussowitsch }
5000e6b6b59SJacob Faibussowitsch 
5010e6b6b59SJacob Faibussowitsch template <DeviceType T>
5028eb1d50fSPierre Jolivet inline PetscErrorCode DeviceContext<T>::createEvent(PetscDeviceContext, PetscEvent event) noexcept
503d71ae5a4SJacob Faibussowitsch {
5040e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
5050e6b6b59SJacob Faibussowitsch   PetscCallCXX(event->data = new event_type());
5060e6b6b59SJacob Faibussowitsch   event->destroy = [](PetscEvent event) {
5070e6b6b59SJacob Faibussowitsch     PetscFunctionBegin;
5080e6b6b59SJacob Faibussowitsch     delete event_cast_(event);
5090e6b6b59SJacob Faibussowitsch     event->data = nullptr;
5103ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
5110e6b6b59SJacob Faibussowitsch   };
5123ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5130e6b6b59SJacob Faibussowitsch }
5140e6b6b59SJacob Faibussowitsch 
5150e6b6b59SJacob Faibussowitsch template <DeviceType T>
5166d54fb17SJacob Faibussowitsch inline PetscErrorCode DeviceContext<T>::recordEvent(PetscDeviceContext dctx, PetscEvent event) noexcept
517d71ae5a4SJacob Faibussowitsch {
5180e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
5190e6b6b59SJacob Faibussowitsch   PetscCall(impls_cast_(dctx)->stream.record_event(*event_cast_(event)));
5203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5210e6b6b59SJacob Faibussowitsch }
5220e6b6b59SJacob Faibussowitsch 
5230e6b6b59SJacob Faibussowitsch template <DeviceType T>
5246d54fb17SJacob Faibussowitsch inline PetscErrorCode DeviceContext<T>::waitForEvent(PetscDeviceContext dctx, PetscEvent event) noexcept
525d71ae5a4SJacob Faibussowitsch {
5260e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
5270e6b6b59SJacob Faibussowitsch   PetscCall(impls_cast_(dctx)->stream.wait_for_event(*event_cast_(event)));
5283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5290e6b6b59SJacob Faibussowitsch }
5300e6b6b59SJacob Faibussowitsch 
531030f984aSJacob Faibussowitsch // initialize the static member variables
5329371c9d4SSatish Balay template <DeviceType T>
5339371c9d4SSatish Balay bool DeviceContext<T>::initialized_ = false;
534030f984aSJacob Faibussowitsch 
53517f48955SJacob Faibussowitsch template <DeviceType T>
53617f48955SJacob Faibussowitsch std::array<typename DeviceContext<T>::cupmBlasHandle_t, PETSC_DEVICE_MAX_DEVICES> DeviceContext<T>::blashandles_ = {};
537030f984aSJacob Faibussowitsch 
53817f48955SJacob Faibussowitsch template <DeviceType T>
53917f48955SJacob Faibussowitsch std::array<typename DeviceContext<T>::cupmSolverHandle_t, PETSC_DEVICE_MAX_DEVICES> DeviceContext<T>::solverhandles_ = {};
54017f48955SJacob Faibussowitsch 
5416ff55be4SJacob Faibussowitsch template <DeviceType T>
5426ff55be4SJacob Faibussowitsch constexpr _DeviceContextOps DeviceContext<T>::ops;
5436ff55be4SJacob Faibussowitsch 
5440e6b6b59SJacob Faibussowitsch } // namespace impl
545030f984aSJacob Faibussowitsch 
546a4af0ceeSJacob Faibussowitsch // shorten this one up a bit (and instantiate the templates)
5470e6b6b59SJacob Faibussowitsch using CUPMContextCuda = impl::DeviceContext<DeviceType::CUDA>;
5480e6b6b59SJacob Faibussowitsch using CUPMContextHip  = impl::DeviceContext<DeviceType::HIP>;
549030f984aSJacob Faibussowitsch 
550030f984aSJacob Faibussowitsch   // shorthand for what is an EXTREMELY long name
5510e6b6b59SJacob Faibussowitsch   #define PetscDeviceContext_(IMPLS) ::Petsc::device::cupm::impl::DeviceContext<::Petsc::device::cupm::DeviceType::IMPLS>::PetscDeviceContext_IMPLS
552030f984aSJacob Faibussowitsch 
5530e6b6b59SJacob Faibussowitsch } // namespace cupm
55417f48955SJacob Faibussowitsch 
5550e6b6b59SJacob Faibussowitsch } // namespace device
55617f48955SJacob Faibussowitsch 
55717f48955SJacob Faibussowitsch } // namespace Petsc
558030f984aSJacob Faibussowitsch 
5590e6b6b59SJacob Faibussowitsch #endif // __cplusplus
5600e6b6b59SJacob Faibussowitsch 
561a4af0ceeSJacob Faibussowitsch #endif // PETSCDEVICECONTEXTCUDA_HPP
562