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(>ime, 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, ®istered, &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