Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:05:00

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