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) 9*d71ae5a4SJacob Faibussowitsch namespace Petsc 10*d71ae5a4SJacob Faibussowitsch { 110e6b6b59SJacob Faibussowitsch 12*d71ae5a4SJacob Faibussowitsch namespace device 13*d71ae5a4SJacob Faibussowitsch { 140e6b6b59SJacob Faibussowitsch 15*d71ae5a4SJacob Faibussowitsch namespace cupm 16*d71ae5a4SJacob Faibussowitsch { 170e6b6b59SJacob Faibussowitsch 18*d71ae5a4SJacob Faibussowitsch namespace 19*d71ae5a4SJacob Faibussowitsch { 200e6b6b59SJacob Faibussowitsch 210e6b6b59SJacob Faibussowitsch // A pool for allocating cupmEvent_t's. While events are generally very cheap to create and 220e6b6b59SJacob Faibussowitsch // destroy, they are not free. Using the pool vs on-demand creation and destruction yields a ~20% 230e6b6b59SJacob Faibussowitsch // speedup. 240e6b6b59SJacob Faibussowitsch template <DeviceType T, unsigned long flags> 250e6b6b59SJacob Faibussowitsch struct CUPMEventPoolAllocator : impl::Interface<T>, AllocatorBase<typename impl::Interface<T>::cupmEvent_t> { 260e6b6b59SJacob Faibussowitsch PETSC_CUPM_INHERIT_INTERFACE_TYPEDEFS_USING(interface_type, T); 270e6b6b59SJacob Faibussowitsch 280e6b6b59SJacob Faibussowitsch PETSC_NODISCARD static PetscErrorCode create(cupmEvent_t *) noexcept; 290e6b6b59SJacob Faibussowitsch PETSC_NODISCARD static PetscErrorCode destroy(cupmEvent_t) noexcept; 300e6b6b59SJacob Faibussowitsch }; 310e6b6b59SJacob Faibussowitsch 320e6b6b59SJacob Faibussowitsch template <DeviceType T, unsigned long flags> 33*d71ae5a4SJacob Faibussowitsch inline PetscErrorCode CUPMEventPoolAllocator<T, flags>::create(cupmEvent_t *event) noexcept 34*d71ae5a4SJacob Faibussowitsch { 350e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 360e6b6b59SJacob Faibussowitsch PetscCallCUPM(cupmEventCreateWithFlags(event, flags)); 370e6b6b59SJacob Faibussowitsch PetscFunctionReturn(0); 380e6b6b59SJacob Faibussowitsch } 390e6b6b59SJacob Faibussowitsch 400e6b6b59SJacob Faibussowitsch template <DeviceType T, unsigned long flags> 41*d71ae5a4SJacob Faibussowitsch inline PetscErrorCode CUPMEventPoolAllocator<T, flags>::destroy(cupmEvent_t event) noexcept 42*d71ae5a4SJacob Faibussowitsch { 430e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 440e6b6b59SJacob Faibussowitsch PetscCallCUPM(cupmEventDestroy(event)); 450e6b6b59SJacob Faibussowitsch PetscFunctionReturn(0); 460e6b6b59SJacob Faibussowitsch } 470e6b6b59SJacob Faibussowitsch 480e6b6b59SJacob Faibussowitsch } // anonymous namespace 490e6b6b59SJacob Faibussowitsch 500e6b6b59SJacob Faibussowitsch template <DeviceType T, unsigned long flags, typename allocator_type = CUPMEventPoolAllocator<T, flags>, typename pool_type = ObjectPool<typename allocator_type::value_type, allocator_type>> 51*d71ae5a4SJacob Faibussowitsch pool_type &cupm_event_pool() noexcept 52*d71ae5a4SJacob Faibussowitsch { 530e6b6b59SJacob Faibussowitsch static pool_type pool; 540e6b6b59SJacob Faibussowitsch return pool; 550e6b6b59SJacob Faibussowitsch } 560e6b6b59SJacob Faibussowitsch 570e6b6b59SJacob Faibussowitsch // pool of events with timing disabled 580e6b6b59SJacob Faibussowitsch template <DeviceType T> 59*d71ae5a4SJacob Faibussowitsch inline auto cupm_fast_event_pool() noexcept -> decltype(cupm_event_pool<T, impl::Interface<T>::cupmEventDisableTiming>()) & 60*d71ae5a4SJacob Faibussowitsch { 610e6b6b59SJacob Faibussowitsch return cupm_event_pool<T, impl::Interface<T>::cupmEventDisableTiming>(); 620e6b6b59SJacob Faibussowitsch } 630e6b6b59SJacob Faibussowitsch 640e6b6b59SJacob Faibussowitsch // pool of events with timing enabled 650e6b6b59SJacob Faibussowitsch template <DeviceType T> 66*d71ae5a4SJacob Faibussowitsch inline auto cupm_timer_event_pool() noexcept -> decltype(cupm_event_pool<T, impl::Interface<T>::cupmEventDefault>()) & 67*d71ae5a4SJacob Faibussowitsch { 680e6b6b59SJacob Faibussowitsch return cupm_event_pool<T, impl::Interface<T>::cupmEventDefault>(); 690e6b6b59SJacob Faibussowitsch } 700e6b6b59SJacob Faibussowitsch 710e6b6b59SJacob Faibussowitsch // A simple wrapper of cupmEvent_t. This is used in conjunction with CUPMStream to build the 720e6b6b59SJacob Faibussowitsch // event-stream pairing for the async allocator. It is also used as the data member of 730e6b6b59SJacob Faibussowitsch // PetscEvent. 740e6b6b59SJacob Faibussowitsch template <DeviceType T> 750e6b6b59SJacob Faibussowitsch class CUPMEvent : impl::Interface<T>, public memory::PoolAllocated<CUPMEvent<T>> { 760e6b6b59SJacob Faibussowitsch using pool_type = memory::PoolAllocated<CUPMEvent<T>>; 770e6b6b59SJacob Faibussowitsch 780e6b6b59SJacob Faibussowitsch public: 790e6b6b59SJacob Faibussowitsch PETSC_CUPM_INHERIT_INTERFACE_TYPEDEFS_USING(interface_type, T); 800e6b6b59SJacob Faibussowitsch 810e6b6b59SJacob Faibussowitsch constexpr CUPMEvent() noexcept = default; 820e6b6b59SJacob Faibussowitsch ~CUPMEvent() noexcept; 830e6b6b59SJacob Faibussowitsch 840e6b6b59SJacob Faibussowitsch CUPMEvent(CUPMEvent &&) noexcept; 850e6b6b59SJacob Faibussowitsch CUPMEvent &operator=(CUPMEvent &&) noexcept; 860e6b6b59SJacob Faibussowitsch 870e6b6b59SJacob Faibussowitsch // event is not copyable 880e6b6b59SJacob Faibussowitsch CUPMEvent(const CUPMEvent &) = delete; 890e6b6b59SJacob Faibussowitsch CUPMEvent &operator=(const CUPMEvent &) = delete; 900e6b6b59SJacob Faibussowitsch 910e6b6b59SJacob Faibussowitsch PETSC_NODISCARD cupmEvent_t get() noexcept; 920e6b6b59SJacob Faibussowitsch PETSC_NODISCARD PetscErrorCode record(cupmStream_t) noexcept; 930e6b6b59SJacob Faibussowitsch 940e6b6b59SJacob Faibussowitsch explicit operator bool() const noexcept; 950e6b6b59SJacob Faibussowitsch 960e6b6b59SJacob Faibussowitsch private: 970e6b6b59SJacob Faibussowitsch cupmEvent_t event_{}; 980e6b6b59SJacob Faibussowitsch }; 990e6b6b59SJacob Faibussowitsch 1000e6b6b59SJacob Faibussowitsch template <DeviceType T> 101*d71ae5a4SJacob Faibussowitsch inline CUPMEvent<T>::~CUPMEvent() noexcept 102*d71ae5a4SJacob Faibussowitsch { 1030e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 1040e6b6b59SJacob Faibussowitsch if (event_) PetscCallAbort(PETSC_COMM_SELF, cupm_fast_event_pool<T>().deallocate(std::move(event_))); 1050e6b6b59SJacob Faibussowitsch PetscFunctionReturnVoid(); 1060e6b6b59SJacob Faibussowitsch } 1070e6b6b59SJacob Faibussowitsch 1080e6b6b59SJacob Faibussowitsch template <DeviceType T> 109*d71ae5a4SJacob Faibussowitsch inline CUPMEvent<T>::CUPMEvent(CUPMEvent &&other) noexcept : interface_type(std::move(other)), pool_type(std::move(other)), event_(util::exchange(other.event_, cupmEvent_t{})) 110*d71ae5a4SJacob Faibussowitsch { 111*d71ae5a4SJacob Faibussowitsch } 1120e6b6b59SJacob Faibussowitsch 1130e6b6b59SJacob Faibussowitsch template <DeviceType T> 114*d71ae5a4SJacob Faibussowitsch inline CUPMEvent<T> &CUPMEvent<T>::operator=(CUPMEvent &&other) noexcept 115*d71ae5a4SJacob Faibussowitsch { 1160e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 1170e6b6b59SJacob Faibussowitsch if (this != &other) { 1180e6b6b59SJacob Faibussowitsch interface_type::operator=(std::move(other)); 1190e6b6b59SJacob Faibussowitsch pool_type:: operator=(std::move(other)); 1200e6b6b59SJacob Faibussowitsch if (event_) PetscCall(cupm_fast_event_pool<T>().deallocate(std::move(event_))); 1210e6b6b59SJacob Faibussowitsch event_ = util::exchange(other.event_, cupmEvent_t{}); 1220e6b6b59SJacob Faibussowitsch } 1230e6b6b59SJacob Faibussowitsch PetscFunctionReturn(*this); 1240e6b6b59SJacob Faibussowitsch } 1250e6b6b59SJacob Faibussowitsch 1260e6b6b59SJacob Faibussowitsch template <DeviceType T> 127*d71ae5a4SJacob Faibussowitsch inline typename CUPMEvent<T>::cupmEvent_t CUPMEvent<T>::get() noexcept 128*d71ae5a4SJacob Faibussowitsch { 1290e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 1300e6b6b59SJacob Faibussowitsch if (PetscUnlikely(!event_)) PetscCallAbort(PETSC_COMM_SELF, cupm_fast_event_pool<T>().allocate(&event_)); 1310e6b6b59SJacob Faibussowitsch PetscFunctionReturn(event_); 1320e6b6b59SJacob Faibussowitsch } 1330e6b6b59SJacob Faibussowitsch 1340e6b6b59SJacob Faibussowitsch template <DeviceType T> 135*d71ae5a4SJacob Faibussowitsch inline PetscErrorCode CUPMEvent<T>::record(cupmStream_t stream) noexcept 136*d71ae5a4SJacob Faibussowitsch { 1370e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 1380e6b6b59SJacob Faibussowitsch PetscCallCUPM(cupmEventRecord(get(), stream)); 1390e6b6b59SJacob Faibussowitsch PetscFunctionReturn(0); 1400e6b6b59SJacob Faibussowitsch } 1410e6b6b59SJacob Faibussowitsch 1420e6b6b59SJacob Faibussowitsch template <DeviceType T> 143*d71ae5a4SJacob Faibussowitsch inline CUPMEvent<T>::operator bool() const noexcept 144*d71ae5a4SJacob Faibussowitsch { 1450e6b6b59SJacob Faibussowitsch return event_ != cupmEvent_t{}; 1460e6b6b59SJacob Faibussowitsch } 1470e6b6b59SJacob Faibussowitsch 1480e6b6b59SJacob Faibussowitsch } // namespace cupm 1490e6b6b59SJacob Faibussowitsch 1500e6b6b59SJacob Faibussowitsch } // namespace device 1510e6b6b59SJacob Faibussowitsch 1520e6b6b59SJacob Faibussowitsch } // namespace Petsc 1530e6b6b59SJacob Faibussowitsch #endif // __cplusplus 1540e6b6b59SJacob Faibussowitsch 1550e6b6b59SJacob Faibussowitsch #endif // PETSC_CUPMEVENT_HPP 156