10e6b6b59SJacob Faibussowitsch #ifndef PETSC_CUPMEVENT_HPP 20e6b6b59SJacob Faibussowitsch #define PETSC_CUPMEVENT_HPP 30e6b6b59SJacob Faibussowitsch 40e6b6b59SJacob Faibussowitsch #include <petsc/private/cupminterface.hpp> 50e6b6b59SJacob Faibussowitsch #include <petsc/private/cpp/memory.hpp> 60e6b6b59SJacob Faibussowitsch #include <petsc/private/cpp/object_pool.hpp> 70e6b6b59SJacob Faibussowitsch 80e6b6b59SJacob Faibussowitsch #if defined(__cplusplus) 9146a86ebSJacob Faibussowitsch #include <stack> 10d71ae5a4SJacob Faibussowitsch namespace Petsc 11d71ae5a4SJacob Faibussowitsch { 120e6b6b59SJacob Faibussowitsch 13d71ae5a4SJacob Faibussowitsch namespace device 14d71ae5a4SJacob Faibussowitsch { 150e6b6b59SJacob Faibussowitsch 16d71ae5a4SJacob Faibussowitsch namespace cupm 17d71ae5a4SJacob Faibussowitsch { 180e6b6b59SJacob Faibussowitsch 190e6b6b59SJacob Faibussowitsch // A pool for allocating cupmEvent_t's. While events are generally very cheap to create and 200e6b6b59SJacob Faibussowitsch // destroy, they are not free. Using the pool vs on-demand creation and destruction yields a ~20% 210e6b6b59SJacob Faibussowitsch // speedup. 220e6b6b59SJacob Faibussowitsch template <DeviceType T, unsigned long flags> 23146a86ebSJacob Faibussowitsch class CUPMEventPool : impl::Interface<T>, public RegisterFinalizeable<CUPMEventPool<T, flags>> { 24146a86ebSJacob Faibussowitsch public: 25*96a4b4d9SJacob Faibussowitsch PETSC_CUPM_INHERIT_INTERFACE_TYPEDEFS_USING(T); 260e6b6b59SJacob Faibussowitsch 27089fb57cSJacob Faibussowitsch PetscErrorCode allocate(cupmEvent_t *) noexcept; 28089fb57cSJacob Faibussowitsch PetscErrorCode deallocate(cupmEvent_t *) noexcept; 29146a86ebSJacob Faibussowitsch 30089fb57cSJacob Faibussowitsch PetscErrorCode finalize_() noexcept; 31146a86ebSJacob Faibussowitsch 32146a86ebSJacob Faibussowitsch private: 33146a86ebSJacob Faibussowitsch std::stack<cupmEvent_t> pool_; 340e6b6b59SJacob Faibussowitsch }; 350e6b6b59SJacob Faibussowitsch 360e6b6b59SJacob Faibussowitsch template <DeviceType T, unsigned long flags> 37146a86ebSJacob Faibussowitsch inline PetscErrorCode CUPMEventPool<T, flags>::finalize_() noexcept 38d71ae5a4SJacob Faibussowitsch { 390e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 40146a86ebSJacob Faibussowitsch while (!pool_.empty()) { 41146a86ebSJacob Faibussowitsch PetscCallCUPM(cupmEventDestroy(std::move(pool_.top()))); 42146a86ebSJacob Faibussowitsch PetscCallCXX(pool_.pop()); 43146a86ebSJacob Faibussowitsch } 443ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 450e6b6b59SJacob Faibussowitsch } 460e6b6b59SJacob Faibussowitsch 470e6b6b59SJacob Faibussowitsch template <DeviceType T, unsigned long flags> 48146a86ebSJacob Faibussowitsch inline PetscErrorCode CUPMEventPool<T, flags>::allocate(cupmEvent_t *event) noexcept 49d71ae5a4SJacob Faibussowitsch { 500e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 51146a86ebSJacob Faibussowitsch PetscValidPointer(event, 1); 52146a86ebSJacob Faibussowitsch if (pool_.empty()) { 53146a86ebSJacob Faibussowitsch PetscCall(this->register_finalize()); 54146a86ebSJacob Faibussowitsch PetscCallCUPM(cupmEventCreateWithFlags(event, flags)); 55146a86ebSJacob Faibussowitsch } else { 56146a86ebSJacob Faibussowitsch PetscCallCXX(*event = std::move(pool_.top())); 57146a86ebSJacob Faibussowitsch PetscCallCXX(pool_.pop()); 58146a86ebSJacob Faibussowitsch } 593ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 600e6b6b59SJacob Faibussowitsch } 610e6b6b59SJacob Faibussowitsch 62146a86ebSJacob Faibussowitsch template <DeviceType T, unsigned long flags> 63146a86ebSJacob Faibussowitsch inline PetscErrorCode CUPMEventPool<T, flags>::deallocate(cupmEvent_t *in_event) noexcept 64d71ae5a4SJacob Faibussowitsch { 65146a86ebSJacob Faibussowitsch PetscFunctionBegin; 66146a86ebSJacob Faibussowitsch PetscValidPointer(in_event, 1); 67146a86ebSJacob Faibussowitsch if (auto event = std::exchange(*in_event, cupmEvent_t{})) { 68146a86ebSJacob Faibussowitsch if (this->registered()) { 69146a86ebSJacob Faibussowitsch PetscCallCXX(pool_.push(std::move(event))); 70146a86ebSJacob Faibussowitsch } else { 71146a86ebSJacob Faibussowitsch PetscCallCUPM(cupmEventDestroy(event)); 72146a86ebSJacob Faibussowitsch } 73146a86ebSJacob Faibussowitsch } 743ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 75146a86ebSJacob Faibussowitsch } 76146a86ebSJacob Faibussowitsch 77146a86ebSJacob Faibussowitsch template <DeviceType T, unsigned long flags> 78146a86ebSJacob Faibussowitsch CUPMEventPool<T, flags> &cupm_event_pool() noexcept 79146a86ebSJacob Faibussowitsch { 80146a86ebSJacob Faibussowitsch static CUPMEventPool<T, flags> pool; 810e6b6b59SJacob Faibussowitsch return pool; 820e6b6b59SJacob Faibussowitsch } 830e6b6b59SJacob Faibussowitsch 840e6b6b59SJacob Faibussowitsch // pool of events with timing disabled 850e6b6b59SJacob Faibussowitsch template <DeviceType T> 86d71ae5a4SJacob Faibussowitsch inline auto cupm_fast_event_pool() noexcept -> decltype(cupm_event_pool<T, impl::Interface<T>::cupmEventDisableTiming>()) & 87d71ae5a4SJacob Faibussowitsch { 880e6b6b59SJacob Faibussowitsch return cupm_event_pool<T, impl::Interface<T>::cupmEventDisableTiming>(); 890e6b6b59SJacob Faibussowitsch } 900e6b6b59SJacob Faibussowitsch 910e6b6b59SJacob Faibussowitsch // pool of events with timing enabled 920e6b6b59SJacob Faibussowitsch template <DeviceType T> 93d71ae5a4SJacob Faibussowitsch inline auto cupm_timer_event_pool() noexcept -> decltype(cupm_event_pool<T, impl::Interface<T>::cupmEventDefault>()) & 94d71ae5a4SJacob Faibussowitsch { 950e6b6b59SJacob Faibussowitsch return cupm_event_pool<T, impl::Interface<T>::cupmEventDefault>(); 960e6b6b59SJacob Faibussowitsch } 970e6b6b59SJacob Faibussowitsch 980e6b6b59SJacob Faibussowitsch // A simple wrapper of cupmEvent_t. This is used in conjunction with CUPMStream to build the 990e6b6b59SJacob Faibussowitsch // event-stream pairing for the async allocator. It is also used as the data member of 1000e6b6b59SJacob Faibussowitsch // PetscEvent. 1010e6b6b59SJacob Faibussowitsch template <DeviceType T> 1020e6b6b59SJacob Faibussowitsch class CUPMEvent : impl::Interface<T>, public memory::PoolAllocated<CUPMEvent<T>> { 1030e6b6b59SJacob Faibussowitsch using pool_type = memory::PoolAllocated<CUPMEvent<T>>; 1040e6b6b59SJacob Faibussowitsch 1050e6b6b59SJacob Faibussowitsch public: 106*96a4b4d9SJacob Faibussowitsch PETSC_CUPM_INHERIT_INTERFACE_TYPEDEFS_USING(T); 1070e6b6b59SJacob Faibussowitsch 1080e6b6b59SJacob Faibussowitsch constexpr CUPMEvent() noexcept = default; 1090e6b6b59SJacob Faibussowitsch ~CUPMEvent() noexcept; 1100e6b6b59SJacob Faibussowitsch 1110e6b6b59SJacob Faibussowitsch CUPMEvent(CUPMEvent &&) noexcept; 1120e6b6b59SJacob Faibussowitsch CUPMEvent &operator=(CUPMEvent &&) noexcept; 1130e6b6b59SJacob Faibussowitsch 1140e6b6b59SJacob Faibussowitsch // event is not copyable 1150e6b6b59SJacob Faibussowitsch CUPMEvent(const CUPMEvent &) = delete; 1160e6b6b59SJacob Faibussowitsch CUPMEvent &operator=(const CUPMEvent &) = delete; 1170e6b6b59SJacob Faibussowitsch 1180e6b6b59SJacob Faibussowitsch PETSC_NODISCARD cupmEvent_t get() noexcept; 119089fb57cSJacob Faibussowitsch PetscErrorCode record(cupmStream_t) noexcept; 1200e6b6b59SJacob Faibussowitsch 1210e6b6b59SJacob Faibussowitsch explicit operator bool() const noexcept; 1220e6b6b59SJacob Faibussowitsch 1230e6b6b59SJacob Faibussowitsch private: 1240e6b6b59SJacob Faibussowitsch cupmEvent_t event_{}; 1250e6b6b59SJacob Faibussowitsch }; 1260e6b6b59SJacob Faibussowitsch 1270e6b6b59SJacob Faibussowitsch template <DeviceType T> 128d71ae5a4SJacob Faibussowitsch inline CUPMEvent<T>::~CUPMEvent() noexcept 129d71ae5a4SJacob Faibussowitsch { 1300e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 131146a86ebSJacob Faibussowitsch PetscCallAbort(PETSC_COMM_SELF, cupm_fast_event_pool<T>().deallocate(&event_)); 1320e6b6b59SJacob Faibussowitsch PetscFunctionReturnVoid(); 1330e6b6b59SJacob Faibussowitsch } 1340e6b6b59SJacob Faibussowitsch 1350e6b6b59SJacob Faibussowitsch template <DeviceType T> 136*96a4b4d9SJacob Faibussowitsch inline CUPMEvent<T>::CUPMEvent(CUPMEvent &&other) noexcept : pool_type(std::move(other)), event_(util::exchange(other.event_, cupmEvent_t{})) 137d71ae5a4SJacob Faibussowitsch { 138*96a4b4d9SJacob Faibussowitsch static_assert(std::is_empty<impl::Interface<T>>::value, ""); 139d71ae5a4SJacob Faibussowitsch } 1400e6b6b59SJacob Faibussowitsch 1410e6b6b59SJacob Faibussowitsch template <DeviceType T> 142d71ae5a4SJacob Faibussowitsch inline CUPMEvent<T> &CUPMEvent<T>::operator=(CUPMEvent &&other) noexcept 143d71ae5a4SJacob Faibussowitsch { 1440e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 1450e6b6b59SJacob Faibussowitsch if (this != &other) { 1460e6b6b59SJacob Faibussowitsch pool_type::operator=(std::move(other)); 147146a86ebSJacob Faibussowitsch PetscCallAbort(PETSC_COMM_SELF, cupm_fast_event_pool<T>().deallocate(&event_)); 1480e6b6b59SJacob Faibussowitsch event_ = util::exchange(other.event_, cupmEvent_t{}); 1490e6b6b59SJacob Faibussowitsch } 1500e6b6b59SJacob Faibussowitsch PetscFunctionReturn(*this); 1510e6b6b59SJacob Faibussowitsch } 1520e6b6b59SJacob Faibussowitsch 1530e6b6b59SJacob Faibussowitsch template <DeviceType T> 154d71ae5a4SJacob Faibussowitsch inline typename CUPMEvent<T>::cupmEvent_t CUPMEvent<T>::get() noexcept 155d71ae5a4SJacob Faibussowitsch { 1560e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 1570e6b6b59SJacob Faibussowitsch if (PetscUnlikely(!event_)) PetscCallAbort(PETSC_COMM_SELF, cupm_fast_event_pool<T>().allocate(&event_)); 1580e6b6b59SJacob Faibussowitsch PetscFunctionReturn(event_); 1590e6b6b59SJacob Faibussowitsch } 1600e6b6b59SJacob Faibussowitsch 1610e6b6b59SJacob Faibussowitsch template <DeviceType T> 162d71ae5a4SJacob Faibussowitsch inline PetscErrorCode CUPMEvent<T>::record(cupmStream_t stream) noexcept 163d71ae5a4SJacob Faibussowitsch { 1640e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 1650e6b6b59SJacob Faibussowitsch PetscCallCUPM(cupmEventRecord(get(), stream)); 1663ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1670e6b6b59SJacob Faibussowitsch } 1680e6b6b59SJacob Faibussowitsch 1690e6b6b59SJacob Faibussowitsch template <DeviceType T> 170d71ae5a4SJacob Faibussowitsch inline CUPMEvent<T>::operator bool() const noexcept 171d71ae5a4SJacob Faibussowitsch { 1720e6b6b59SJacob Faibussowitsch return event_ != cupmEvent_t{}; 1730e6b6b59SJacob Faibussowitsch } 1740e6b6b59SJacob Faibussowitsch 1750e6b6b59SJacob Faibussowitsch } // namespace cupm 1760e6b6b59SJacob Faibussowitsch 1770e6b6b59SJacob Faibussowitsch } // namespace device 1780e6b6b59SJacob Faibussowitsch 1790e6b6b59SJacob Faibussowitsch } // namespace Petsc 1800e6b6b59SJacob Faibussowitsch #endif // __cplusplus 1810e6b6b59SJacob Faibussowitsch 1820e6b6b59SJacob Faibussowitsch #endif // PETSC_CUPMEVENT_HPP 183