1a4963045SJacob Faibussowitsch #pragma once 20e6b6b59SJacob Faibussowitsch 30e6b6b59SJacob Faibussowitsch #include <petsc/private/cupminterface.hpp> 40e6b6b59SJacob Faibussowitsch #include <petsc/private/cpp/memory.hpp> 50e6b6b59SJacob Faibussowitsch #include <petsc/private/cpp/object_pool.hpp> 60e6b6b59SJacob Faibussowitsch 7146a86ebSJacob Faibussowitsch #include <stack> 8f13b9fe2SJacob Faibussowitsch 9d71ae5a4SJacob Faibussowitsch namespace Petsc 10d71ae5a4SJacob Faibussowitsch { 110e6b6b59SJacob Faibussowitsch 12d71ae5a4SJacob Faibussowitsch namespace device 13d71ae5a4SJacob Faibussowitsch { 140e6b6b59SJacob Faibussowitsch 15d71ae5a4SJacob Faibussowitsch namespace cupm 16d71ae5a4SJacob Faibussowitsch { 170e6b6b59SJacob Faibussowitsch 180e6b6b59SJacob Faibussowitsch // A pool for allocating cupmEvent_t's. While events are generally very cheap to create and 190e6b6b59SJacob Faibussowitsch // destroy, they are not free. Using the pool vs on-demand creation and destruction yields a ~20% 200e6b6b59SJacob Faibussowitsch // speedup. 210e6b6b59SJacob Faibussowitsch template <DeviceType T, unsigned long flags> 2285f25e71SJed Brown class PETSC_SINGLE_LIBRARY_VISIBILITY_INTERNAL CUPMEventPool : impl::Interface<T>, public RegisterFinalizeable<CUPMEventPool<T, flags>> { 23146a86ebSJacob Faibussowitsch public: 2496a4b4d9SJacob Faibussowitsch PETSC_CUPM_INHERIT_INTERFACE_TYPEDEFS_USING(T); 250e6b6b59SJacob Faibussowitsch 26089fb57cSJacob Faibussowitsch PetscErrorCode allocate(cupmEvent_t *) noexcept; 27089fb57cSJacob Faibussowitsch PetscErrorCode deallocate(cupmEvent_t *) noexcept; 28146a86ebSJacob Faibussowitsch 29089fb57cSJacob Faibussowitsch PetscErrorCode finalize_() noexcept; 30146a86ebSJacob Faibussowitsch 31146a86ebSJacob Faibussowitsch private: 32146a86ebSJacob Faibussowitsch std::stack<cupmEvent_t> pool_; 330e6b6b59SJacob Faibussowitsch }; 340e6b6b59SJacob Faibussowitsch 350e6b6b59SJacob Faibussowitsch template <DeviceType T, unsigned long flags> 36146a86ebSJacob Faibussowitsch inline PetscErrorCode CUPMEventPool<T, flags>::finalize_() noexcept 37d71ae5a4SJacob Faibussowitsch { 380e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 39146a86ebSJacob Faibussowitsch while (!pool_.empty()) { 40146a86ebSJacob Faibussowitsch PetscCallCUPM(cupmEventDestroy(std::move(pool_.top()))); 41146a86ebSJacob Faibussowitsch PetscCallCXX(pool_.pop()); 42146a86ebSJacob Faibussowitsch } 433ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 440e6b6b59SJacob Faibussowitsch } 450e6b6b59SJacob Faibussowitsch 460e6b6b59SJacob Faibussowitsch template <DeviceType T, unsigned long flags> 47146a86ebSJacob Faibussowitsch inline PetscErrorCode CUPMEventPool<T, flags>::allocate(cupmEvent_t *event) noexcept 48d71ae5a4SJacob Faibussowitsch { 490e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 504f572ea9SToby Isaac PetscAssertPointer(event, 1); 51146a86ebSJacob Faibussowitsch if (pool_.empty()) { 52146a86ebSJacob Faibussowitsch PetscCall(this->register_finalize()); 53*6497c311SBarry Smith PetscCallCUPM(cupmEventCreateWithFlags(event, (unsigned int)flags)); 54146a86ebSJacob Faibussowitsch } else { 55146a86ebSJacob Faibussowitsch PetscCallCXX(*event = std::move(pool_.top())); 56146a86ebSJacob Faibussowitsch PetscCallCXX(pool_.pop()); 57146a86ebSJacob Faibussowitsch } 583ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 590e6b6b59SJacob Faibussowitsch } 600e6b6b59SJacob Faibussowitsch 61146a86ebSJacob Faibussowitsch template <DeviceType T, unsigned long flags> 62146a86ebSJacob Faibussowitsch inline PetscErrorCode CUPMEventPool<T, flags>::deallocate(cupmEvent_t *in_event) noexcept 63d71ae5a4SJacob Faibussowitsch { 64146a86ebSJacob Faibussowitsch PetscFunctionBegin; 654f572ea9SToby Isaac PetscAssertPointer(in_event, 1); 66146a86ebSJacob Faibussowitsch if (auto event = std::exchange(*in_event, cupmEvent_t{})) { 67146a86ebSJacob Faibussowitsch if (this->registered()) { 68146a86ebSJacob Faibussowitsch PetscCallCXX(pool_.push(std::move(event))); 69146a86ebSJacob Faibussowitsch } else { 70146a86ebSJacob Faibussowitsch PetscCallCUPM(cupmEventDestroy(event)); 71146a86ebSJacob Faibussowitsch } 72146a86ebSJacob Faibussowitsch } 733ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 74146a86ebSJacob Faibussowitsch } 75146a86ebSJacob Faibussowitsch 76146a86ebSJacob Faibussowitsch template <DeviceType T, unsigned long flags> 77146a86ebSJacob Faibussowitsch CUPMEventPool<T, flags> &cupm_event_pool() noexcept 78146a86ebSJacob Faibussowitsch { 79146a86ebSJacob Faibussowitsch static CUPMEventPool<T, flags> pool; 800e6b6b59SJacob Faibussowitsch return pool; 810e6b6b59SJacob Faibussowitsch } 820e6b6b59SJacob Faibussowitsch 830e6b6b59SJacob Faibussowitsch // pool of events with timing disabled 840e6b6b59SJacob Faibussowitsch template <DeviceType T> 85d71ae5a4SJacob Faibussowitsch inline auto cupm_fast_event_pool() noexcept -> decltype(cupm_event_pool<T, impl::Interface<T>::cupmEventDisableTiming>()) & 86d71ae5a4SJacob Faibussowitsch { 870e6b6b59SJacob Faibussowitsch return cupm_event_pool<T, impl::Interface<T>::cupmEventDisableTiming>(); 880e6b6b59SJacob Faibussowitsch } 890e6b6b59SJacob Faibussowitsch 900e6b6b59SJacob Faibussowitsch // pool of events with timing enabled 910e6b6b59SJacob Faibussowitsch template <DeviceType T> 92d71ae5a4SJacob Faibussowitsch inline auto cupm_timer_event_pool() noexcept -> decltype(cupm_event_pool<T, impl::Interface<T>::cupmEventDefault>()) & 93d71ae5a4SJacob Faibussowitsch { 940e6b6b59SJacob Faibussowitsch return cupm_event_pool<T, impl::Interface<T>::cupmEventDefault>(); 950e6b6b59SJacob Faibussowitsch } 960e6b6b59SJacob Faibussowitsch 970e6b6b59SJacob Faibussowitsch // A simple wrapper of cupmEvent_t. This is used in conjunction with CUPMStream to build the 980e6b6b59SJacob Faibussowitsch // event-stream pairing for the async allocator. It is also used as the data member of 990e6b6b59SJacob Faibussowitsch // PetscEvent. 1000e6b6b59SJacob Faibussowitsch template <DeviceType T> 10185f25e71SJed Brown class PETSC_SINGLE_LIBRARY_VISIBILITY_INTERNAL CUPMEvent : impl::Interface<T>, public memory::PoolAllocated { 1023048253cSJacob Faibussowitsch using pool_type = memory::PoolAllocated; 1030e6b6b59SJacob Faibussowitsch 1040e6b6b59SJacob Faibussowitsch public: 10596a4b4d9SJacob Faibussowitsch PETSC_CUPM_INHERIT_INTERFACE_TYPEDEFS_USING(T); 1060e6b6b59SJacob Faibussowitsch 1070e6b6b59SJacob Faibussowitsch constexpr CUPMEvent() noexcept = default; 1080e6b6b59SJacob Faibussowitsch ~CUPMEvent() noexcept; 1090e6b6b59SJacob Faibussowitsch 1100e6b6b59SJacob Faibussowitsch CUPMEvent(CUPMEvent &&) noexcept; 1110e6b6b59SJacob Faibussowitsch CUPMEvent &operator=(CUPMEvent &&) noexcept; 1120e6b6b59SJacob Faibussowitsch 1130e6b6b59SJacob Faibussowitsch // event is not copyable 1140e6b6b59SJacob Faibussowitsch CUPMEvent(const CUPMEvent &) = delete; 1150e6b6b59SJacob Faibussowitsch CUPMEvent &operator=(const CUPMEvent &) = delete; 1160e6b6b59SJacob Faibussowitsch 1170e6b6b59SJacob Faibussowitsch PETSC_NODISCARD cupmEvent_t get() noexcept; 118089fb57cSJacob Faibussowitsch PetscErrorCode record(cupmStream_t) noexcept; 1190e6b6b59SJacob Faibussowitsch 1200e6b6b59SJacob Faibussowitsch explicit operator bool() const noexcept; 1210e6b6b59SJacob Faibussowitsch 1220e6b6b59SJacob Faibussowitsch private: 1230e6b6b59SJacob Faibussowitsch cupmEvent_t event_{}; 1240e6b6b59SJacob Faibussowitsch }; 1250e6b6b59SJacob Faibussowitsch 1260e6b6b59SJacob Faibussowitsch template <DeviceType T> 127d71ae5a4SJacob Faibussowitsch inline CUPMEvent<T>::~CUPMEvent() noexcept 128d71ae5a4SJacob Faibussowitsch { 1290e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 130146a86ebSJacob Faibussowitsch PetscCallAbort(PETSC_COMM_SELF, cupm_fast_event_pool<T>().deallocate(&event_)); 1310e6b6b59SJacob Faibussowitsch PetscFunctionReturnVoid(); 1320e6b6b59SJacob Faibussowitsch } 1330e6b6b59SJacob Faibussowitsch 1340e6b6b59SJacob Faibussowitsch template <DeviceType T> 13596a4b4d9SJacob Faibussowitsch inline CUPMEvent<T>::CUPMEvent(CUPMEvent &&other) noexcept : pool_type(std::move(other)), event_(util::exchange(other.event_, cupmEvent_t{})) 136d71ae5a4SJacob Faibussowitsch { 13796a4b4d9SJacob Faibussowitsch static_assert(std::is_empty<impl::Interface<T>>::value, ""); 138d71ae5a4SJacob Faibussowitsch } 1390e6b6b59SJacob Faibussowitsch 1400e6b6b59SJacob Faibussowitsch template <DeviceType T> 141d71ae5a4SJacob Faibussowitsch inline CUPMEvent<T> &CUPMEvent<T>::operator=(CUPMEvent &&other) noexcept 142d71ae5a4SJacob Faibussowitsch { 1430e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 1440e6b6b59SJacob Faibussowitsch if (this != &other) { 1450e6b6b59SJacob Faibussowitsch pool_type::operator=(std::move(other)); 146146a86ebSJacob Faibussowitsch PetscCallAbort(PETSC_COMM_SELF, cupm_fast_event_pool<T>().deallocate(&event_)); 1470e6b6b59SJacob Faibussowitsch event_ = util::exchange(other.event_, cupmEvent_t{}); 1480e6b6b59SJacob Faibussowitsch } 1490e6b6b59SJacob Faibussowitsch PetscFunctionReturn(*this); 1500e6b6b59SJacob Faibussowitsch } 1510e6b6b59SJacob Faibussowitsch 1520e6b6b59SJacob Faibussowitsch template <DeviceType T> 153d71ae5a4SJacob Faibussowitsch inline typename CUPMEvent<T>::cupmEvent_t CUPMEvent<T>::get() noexcept 154d71ae5a4SJacob Faibussowitsch { 1550e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 1560e6b6b59SJacob Faibussowitsch if (PetscUnlikely(!event_)) PetscCallAbort(PETSC_COMM_SELF, cupm_fast_event_pool<T>().allocate(&event_)); 1570e6b6b59SJacob Faibussowitsch PetscFunctionReturn(event_); 1580e6b6b59SJacob Faibussowitsch } 1590e6b6b59SJacob Faibussowitsch 1600e6b6b59SJacob Faibussowitsch template <DeviceType T> 161d71ae5a4SJacob Faibussowitsch inline PetscErrorCode CUPMEvent<T>::record(cupmStream_t stream) noexcept 162d71ae5a4SJacob Faibussowitsch { 1630e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 1640e6b6b59SJacob Faibussowitsch PetscCallCUPM(cupmEventRecord(get(), stream)); 1653ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1660e6b6b59SJacob Faibussowitsch } 1670e6b6b59SJacob Faibussowitsch 1680e6b6b59SJacob Faibussowitsch template <DeviceType T> 169d71ae5a4SJacob Faibussowitsch inline CUPMEvent<T>::operator bool() const noexcept 170d71ae5a4SJacob Faibussowitsch { 1710e6b6b59SJacob Faibussowitsch return event_ != cupmEvent_t{}; 1720e6b6b59SJacob Faibussowitsch } 1730e6b6b59SJacob Faibussowitsch 1740e6b6b59SJacob Faibussowitsch } // namespace cupm 1750e6b6b59SJacob Faibussowitsch 1760e6b6b59SJacob Faibussowitsch } // namespace device 1770e6b6b59SJacob Faibussowitsch 1780e6b6b59SJacob Faibussowitsch } // namespace Petsc 179