Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-12-12 03:12:12

0001 #ifndef DataFormats_Portable_interface_PortableDeviceCollection_h
0002 #define DataFormats_Portable_interface_PortableDeviceCollection_h
0003 
0004 #include <cassert>
0005 #include <optional>
0006 #include <type_traits>
0007 
0008 #include <alpaka/alpaka.hpp>
0009 
0010 #include "DataFormats/Common/interface/Uninitialized.h"
0011 #include "DataFormats/Portable/interface/PortableCollectionCommon.h"
0012 #include "HeterogeneousCore/AlpakaInterface/interface/config.h"
0013 #include "HeterogeneousCore/AlpakaInterface/interface/memory.h"
0014 
0015 // generic SoA-based product in device memory
0016 template <typename T, typename TDev, typename = std::enable_if_t<alpaka::isDevice<TDev>>>
0017 class PortableDeviceCollection {
0018   static_assert(not std::is_same_v<TDev, alpaka_common::DevHost>,
0019                 "Use PortableHostCollection<T> instead of PortableDeviceCollection<T, DevHost>");
0020 
0021 public:
0022   using Layout = T;
0023   using View = typename Layout::View;
0024   using ConstView = typename Layout::ConstView;
0025   using Buffer = cms::alpakatools::device_buffer<TDev, std::byte[]>;
0026   using ConstBuffer = cms::alpakatools::const_device_buffer<TDev, std::byte[]>;
0027 
0028   PortableDeviceCollection() = delete;
0029 
0030   explicit PortableDeviceCollection(edm::Uninitialized) noexcept {}
0031 
0032   PortableDeviceCollection(int32_t elements, TDev const& device)
0033       : buffer_{cms::alpakatools::make_device_buffer<std::byte[]>(device, Layout::computeDataSize(elements))},
0034         layout_{buffer_->data(), elements},
0035         view_{layout_} {
0036     // Alpaka set to a default alignment of 128 bytes defining ALPAKA_DEFAULT_HOST_MEMORY_ALIGNMENT=128
0037     assert(reinterpret_cast<uintptr_t>(buffer_->data()) % Layout::alignment == 0);
0038   }
0039 
0040   template <typename TQueue, typename = std::enable_if_t<alpaka::isQueue<TQueue>>>
0041   PortableDeviceCollection(int32_t elements, TQueue const& queue)
0042       : buffer_{cms::alpakatools::make_device_buffer<std::byte[]>(queue, Layout::computeDataSize(elements))},
0043         layout_{buffer_->data(), elements},
0044         view_{layout_} {
0045     // Alpaka set to a default alignment of 128 bytes defining ALPAKA_DEFAULT_HOST_MEMORY_ALIGNMENT=128
0046     assert(reinterpret_cast<uintptr_t>(buffer_->data()) % Layout::alignment == 0);
0047   }
0048 
0049   // non-copyable
0050   PortableDeviceCollection(PortableDeviceCollection const&) = delete;
0051   PortableDeviceCollection& operator=(PortableDeviceCollection const&) = delete;
0052 
0053   // movable
0054   PortableDeviceCollection(PortableDeviceCollection&&) = default;
0055   PortableDeviceCollection& operator=(PortableDeviceCollection&&) = default;
0056 
0057   // default destructor
0058   ~PortableDeviceCollection() = default;
0059 
0060   // access the View
0061   View& view() { return view_; }
0062   ConstView const& view() const { return view_; }
0063   ConstView const& const_view() const { return view_; }
0064 
0065   View& operator*() { return view_; }
0066   ConstView const& operator*() const { return view_; }
0067 
0068   View* operator->() { return &view_; }
0069   ConstView const* operator->() const { return &view_; }
0070 
0071   // access the Buffer
0072   Buffer buffer() { return *buffer_; }
0073   ConstBuffer buffer() const { return *buffer_; }
0074   ConstBuffer const_buffer() const { return *buffer_; }
0075 
0076   // erases the data in the Buffer by writing zeros (bytes containing '\0') to it
0077   template <typename TQueue, typename = std::enable_if_t<alpaka::isQueue<TQueue>>>
0078   void zeroInitialise(TQueue&& queue) {
0079     alpaka::memset(std::forward<TQueue>(queue), *buffer_, 0x00);
0080   }
0081 
0082 private:
0083   std::optional<Buffer> buffer_;  //!
0084   Layout layout_;                 //
0085   View view_;                     //!
0086 };
0087 
0088 // generic SoA-based product in device memory
0089 template <typename TDev, typename T0, typename... Args>
0090 class PortableDeviceMultiCollection {
0091   //static_assert(alpaka::isDevice<TDev>);
0092   static_assert(not std::is_same_v<TDev, alpaka_common::DevHost>,
0093                 "Use PortableHostCollection<T> instead of PortableDeviceCollection<T, DevHost>");
0094 
0095   template <typename T>
0096   static constexpr std::size_t count_t_ = portablecollection::typeCount<T, T0, Args...>;
0097 
0098   template <typename T>
0099   static constexpr std::size_t index_t_ = portablecollection::typeIndex<T, T0, Args...>;
0100 
0101   static constexpr std::size_t members_ = sizeof...(Args) + 1;
0102 
0103 public:
0104   using Buffer = cms::alpakatools::device_buffer<TDev, std::byte[]>;
0105   using ConstBuffer = cms::alpakatools::const_device_buffer<TDev, std::byte[]>;
0106   using Implementation = portablecollection::CollectionImpl<0, T0, Args...>;
0107 
0108   using SizesArray = std::array<int32_t, members_>;
0109 
0110   template <std::size_t Idx = 0>
0111   using Layout = portablecollection::TypeResolver<Idx, T0, Args...>;
0112 
0113   //template <std::size_t Idx = 0>
0114   //using View = typename Layout<Idx>::View;
0115   // Workaround for flaky expansion of tempaltes by nvcc (expanding with "Args" instead of "Args...
0116   template <std::size_t Idx = 0UL>
0117   using View = typename std::tuple_element<Idx, std::tuple<T0, Args...>>::type::View;
0118 
0119   //template <std::size_t Idx = 0>
0120   //using ConstView = typename Layout<Idx>::ConstView;
0121   // Workaround for flaky expansion of tempaltes by nvcc (expanding with "Args" instead of "Args..."
0122   template <std::size_t Idx = 0UL>
0123   using ConstView = typename std::tuple_element<Idx, std::tuple<T0, Args...>>::type::ConstView;
0124 
0125 private:
0126   template <std::size_t Idx>
0127   using Leaf = portablecollection::CollectionLeaf<Idx, Layout<Idx>>;
0128 
0129   template <std::size_t Idx>
0130   Leaf<Idx>& get() {
0131     return static_cast<Leaf<Idx>&>(impl_);
0132   }
0133 
0134   template <std::size_t Idx>
0135   Leaf<Idx> const& get() const {
0136     return static_cast<Leaf<Idx> const&>(impl_);
0137   }
0138 
0139   template <typename T>
0140   Leaf<index_t_<T>>& get() {
0141     return static_cast<Leaf<index_t_<T>>&>(impl_);
0142   }
0143 
0144   template <typename T>
0145   Leaf<index_t_<T>> const& get() const {
0146     return static_cast<Leaf<index_t_<T>> const&>(impl_);
0147   }
0148 
0149 public:
0150   PortableDeviceMultiCollection() = delete;
0151 
0152   explicit PortableDeviceMultiCollection(edm::Uninitialized) noexcept {};
0153 
0154   PortableDeviceMultiCollection(int32_t elements, TDev const& device)
0155       : buffer_{cms::alpakatools::make_device_buffer<std::byte[]>(device, Layout<>::computeDataSize(elements))},
0156         impl_{buffer_->data(), elements} {
0157     // Alpaka set to a default alignment of 128 bytes defining ALPAKA_DEFAULT_HOST_MEMORY_ALIGNMENT=128
0158     assert(reinterpret_cast<uintptr_t>(buffer_->data()) % Layout<>::alignment == 0);
0159     static_assert(members_ == 1);
0160   }
0161 
0162   template <typename TQueue, typename = std::enable_if_t<alpaka::isQueue<TQueue>>>
0163   PortableDeviceMultiCollection(int32_t elements, TQueue const& queue)
0164       : buffer_{cms::alpakatools::make_device_buffer<std::byte[]>(queue, Layout<>::computeDataSize(elements))},
0165         impl_{buffer_->data(), elements} {
0166     // Alpaka set to a default alignment of 128 bytes defining ALPAKA_DEFAULT_HOST_MEMORY_ALIGNMENT=128
0167     assert(reinterpret_cast<uintptr_t>(buffer_->data()) % Layout<>::alignment == 0);
0168     static_assert(members_ == 1);
0169   }
0170 
0171   static int32_t computeDataSize(const SizesArray& sizes) {
0172     int32_t ret = 0;
0173     portablecollection::constexpr_for<0, members_>(
0174         [&sizes, &ret](auto i) { ret += Layout<i>::computeDataSize(sizes[i]); });
0175     return ret;
0176   }
0177 
0178   PortableDeviceMultiCollection(const SizesArray& sizes, TDev const& device)
0179       // allocate device memory
0180       : buffer_{cms::alpakatools::make_device_buffer<std::byte[]>(device, computeDataSize(sizes))},
0181         impl_{buffer_->data(), sizes} {
0182     portablecollection::constexpr_for<0, members_>(
0183         [&](auto i) { assert(reinterpret_cast<uintptr_t>(buffer_->data()) % Layout<i>::alignment == 0); });
0184     constexpr auto alignment = Layout<0>::alignment;
0185     portablecollection::constexpr_for<1, members_>(
0186         [&alignment](auto i) { static_assert(alignment == Layout<i>::alignment); });
0187   }
0188 
0189   template <typename TQueue, typename = std::enable_if_t<alpaka::isQueue<TQueue>>>
0190   PortableDeviceMultiCollection(const SizesArray& sizes, TQueue const& queue)
0191       // allocate device memory asynchronously on the given work queue
0192       : buffer_{cms::alpakatools::make_device_buffer<std::byte[]>(queue, computeDataSize(sizes))},
0193         impl_{buffer_->data(), sizes} {
0194     portablecollection::constexpr_for<0, members_>(
0195         [&](auto i) { assert(reinterpret_cast<uintptr_t>(buffer_->data()) % Layout<i>::alignment == 0); });
0196     constexpr auto alignment = Layout<0>::alignment;
0197     portablecollection::constexpr_for<1, members_>(
0198         [&alignment](auto i) { static_assert(alignment == Layout<i>::alignment); });
0199   }
0200 
0201   // non-copyable
0202   PortableDeviceMultiCollection(PortableDeviceMultiCollection const&) = delete;
0203   PortableDeviceMultiCollection& operator=(PortableDeviceMultiCollection const&) = delete;
0204 
0205   // movable
0206   PortableDeviceMultiCollection(PortableDeviceMultiCollection&&) = default;
0207   PortableDeviceMultiCollection& operator=(PortableDeviceMultiCollection&&) = default;
0208 
0209   // default destructor
0210   ~PortableDeviceMultiCollection() = default;
0211 
0212   // access the View by index
0213   template <std::size_t Idx = 0, typename = std::enable_if_t<(members_ > Idx)>>
0214   View<Idx>& view() {
0215     return get<Idx>().view_;
0216   }
0217 
0218   template <std::size_t Idx = 0, typename = std::enable_if_t<(members_ > Idx)>>
0219   ConstView<Idx> const& view() const {
0220     return get<Idx>().view_;
0221   }
0222 
0223   template <std::size_t Idx = 0, typename = std::enable_if_t<(members_ > Idx)>>
0224   ConstView<Idx> const& const_view() const {
0225     return get<Idx>().view_;
0226   }
0227 
0228   template <std::size_t Idx = 0, typename = std::enable_if_t<(members_ > Idx)>>
0229   View<Idx>& operator*() {
0230     return get<Idx>().view_;
0231   }
0232 
0233   template <std::size_t Idx = 0, typename = std::enable_if_t<(members_ > Idx)>>
0234   ConstView<Idx> const& operator*() const {
0235     return get<Idx>().view_;
0236   }
0237 
0238   template <std::size_t Idx = 0, typename = std::enable_if_t<(members_ > Idx)>>
0239   View<Idx>* operator->() {
0240     return &get<Idx>().view_;
0241   }
0242 
0243   template <std::size_t Idx = 0, typename = std::enable_if_t<(members_ > Idx)>>
0244   ConstView<Idx> const* operator->() const {
0245     return &get<Idx>().view_;
0246   }
0247 
0248   // access the View by type
0249   template <typename T>
0250   typename T::View& view() {
0251     return get<T>().view_;
0252   }
0253 
0254   template <typename T>
0255   typename T::ConstView const& view() const {
0256     return get<T>().view_;
0257   }
0258 
0259   template <typename T>
0260   typename T::ConstView const& const_view() const {
0261     return get<T>().view_;
0262   }
0263 
0264   template <typename T>
0265   typename T::View& operator*() {
0266     return get<T>().view_;
0267   }
0268 
0269   template <typename T>
0270   typename T::ConstView const& operator*() const {
0271     return get<T>().view_;
0272   }
0273 
0274   template <typename T>
0275   typename T::View* operator->() {
0276     return &get<T>().view_;
0277   }
0278 
0279   template <typename T>
0280   typename T::ConstView const* operator->() const {
0281     return &get<T>().view_;
0282   }
0283 
0284   // access the Buffer
0285   Buffer buffer() { return *buffer_; }
0286   ConstBuffer buffer() const { return *buffer_; }
0287   ConstBuffer const_buffer() const { return *buffer_; }
0288 
0289   // erases the data in the Buffer by writing zeros (bytes containing '\0') to it
0290   template <typename TQueue, typename = std::enable_if_t<alpaka::isQueue<TQueue>>>
0291   void zeroInitialise(TQueue&& queue) {
0292     alpaka::memset(std::forward<TQueue>(queue), *buffer_, 0x00);
0293   }
0294 
0295   // extract the sizes array
0296   SizesArray sizes() const {
0297     SizesArray ret;
0298     portablecollection::constexpr_for<0, members_>([&](auto i) { ret[i] = get<i>().layout_.metadata().size(); });
0299     return ret;
0300   }
0301 
0302 private:
0303   std::optional<Buffer> buffer_;  //!
0304   Implementation impl_;           // (serialized: this is where the layouts live)
0305 };
0306 
0307 #endif  // DataFormats_Portable_interface_PortableDeviceCollection_h