Kokkos Core Kernels Package  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
Kokkos_ScatterView.hpp
Go to the documentation of this file.
1 /*
2 //@HEADER
3 // ************************************************************************
4 //
5 // Kokkos v. 2.0
6 // Copyright (2014) Sandia Corporation
7 //
8 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
9 // the U.S. Government retains certain rights in this software.
10 //
11 // Redistribution and use in source and binary forms, with or without
12 // modification, are permitted provided that the following conditions are
13 // met:
14 //
15 // 1. Redistributions of source code must retain the above copyright
16 // notice, this list of conditions and the following disclaimer.
17 //
18 // 2. Redistributions in binary form must reproduce the above copyright
19 // notice, this list of conditions and the following disclaimer in the
20 // documentation and/or other materials provided with the distribution.
21 //
22 // 3. Neither the name of the Corporation nor the names of the
23 // contributors may be used to endorse or promote products derived from
24 // this software without specific prior written permission.
25 //
26 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 //
38 // Questions? Contact Christian R. Trott (crtrott@sandia.gov)
39 //
40 // ************************************************************************
41 //@HEADER
42 */
43 
44 
50 
51 #ifndef KOKKOS_SCATTER_VIEW_HPP
52 #define KOKKOS_SCATTER_VIEW_HPP
53 
54 #include <Kokkos_Core.hpp>
55 #include <utility>
56 
57 namespace Kokkos {
58 namespace Experimental {
59 
60 //TODO: replace this enum with the Kokkos::Sum, etc reducers for parallel_reduce
61 enum : int {
62  ScatterSum,
63 };
64 
65 enum : int {
66  ScatterNonDuplicated = 0,
67  ScatterDuplicated = 1
68 };
69 
70 enum : int {
71  ScatterNonAtomic = 0,
72  ScatterAtomic = 1
73 };
74 
75 }} // Kokkos::Experimental
76 
77 namespace Kokkos {
78 namespace Impl {
79 namespace Experimental {
80 
81 template <typename ExecSpace>
82 struct DefaultDuplication;
83 
84 template <typename ExecSpace, int duplication>
85 struct DefaultContribution;
86 
87 #ifdef KOKKOS_ENABLE_SERIAL
88 template <>
89 struct DefaultDuplication<Kokkos::Serial> {
90  enum : int { value = Kokkos::Experimental::ScatterNonDuplicated };
91 };
92 template <>
93 struct DefaultContribution<Kokkos::Serial, Kokkos::Experimental::ScatterNonDuplicated> {
94  enum : int { value = Kokkos::Experimental::ScatterNonAtomic };
95 };
96 template <>
97 struct DefaultContribution<Kokkos::Serial, Kokkos::Experimental::ScatterDuplicated> {
98  enum : int { value = Kokkos::Experimental::ScatterNonAtomic };
99 };
100 #endif
101 
102 #ifdef KOKKOS_ENABLE_OPENMP
103 template <>
104 struct DefaultDuplication<Kokkos::OpenMP> {
105  enum : int { value = Kokkos::Experimental::ScatterDuplicated };
106 };
107 template <>
108 struct DefaultContribution<Kokkos::OpenMP, Kokkos::Experimental::ScatterNonDuplicated> {
109  enum : int { value = Kokkos::Experimental::ScatterAtomic };
110 };
111 template <>
112 struct DefaultContribution<Kokkos::OpenMP, Kokkos::Experimental::ScatterDuplicated> {
113  enum : int { value = Kokkos::Experimental::ScatterNonAtomic };
114 };
115 #endif
116 
117 #ifdef KOKKOS_ENABLE_THREADS
118 template <>
119 struct DefaultDuplication<Kokkos::Threads> {
120  enum : int { value = Kokkos::Experimental::ScatterDuplicated };
121 };
122 template <>
123 struct DefaultContribution<Kokkos::Threads, Kokkos::Experimental::ScatterNonDuplicated> {
124  enum : int { value = Kokkos::Experimental::ScatterAtomic };
125 };
126 template <>
127 struct DefaultContribution<Kokkos::Threads, Kokkos::Experimental::ScatterDuplicated> {
128  enum : int { value = Kokkos::Experimental::ScatterNonAtomic };
129 };
130 #endif
131 
132 #ifdef KOKKOS_ENABLE_CUDA
133 template <>
134 struct DefaultDuplication<Kokkos::Cuda> {
135  enum : int { value = Kokkos::Experimental::ScatterNonDuplicated };
136 };
137 template <>
138 struct DefaultContribution<Kokkos::Cuda, Kokkos::Experimental::ScatterNonDuplicated> {
139  enum : int { value = Kokkos::Experimental::ScatterAtomic };
140 };
141 template <>
142 struct DefaultContribution<Kokkos::Cuda, Kokkos::Experimental::ScatterDuplicated> {
143  enum : int { value = Kokkos::Experimental::ScatterAtomic };
144 };
145 #endif
146 
147 /* ScatterValue is the object returned by the access operator() of ScatterAccess,
148  similar to that returned by an Atomic View, it wraps Kokkos::atomic_add with convenient
149  operator+=, etc. */
150 template <typename ValueType, int Op, int contribution>
151 struct ScatterValue;
152 
153 template <typename ValueType>
154 struct ScatterValue<ValueType, Kokkos::Experimental::ScatterSum, Kokkos::Experimental::ScatterNonAtomic> {
155  public:
156  KOKKOS_FORCEINLINE_FUNCTION ScatterValue(ValueType& value_in) : value( value_in ) {}
157  KOKKOS_FORCEINLINE_FUNCTION ScatterValue(ScatterValue&& other) : value( other.value ) {}
158  KOKKOS_FORCEINLINE_FUNCTION void operator+=(ValueType const& rhs) {
159  value += rhs;
160  }
161  KOKKOS_FORCEINLINE_FUNCTION void operator-=(ValueType const& rhs) {
162  value -= rhs;
163  }
164  private:
165  ValueType& value;
166 };
167 
168 template <typename ValueType>
169 struct ScatterValue<ValueType, Kokkos::Experimental::ScatterSum, Kokkos::Experimental::ScatterAtomic> {
170  public:
171  KOKKOS_FORCEINLINE_FUNCTION ScatterValue(ValueType& value_in) : value( value_in ) {}
172  KOKKOS_FORCEINLINE_FUNCTION void operator+=(ValueType const& rhs) {
173  Kokkos::atomic_add(&value, rhs);
174  }
175  KOKKOS_FORCEINLINE_FUNCTION void operator-=(ValueType const& rhs) {
176  Kokkos::atomic_add(&value, -rhs);
177  }
178  private:
179  ValueType& value;
180 };
181 
182 /* DuplicatedDataType, given a View DataType, will create a new DataType
183  that has a new runtime dimension which becomes the largest-stride dimension.
184  In the case of LayoutLeft, due to the limitation induced by the design of DataType
185  itself, it must convert any existing compile-time dimensions into runtime dimensions. */
186 template <typename T, typename Layout>
187 struct DuplicatedDataType;
188 
189 template <typename T>
190 struct DuplicatedDataType<T, Kokkos::LayoutRight> {
191  typedef T* value_type; // For LayoutRight, add a star all the way on the left
192 };
193 
194 template <typename T, size_t N>
195 struct DuplicatedDataType<T[N], Kokkos::LayoutRight> {
196  typedef typename DuplicatedDataType<T, Kokkos::LayoutRight>::value_type value_type[N];
197 };
198 
199 template <typename T>
200 struct DuplicatedDataType<T[], Kokkos::LayoutRight> {
201  typedef typename DuplicatedDataType<T, Kokkos::LayoutRight>::value_type value_type[];
202 };
203 
204 template <typename T>
205 struct DuplicatedDataType<T*, Kokkos::LayoutRight> {
206  typedef typename DuplicatedDataType<T, Kokkos::LayoutRight>::value_type* value_type;
207 };
208 
209 template <typename T>
210 struct DuplicatedDataType<T, Kokkos::LayoutLeft> {
211  typedef T* value_type;
212 };
213 
214 template <typename T, size_t N>
215 struct DuplicatedDataType<T[N], Kokkos::LayoutLeft> {
216  typedef typename DuplicatedDataType<T, Kokkos::LayoutLeft>::value_type* value_type;
217 };
218 
219 template <typename T>
220 struct DuplicatedDataType<T[], Kokkos::LayoutLeft> {
221  typedef typename DuplicatedDataType<T, Kokkos::LayoutLeft>::value_type* value_type;
222 };
223 
224 template <typename T>
225 struct DuplicatedDataType<T*, Kokkos::LayoutLeft> {
226  typedef typename DuplicatedDataType<T, Kokkos::LayoutLeft>::value_type* value_type;
227 };
228 
229 /* Slice is just responsible for stuffing the correct number of Kokkos::ALL
230  arguments on the correct side of the index in a call to subview() to get a
231  subview where the index specified is the largest-stride one. */
232 template <typename Layout, int rank, typename V, typename ... Args>
233 struct Slice {
234  typedef Slice<Layout, rank - 1, V, Kokkos::Impl::ALL_t, Args...> next;
235  typedef typename next::value_type value_type;
236 
237  static
238  value_type get(V const& src, const size_t i, Args ... args) {
239  return next::get(src, i, Kokkos::ALL, args...);
240  }
241 };
242 
243 template <typename V, typename ... Args>
244 struct Slice<Kokkos::LayoutRight, 1, V, Args...> {
245  typedef typename Kokkos::Impl::ViewMapping
246  < void
247  , V
248  , const size_t
249  , Args ...
250  >::type value_type;
251  static
252  value_type get(V const& src, const size_t i, Args ... args) {
253  return Kokkos::subview(src, i, args...);
254  }
255 };
256 
257 template <typename V, typename ... Args>
258 struct Slice<Kokkos::LayoutLeft, 1, V, Args...> {
259  typedef typename Kokkos::Impl::ViewMapping
260  < void
261  , V
262  , Args ...
263  , const size_t
264  >::type value_type;
265  static
266  value_type get(V const& src, const size_t i, Args ... args) {
267  return Kokkos::subview(src, args..., i);
268  }
269 };
270 
271 template <typename ExecSpace, typename ValueType, int Op>
272 struct ReduceDuplicates;
273 
274 template <typename ExecSpace, typename ValueType, int Op>
275 struct ReduceDuplicatesBase {
276  typedef ReduceDuplicates<ExecSpace, ValueType, Op> Derived;
277  ValueType const* src;
278  ValueType* dst;
279  size_t stride;
280  size_t start;
281  size_t n;
282  ReduceDuplicatesBase(ValueType const* src_in, ValueType* dest_in, size_t stride_in, size_t start_in, size_t n_in, std::string const& name)
283  : src(src_in)
284  , dst(dest_in)
285  , stride(stride_in)
286  , start(start_in)
287  , n(n_in)
288  {
289 #if defined(KOKKOS_ENABLE_PROFILING)
290  uint64_t kpID = 0;
291  if(Kokkos::Profiling::profileLibraryLoaded()) {
292  Kokkos::Profiling::beginParallelFor(std::string("reduce_") + name, 0, &kpID);
293  }
294 #endif
295  typedef RangePolicy<ExecSpace, size_t> policy_type;
297  const closure_type closure(*(static_cast<Derived*>(this)), policy_type(0, stride));
298  closure.execute();
299 #if defined(KOKKOS_ENABLE_PROFILING)
300  if(Kokkos::Profiling::profileLibraryLoaded()) {
301  Kokkos::Profiling::endParallelFor(kpID);
302  }
303 #endif
304  }
305 };
306 
307 template <typename ExecSpace, typename ValueType>
308 struct ReduceDuplicates<ExecSpace, ValueType, Kokkos::Experimental::ScatterSum> :
309  public ReduceDuplicatesBase<ExecSpace, ValueType, Kokkos::Experimental::ScatterSum>
310 {
311  typedef ReduceDuplicatesBase<ExecSpace, ValueType, Kokkos::Experimental::ScatterSum> Base;
312  ReduceDuplicates(ValueType const* src_in, ValueType* dst_in, size_t stride_in, size_t start_in, size_t n_in, std::string const& name):
313  Base(src_in, dst_in, stride_in, start_in, n_in, name)
314  {}
315  KOKKOS_FORCEINLINE_FUNCTION void operator()(size_t i) const {
316  for (size_t j = Base::start; j < Base::n; ++j) {
317  Base::dst[i] += Base::src[i + Base::stride * j];
318  }
319  }
320 };
321 
322 template <typename ExecSpace, typename ValueType, int Op>
323 struct ResetDuplicates;
324 
325 template <typename ExecSpace, typename ValueType, int Op>
326 struct ResetDuplicatesBase {
327  typedef ResetDuplicates<ExecSpace, ValueType, Op> Derived;
328  ValueType* data;
329  ResetDuplicatesBase(ValueType* data_in, size_t size_in, std::string const& name)
330  : data(data_in)
331  {
332 #if defined(KOKKOS_ENABLE_PROFILING)
333  uint64_t kpID = 0;
334  if(Kokkos::Profiling::profileLibraryLoaded()) {
335  Kokkos::Profiling::beginParallelFor(std::string("reduce_") + name, 0, &kpID);
336  }
337 #endif
338  typedef RangePolicy<ExecSpace, size_t> policy_type;
340  const closure_type closure(*(static_cast<Derived*>(this)), policy_type(0, size_in));
341  closure.execute();
342 #if defined(KOKKOS_ENABLE_PROFILING)
343  if(Kokkos::Profiling::profileLibraryLoaded()) {
344  Kokkos::Profiling::endParallelFor(kpID);
345  }
346 #endif
347  }
348 };
349 
350 template <typename ExecSpace, typename ValueType>
351 struct ResetDuplicates<ExecSpace, ValueType, Kokkos::Experimental::ScatterSum> :
352  public ResetDuplicatesBase<ExecSpace, ValueType, Kokkos::Experimental::ScatterSum>
353 {
354  typedef ResetDuplicatesBase<ExecSpace, ValueType, Kokkos::Experimental::ScatterSum> Base;
355  ResetDuplicates(ValueType* data_in, size_t size_in, std::string const& name):
356  Base(data_in, size_in, name)
357  {}
358  KOKKOS_FORCEINLINE_FUNCTION void operator()(size_t i) const {
359  Base::data[i] = Kokkos::reduction_identity<ValueType>::sum();
360  }
361 };
362 
363 }}} // Kokkos::Impl::Experimental
364 
365 namespace Kokkos {
366 namespace Experimental {
367 
368 template <typename DataType
369  ,typename Layout = Kokkos::DefaultExecutionSpace::array_layout
370  ,typename ExecSpace = Kokkos::DefaultExecutionSpace
371  ,int Op = ScatterSum
372  ,int duplication = Kokkos::Impl::Experimental::DefaultDuplication<ExecSpace>::value
373  ,int contribution = Kokkos::Impl::Experimental::DefaultContribution<ExecSpace, duplication>::value
374  >
375 class ScatterView;
376 
377 template <typename DataType
378  ,int Op
379  ,typename ExecSpace
380  ,typename Layout
381  ,int duplication
382  ,int contribution
383  ,int override_contribution
384  >
385 class ScatterAccess;
386 
387 // non-duplicated implementation
388 template <typename DataType
389  ,int Op
390  ,typename ExecSpace
391  ,typename Layout
392  ,int contribution
393  >
394 class ScatterView<DataType
395  ,Layout
396  ,ExecSpace
397  ,Op
398  ,ScatterNonDuplicated
399  ,contribution>
400 {
401 public:
402  typedef Kokkos::View<DataType, Layout, ExecSpace> original_view_type;
403  typedef typename original_view_type::value_type original_value_type;
404  typedef typename original_view_type::reference_type original_reference_type;
405  friend class ScatterAccess<DataType, Op, ExecSpace, Layout, ScatterNonDuplicated, contribution, ScatterNonAtomic>;
406  friend class ScatterAccess<DataType, Op, ExecSpace, Layout, ScatterNonDuplicated, contribution, ScatterAtomic>;
407 
408  ScatterView()
409  {
410  }
411 
412  template <typename RT, typename ... RP>
413  ScatterView(View<RT, RP...> const& original_view)
414  : internal_view(original_view)
415  {
416  }
417 
418  template <typename ... Dims>
419  ScatterView(std::string const& name, Dims ... dims)
420  : internal_view(name, dims ...)
421  {
422  }
423 
424  template <int override_contrib = contribution>
425  KOKKOS_FORCEINLINE_FUNCTION
426  ScatterAccess<DataType, Op, ExecSpace, Layout, ScatterNonDuplicated, contribution, override_contrib>
427  access() const {
428  return ScatterAccess<DataType, Op, ExecSpace, Layout, ScatterNonDuplicated, contribution, override_contrib>{*this};
429  }
430 
431  original_view_type subview() const {
432  return internal_view;
433  }
434 
435  template <typename DT, typename ... RP>
436  void contribute_into(View<DT, RP...> const& dest) const
437  {
438  typedef View<DT, RP...> dest_type;
439  static_assert(std::is_same<
440  typename dest_type::array_layout,
441  Layout>::value,
442  "ScatterView contribute destination has different layout");
443  static_assert(Kokkos::Impl::VerifyExecutionCanAccessMemorySpace<
444  typename ExecSpace::memory_space,
445  typename dest_type::memory_space>::value,
446  "ScatterView contribute destination memory space not accessible");
447  if (dest.data() == internal_view.data()) return;
448  Kokkos::Impl::Experimental::ReduceDuplicates<ExecSpace, original_value_type, Op>(
449  internal_view.data(),
450  dest.data(),
451  0,
452  0,
453  1,
454  internal_view.label());
455  }
456 
457  void reset() {
458  Kokkos::Impl::Experimental::ResetDuplicates<ExecSpace, original_value_type, Op>(
459  internal_view.data(),
460  internal_view.size(),
461  internal_view.label());
462  }
463  template <typename DT, typename ... RP>
464  void reset_except(View<DT, RP...> const& view) {
465  if (view.data() != internal_view.data()) reset();
466  }
467 
468  void resize(const size_t n0 = 0,
469  const size_t n1 = 0,
470  const size_t n2 = 0,
471  const size_t n3 = 0,
472  const size_t n4 = 0,
473  const size_t n5 = 0,
474  const size_t n6 = 0,
475  const size_t n7 = 0) {
476  ::Kokkos::resize(internal_view,n0,n1,n2,n3,n4,n5,n6,n7);
477  }
478 
479  void realloc(const size_t n0 = 0,
480  const size_t n1 = 0,
481  const size_t n2 = 0,
482  const size_t n3 = 0,
483  const size_t n4 = 0,
484  const size_t n5 = 0,
485  const size_t n6 = 0,
486  const size_t n7 = 0) {
487  ::Kokkos::realloc(internal_view,n0,n1,n2,n3,n4,n5,n6,n7);
488  }
489 
490 protected:
491  template <typename ... Args>
492  KOKKOS_FORCEINLINE_FUNCTION
493  original_reference_type at(Args ... args) const {
494  return internal_view(args...);
495  }
496 private:
497  typedef original_view_type internal_view_type;
498  internal_view_type internal_view;
499 };
500 
501 template <typename DataType
502  ,int Op
503  ,typename ExecSpace
504  ,typename Layout
505  ,int contribution
506  ,int override_contribution
507  >
508 class ScatterAccess<DataType
509  ,Op
510  ,ExecSpace
511  ,Layout
512  ,ScatterNonDuplicated
513  ,contribution
514  ,override_contribution>
515 {
516 public:
517  typedef ScatterView<DataType, Layout, ExecSpace, Op, ScatterNonDuplicated, contribution> view_type;
518  typedef typename view_type::original_value_type original_value_type;
519  typedef Kokkos::Impl::Experimental::ScatterValue<
520  original_value_type, Op, override_contribution> value_type;
521 
522  KOKKOS_INLINE_FUNCTION
523  ScatterAccess(view_type const& view_in)
524  : view(view_in)
525  {
526  }
527 
528  template <typename ... Args>
529  KOKKOS_FORCEINLINE_FUNCTION
530  value_type operator()(Args ... args) const {
531  return view.at(args...);
532  }
533 
534  template <typename Arg>
535  KOKKOS_FORCEINLINE_FUNCTION
536  typename std::enable_if<view_type::original_view_type::rank == 1 &&
537  std::is_integral<Arg>::value, value_type>::type
538  operator[](Arg arg) const {
539  return view.at(arg);
540  }
541 
542 private:
543  view_type const& view;
544 };
545 
546 // duplicated implementation
547 // LayoutLeft and LayoutRight are different enough that we'll just specialize each
548 
549 template <typename DataType
550  ,int Op
551  ,typename ExecSpace
552  ,int contribution
553  >
554 class ScatterView<DataType
555  ,Kokkos::LayoutRight
556  ,ExecSpace
557  ,Op
558  ,ScatterDuplicated
559  ,contribution>
560 {
561 public:
563  typedef typename original_view_type::value_type original_value_type;
564  typedef typename original_view_type::reference_type original_reference_type;
565  friend class ScatterAccess<DataType, Op, ExecSpace, Kokkos::LayoutRight, ScatterDuplicated, contribution, ScatterNonAtomic>;
566  friend class ScatterAccess<DataType, Op, ExecSpace, Kokkos::LayoutRight, ScatterDuplicated, contribution, ScatterAtomic>;
567  typedef typename Kokkos::Impl::Experimental::DuplicatedDataType<DataType, Kokkos::LayoutRight> data_type_info;
568  typedef typename data_type_info::value_type internal_data_type;
569  typedef Kokkos::View<internal_data_type, Kokkos::LayoutRight, ExecSpace> internal_view_type;
570 
571  ScatterView()
572  {
573  }
574 
575  template <typename RT, typename ... RP >
576  ScatterView(View<RT, RP...> const& original_view)
577  : unique_token()
578  , internal_view(Kokkos::ViewAllocateWithoutInitializing(
579  std::string("duplicated_") + original_view.label()),
580  unique_token.size(),
581 #ifdef KOKKOS_ENABLE_DEPRECATED_CODE
582  original_view.extent(0),
583  original_view.extent(1),
584  original_view.extent(2),
585  original_view.extent(3),
586  original_view.extent(4),
587  original_view.extent(5),
588  original_view.extent(6) )
589 #else
590  original_view.rank_dynamic > 0 ? original_view.extent(0): KOKKOS_IMPL_CTOR_DEFAULT_ARG,
591  original_view.rank_dynamic > 1 ? original_view.extent(1): KOKKOS_IMPL_CTOR_DEFAULT_ARG,
592  original_view.rank_dynamic > 2 ? original_view.extent(2): KOKKOS_IMPL_CTOR_DEFAULT_ARG,
593  original_view.rank_dynamic > 3 ? original_view.extent(3): KOKKOS_IMPL_CTOR_DEFAULT_ARG,
594  original_view.rank_dynamic > 4 ? original_view.extent(4): KOKKOS_IMPL_CTOR_DEFAULT_ARG,
595  original_view.rank_dynamic > 5 ? original_view.extent(5): KOKKOS_IMPL_CTOR_DEFAULT_ARG,
596  original_view.rank_dynamic > 6 ? original_view.extent(6): KOKKOS_IMPL_CTOR_DEFAULT_ARG)
597 
598 #endif
599  {
600  reset();
601  }
602 
603  template <typename ... Dims>
604  ScatterView(std::string const& name, Dims ... dims)
605  : internal_view(Kokkos::ViewAllocateWithoutInitializing(name), unique_token.size(), dims ...)
606  {
607  reset();
608  }
609 
610  template <int override_contribution = contribution>
611  inline
612  ScatterAccess<DataType, Op, ExecSpace, Kokkos::LayoutRight, ScatterDuplicated, contribution, override_contribution>
613  access() const {
614  return ScatterAccess<DataType, Op, ExecSpace, Kokkos::LayoutRight, ScatterDuplicated, contribution, override_contribution>{*this};
615  }
616 
617  typename Kokkos::Impl::Experimental::Slice<
618  Kokkos::LayoutRight, internal_view_type::rank, internal_view_type>::value_type
619  subview() const
620  {
621  return Kokkos::Impl::Experimental::Slice<
622  Kokkos::LayoutRight, internal_view_type::Rank, internal_view_type>::get(internal_view, 0);
623  }
624 
625  template <typename DT, typename ... RP>
626  void contribute_into(View<DT, RP...> const& dest) const
627  {
628  typedef View<DT, RP...> dest_type;
629  static_assert(std::is_same<
630  typename dest_type::array_layout,
631  Kokkos::LayoutRight>::value,
632  "ScatterView deep_copy destination has different layout");
633  static_assert(Kokkos::Impl::VerifyExecutionCanAccessMemorySpace<
634  typename ExecSpace::memory_space,
635  typename dest_type::memory_space>::value,
636  "ScatterView deep_copy destination memory space not accessible");
637  bool is_equal = (dest.data() == internal_view.data());
638  size_t start = is_equal ? 1 : 0;
639  Kokkos::Impl::Experimental::ReduceDuplicates<ExecSpace, original_value_type, Op>(
640  internal_view.data(),
641  dest.data(),
642  internal_view.stride(0),
643  start,
644  internal_view.extent(0),
645  internal_view.label());
646  }
647 
648  void reset() {
649  Kokkos::Impl::Experimental::ResetDuplicates<ExecSpace, original_value_type, Op>(
650  internal_view.data(),
651  internal_view.size(),
652  internal_view.label());
653  }
654  template <typename DT, typename ... RP>
655  void reset_except(View<DT, RP...> const& view) {
656  if (view.data() != internal_view.data()) {
657  reset();
658  return;
659  }
660  Kokkos::Impl::Experimental::ResetDuplicates<ExecSpace, original_value_type, Op>(
661  internal_view.data() + view.size(),
662  internal_view.size() - view.size(),
663  internal_view.label());
664  }
665 
666  void resize(const size_t n0 = 0,
667  const size_t n1 = 0,
668  const size_t n2 = 0,
669  const size_t n3 = 0,
670  const size_t n4 = 0,
671  const size_t n5 = 0,
672  const size_t n6 = 0) {
673  ::Kokkos::resize(internal_view,unique_token.size(),n0,n1,n2,n3,n4,n5,n6);
674  }
675 
676  void realloc(const size_t n0 = 0,
677  const size_t n1 = 0,
678  const size_t n2 = 0,
679  const size_t n3 = 0,
680  const size_t n4 = 0,
681  const size_t n5 = 0,
682  const size_t n6 = 0) {
683  ::Kokkos::realloc(internal_view,unique_token.size(),n0,n1,n2,n3,n4,n5,n6);
684  }
685 
686 protected:
687  template <typename ... Args>
688  KOKKOS_FORCEINLINE_FUNCTION
689  original_reference_type at(int rank, Args ... args) const {
690  return internal_view(rank, args...);
691  }
692 
693 protected:
695  ExecSpace, Kokkos::Experimental::UniqueTokenScope::Global> unique_token_type;
696 
697  unique_token_type unique_token;
698  internal_view_type internal_view;
699 };
700 
701 template <typename DataType
702  ,int Op
703  ,typename ExecSpace
704  ,int contribution
705  >
706 class ScatterView<DataType
707  ,Kokkos::LayoutLeft
708  ,ExecSpace
709  ,Op
710  ,ScatterDuplicated
711  ,contribution>
712 {
713 public:
715  typedef typename original_view_type::value_type original_value_type;
716  typedef typename original_view_type::reference_type original_reference_type;
717  friend class ScatterAccess<DataType, Op, ExecSpace, Kokkos::LayoutLeft, ScatterDuplicated, contribution, ScatterNonAtomic>;
718  friend class ScatterAccess<DataType, Op, ExecSpace, Kokkos::LayoutLeft, ScatterDuplicated, contribution, ScatterAtomic>;
719  typedef typename Kokkos::Impl::Experimental::DuplicatedDataType<DataType, Kokkos::LayoutLeft> data_type_info;
720  typedef typename data_type_info::value_type internal_data_type;
721  typedef Kokkos::View<internal_data_type, Kokkos::LayoutLeft, ExecSpace> internal_view_type;
722 
723  ScatterView()
724  {
725  }
726 
727  template <typename RT, typename ... RP >
728  ScatterView(View<RT, RP...> const& original_view)
729  : unique_token()
730  {
731  size_t arg_N[8] = {
732  original_view.extent(0),
733  original_view.extent(1),
734  original_view.extent(2),
735  original_view.extent(3),
736  original_view.extent(4),
737  original_view.extent(5),
738  original_view.extent(6),
739  0
740  };
741  arg_N[internal_view_type::rank - 1] = unique_token.size();
742  internal_view = internal_view_type(
743  Kokkos::ViewAllocateWithoutInitializing(
744  std::string("duplicated_") + original_view.label()),
745  arg_N[0], arg_N[1], arg_N[2], arg_N[3],
746  arg_N[4], arg_N[5], arg_N[6], arg_N[7]);
747  reset();
748  }
749 
750  template <typename ... Dims>
751  ScatterView(std::string const& name, Dims ... dims)
752  : internal_view(Kokkos::ViewAllocateWithoutInitializing(name), dims ..., unique_token.size())
753  {
754  reset();
755  }
756 
757  template <int override_contribution = contribution>
758  inline
759  ScatterAccess<DataType, Op, ExecSpace, Kokkos::LayoutLeft, ScatterDuplicated, contribution, override_contribution>
760  access() const {
761  return ScatterAccess<DataType, Op, ExecSpace, Kokkos::LayoutLeft, ScatterDuplicated, contribution, override_contribution>{*this};
762  }
763 
764  typename Kokkos::Impl::Experimental::Slice<
765  Kokkos::LayoutLeft, internal_view_type::rank, internal_view_type>::value_type
766  subview() const
767  {
768  return Kokkos::Impl::Experimental::Slice<
769  Kokkos::LayoutLeft, internal_view_type::rank, internal_view_type>::get(internal_view, 0);
770  }
771 
772  template <typename ... RP>
773  void contribute_into(View<DataType, RP...> const& dest) const
774  {
775  typedef View<DataType, RP...> dest_type;
776  static_assert(std::is_same<
777  typename dest_type::array_layout,
778  Kokkos::LayoutLeft>::value,
779  "ScatterView deep_copy destination has different layout");
780  static_assert(Kokkos::Impl::VerifyExecutionCanAccessMemorySpace<
781  typename ExecSpace::memory_space,
782  typename dest_type::memory_space>::value,
783  "ScatterView deep_copy destination memory space not accessible");
784  auto extent = internal_view.extent(
785  internal_view_type::rank - 1);
786  bool is_equal = (dest.data() == internal_view.data());
787  size_t start = is_equal ? 1 : 0;
788  Kokkos::Impl::Experimental::ReduceDuplicates<ExecSpace, original_value_type, Op>(
789  internal_view.data(),
790  dest.data(),
791  internal_view.stride(internal_view_type::rank - 1),
792  start,
793  extent,
794  internal_view.label());
795  }
796 
797  void reset() {
798  Kokkos::Impl::Experimental::ResetDuplicates<ExecSpace, original_value_type, Op>(
799  internal_view.data(),
800  internal_view.size(),
801  internal_view.label());
802  }
803  template <typename DT, typename ... RP>
804  void reset_except(View<DT, RP...> const& view) {
805  if (view.data() != internal_view.data()) {
806  reset();
807  return;
808  }
809  Kokkos::Impl::Experimental::ResetDuplicates<ExecSpace, original_value_type, Op>(
810  internal_view.data() + view.size(),
811  internal_view.size() - view.size(),
812  internal_view.label());
813  }
814 
815  void resize(const size_t n0 = 0,
816  const size_t n1 = 0,
817  const size_t n2 = 0,
818  const size_t n3 = 0,
819  const size_t n4 = 0,
820  const size_t n5 = 0,
821  const size_t n6 = 0) {
822 
823  size_t arg_N[8] = {n0,n1,n2,n3,n4,n5,n6,0};
824  const int i = internal_view.rank-1;
825  arg_N[i] = unique_token.size();
826 
827  ::Kokkos::resize(internal_view,
828  arg_N[0], arg_N[1], arg_N[2], arg_N[3],
829  arg_N[4], arg_N[5], arg_N[6], arg_N[7]);
830  }
831 
832  void realloc(const size_t n0 = 0,
833  const size_t n1 = 0,
834  const size_t n2 = 0,
835  const size_t n3 = 0,
836  const size_t n4 = 0,
837  const size_t n5 = 0,
838  const size_t n6 = 0) {
839 
840  size_t arg_N[8] = {n0,n1,n2,n3,n4,n5,n6,0};
841  const int i = internal_view.rank-1;
842  arg_N[i] = unique_token.size();
843 
844  ::Kokkos::realloc(internal_view,
845  arg_N[0], arg_N[1], arg_N[2], arg_N[3],
846  arg_N[4], arg_N[5], arg_N[6], arg_N[7]);
847  }
848 
849 protected:
850  template <typename ... Args>
851  inline original_reference_type at(int thread_id, Args ... args) const {
852  return internal_view(args..., thread_id);
853  }
854 
855 protected:
857  ExecSpace, Kokkos::Experimental::UniqueTokenScope::Global> unique_token_type;
858 
859  unique_token_type unique_token;
860  internal_view_type internal_view;
861 };
862 
863 
864 /* This object has to be separate in order to store the thread ID, which cannot
865  be obtained until one is inside a parallel construct, and may be relatively
866  expensive to obtain at every contribution
867  (calls a non-inlined function, looks up a thread-local variable).
868  Due to the expense, it is sensible to query it at most once per parallel iterate
869  (ideally once per thread, but parallel_for doesn't expose that)
870  and then store it in a stack variable.
871  ScatterAccess serves as a non-const object on the stack which can store the thread ID */
872 
873 template <typename DataType
874  ,int Op
875  ,typename ExecSpace
876  ,typename Layout
877  ,int contribution
878  ,int override_contribution
879  >
880 class ScatterAccess<DataType
881  ,Op
882  ,ExecSpace
883  ,Layout
884  ,ScatterDuplicated
885  ,contribution
886  ,override_contribution>
887 {
888 public:
889  typedef ScatterView<DataType, Layout, ExecSpace, Op, ScatterDuplicated, contribution> view_type;
890  typedef typename view_type::original_value_type original_value_type;
891  typedef Kokkos::Impl::Experimental::ScatterValue<
892  original_value_type, Op, override_contribution> value_type;
893 
894  inline ScatterAccess(view_type const& view_in)
895  : view(view_in)
896  , thread_id(view_in.unique_token.acquire()) {
897  }
898 
899  inline ~ScatterAccess() {
900  if (thread_id != ~thread_id_type(0)) view.unique_token.release(thread_id);
901  }
902 
903  template <typename ... Args>
904  KOKKOS_FORCEINLINE_FUNCTION
905  value_type operator()(Args ... args) const {
906  return view.at(thread_id, args...);
907  }
908 
909  template <typename Arg>
910  KOKKOS_FORCEINLINE_FUNCTION
911  typename std::enable_if<view_type::original_view_type::rank == 1 &&
912  std::is_integral<Arg>::value, value_type>::type
913  operator[](Arg arg) const {
914  return view.at(thread_id, arg);
915  }
916 
917 private:
918 
919  view_type const& view;
920 
921  // simplify RAII by disallowing copies
922  ScatterAccess(ScatterAccess const& other) = delete;
923  ScatterAccess& operator=(ScatterAccess const& other) = delete;
924  ScatterAccess& operator=(ScatterAccess&& other) = delete;
925 
926 public:
927  // do need to allow moves though, for the common
928  // auto b = a.access();
929  // that assignments turns into a move constructor call
930  inline ScatterAccess(ScatterAccess&& other)
931  : view(other.view)
932  , thread_id(other.thread_id)
933  {
934  other.thread_id = ~thread_id_type(0);
935  }
936 
937 private:
938 
939  typedef typename view_type::unique_token_type unique_token_type;
940  typedef typename unique_token_type::size_type thread_id_type;
941  thread_id_type thread_id;
942 };
943 
944 template <int Op = Kokkos::Experimental::ScatterSum,
945  int duplication = -1,
946  int contribution = -1,
947  typename RT, typename ... RP>
948 ScatterView
949  < RT
950  , typename ViewTraits<RT, RP...>::array_layout
951  , typename ViewTraits<RT, RP...>::execution_space
952  , Op
953  /* just setting defaults if not specified... things got messy because the view type
954  does not come before the duplication/contribution settings in the
955  template parameter list */
956  , duplication == -1 ? Kokkos::Impl::Experimental::DefaultDuplication<typename ViewTraits<RT, RP...>::execution_space>::value : duplication
957  , contribution == -1 ?
958  Kokkos::Impl::Experimental::DefaultContribution<
959  typename ViewTraits<RT, RP...>::execution_space,
960  (duplication == -1 ?
961  Kokkos::Impl::Experimental::DefaultDuplication<
962  typename ViewTraits<RT, RP...>::execution_space
963  >::value
964  : duplication
965  )
966  >::value
967  : contribution
968  >
969 create_scatter_view(View<RT, RP...> const& original_view) {
970  return original_view; // implicit ScatterView constructor call
971 }
972 
973 }} // namespace Kokkos::Experimental
974 
975 namespace Kokkos {
976 namespace Experimental {
977 
978 template <typename DT1, typename DT2, typename LY, typename ES, int OP, int CT, int DP, typename ... VP>
979 void
980 contribute(View<DT1, VP...>& dest, Kokkos::Experimental::ScatterView<DT2, LY, ES, OP, CT, DP> const& src)
981 {
982  src.contribute_into(dest);
983 }
984 
985 }} // namespace Kokkos::Experimental
986 
987 namespace Kokkos {
988 
989 template <typename DT, typename LY, typename ES, int OP, int CT, int DP, typename ... IS>
990 void
991 realloc(Kokkos::Experimental::ScatterView<DT, LY, ES, OP, CT, DP>& scatter_view, IS ... is)
992 {
993  scatter_view.realloc(is ...);
994 }
995 
996 template <typename DT, typename LY, typename ES, int OP, int CT, int DP, typename ... IS>
997 void
998 resize(Kokkos::Experimental::ScatterView<DT, LY, ES, OP, CT, DP>& scatter_view, IS ... is)
999 {
1000  scatter_view.resize(is ...);
1001 }
1002 
1003 } // namespace Kokkos
1004 
1005 #endif
Memory layout tag indicating left-to-right (Fortran scheme) striding of multi-indices.
class to generate unique ids base on the required amount of concurrency
std::enable_if< std::is_same< typename Kokkos::View< T, P...>::array_layout, Kokkos::LayoutLeft >::value||std::is_same< typename Kokkos::View< T, P...>::array_layout, Kokkos::LayoutRight >::value >::type resize(Kokkos::View< T, P...> &v, const size_t n0=KOKKOS_IMPL_CTOR_DEFAULT_ARG, const size_t n1=KOKKOS_IMPL_CTOR_DEFAULT_ARG, const size_t n2=KOKKOS_IMPL_CTOR_DEFAULT_ARG, const size_t n3=KOKKOS_IMPL_CTOR_DEFAULT_ARG, const size_t n4=KOKKOS_IMPL_CTOR_DEFAULT_ARG, const size_t n5=KOKKOS_IMPL_CTOR_DEFAULT_ARG, const size_t n6=KOKKOS_IMPL_CTOR_DEFAULT_ARG, const size_t n7=KOKKOS_IMPL_CTOR_DEFAULT_ARG)
Resize a view with copying old data to new data at the corresponding indices.
View to an array of data.
Memory layout tag indicating right-to-left (C or lexigraphical scheme) striding of multi-indices...
void resize(DynRankView< T, P...> &v, const size_t n0=KOKKOS_INVALID_INDEX, const size_t n1=KOKKOS_INVALID_INDEX, const size_t n2=KOKKOS_INVALID_INDEX, const size_t n3=KOKKOS_INVALID_INDEX, const size_t n4=KOKKOS_INVALID_INDEX, const size_t n5=KOKKOS_INVALID_INDEX, const size_t n6=KOKKOS_INVALID_INDEX, const size_t n7=KOKKOS_INVALID_INDEX)
Resize a view with copying old data to new data at the corresponding indices.
Implementation of the ParallelFor operator that has a partial specialization for the device...
std::enable_if< std::is_same< typename Kokkos::View< T, P...>::array_layout, Kokkos::LayoutLeft >::value||std::is_same< typename Kokkos::View< T, P...>::array_layout, Kokkos::LayoutRight >::value >::type realloc(Kokkos::View< T, P...> &v, const size_t n0=KOKKOS_IMPL_CTOR_DEFAULT_ARG, const size_t n1=KOKKOS_IMPL_CTOR_DEFAULT_ARG, const size_t n2=KOKKOS_IMPL_CTOR_DEFAULT_ARG, const size_t n3=KOKKOS_IMPL_CTOR_DEFAULT_ARG, const size_t n4=KOKKOS_IMPL_CTOR_DEFAULT_ARG, const size_t n5=KOKKOS_IMPL_CTOR_DEFAULT_ARG, const size_t n6=KOKKOS_IMPL_CTOR_DEFAULT_ARG, const size_t n7=KOKKOS_IMPL_CTOR_DEFAULT_ARG)
Resize a view with discarding old data.
KOKKOS_INLINE_FUNCTION constexpr unsigned rank(const View< D, P...> &V)
Temporary free function rank() until rank() is implemented in the View.
void realloc(DynRankView< T, P...> &v, const size_t n0=KOKKOS_INVALID_INDEX, const size_t n1=KOKKOS_INVALID_INDEX, const size_t n2=KOKKOS_INVALID_INDEX, const size_t n3=KOKKOS_INVALID_INDEX, const size_t n4=KOKKOS_INVALID_INDEX, const size_t n5=KOKKOS_INVALID_INDEX, const size_t n6=KOKKOS_INVALID_INDEX, const size_t n7=KOKKOS_INVALID_INDEX)
Resize a view with copying old data to new data at the corresponding indices.