File indexing completed on 2025-01-18 09:54:47
0001
0002
0003
0004
0005
0006
0007
0008 #pragma once
0009
0010 #include <type_traits>
0011
0012 #include "corecel/cont/InitializedValue.hh"
0013 #include "corecel/cont/Span.hh"
0014 #include "corecel/sys/ThreadId.hh"
0015
0016 #include "DeviceAllocation.hh"
0017 #include "ObserverPtr.hh"
0018
0019 namespace celeritas
0020 {
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045 template<class T>
0046 class DeviceVector
0047 {
0048 #if !CELERITAS_USE_HIP
0049
0050
0051 static_assert(std::is_trivially_copyable<T>::value,
0052 "DeviceVector element is not trivially copyable");
0053
0054 static_assert(std::is_trivially_destructible<T>::value,
0055 "DeviceVector element is not trivially destructible");
0056 #endif
0057
0058 public:
0059
0060
0061 using value_type = T;
0062 using SpanT = Span<T>;
0063 using SpanConstT = Span<T const>;
0064
0065
0066 public:
0067
0068 DeviceVector() = default;
0069
0070
0071 explicit DeviceVector(StreamId stream);
0072
0073
0074 explicit DeviceVector(size_type count);
0075
0076
0077 DeviceVector(size_type count, StreamId stream);
0078
0079
0080 inline void swap(DeviceVector& other) noexcept;
0081
0082
0083 void assign(T const* first, T const* last);
0084
0085
0086
0087
0088 size_type size() const { return size_; }
0089
0090
0091 bool empty() const { return size_ == 0; }
0092
0093
0094
0095
0096 inline void copy_to_device(SpanConstT host_data);
0097
0098
0099 inline void copy_to_host(SpanT host_data) const;
0100
0101
0102 SpanT device_ref() { return {this->data(), this->size()}; }
0103
0104
0105 SpanConstT device_ref() const { return {this->data(), this->size()}; }
0106
0107
0108 inline T* data();
0109
0110
0111 inline T const* data() const;
0112
0113 private:
0114 DeviceAllocation allocation_;
0115 InitializedValue<size_type> size_;
0116 };
0117
0118
0119 template<class T>
0120 inline void swap(DeviceVector<T>& a, DeviceVector<T>& b) noexcept;
0121
0122
0123
0124
0125
0126
0127
0128 template<class T>
0129 DeviceVector<T>::DeviceVector(StreamId stream) : allocation_{stream}, size_{0}
0130 {
0131 }
0132
0133
0134
0135
0136
0137 template<class T>
0138 DeviceVector<T>::DeviceVector(size_type count)
0139 : allocation_{count * sizeof(T)}, size_{count}
0140 {
0141 }
0142
0143
0144
0145
0146
0147 template<class T>
0148 DeviceVector<T>::DeviceVector(size_type count, StreamId stream)
0149 : allocation_{count * sizeof(T), stream}, size_{count}
0150 {
0151 }
0152
0153
0154
0155
0156
0157 template<class T>
0158 void DeviceVector<T>::swap(DeviceVector& other) noexcept
0159 {
0160 using std::swap;
0161 swap(size_, other.size_);
0162 swap(allocation_, other.allocation_);
0163 }
0164
0165
0166
0167
0168
0169
0170
0171 template<class T>
0172 void DeviceVector<T>::assign(T const* first, T const* last)
0173 {
0174 auto const new_size = static_cast<size_type>(last - first);
0175 if (new_size > size_ && new_size * sizeof(T) > allocation_.size())
0176 {
0177
0178 *this = DeviceVector<T>(new_size, allocation_.stream_id());
0179 }
0180 else
0181 {
0182
0183 size_ = new_size;
0184 }
0185
0186 this->copy_to_device({first, new_size});
0187 }
0188
0189
0190
0191
0192
0193 template<class T>
0194 void DeviceVector<T>::copy_to_device(SpanConstT data)
0195 {
0196 CELER_EXPECT(data.size() == this->size());
0197 allocation_.copy_to_device({reinterpret_cast<std::byte const*>(data.data()),
0198 data.size() * sizeof(T)});
0199 }
0200
0201
0202
0203
0204
0205 template<class T>
0206 void DeviceVector<T>::copy_to_host(SpanT data) const
0207 {
0208 CELER_EXPECT(data.size() == this->size());
0209 allocation_.copy_to_host(
0210 {reinterpret_cast<std::byte*>(data.data()), data.size() * sizeof(T)});
0211 }
0212
0213
0214
0215
0216
0217 template<class T>
0218 T* DeviceVector<T>::data()
0219 {
0220 return reinterpret_cast<T*>(allocation_.device_ref().data());
0221 }
0222
0223
0224
0225
0226
0227 template<class T>
0228 T const* DeviceVector<T>::data() const
0229 {
0230 return reinterpret_cast<T const*>(allocation_.device_ref().data());
0231 }
0232
0233
0234
0235
0236
0237 template<class T>
0238 void swap(DeviceVector<T>& a, DeviceVector<T>& b) noexcept
0239 {
0240 return a.swap(b);
0241 }
0242
0243
0244
0245
0246
0247
0248
0249 template<class T>
0250 CELER_FUNCTION Span<T const> make_span(DeviceVector<T> const& dv)
0251 {
0252 static_assert(sizeof(T) == 0, "Cannot 'make_span' from a device vector");
0253 return {dv.data(), dv.size()};
0254 }
0255
0256
0257
0258 template<class T>
0259 CELER_FUNCTION Span<T> make_span(DeviceVector<T>& dv)
0260 {
0261 static_assert(sizeof(T) == 0, "Cannot 'make_span' from a device vector");
0262 return {dv.data(), dv.size()};
0263 }
0264
0265
0266
0267 template<class T>
0268 ObserverPtr<T, MemSpace::device> make_observer(DeviceVector<T>& vec) noexcept
0269 {
0270 return ObserverPtr<T, MemSpace::device>{vec.data()};
0271 }
0272
0273
0274
0275 template<class T>
0276 ObserverPtr<T const, MemSpace::device>
0277 make_observer(DeviceVector<T> const& vec) noexcept
0278 {
0279 return ObserverPtr<T const, MemSpace::device>{vec.data()};
0280 }
0281
0282
0283 }