xref: /petsc/src/sys/objects/device/impls/cupm/cupmevent.hpp (revision d8e47b638cf8f604a99e9678e1df24f82d959cd7)
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>
finalize_()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>
allocate(cupmEvent_t * event)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>
deallocate(cupmEvent_t * in_event)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>
cupm_event_pool()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>
cupm_fast_event_pool()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>
cupm_timer_event_pool()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>
~CUPMEvent()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>
CUPMEvent(CUPMEvent && other)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>
operator =(CUPMEvent && other)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>
get()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>
record(cupmStream_t stream)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>
operator bool() const169d71ae5a4SJacob 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