Kokkos Core Kernels Package  Version of the Day
Kokkos_Vector.hpp
1 /*
2 //@HEADER
3 // ************************************************************************
4 //
5 // Kokkos v. 3.0
6 // Copyright (2020) National Technology & Engineering
7 // Solutions of Sandia, LLC (NTESS).
8 //
9 // Under the terms of Contract DE-NA0003525 with NTESS,
10 // the U.S. Government retains certain rights in this software.
11 //
12 // Redistribution and use in source and binary forms, with or without
13 // modification, are permitted provided that the following conditions are
14 // met:
15 //
16 // 1. Redistributions of source code must retain the above copyright
17 // notice, this list of conditions and the following disclaimer.
18 //
19 // 2. Redistributions in binary form must reproduce the above copyright
20 // notice, this list of conditions and the following disclaimer in the
21 // documentation and/or other materials provided with the distribution.
22 //
23 // 3. Neither the name of the Corporation nor the names of the
24 // contributors may be used to endorse or promote products derived from
25 // this software without specific prior written permission.
26 //
27 // THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
28 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
31 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
32 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
33 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
34 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
35 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
36 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
37 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 //
39 // Questions? Contact Christian R. Trott (crtrott@sandia.gov)
40 //
41 // ************************************************************************
42 //@HEADER
43 */
44 
45 #ifndef KOKKOS_VECTOR_HPP
46 #define KOKKOS_VECTOR_HPP
47 
48 #include <Kokkos_Core_fwd.hpp>
49 #include <Kokkos_DualView.hpp>
50 
51 /* Drop in replacement for std::vector based on Kokkos::DualView
52  * Most functions only work on the host (it will not compile if called from
53  * device kernel)
54  *
55  */
56 namespace Kokkos {
57 
58 template <class Scalar, class Arg1Type = void>
59 class vector : public DualView<Scalar*, LayoutLeft, Arg1Type> {
60  public:
61  using value_type = Scalar;
62  using pointer = Scalar*;
63  using const_pointer = const Scalar*;
64  using reference = Scalar&;
65  using const_reference = const Scalar&;
66  using iterator = Scalar*;
67  using const_iterator = const Scalar*;
68  using size_type = size_t;
69 
70  private:
71  size_t _size;
72  float _extra_storage;
73  using DV = DualView<Scalar*, LayoutLeft, Arg1Type>;
74 
75  public:
76 #ifdef KOKKOS_ENABLE_CUDA_UVM
77  KOKKOS_INLINE_FUNCTION reference operator()(int i) const {
78  return DV::h_view(i);
79  };
80  KOKKOS_INLINE_FUNCTION reference operator[](int i) const {
81  return DV::h_view(i);
82  };
83 #else
84  inline reference operator()(int i) const { return DV::h_view(i); };
85  inline reference operator[](int i) const { return DV::h_view(i); };
86 #endif
87 
88  /* Member functions which behave like std::vector functions */
89 
90  vector() : DV() {
91  _size = 0;
92  _extra_storage = 1.1;
93  }
94 
95  vector(int n, Scalar val = Scalar())
96  : DualView<Scalar*, LayoutLeft, Arg1Type>("Vector", size_t(n * (1.1))) {
97  _size = n;
98  _extra_storage = 1.1;
99  DV::modified_flags(0) = 1;
100 
101  assign(n, val);
102  }
103 
104  void resize(size_t n) {
105  if (n >= span()) DV::resize(size_t(n * _extra_storage));
106  _size = n;
107  }
108 
109  void resize(size_t n, const Scalar& val) { assign(n, val); }
110 
111  void assign(size_t n, const Scalar& val) {
112  /* Resize if necessary (behavior of std:vector) */
113 
114  if (n > span()) DV::resize(size_t(n * _extra_storage));
115  _size = n;
116 
117  /* Assign value either on host or on device */
118 
119  if (DV::template need_sync<typename DV::t_dev::device_type>()) {
120  set_functor_host f(DV::h_view, val);
121  parallel_for("Kokkos::vector::assign", n, f);
122  typename DV::t_host::execution_space().fence();
123  DV::template modify<typename DV::t_host::device_type>();
124  } else {
125  set_functor f(DV::d_view, val);
126  parallel_for("Kokkos::vector::assign", n, f);
127  typename DV::t_dev::execution_space().fence();
128  DV::template modify<typename DV::t_dev::device_type>();
129  }
130  }
131 
132  void reserve(size_t n) { DV::resize(size_t(n * _extra_storage)); }
133 
134  void push_back(Scalar val) {
135  DV::template sync<typename DV::t_host::device_type>();
136  DV::template modify<typename DV::t_host::device_type>();
137  if (_size == span()) {
138  size_t new_size = _size * _extra_storage;
139  if (new_size == _size) new_size++;
140  DV::resize(new_size);
141  }
142 
143  DV::h_view(_size) = val;
144  _size++;
145  }
146 
147  void pop_back() { _size--; }
148 
149  void clear() { _size = 0; }
150 
151  iterator insert(iterator it, const value_type& val) {
152  return insert(it, 1, val);
153  }
154 
155  iterator insert(iterator it, size_type count, const value_type& val) {
156  if ((size() == 0) && (it == begin())) {
157  resize(count, val);
158  DV::sync_host();
159  return begin();
160  }
161  DV::sync_host();
162  DV::modify_host();
163  if (it < begin() || it > end())
164  Kokkos::abort("Kokkos::vector::insert : invalid insert iterator");
165  if (count == 0) return it;
166  ptrdiff_t start = std::distance(begin(), it);
167  auto org_size = size();
168  resize(size() + count);
169 
170  std::copy_backward(begin() + start, begin() + org_size,
171  begin() + org_size + count);
172  std::fill_n(begin() + start, count, val);
173 
174  return begin() + start;
175  }
176 
177  private:
178  template <class T>
179  struct impl_is_input_iterator
180  : /* TODO replace this */ std::integral_constant<
181  bool, !std::is_convertible<T, size_type>::value> {};
182 
183  public:
184  // TODO: can use detection idiom to generate better error message here later
185  template <typename InputIterator>
186  typename std::enable_if<impl_is_input_iterator<InputIterator>::value,
187  iterator>::type
188  insert(iterator it, InputIterator b, InputIterator e) {
189  ptrdiff_t count = std::distance(b, e);
190  if (count == 0) return it;
191 
192  DV::sync_host();
193  DV::modify_host();
194  if (it < begin() || it > end())
195  Kokkos::abort("Kokkos::vector::insert : invalid insert iterator");
196 
197  bool resized = false;
198  if ((size() == 0) && (it == begin())) {
199  resize(count);
200  it = begin();
201  resized = true;
202  }
203  ptrdiff_t start = std::distance(begin(), it);
204  auto org_size = size();
205  if (!resized) resize(size() + count);
206  it = begin() + start;
207 
208  std::copy_backward(begin() + start, begin() + org_size,
209  begin() + org_size + count);
210  std::copy(b, e, it);
211 
212  return begin() + start;
213  }
214 
215  KOKKOS_INLINE_FUNCTION constexpr bool is_allocated() const {
216  return DV::is_allocated();
217  }
218 
219  size_type size() const { return _size; }
220  size_type max_size() const { return 2000000000; }
221  size_type span() const { return DV::span(); }
222  bool empty() const { return _size == 0; }
223 
224  pointer data() const { return DV::h_view.data(); }
225 
226  iterator begin() const { return DV::h_view.data(); }
227 
228  iterator end() const {
229  return _size > 0 ? DV::h_view.data() + _size : DV::h_view.data();
230  }
231 
232  reference front() { return DV::h_view(0); }
233 
234  reference back() { return DV::h_view(_size - 1); }
235 
236  const_reference front() const { return DV::h_view(0); }
237 
238  const_reference back() const { return DV::h_view(_size - 1); }
239 
240  /* std::algorithms which work originally with iterators, here they are
241  * implemented as member functions */
242 
243  size_t lower_bound(const size_t& start, const size_t& theEnd,
244  const Scalar& comp_val) const {
245  int lower = start; // FIXME (mfh 24 Apr 2014) narrowing conversion
246  int upper =
247  _size > theEnd
248  ? theEnd
249  : _size - 1; // FIXME (mfh 24 Apr 2014) narrowing conversion
250  if (upper <= lower) {
251  return theEnd;
252  }
253 
254  Scalar lower_val = DV::h_view(lower);
255  Scalar upper_val = DV::h_view(upper);
256  size_t idx = (upper + lower) / 2;
257  Scalar val = DV::h_view(idx);
258  if (val > upper_val) return upper;
259  if (val < lower_val) return start;
260 
261  while (upper > lower) {
262  if (comp_val > val) {
263  lower = ++idx;
264  } else {
265  upper = idx;
266  }
267  idx = (upper + lower) / 2;
268  val = DV::h_view(idx);
269  }
270  return idx;
271  }
272 
273  bool is_sorted() {
274  for (int i = 0; i < _size - 1; i++) {
275  if (DV::h_view(i) > DV::h_view(i + 1)) return false;
276  }
277  return true;
278  }
279 
280  iterator find(Scalar val) const {
281  if (_size == 0) return end();
282 
283  int upper, lower, current;
284  current = _size / 2;
285  upper = _size - 1;
286  lower = 0;
287 
288  if ((val < DV::h_view(0)) || (val > DV::h_view(_size - 1))) return end();
289 
290  while (upper > lower) {
291  if (val > DV::h_view(current))
292  lower = current + 1;
293  else
294  upper = current;
295  current = (upper + lower) / 2;
296  }
297 
298  if (val == DV::h_view(current))
299  return &DV::h_view(current);
300  else
301  return end();
302  }
303 
304  /* Additional functions for data management */
305 
306  void device_to_host() { deep_copy(DV::h_view, DV::d_view); }
307  void host_to_device() const { deep_copy(DV::d_view, DV::h_view); }
308 
309  void on_host() { DV::template modify<typename DV::t_host::device_type>(); }
310  void on_device() { DV::template modify<typename DV::t_dev::device_type>(); }
311 
312  void set_overallocation(float extra) { _extra_storage = 1.0 + extra; }
313 
314  public:
315  struct set_functor {
316  using execution_space = typename DV::t_dev::execution_space;
317  typename DV::t_dev _data;
318  Scalar _val;
319 
320  set_functor(typename DV::t_dev data, Scalar val) : _data(data), _val(val) {}
321 
322  KOKKOS_INLINE_FUNCTION
323  void operator()(const int& i) const { _data(i) = _val; }
324  };
325 
326  struct set_functor_host {
327  using execution_space = typename DV::t_host::execution_space;
328  typename DV::t_host _data;
329  Scalar _val;
330 
331  set_functor_host(typename DV::t_host data, Scalar val)
332  : _data(data), _val(val) {}
333 
334  KOKKOS_INLINE_FUNCTION
335  void operator()(const int& i) const { _data(i) = _val; }
336  };
337 };
338 
339 } // namespace Kokkos
340 #endif
Declaration and definition of Kokkos::DualView.
void parallel_for(const ExecPolicy &policy, const FunctorType &functor, const std::string &str="", typename std::enable_if< Kokkos::Impl::is_execution_policy< ExecPolicy >::value >::type *=nullptr)
Execute functor in parallel according to the execution policy.
Definition: dummy.cpp:3