#ifndef PETSC_CUPMEVENT_HPP #define PETSC_CUPMEVENT_HPP #include #include #include #if defined(__cplusplus) namespace Petsc { namespace device { namespace cupm { namespace { // A pool for allocating cupmEvent_t's. While events are generally very cheap to create and // destroy, they are not free. Using the pool vs on-demand creation and destruction yields a ~20% // speedup. template struct CUPMEventPoolAllocator : impl::Interface, AllocatorBase::cupmEvent_t> { PETSC_CUPM_INHERIT_INTERFACE_TYPEDEFS_USING(interface_type, T); PETSC_NODISCARD static PetscErrorCode create(cupmEvent_t *) noexcept; PETSC_NODISCARD static PetscErrorCode destroy(cupmEvent_t) noexcept; }; template inline PetscErrorCode CUPMEventPoolAllocator::create(cupmEvent_t *event) noexcept { PetscFunctionBegin; PetscCallCUPM(cupmEventCreateWithFlags(event, flags)); PetscFunctionReturn(0); } template inline PetscErrorCode CUPMEventPoolAllocator::destroy(cupmEvent_t event) noexcept { PetscFunctionBegin; PetscCallCUPM(cupmEventDestroy(event)); PetscFunctionReturn(0); } } // anonymous namespace template , typename pool_type = ObjectPool> pool_type &cupm_event_pool() noexcept { static pool_type pool; return pool; } // pool of events with timing disabled template inline auto cupm_fast_event_pool() noexcept -> decltype(cupm_event_pool::cupmEventDisableTiming>()) & { return cupm_event_pool::cupmEventDisableTiming>(); } // pool of events with timing enabled template inline auto cupm_timer_event_pool() noexcept -> decltype(cupm_event_pool::cupmEventDefault>()) & { return cupm_event_pool::cupmEventDefault>(); } // A simple wrapper of cupmEvent_t. This is used in conjunction with CUPMStream to build the // event-stream pairing for the async allocator. It is also used as the data member of // PetscEvent. template class CUPMEvent : impl::Interface, public memory::PoolAllocated> { using pool_type = memory::PoolAllocated>; public: PETSC_CUPM_INHERIT_INTERFACE_TYPEDEFS_USING(interface_type, T); constexpr CUPMEvent() noexcept = default; ~CUPMEvent() noexcept; CUPMEvent(CUPMEvent &&) noexcept; CUPMEvent &operator=(CUPMEvent &&) noexcept; // event is not copyable CUPMEvent(const CUPMEvent &) = delete; CUPMEvent &operator=(const CUPMEvent &) = delete; PETSC_NODISCARD cupmEvent_t get() noexcept; PETSC_NODISCARD PetscErrorCode record(cupmStream_t) noexcept; explicit operator bool() const noexcept; private: cupmEvent_t event_{}; }; template inline CUPMEvent::~CUPMEvent() noexcept { PetscFunctionBegin; if (event_) PetscCallAbort(PETSC_COMM_SELF, cupm_fast_event_pool().deallocate(std::move(event_))); PetscFunctionReturnVoid(); } template inline CUPMEvent::CUPMEvent(CUPMEvent &&other) noexcept : interface_type(std::move(other)), pool_type(std::move(other)), event_(util::exchange(other.event_, cupmEvent_t{})) { } template inline CUPMEvent &CUPMEvent::operator=(CUPMEvent &&other) noexcept { PetscFunctionBegin; if (this != &other) { interface_type::operator=(std::move(other)); pool_type:: operator=(std::move(other)); if (event_) PetscCall(cupm_fast_event_pool().deallocate(std::move(event_))); event_ = util::exchange(other.event_, cupmEvent_t{}); } PetscFunctionReturn(*this); } template inline typename CUPMEvent::cupmEvent_t CUPMEvent::get() noexcept { PetscFunctionBegin; if (PetscUnlikely(!event_)) PetscCallAbort(PETSC_COMM_SELF, cupm_fast_event_pool().allocate(&event_)); PetscFunctionReturn(event_); } template inline PetscErrorCode CUPMEvent::record(cupmStream_t stream) noexcept { PetscFunctionBegin; PetscCallCUPM(cupmEventRecord(get(), stream)); PetscFunctionReturn(0); } template inline CUPMEvent::operator bool() const noexcept { return event_ != cupmEvent_t{}; } } // namespace cupm } // namespace device } // namespace Petsc #endif // __cplusplus #endif // PETSC_CUPMEVENT_HPP