xref: /petsc/src/sys/objects/device/impls/cupm/cupmevent.hpp (revision d71ae5a4db6382e7f06317b8d368875286fe9008)
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