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 */
56namespace Kokkos {
57
58template <class Scalar, class Arg1Type = void>
59class 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.