QMCPACK
VectorSoaContainer.h
Go to the documentation of this file.
1 //////////////////////////////////////////////////////////////////////////////////////
2 // This file is distributed under the University of Illinois/NCSA Open Source License.
3 // See LICENSE file in top directory for details.
4 //
5 // Copyright (c) 2021 QMCPACK developers.
6 //
7 // File developed by: Jeongnim Kim, jeongnim.kim@intel.com, Intel Corp.
8 // Peter Doak, doakpw@ornl.gov, Oak Ridge National Laboratory
9 //
10 // File created by: Jeongnim Kim, jeongnim.kim@intel.com, Intel Corp.
11 //////////////////////////////////////////////////////////////////////////////////////
12 // -*- C++ -*-
13 /** @file VectorSoaContainer.h
14  * Soa Container for D-dim vectors
15  *
16  * Alternative to Container<TinyVector<T,D> > to support SoA algorithms
17  */
18 #ifndef QMCPLUSPLUS_VECTOR_SOA_H
19 #define QMCPLUSPLUS_VECTOR_SOA_H
20 
21 #include <type_traits>
23 #include "OhmmsPETE/TinyVector.h"
24 #include "OhmmsPETE/OhmmsVector.h"
26 
27 namespace qmcplusplus
28 {
29 /** SoA adaptor class for Vector<TinyVector<T,D> >
30  * @tparam T data type, float, double, complex<float>, complex<double>
31  * @tparam Alloc memory allocator
32  */
33 template<typename T, unsigned D, typename Alloc = aligned_allocator<T>>
35 {
37  using size_type = size_t;
38  using value_type = T;
39 
40  ///default constructor
41  VectorSoaContainer() : nLocal(0), nGhosts(0), nAllocated(0), myData(nullptr) {}
42 
43  /** constructor for a view, attach to pre-allocated data
44  * @param ptr new myData
45  * @param n new nLocal
46  * @param n_padded new nGhosts
47  */
48  VectorSoaContainer(T* ptr, size_type n, size_type n_padded) : nLocal(n), nGhosts(n_padded), nAllocated(0), myData(ptr) {}
49 
50  ///destructor
52 
53  ///default copy constructor
55  {
56  resize(in.nLocal);
57  std::copy_n(in.myData, nGhosts * D, myData);
58  }
59 
60  ///default copy operator
62  {
63  if (myData != in.myData)
64  {
65  if (nLocal != in.nLocal)
66  resize(in.nLocal);
67  std::copy_n(in.myData, nGhosts * D, myData);
68  }
69  return *this;
70  }
71 
72  ///move constructor
74  : nLocal(in.nLocal), nGhosts(in.nGhosts), nAllocated(in.nAllocated), myData(std::move(in.myData))
75  {
76  in.myData = nullptr;
77  in.nAllocated = 0;
78  in.nLocal = 0;
79  in.nGhosts = 0;
80  }
81 
82  /// constructor with size n without initialization
83  explicit VectorSoaContainer(size_type n) : nLocal(0), nGhosts(0), nAllocated(0), myData(nullptr) { resize(n); }
84 
85  /** constructor with Vector<T1,D> */
86  template<typename T1>
88  {
89  resize(in.size());
90  copyIn(in);
91  }
92 
93  template<typename T1>
95  {
96  resize(in.size());
97  copyIn(in);
98  return *this;
99  }
100 
101  /** need A=0.0;
102  */
103  template<typename T1>
105  {
106  std::fill(myData, myData + nGhosts * D, static_cast<T>(in));
107  return *this;
108  }
109 
110  /** resize myData
111  * @param n nLocal
112  *
113  * nAllocated is used to ensure no memory leak
114  */
115  inline void resize(size_type n)
116  {
117  static_assert(std::is_same<T, typename Alloc::value_type>::value,
118  "VectorSoaContainer and Alloc data types must agree!");
119  if (isRefAttached())
120  throw std::runtime_error("Resize not allowed on VectorSoaContainer constructed by initialized memory.");
121 
122  size_type n_padded = getAlignedSize<T, Alloc::alignment>(n);
123 
124  if (n_padded * D > nAllocated)
125  {
126  if (nAllocated)
127  mAllocator.deallocate(myData, nAllocated);
128  nLocal = n;
129  nGhosts = n_padded;
130  nAllocated = nGhosts * D;
131  myData = mAllocator.allocate(nAllocated);
132  }
133  else
134  {
135  nLocal = n;
136  nGhosts = n_padded;
137  }
138  }
139 
140  ///clear
141  inline void clear()
142  {
143  nLocal = 0;
144  nGhosts = 0;
145  }
146 
147  /// free allocated memory and clear status variables
148  inline void free()
149  {
150  if (nAllocated)
151  mAllocator.deallocate(myData, nAllocated);
152  nLocal = 0;
153  nGhosts = 0;
154  nAllocated = 0;
155  myData = nullptr;
156  }
157 
158  /** attach to pre-allocated data
159  * @param n new nLocal
160  * @param n_padded new nGhosts
161  * @param ptr new myData
162  *
163  * To attach to existing memory, currently owned memory must be freed before calling attachReference
164  */
165  inline void attachReference(size_type n, size_type n_padded, T* ptr)
166  {
167  if (nAllocated)
168  {
169  free();
170  // This is too noisy right now.
171  // std::cerr << "OhmmsVectorSoa attachReference called on previously allocated vector.\n" << std::endl;
172  /// \todo return this when buffer system is simplified.
173  }
174  nLocal = n;
175  nGhosts = n_padded;
176  myData = ptr;
177  }
178 
179  /** attach to pre-allocated data
180  * @param n new nLocal
181  * @param n_padded new nGhosts
182  * @param other the container that owns the memory that ptr points to
183  * @param ptr new myData
184  *
185  * To attach to existing memory, currently owned memory must be freed before calling attachReference
186  */
187  template<typename CONTAINER>
188  void attachReference(size_type n, size_type n_padded, const CONTAINER& other, T* ptr)
189  {
190  if (nAllocated)
191  {
192  free();
193  // This is too noisy right now.
194  // std::cerr << "OhmmsVectorSoa attachReference called on previously allocated vector.\n" << std::endl;
195  /// \todo return this when buffer system is simplified.
196  }
197  nLocal = n;
198  nGhosts = n_padded;
199  myData = ptr;
200  qmc_allocator_traits<Alloc>::attachReference(other.mAllocator, mAllocator, other.data(), ptr);
201  }
202 
203  ///return the physical size
204  inline size_type size() const { return nLocal; }
205  ///return the physical size
206  inline size_type capacity() const { return nGhosts; }
207 
208  /** AoS to SoA : copy from Vector<TinyVector<>>
209  *
210  * The same sizes are assumed.
211  */
212  void copyIn(const Vector<TinyVector<T, D>>& in)
213  {
214  PosAoS2SoA(nLocal, D, reinterpret_cast<const T*>(in.first_address()), D, myData, nGhosts);
215  }
216 
217  /** SoA to AoS : copy to Vector<TinyVector<>>
218  *
219  * The same sizes are assumed.
220  */
221  void copyOut(Vector<TinyVector<T, D>>& out) const
222  {
223  PosSoA2AoS(nLocal, D, myData, nGhosts, reinterpret_cast<T*>(out.first_address()), D);
224  }
225 
226  /** return TinyVector<T,D>
227  */
228  inline const AoSElement_t operator[](size_type i) const { return AoSElement_t(myData + i, nGhosts); }
229 
230  ///helper class for operator ()(size_type i) to assign a value
231  struct Accessor
232  {
233  T* _base;
235  inline Accessor(T* a, size_type ng) : _base(a), M(ng) {}
236  template<typename T1>
238  {
239 #pragma unroll
240  for (size_type i = 0; i < D; ++i)
241  *(_base + M * i) = rhs[i];
242  return *this;
243  }
244 
245  /** assign value */
246  template<typename T1>
247  inline Accessor& operator=(const T1 rhs)
248  {
249 #pragma unroll
250  for (size_type i = 0; i < D; ++i)
251  *(_base + M * i) = rhs;
252  return *this;
253  }
254  };
255 
256  /** access operator for assignment of the i-th value
257  *
258  * Use for (*this)[i]=TinyVector<T,D>;
259  */
260  inline Accessor operator()(size_type i) { return Accessor(myData + i, nGhosts); }
261  ///return the base
262  inline T* data() { return myData; }
263  ///return the base
264  inline const T* data() const { return myData; }
265  /// return non_const data
266  T* getNonConstData() const { return myData; }
267  ///return the pointer of the i-th components
268  inline T* restrict data(size_type i) { return myData + i * nGhosts; }
269  ///return the const pointer of the i-th components
270  inline const T* restrict data(size_type i) const { return myData + i * nGhosts; }
271  ///return the end
272  inline T* end() { return myData + D * nGhosts; }
273  ///return the end
274  inline const T* end() const { return myData + D * nGhosts; }
275 
276 
277  ///return the base, device
278  template<typename Allocator = Alloc, typename = IsDualSpace<Allocator>>
279  inline T* device_data()
280  {
281  return mAllocator.get_device_ptr();
282  }
283  ///return the base, device
284  template<typename Allocator = Alloc, typename = IsDualSpace<Allocator>>
285  inline const T* device_data() const
286  {
287  return mAllocator.get_device_ptr();
288  }
289  ///return the pointer of the i-th components, device
290  template<typename Allocator = Alloc, typename = IsDualSpace<Allocator>>
291  inline T* restrict device_data(size_type i)
292  {
293  return mAllocator.get_device_ptr() + i * nGhosts;
294  }
295  ///return the const pointer of the i-th components, device
296  template<typename Allocator = Alloc, typename = IsDualSpace<Allocator>>
297  inline const T* restrict device_data(size_type i) const
298  {
299  return mAllocator.get_device_ptr() + i * nGhosts;
300  }
301 
302  // Abstract Dual Space Transfers
303  template<typename Allocator = Alloc, typename = IsDualSpace<Allocator>>
304  void updateTo()
305  {
307  }
308  template<typename Allocator = Alloc, typename = IsDualSpace<Allocator>>
309  void updateFrom()
310  {
312  }
313 
314  // For tesing copy on device side from one data index to another
315  template<typename Allocator = Alloc, typename = IsDualSpace<Allocator>>
316  void copyDeviceDataByIndex(unsigned to, unsigned from)
317  {
318  auto* host_ptr = this->data();
319  auto offset_from = this->data(from) - host_ptr;
320  auto offset_to = this->data(to) - host_ptr;
321  auto nsize = this->size();
322  qmc_allocator_traits<Alloc>::deviceSideCopyN(mAllocator, offset_to, nsize, offset_from);
323  }
324 
325 private:
326  /// number of elements
328  /// number of elements + padded
330  /// number of elements allocated by myAlloc
332  /// pointer: what type????
333  T* myData;
334  /// allocator
335  Alloc mAllocator;
336 
337  /// return true if memory is not owned by the container but from outside.
338  inline bool isRefAttached() const { return nGhosts * D > nAllocated; }
339 
340  // We need this because of the hack propagation of the VectorSoaContainer allocator
341  // to allow proper OhmmsVector based views of VectorSoAContainer elements with OMPallocator
342  friend class qmcplusplus::Vector<T, Alloc>;
343 
344  template<typename OtherT, unsigned OtherD, typename OtherAlloc>
345  friend struct VectorSoaContainer;
346 };
347 
348 } // namespace qmcplusplus
349 
350 #endif
VectorSoaContainer & operator=(const Vector< TinyVector< T1, D >> &in)
Accessor & operator=(const TinyVector< T1, D > &rhs)
T * getNonConstData() const
return non_const data
void copyOut(Vector< TinyVector< T, D >> &out) const
SoA to AoS : copy to Vector<TinyVector<>>
size_type capacity() const
return the physical size
helper functions for EinsplineSetBuilder
Definition: Configuration.h:43
static void updateTo(Allocator &a, value_type *host_ptr, size_t n, size_t offset=0)
const T * end() const
return the end
const T *restrict device_data(size_type i) const
return the const pointer of the i-th components, device
T * myData
pointer: what type????
T * device_data()
return the base, device
void copyDeviceDataByIndex(unsigned to, unsigned from)
VectorSoaContainer(size_type n)
constructor with size n without initialization
Accessor & operator=(const T1 rhs)
assign value
SoA adaptor class for Vector<TinyVector<T,D> >
static void deviceSideCopyN(Allocator &a, size_t to, size_t n, size_t from)
static void attachReference(Allocator &from, Allocator &to, std::ptrdiff_t ptr_offset)
So we can write generic tests that work with all QMCPACK allocators.
VectorSoaContainer(const Vector< TinyVector< T1, D >> &in)
constructor with Vector<T1,D>
Accessor operator()(size_type i)
access operator for assignment of the i-th value
T *restrict data(size_type i)
return the pointer of the i-th components
const T * device_data() const
return the base, device
void attachReference(size_type n, size_type n_padded, const CONTAINER &other, T *ptr)
attach to pre-allocated data
VectorSoaContainer(VectorSoaContainer &&in) noexcept
move constructor
VectorSoaContainer & operator=(const VectorSoaContainer &in)
default copy operator
const T * data() const
return the base
void PosSoA2AoS(int nrows, int ncols, const T *restrict iptr, int lda, T *restrict out, int ldb)
General conversion function from SoA[ncols][ldb] to AoS[nrows][ncols].
size_type nGhosts
number of elements + padded
void copyIn(const Vector< TinyVector< T, D >> &in)
AoS to SoA : copy from Vector<TinyVector<>>
VectorSoaContainer & operator=(const T1 in)
need A=0.0;
static void updateFrom(Allocator &a, value_type *host_ptr, size_t n, size_t offset=0)
VectorSoaContainer(T *ptr, size_type n, size_type n_padded)
constructor for a view, attach to pre-allocated data
helper class for operator ()(size_type i) to assign a value
Declaraton of Vector<T,Alloc> Manage memory through Alloc directly and allow referencing an existing ...
const T *restrict data(size_type i) const
return the const pointer of the i-th components
sycl::event copy_n(sycl::queue &aq, const T1 *restrict VA, size_t array_size, T2 *restrict VC, const std::vector< sycl::event > &events)
Definition: syclBLAS.cpp:548
void PosAoS2SoA(int nrows, int ncols, const T *restrict iptr, int lda, T *restrict out, int ldb)
General conversion function from AoS[nrows][ncols] to SoA[ncols][ldb].
void free()
free allocated memory and clear status variables
VectorSoaContainer(const VectorSoaContainer &in)
default copy constructor
T *restrict device_data(size_type i)
return the pointer of the i-th components, device
bool isRefAttached() const
return true if memory is not owned by the container but from outside.
VectorSoaContainer()
default constructor
void resize(size_type n)
resize myData
size_type size() const
return the physical size
void attachReference(size_type n, size_type n_padded, T *ptr)
attach to pre-allocated data
size_type nAllocated
number of elements allocated by myAlloc
const AoSElement_t operator[](size_type i) const
return TinyVector<T,D>
size_type nLocal
number of elements