File indexing completed on 2025-06-26 23:26:38
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
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 Descriptor = typename Layout::Descriptor;
0026 using ConstDescriptor = typename Layout::ConstDescriptor;
0027 using Buffer = cms::alpakatools::device_buffer<TDev, std::byte[]>;
0028 using ConstBuffer = cms::alpakatools::const_device_buffer<TDev, std::byte[]>;
0029
0030 PortableDeviceCollection() = delete;
0031
0032 explicit PortableDeviceCollection(edm::Uninitialized) noexcept {}
0033
0034 PortableDeviceCollection(int32_t elements, TDev const& device)
0035 : buffer_{cms::alpakatools::make_device_buffer<std::byte[]>(device, Layout::computeDataSize(elements))},
0036 layout_{buffer_->data(), elements},
0037 view_{layout_} {
0038
0039 assert(reinterpret_cast<uintptr_t>(buffer_->data()) % Layout::alignment == 0);
0040 }
0041
0042 template <typename TQueue, typename = std::enable_if_t<alpaka::isQueue<TQueue>>>
0043 PortableDeviceCollection(int32_t elements, TQueue const& queue)
0044 : buffer_{cms::alpakatools::make_device_buffer<std::byte[]>(queue, Layout::computeDataSize(elements))},
0045 layout_{buffer_->data(), elements},
0046 view_{layout_} {
0047
0048 assert(reinterpret_cast<uintptr_t>(buffer_->data()) % Layout::alignment == 0);
0049 }
0050
0051
0052 PortableDeviceCollection(PortableDeviceCollection const&) = delete;
0053 PortableDeviceCollection& operator=(PortableDeviceCollection const&) = delete;
0054
0055
0056 PortableDeviceCollection(PortableDeviceCollection&&) = default;
0057 PortableDeviceCollection& operator=(PortableDeviceCollection&&) = default;
0058
0059
0060 ~PortableDeviceCollection() = default;
0061
0062
0063 View& view() { return view_; }
0064 ConstView const& view() const { return view_; }
0065 ConstView const& const_view() const { return view_; }
0066
0067 View& operator*() { return view_; }
0068 ConstView const& operator*() const { return view_; }
0069
0070 View* operator->() { return &view_; }
0071 ConstView const* operator->() const { return &view_; }
0072
0073
0074 Buffer buffer() { return *buffer_; }
0075 ConstBuffer buffer() const { return *buffer_; }
0076 ConstBuffer const_buffer() const { return *buffer_; }
0077
0078
0079 template <typename TQueue, typename = std::enable_if_t<alpaka::isQueue<TQueue>>>
0080 void zeroInitialise(TQueue&& queue) {
0081 alpaka::memset(std::forward<TQueue>(queue), *buffer_, 0x00);
0082 }
0083
0084
0085 template <typename TQueue>
0086 void deepCopy(ConstView const& view, TQueue& queue) {
0087 ConstDescriptor desc{view};
0088 Descriptor desc_{view_};
0089 _deepCopy<0>(desc_, desc, queue);
0090 }
0091
0092 private:
0093
0094 template <int I, typename TQueue>
0095 void _deepCopy(Descriptor& dest, ConstDescriptor const& src, TQueue& queue) {
0096 if constexpr (I < ConstDescriptor::num_cols) {
0097 assert(std::get<I>(dest.buff).size_bytes() == std::get<I>(src.buff).size_bytes());
0098 alpaka::memcpy(
0099 queue,
0100 alpaka::createView(alpaka::getDev(queue), std::get<I>(dest.buff).data(), std::get<I>(dest.buff).size()),
0101 alpaka::createView(alpaka::getDev(queue), std::get<I>(src.buff).data(), std::get<I>(src.buff).size()));
0102 _deepCopy<I + 1>(dest, src, queue);
0103 }
0104 }
0105
0106
0107 std::optional<Buffer> buffer_;
0108 Layout layout_;
0109 View view_;
0110 };
0111
0112
0113 template <typename TDev, typename T0, typename... Args>
0114 class PortableDeviceMultiCollection {
0115
0116 static_assert(not std::is_same_v<TDev, alpaka_common::DevHost>,
0117 "Use PortableHostCollection<T> instead of PortableDeviceCollection<T, DevHost>");
0118
0119 template <typename T>
0120 static constexpr std::size_t count_t_ = portablecollection::typeCount<T, T0, Args...>;
0121
0122 template <typename T>
0123 static constexpr std::size_t index_t_ = portablecollection::typeIndex<T, T0, Args...>;
0124
0125 static constexpr std::size_t members_ = sizeof...(Args) + 1;
0126
0127 public:
0128 using Buffer = cms::alpakatools::device_buffer<TDev, std::byte[]>;
0129 using ConstBuffer = cms::alpakatools::const_device_buffer<TDev, std::byte[]>;
0130 using Implementation = portablecollection::CollectionImpl<0, T0, Args...>;
0131
0132 using SizesArray = std::array<int32_t, members_>;
0133
0134 template <std::size_t Idx = 0>
0135 using Layout = portablecollection::TypeResolver<Idx, T0, Args...>;
0136
0137
0138
0139
0140 template <std::size_t Idx = 0UL>
0141 using View = typename std::tuple_element<Idx, std::tuple<T0, Args...>>::type::View;
0142
0143
0144
0145
0146 template <std::size_t Idx = 0UL>
0147 using ConstView = typename std::tuple_element<Idx, std::tuple<T0, Args...>>::type::ConstView;
0148
0149 private:
0150 template <std::size_t Idx>
0151 using Leaf = portablecollection::CollectionLeaf<Idx, Layout<Idx>>;
0152
0153 template <std::size_t Idx>
0154 Leaf<Idx>& get() {
0155 return static_cast<Leaf<Idx>&>(impl_);
0156 }
0157
0158 template <std::size_t Idx>
0159 Leaf<Idx> const& get() const {
0160 return static_cast<Leaf<Idx> const&>(impl_);
0161 }
0162
0163 template <typename T>
0164 Leaf<index_t_<T>>& get() {
0165 return static_cast<Leaf<index_t_<T>>&>(impl_);
0166 }
0167
0168 template <typename T>
0169 Leaf<index_t_<T>> const& get() const {
0170 return static_cast<Leaf<index_t_<T>> const&>(impl_);
0171 }
0172
0173 public:
0174 PortableDeviceMultiCollection() = delete;
0175
0176 explicit PortableDeviceMultiCollection(edm::Uninitialized) noexcept {};
0177
0178 PortableDeviceMultiCollection(int32_t elements, TDev const& device)
0179 : buffer_{cms::alpakatools::make_device_buffer<std::byte[]>(device, Layout<>::computeDataSize(elements))},
0180 impl_{buffer_->data(), elements} {
0181
0182 assert(reinterpret_cast<uintptr_t>(buffer_->data()) % Layout<>::alignment == 0);
0183 static_assert(members_ == 1);
0184 }
0185
0186 template <typename TQueue, typename = std::enable_if_t<alpaka::isQueue<TQueue>>>
0187 PortableDeviceMultiCollection(int32_t elements, TQueue const& queue)
0188 : buffer_{cms::alpakatools::make_device_buffer<std::byte[]>(queue, Layout<>::computeDataSize(elements))},
0189 impl_{buffer_->data(), elements} {
0190
0191 assert(reinterpret_cast<uintptr_t>(buffer_->data()) % Layout<>::alignment == 0);
0192 static_assert(members_ == 1);
0193 }
0194
0195 static int32_t computeDataSize(const SizesArray& sizes) {
0196 int32_t ret = 0;
0197 portablecollection::constexpr_for<0, members_>(
0198 [&sizes, &ret](auto i) { ret += Layout<i>::computeDataSize(sizes[i]); });
0199 return ret;
0200 }
0201
0202 PortableDeviceMultiCollection(const SizesArray& sizes, TDev const& device)
0203
0204 : buffer_{cms::alpakatools::make_device_buffer<std::byte[]>(device, computeDataSize(sizes))},
0205 impl_{buffer_->data(), sizes} {
0206 portablecollection::constexpr_for<0, members_>(
0207 [&](auto i) { assert(reinterpret_cast<uintptr_t>(buffer_->data()) % Layout<i>::alignment == 0); });
0208 constexpr auto alignment = Layout<0>::alignment;
0209 portablecollection::constexpr_for<1, members_>(
0210 [&alignment](auto i) { static_assert(alignment == Layout<i>::alignment); });
0211 }
0212
0213 template <typename TQueue, typename = std::enable_if_t<alpaka::isQueue<TQueue>>>
0214 PortableDeviceMultiCollection(const SizesArray& sizes, TQueue const& queue)
0215
0216 : buffer_{cms::alpakatools::make_device_buffer<std::byte[]>(queue, computeDataSize(sizes))},
0217 impl_{buffer_->data(), sizes} {
0218 portablecollection::constexpr_for<0, members_>(
0219 [&](auto i) { assert(reinterpret_cast<uintptr_t>(buffer_->data()) % Layout<i>::alignment == 0); });
0220 constexpr auto alignment = Layout<0>::alignment;
0221 portablecollection::constexpr_for<1, members_>(
0222 [&alignment](auto i) { static_assert(alignment == Layout<i>::alignment); });
0223 }
0224
0225
0226 PortableDeviceMultiCollection(PortableDeviceMultiCollection const&) = delete;
0227 PortableDeviceMultiCollection& operator=(PortableDeviceMultiCollection const&) = delete;
0228
0229
0230 PortableDeviceMultiCollection(PortableDeviceMultiCollection&&) = default;
0231 PortableDeviceMultiCollection& operator=(PortableDeviceMultiCollection&&) = default;
0232
0233
0234 ~PortableDeviceMultiCollection() = default;
0235
0236
0237 template <std::size_t Idx = 0, typename = std::enable_if_t<(members_ > Idx)>>
0238 View<Idx>& view() {
0239 return get<Idx>().view_;
0240 }
0241
0242 template <std::size_t Idx = 0, typename = std::enable_if_t<(members_ > Idx)>>
0243 ConstView<Idx> const& view() const {
0244 return get<Idx>().view_;
0245 }
0246
0247 template <std::size_t Idx = 0, typename = std::enable_if_t<(members_ > Idx)>>
0248 ConstView<Idx> const& const_view() const {
0249 return get<Idx>().view_;
0250 }
0251
0252 template <std::size_t Idx = 0, typename = std::enable_if_t<(members_ > Idx)>>
0253 View<Idx>& operator*() {
0254 return get<Idx>().view_;
0255 }
0256
0257 template <std::size_t Idx = 0, typename = std::enable_if_t<(members_ > Idx)>>
0258 ConstView<Idx> const& operator*() const {
0259 return get<Idx>().view_;
0260 }
0261
0262 template <std::size_t Idx = 0, typename = std::enable_if_t<(members_ > Idx)>>
0263 View<Idx>* operator->() {
0264 return &get<Idx>().view_;
0265 }
0266
0267 template <std::size_t Idx = 0, typename = std::enable_if_t<(members_ > Idx)>>
0268 ConstView<Idx> const* operator->() const {
0269 return &get<Idx>().view_;
0270 }
0271
0272
0273 template <typename T>
0274 typename T::View& view() {
0275 return get<T>().view_;
0276 }
0277
0278 template <typename T>
0279 typename T::ConstView const& view() const {
0280 return get<T>().view_;
0281 }
0282
0283 template <typename T>
0284 typename T::ConstView const& const_view() const {
0285 return get<T>().view_;
0286 }
0287
0288 template <typename T>
0289 typename T::View& operator*() {
0290 return get<T>().view_;
0291 }
0292
0293 template <typename T>
0294 typename T::ConstView const& operator*() const {
0295 return get<T>().view_;
0296 }
0297
0298 template <typename T>
0299 typename T::View* operator->() {
0300 return &get<T>().view_;
0301 }
0302
0303 template <typename T>
0304 typename T::ConstView const* operator->() const {
0305 return &get<T>().view_;
0306 }
0307
0308
0309 Buffer buffer() { return *buffer_; }
0310 ConstBuffer buffer() const { return *buffer_; }
0311 ConstBuffer const_buffer() const { return *buffer_; }
0312
0313
0314 template <typename TQueue, typename = std::enable_if_t<alpaka::isQueue<TQueue>>>
0315 void zeroInitialise(TQueue&& queue) {
0316 alpaka::memset(std::forward<TQueue>(queue), *buffer_, 0x00);
0317 }
0318
0319
0320 SizesArray sizes() const {
0321 SizesArray ret;
0322 portablecollection::constexpr_for<0, members_>([&](auto i) { ret[i] = get<i>().layout_.metadata().size(); });
0323 return ret;
0324 }
0325
0326 private:
0327 std::optional<Buffer> buffer_;
0328 Implementation impl_;
0329 };
0330
0331 #endif