xref: /petsc/src/sys/objects/device/impls/cupm/cupmcontext.hpp (revision 96a4b4d95ea58ea02aff154c6b83fc6968de23ca)
117f48955SJacob Faibussowitsch #ifndef PETSCDEVICECONTEXTCUPM_HPP
2030f984aSJacob Faibussowitsch #define PETSCDEVICECONTEXTCUPM_HPP
3030f984aSJacob Faibussowitsch 
4a4af0ceeSJacob Faibussowitsch #include <petsc/private/deviceimpl.h>
5*96a4b4d9SJacob 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>
30*96a4b4d9SJacob Faibussowitsch class DeviceContext : SolverInterface<T> {
3117f48955SJacob Faibussowitsch public:
32*96a4b4d9SJacob 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 
65d71ae5a4SJacob Faibussowitsch     PETSC_NODISCARD cupmStream_t get(stream_tag) const noexcept { return this->stream.get_stream(); }
660e6b6b59SJacob Faibussowitsch 
67d71ae5a4SJacob Faibussowitsch     PETSC_NODISCARD cupmBlasHandle_t get(blas_tag) const noexcept { return this->blas; }
680e6b6b59SJacob Faibussowitsch 
69d71ae5a4SJacob Faibussowitsch     PETSC_NODISCARD 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 
90*96a4b4d9SJacob Faibussowitsch   static PetscErrorCode initialize_handle_(blas_tag, PetscDeviceContext dctx) noexcept
91d71ae5a4SJacob Faibussowitsch   {
92*96a4b4d9SJacob Faibussowitsch     const auto dci    = impls_cast_(dctx);
93*96a4b4d9SJacob Faibussowitsch     auto      &handle = blashandles_[dctx->device->deviceId];
947a101e5eSJacob Faibussowitsch 
95030f984aSJacob Faibussowitsch     PetscFunctionBegin;
96*96a4b4d9SJacob Faibussowitsch     if (!handle) {
97*96a4b4d9SJacob Faibussowitsch       PetscLogEvent event;
98*96a4b4d9SJacob 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) {
102*96a4b4d9SJacob 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;
125*96a4b4d9SJacob Faibussowitsch     if (!handle) {
126*96a4b4d9SJacob Faibussowitsch       PetscLogEvent event;
127*96a4b4d9SJacob Faibussowitsch 
1287a101e5eSJacob Faibussowitsch       PetscCall(PetscLogPauseCurrentEvent_Internal(&event));
1297a101e5eSJacob Faibussowitsch       PetscCall(PetscLogEventBegin(CUPMSOLVER_HANDLE_CREATE(), 0, 0, 0, 0));
130*96a4b4d9SJacob Faibussowitsch       for (auto i = 0; i < 3; ++i) {
131*96a4b4d9SJacob Faibussowitsch         const auto cerr = cupmSolverCreate(&handle);
132*96a4b4d9SJacob Faibussowitsch         if (PetscLikely(cerr == CUPMSOLVER_STATUS_SUCCESS)) break;
133*96a4b4d9SJacob Faibussowitsch         if ((cerr != CUPMSOLVER_STATUS_NOT_INITIALIZED) && (cerr != CUPMSOLVER_STATUS_ALLOC_FAILED)) PetscCallCUPMSOLVER(cerr);
134*96a4b4d9SJacob Faibussowitsch         if (i < 2) {
135*96a4b4d9SJacob Faibussowitsch           PetscCall(PetscSleep(3));
136*96a4b4d9SJacob Faibussowitsch           continue;
137*96a4b4d9SJacob Faibussowitsch         }
138*96a4b4d9SJacob Faibussowitsch         PetscCheck(cerr == CUPMSOLVER_STATUS_SUCCESS, PETSC_COMM_SELF, PETSC_ERR_GPU_RESOURCE, "Unable to initialize %s", cupmSolverName());
139*96a4b4d9SJacob Faibussowitsch       }
1407a101e5eSJacob Faibussowitsch       PetscCall(PetscLogEventEnd(CUPMSOLVER_HANDLE_CREATE(), 0, 0, 0, 0));
1417a101e5eSJacob Faibussowitsch       PetscCall(PetscLogEventResume_Internal(event));
142*96a4b4d9SJacob Faibussowitsch     }
143*96a4b4d9SJacob 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) {
175*96a4b4d9SJacob 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;
208089fb57cSJacob Faibussowitsch   static PetscErrorCode beginTimer(PetscDeviceContext) noexcept;
209089fb57cSJacob Faibussowitsch   static PetscErrorCode endTimer(PetscDeviceContext, PetscLogDouble *) noexcept;
210089fb57cSJacob Faibussowitsch   static PetscErrorCode memAlloc(PetscDeviceContext, PetscBool, PetscMemType, std::size_t, std::size_t, void **) noexcept;
211089fb57cSJacob Faibussowitsch   static PetscErrorCode memFree(PetscDeviceContext, PetscMemType, void **) noexcept;
212089fb57cSJacob Faibussowitsch   static PetscErrorCode memCopy(PetscDeviceContext, void *PETSC_RESTRICT, const void *PETSC_RESTRICT, std::size_t, PetscDeviceCopyMode) noexcept;
213089fb57cSJacob Faibussowitsch   static PetscErrorCode memSet(PetscDeviceContext, PetscMemType, void *, PetscInt, std::size_t) noexcept;
214089fb57cSJacob Faibussowitsch   static PetscErrorCode createEvent(PetscDeviceContext, PetscEvent) noexcept;
215089fb57cSJacob Faibussowitsch   static PetscErrorCode recordEvent(PetscDeviceContext, PetscEvent) noexcept;
216089fb57cSJacob Faibussowitsch   static PetscErrorCode waitForEvent(PetscDeviceContext, PetscEvent) noexcept;
2177a101e5eSJacob Faibussowitsch 
2187a101e5eSJacob Faibussowitsch   // not a PetscDeviceContext method, this registers the class
219089fb57cSJacob Faibussowitsch   static PetscErrorCode initialize(PetscDevice) noexcept;
2200e6b6b59SJacob Faibussowitsch 
2210e6b6b59SJacob Faibussowitsch   // clang-format off
2226ff55be4SJacob Faibussowitsch   static constexpr _DeviceContextOps ops = {
2236ff55be4SJacob Faibussowitsch     PetscDesignatedInitializer(destroy, destroy),
2246ff55be4SJacob Faibussowitsch     PetscDesignatedInitializer(changestreamtype, changeStreamType),
2256ff55be4SJacob Faibussowitsch     PetscDesignatedInitializer(setup, setUp),
2266ff55be4SJacob Faibussowitsch     PetscDesignatedInitializer(query, query),
2276ff55be4SJacob Faibussowitsch     PetscDesignatedInitializer(waitforcontext, waitForContext),
2286ff55be4SJacob Faibussowitsch     PetscDesignatedInitializer(synchronize, synchronize),
2296ff55be4SJacob Faibussowitsch     PetscDesignatedInitializer(getblashandle, getHandle<blas_tag>),
2306ff55be4SJacob Faibussowitsch     PetscDesignatedInitializer(getsolverhandle, getHandle<solver_tag>),
2316ff55be4SJacob Faibussowitsch     PetscDesignatedInitializer(getstreamhandle, getHandle<stream_tag>),
2326ff55be4SJacob Faibussowitsch     PetscDesignatedInitializer(begintimer, beginTimer),
2336ff55be4SJacob Faibussowitsch     PetscDesignatedInitializer(endtimer, endTimer),
2346ff55be4SJacob Faibussowitsch     PetscDesignatedInitializer(memalloc, memAlloc),
2356ff55be4SJacob Faibussowitsch     PetscDesignatedInitializer(memfree, memFree),
2366ff55be4SJacob Faibussowitsch     PetscDesignatedInitializer(memcopy, memCopy),
2376ff55be4SJacob Faibussowitsch     PetscDesignatedInitializer(memset, memSet),
2386ff55be4SJacob Faibussowitsch     PetscDesignatedInitializer(createevent, createEvent),
2396ff55be4SJacob Faibussowitsch     PetscDesignatedInitializer(recordevent, recordEvent),
2406ff55be4SJacob Faibussowitsch     PetscDesignatedInitializer(waitforevent, waitForEvent)
2410e6b6b59SJacob Faibussowitsch   };
2420e6b6b59SJacob Faibussowitsch   // clang-format on
243030f984aSJacob Faibussowitsch };
244030f984aSJacob Faibussowitsch 
2450e6b6b59SJacob Faibussowitsch // not a PetscDeviceContext method, this initializes the CLASS
24617f48955SJacob Faibussowitsch template <DeviceType T>
2476d54fb17SJacob Faibussowitsch inline PetscErrorCode DeviceContext<T>::initialize(PetscDevice device) noexcept
248d71ae5a4SJacob Faibussowitsch {
2497a101e5eSJacob Faibussowitsch   PetscFunctionBegin;
2507a101e5eSJacob Faibussowitsch   if (PetscUnlikely(!initialized_)) {
2510e6b6b59SJacob Faibussowitsch     uint64_t      threshold = UINT64_MAX;
2526d54fb17SJacob Faibussowitsch     cupmMemPool_t mempool;
2530e6b6b59SJacob Faibussowitsch 
2547a101e5eSJacob Faibussowitsch     initialized_ = true;
2556d54fb17SJacob Faibussowitsch     PetscCallCUPM(cupmDeviceGetMemPool(&mempool, static_cast<int>(device->deviceId)));
2560e6b6b59SJacob Faibussowitsch     PetscCallCUPM(cupmMemPoolSetAttribute(mempool, cupmMemPoolAttrReleaseThreshold, &threshold));
2570e6b6b59SJacob Faibussowitsch     blashandles_.fill(nullptr);
2580e6b6b59SJacob Faibussowitsch     solverhandles_.fill(nullptr);
2597a101e5eSJacob Faibussowitsch     PetscCall(PetscRegisterFinalize(finalize_));
2607a101e5eSJacob Faibussowitsch   }
2613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2627a101e5eSJacob Faibussowitsch }
2637a101e5eSJacob Faibussowitsch 
2647a101e5eSJacob Faibussowitsch template <DeviceType T>
2656d54fb17SJacob Faibussowitsch inline PetscErrorCode DeviceContext<T>::destroy(PetscDeviceContext dctx) noexcept
266d71ae5a4SJacob Faibussowitsch {
267030f984aSJacob Faibussowitsch   PetscFunctionBegin;
2680e6b6b59SJacob Faibussowitsch   if (const auto dci = impls_cast_(dctx)) {
2690e6b6b59SJacob Faibussowitsch     PetscCall(dci->stream.destroy());
270146a86ebSJacob Faibussowitsch     if (dci->event) PetscCall(cupm_fast_event_pool<T>().deallocate(&dci->event));
2719566063dSJacob Faibussowitsch     if (dci->begin) PetscCallCUPM(cupmEventDestroy(dci->begin));
2729566063dSJacob Faibussowitsch     if (dci->end) PetscCallCUPM(cupmEventDestroy(dci->end));
2730e6b6b59SJacob Faibussowitsch     delete dci;
2740e6b6b59SJacob Faibussowitsch     dctx->data = nullptr;
2750e6b6b59SJacob Faibussowitsch   }
2763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
277030f984aSJacob Faibussowitsch }
278030f984aSJacob Faibussowitsch 
27917f48955SJacob Faibussowitsch template <DeviceType T>
2806d54fb17SJacob Faibussowitsch inline PetscErrorCode DeviceContext<T>::changeStreamType(PetscDeviceContext dctx, PETSC_UNUSED PetscStreamType stype) noexcept
281d71ae5a4SJacob Faibussowitsch {
2827a101e5eSJacob Faibussowitsch   const auto dci = impls_cast_(dctx);
283030f984aSJacob Faibussowitsch 
284030f984aSJacob Faibussowitsch   PetscFunctionBegin;
2850e6b6b59SJacob Faibussowitsch   PetscCall(dci->stream.destroy());
286030f984aSJacob Faibussowitsch   // set these to null so they aren't usable until setup is called again
287030f984aSJacob Faibussowitsch   dci->blas   = nullptr;
288030f984aSJacob Faibussowitsch   dci->solver = nullptr;
2893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
290030f984aSJacob Faibussowitsch }
291030f984aSJacob Faibussowitsch 
29217f48955SJacob Faibussowitsch template <DeviceType T>
2936d54fb17SJacob Faibussowitsch inline PetscErrorCode DeviceContext<T>::setUp(PetscDeviceContext dctx) noexcept
294d71ae5a4SJacob Faibussowitsch {
2957a101e5eSJacob Faibussowitsch   const auto dci   = impls_cast_(dctx);
2960e6b6b59SJacob Faibussowitsch   auto      &event = dci->event;
297030f984aSJacob Faibussowitsch 
298030f984aSJacob Faibussowitsch   PetscFunctionBegin;
2990e6b6b59SJacob Faibussowitsch   PetscCall(check_current_device_(dctx));
3000e6b6b59SJacob Faibussowitsch   PetscCall(dci->stream.change_type(dctx->streamType));
3010e6b6b59SJacob Faibussowitsch   if (!event) PetscCall(cupm_fast_event_pool<T>().allocate(&event));
302a4af0ceeSJacob Faibussowitsch   #if PetscDefined(USE_DEBUG)
303a4af0ceeSJacob Faibussowitsch   dci->timerInUse = PETSC_FALSE;
304a4af0ceeSJacob Faibussowitsch   #endif
3053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
306030f984aSJacob Faibussowitsch }
307030f984aSJacob Faibussowitsch 
30817f48955SJacob Faibussowitsch template <DeviceType T>
3096d54fb17SJacob Faibussowitsch inline PetscErrorCode DeviceContext<T>::query(PetscDeviceContext dctx, PetscBool *idle) noexcept
310d71ae5a4SJacob Faibussowitsch {
311030f984aSJacob Faibussowitsch   PetscFunctionBegin;
3120e6b6b59SJacob Faibussowitsch   PetscCall(check_current_device_(dctx));
3134b955ea4SJacob Faibussowitsch   switch (auto cerr = cupmStreamQuery(impls_cast_(dctx)->stream.get_stream())) {
314d71ae5a4SJacob Faibussowitsch   case cupmSuccess:
315d71ae5a4SJacob Faibussowitsch     *idle = PETSC_TRUE;
316d71ae5a4SJacob Faibussowitsch     break;
317d71ae5a4SJacob Faibussowitsch   case cupmErrorNotReady:
318d71ae5a4SJacob Faibussowitsch     *idle = PETSC_FALSE;
3194b955ea4SJacob Faibussowitsch     // reset the error
3204b955ea4SJacob Faibussowitsch     cerr = cupmGetLastError();
3214b955ea4SJacob Faibussowitsch     static_cast<void>(cerr);
322d71ae5a4SJacob Faibussowitsch     break;
323d71ae5a4SJacob Faibussowitsch   default:
324d71ae5a4SJacob Faibussowitsch     PetscCallCUPM(cerr);
325d71ae5a4SJacob Faibussowitsch     PetscUnreachable();
326030f984aSJacob Faibussowitsch   }
3273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
328030f984aSJacob Faibussowitsch }
329030f984aSJacob Faibussowitsch 
33017f48955SJacob Faibussowitsch template <DeviceType T>
3316d54fb17SJacob Faibussowitsch inline PetscErrorCode DeviceContext<T>::waitForContext(PetscDeviceContext dctxa, PetscDeviceContext dctxb) noexcept
332d71ae5a4SJacob Faibussowitsch {
3330e6b6b59SJacob Faibussowitsch   const auto dcib  = impls_cast_(dctxb);
3340e6b6b59SJacob Faibussowitsch   const auto event = dcib->event;
335030f984aSJacob Faibussowitsch 
336030f984aSJacob Faibussowitsch   PetscFunctionBegin;
3370e6b6b59SJacob Faibussowitsch   PetscCall(check_current_device_(dctxa, dctxb));
3380e6b6b59SJacob Faibussowitsch   PetscCallCUPM(cupmEventRecord(event, dcib->stream.get_stream()));
3390e6b6b59SJacob Faibussowitsch   PetscCallCUPM(cupmStreamWaitEvent(impls_cast_(dctxa)->stream.get_stream(), event, 0));
3403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
341030f984aSJacob Faibussowitsch }
342030f984aSJacob Faibussowitsch 
34317f48955SJacob Faibussowitsch template <DeviceType T>
3446d54fb17SJacob Faibussowitsch inline PetscErrorCode DeviceContext<T>::synchronize(PetscDeviceContext dctx) noexcept
345d71ae5a4SJacob Faibussowitsch {
3460e6b6b59SJacob Faibussowitsch   auto idle = PETSC_TRUE;
347030f984aSJacob Faibussowitsch 
348030f984aSJacob Faibussowitsch   PetscFunctionBegin;
3490e6b6b59SJacob Faibussowitsch   PetscCall(query(dctx, &idle));
3500e6b6b59SJacob Faibussowitsch   if (!idle) PetscCallCUPM(cupmStreamSynchronize(impls_cast_(dctx)->stream.get_stream()));
3513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
352030f984aSJacob Faibussowitsch }
353030f984aSJacob Faibussowitsch 
35417f48955SJacob Faibussowitsch template <DeviceType T>
35517f48955SJacob Faibussowitsch template <typename handle_t>
3566d54fb17SJacob Faibussowitsch inline PetscErrorCode DeviceContext<T>::getHandle(PetscDeviceContext dctx, void *handle) noexcept
357d71ae5a4SJacob Faibussowitsch {
358a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
3597a101e5eSJacob Faibussowitsch   PetscCall(initialize_handle_(handle_t{}, dctx));
3607a101e5eSJacob Faibussowitsch   *static_cast<typename handle_t::type *>(handle) = impls_cast_(dctx)->get(handle_t{});
3613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
362a4af0ceeSJacob Faibussowitsch }
363a4af0ceeSJacob Faibussowitsch 
36417f48955SJacob Faibussowitsch template <DeviceType T>
3656d54fb17SJacob Faibussowitsch inline PetscErrorCode DeviceContext<T>::beginTimer(PetscDeviceContext dctx) noexcept
366d71ae5a4SJacob Faibussowitsch {
3670e6b6b59SJacob Faibussowitsch   const auto dci = impls_cast_(dctx);
368a4af0ceeSJacob Faibussowitsch 
369a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
3700e6b6b59SJacob Faibussowitsch   PetscCall(check_current_device_(dctx));
371a4af0ceeSJacob Faibussowitsch   #if PetscDefined(USE_DEBUG)
3725f80ce2aSJacob Faibussowitsch   PetscCheck(!dci->timerInUse, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Forgot to call PetscLogGpuTimeEnd()?");
373a4af0ceeSJacob Faibussowitsch   dci->timerInUse = PETSC_TRUE;
374a4af0ceeSJacob Faibussowitsch   #endif
37517f48955SJacob Faibussowitsch   if (!dci->begin) {
3760e6b6b59SJacob Faibussowitsch     PetscAssert(!dci->end, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Don't have a 'begin' event, but somehow have an end event");
3779566063dSJacob Faibussowitsch     PetscCallCUPM(cupmEventCreate(&dci->begin));
3789566063dSJacob Faibussowitsch     PetscCallCUPM(cupmEventCreate(&dci->end));
37917f48955SJacob Faibussowitsch   }
3800e6b6b59SJacob Faibussowitsch   PetscCallCUPM(cupmEventRecord(dci->begin, dci->stream.get_stream()));
3813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
382a4af0ceeSJacob Faibussowitsch }
383a4af0ceeSJacob Faibussowitsch 
38417f48955SJacob Faibussowitsch template <DeviceType T>
3856d54fb17SJacob Faibussowitsch inline PetscErrorCode DeviceContext<T>::endTimer(PetscDeviceContext dctx, PetscLogDouble *elapsed) noexcept
386d71ae5a4SJacob Faibussowitsch {
387a4af0ceeSJacob Faibussowitsch   float      gtime;
3880e6b6b59SJacob Faibussowitsch   const auto dci = impls_cast_(dctx);
3890e6b6b59SJacob Faibussowitsch   const auto end = dci->end;
390a4af0ceeSJacob Faibussowitsch 
391a4af0ceeSJacob Faibussowitsch   PetscFunctionBegin;
3920e6b6b59SJacob Faibussowitsch   PetscCall(check_current_device_(dctx));
393a4af0ceeSJacob Faibussowitsch   #if PetscDefined(USE_DEBUG)
3945f80ce2aSJacob Faibussowitsch   PetscCheck(dci->timerInUse, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Forgot to call PetscLogGpuTimeBegin()?");
395a4af0ceeSJacob Faibussowitsch   dci->timerInUse = PETSC_FALSE;
396a4af0ceeSJacob Faibussowitsch   #endif
3970e6b6b59SJacob Faibussowitsch   PetscCallCUPM(cupmEventRecord(end, dci->stream.get_stream()));
3980e6b6b59SJacob Faibussowitsch   PetscCallCUPM(cupmEventSynchronize(end));
3990e6b6b59SJacob Faibussowitsch   PetscCallCUPM(cupmEventElapsedTime(&gtime, dci->begin, end));
40017f48955SJacob Faibussowitsch   *elapsed = static_cast<util::remove_pointer_t<decltype(elapsed)>>(gtime);
4013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
402a4af0ceeSJacob Faibussowitsch }
403a4af0ceeSJacob Faibussowitsch 
4040e6b6b59SJacob Faibussowitsch template <DeviceType T>
4056d54fb17SJacob Faibussowitsch inline PetscErrorCode DeviceContext<T>::memAlloc(PetscDeviceContext dctx, PetscBool clear, PetscMemType mtype, std::size_t n, std::size_t alignment, void **dest) noexcept
406d71ae5a4SJacob Faibussowitsch {
4070e6b6b59SJacob Faibussowitsch   const auto &stream = impls_cast_(dctx)->stream;
4080e6b6b59SJacob Faibussowitsch 
4090e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
4100e6b6b59SJacob Faibussowitsch   PetscCall(check_current_device_(dctx));
4110e6b6b59SJacob Faibussowitsch   PetscCall(check_memtype_(mtype, "allocating"));
4120e6b6b59SJacob Faibussowitsch   if (PetscMemTypeHost(mtype)) {
4136797ed33SJacob Faibussowitsch     PetscCall(default_pool_<HostAllocator<T>>().allocate(n, reinterpret_cast<char **>(dest), &stream, alignment));
4140e6b6b59SJacob Faibussowitsch   } else {
4156797ed33SJacob Faibussowitsch     PetscCall(default_pool_<DeviceAllocator<T>>().allocate(n, reinterpret_cast<char **>(dest), &stream, alignment));
4160e6b6b59SJacob Faibussowitsch   }
4176797ed33SJacob Faibussowitsch   if (clear) PetscCallCUPM(cupmMemsetAsync(*dest, 0, n, stream.get_stream()));
4183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4190e6b6b59SJacob Faibussowitsch }
4200e6b6b59SJacob Faibussowitsch 
4210e6b6b59SJacob Faibussowitsch template <DeviceType T>
4226d54fb17SJacob Faibussowitsch inline PetscErrorCode DeviceContext<T>::memFree(PetscDeviceContext dctx, PetscMemType mtype, void **ptr) noexcept
423d71ae5a4SJacob Faibussowitsch {
4240e6b6b59SJacob Faibussowitsch   const auto &stream = impls_cast_(dctx)->stream;
4250e6b6b59SJacob Faibussowitsch 
4260e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
4270e6b6b59SJacob Faibussowitsch   PetscCall(check_current_device_(dctx));
4280e6b6b59SJacob Faibussowitsch   PetscCall(check_memtype_(mtype, "freeing"));
4293ba16761SJacob Faibussowitsch   if (!*ptr) PetscFunctionReturn(PETSC_SUCCESS);
4300e6b6b59SJacob Faibussowitsch   if (PetscMemTypeHost(mtype)) {
4310e6b6b59SJacob Faibussowitsch     PetscCall(default_pool_<HostAllocator<T>>().deallocate(reinterpret_cast<char **>(ptr), &stream));
4320e6b6b59SJacob Faibussowitsch     // if ptr exists still exists the pool didn't own it
4330e6b6b59SJacob Faibussowitsch     if (*ptr) {
4340e6b6b59SJacob Faibussowitsch       auto registered = PETSC_FALSE, managed = PETSC_FALSE;
4350e6b6b59SJacob Faibussowitsch 
4360e6b6b59SJacob Faibussowitsch       PetscCall(PetscCUPMGetMemType(*ptr, nullptr, &registered, &managed));
4370e6b6b59SJacob Faibussowitsch       if (registered) {
4380e6b6b59SJacob Faibussowitsch         PetscCallCUPM(cupmFreeHost(*ptr));
4390e6b6b59SJacob Faibussowitsch       } else if (managed) {
4400e6b6b59SJacob Faibussowitsch         PetscCallCUPM(cupmFreeAsync(*ptr, stream.get_stream()));
4410e6b6b59SJacob Faibussowitsch       }
4420e6b6b59SJacob Faibussowitsch     }
4430e6b6b59SJacob Faibussowitsch   } else {
4440e6b6b59SJacob Faibussowitsch     PetscCall(default_pool_<DeviceAllocator<T>>().deallocate(reinterpret_cast<char **>(ptr), &stream));
4456d54fb17SJacob Faibussowitsch     // if ptr still exists the pool didn't own it
4460e6b6b59SJacob Faibussowitsch     if (*ptr) PetscCallCUPM(cupmFreeAsync(*ptr, stream.get_stream()));
4470e6b6b59SJacob Faibussowitsch   }
4483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4490e6b6b59SJacob Faibussowitsch }
4500e6b6b59SJacob Faibussowitsch 
4510e6b6b59SJacob Faibussowitsch template <DeviceType T>
4526d54fb17SJacob Faibussowitsch inline PetscErrorCode DeviceContext<T>::memCopy(PetscDeviceContext dctx, void *PETSC_RESTRICT dest, const void *PETSC_RESTRICT src, std::size_t n, PetscDeviceCopyMode mode) noexcept
453d71ae5a4SJacob Faibussowitsch {
4540e6b6b59SJacob Faibussowitsch   const auto stream = impls_cast_(dctx)->stream.get_stream();
4550e6b6b59SJacob Faibussowitsch 
4560e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
4570e6b6b59SJacob Faibussowitsch   // can't use PetscCUPMMemcpyAsync here since we don't know sizeof(*src)...
4580e6b6b59SJacob Faibussowitsch   if (mode == PETSC_DEVICE_COPY_HTOH) {
4596d54fb17SJacob Faibussowitsch     const auto cerr = cupmStreamQuery(stream);
4606d54fb17SJacob Faibussowitsch 
4610e6b6b59SJacob Faibussowitsch     // yes this is faster
4626d54fb17SJacob Faibussowitsch     if (cerr == cupmSuccess) {
4630e6b6b59SJacob Faibussowitsch       PetscCall(PetscMemcpy(dest, src, n));
4643ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
4656d54fb17SJacob Faibussowitsch     } else if (cerr == cupmErrorNotReady) {
4666d54fb17SJacob Faibussowitsch       auto PETSC_UNUSED unused = cupmGetLastError();
4676d54fb17SJacob Faibussowitsch 
4686d54fb17SJacob Faibussowitsch       static_cast<void>(unused);
4696d54fb17SJacob Faibussowitsch     } else {
4706d54fb17SJacob Faibussowitsch       PetscCallCUPM(cerr);
4710e6b6b59SJacob Faibussowitsch     }
4720e6b6b59SJacob Faibussowitsch   }
4733ba16761SJacob Faibussowitsch   PetscCallCUPM(cupmMemcpyAsync(dest, src, n, PetscDeviceCopyModeToCUPMMemcpyKind(mode), stream));
4743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4750e6b6b59SJacob Faibussowitsch }
4760e6b6b59SJacob Faibussowitsch 
4770e6b6b59SJacob Faibussowitsch template <DeviceType T>
4786d54fb17SJacob Faibussowitsch inline PetscErrorCode DeviceContext<T>::memSet(PetscDeviceContext dctx, PetscMemType mtype, void *ptr, PetscInt v, std::size_t n) noexcept
479d71ae5a4SJacob Faibussowitsch {
4800e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
4810e6b6b59SJacob Faibussowitsch   PetscCall(check_current_device_(dctx));
4820e6b6b59SJacob Faibussowitsch   PetscCall(check_memtype_(mtype, "zeroing"));
4836797ed33SJacob Faibussowitsch   PetscCallCUPM(cupmMemsetAsync(ptr, static_cast<int>(v), n, impls_cast_(dctx)->stream.get_stream()));
4843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4850e6b6b59SJacob Faibussowitsch }
4860e6b6b59SJacob Faibussowitsch 
4870e6b6b59SJacob Faibussowitsch template <DeviceType T>
4888eb1d50fSPierre Jolivet inline PetscErrorCode DeviceContext<T>::createEvent(PetscDeviceContext, PetscEvent event) noexcept
489d71ae5a4SJacob Faibussowitsch {
4900e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
4910e6b6b59SJacob Faibussowitsch   PetscCallCXX(event->data = new event_type());
4920e6b6b59SJacob Faibussowitsch   event->destroy = [](PetscEvent event) {
4930e6b6b59SJacob Faibussowitsch     PetscFunctionBegin;
4940e6b6b59SJacob Faibussowitsch     delete event_cast_(event);
4950e6b6b59SJacob Faibussowitsch     event->data = nullptr;
4963ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
4970e6b6b59SJacob Faibussowitsch   };
4983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4990e6b6b59SJacob Faibussowitsch }
5000e6b6b59SJacob Faibussowitsch 
5010e6b6b59SJacob Faibussowitsch template <DeviceType T>
5026d54fb17SJacob Faibussowitsch inline PetscErrorCode DeviceContext<T>::recordEvent(PetscDeviceContext dctx, PetscEvent event) noexcept
503d71ae5a4SJacob Faibussowitsch {
5040e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
5050e6b6b59SJacob Faibussowitsch   PetscCall(impls_cast_(dctx)->stream.record_event(*event_cast_(event)));
5063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5070e6b6b59SJacob Faibussowitsch }
5080e6b6b59SJacob Faibussowitsch 
5090e6b6b59SJacob Faibussowitsch template <DeviceType T>
5106d54fb17SJacob Faibussowitsch inline PetscErrorCode DeviceContext<T>::waitForEvent(PetscDeviceContext dctx, PetscEvent event) noexcept
511d71ae5a4SJacob Faibussowitsch {
5120e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
5130e6b6b59SJacob Faibussowitsch   PetscCall(impls_cast_(dctx)->stream.wait_for_event(*event_cast_(event)));
5143ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5150e6b6b59SJacob Faibussowitsch }
5160e6b6b59SJacob Faibussowitsch 
517030f984aSJacob Faibussowitsch // initialize the static member variables
5189371c9d4SSatish Balay template <DeviceType T>
5199371c9d4SSatish Balay bool DeviceContext<T>::initialized_ = false;
520030f984aSJacob Faibussowitsch 
52117f48955SJacob Faibussowitsch template <DeviceType T>
52217f48955SJacob Faibussowitsch std::array<typename DeviceContext<T>::cupmBlasHandle_t, PETSC_DEVICE_MAX_DEVICES> DeviceContext<T>::blashandles_ = {};
523030f984aSJacob Faibussowitsch 
52417f48955SJacob Faibussowitsch template <DeviceType T>
52517f48955SJacob Faibussowitsch std::array<typename DeviceContext<T>::cupmSolverHandle_t, PETSC_DEVICE_MAX_DEVICES> DeviceContext<T>::solverhandles_ = {};
52617f48955SJacob Faibussowitsch 
5276ff55be4SJacob Faibussowitsch template <DeviceType T>
5286ff55be4SJacob Faibussowitsch constexpr _DeviceContextOps DeviceContext<T>::ops;
5296ff55be4SJacob Faibussowitsch 
5300e6b6b59SJacob Faibussowitsch } // namespace impl
531030f984aSJacob Faibussowitsch 
532a4af0ceeSJacob Faibussowitsch // shorten this one up a bit (and instantiate the templates)
5330e6b6b59SJacob Faibussowitsch using CUPMContextCuda = impl::DeviceContext<DeviceType::CUDA>;
5340e6b6b59SJacob Faibussowitsch using CUPMContextHip  = impl::DeviceContext<DeviceType::HIP>;
535030f984aSJacob Faibussowitsch 
536030f984aSJacob Faibussowitsch   // shorthand for what is an EXTREMELY long name
5370e6b6b59SJacob Faibussowitsch   #define PetscDeviceContext_(IMPLS) ::Petsc::device::cupm::impl::DeviceContext<::Petsc::device::cupm::DeviceType::IMPLS>::PetscDeviceContext_IMPLS
538030f984aSJacob Faibussowitsch 
5390e6b6b59SJacob Faibussowitsch } // namespace cupm
54017f48955SJacob Faibussowitsch 
5410e6b6b59SJacob Faibussowitsch } // namespace device
54217f48955SJacob Faibussowitsch 
54317f48955SJacob Faibussowitsch } // namespace Petsc
544030f984aSJacob Faibussowitsch 
5450e6b6b59SJacob Faibussowitsch #endif // __cplusplus
5460e6b6b59SJacob Faibussowitsch 
547a4af0ceeSJacob Faibussowitsch #endif // PETSCDEVICECONTEXTCUDA_HPP
548