Kokkos Core Kernels Package  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
Kokkos_DynamicView.hpp
1 //@HEADER
2 // ************************************************************************
3 //
4 // Kokkos v. 4.0
5 // Copyright (2022) National Technology & Engineering
6 // Solutions of Sandia, LLC (NTESS).
7 //
8 // Under the terms of Contract DE-NA0003525 with NTESS,
9 // the U.S. Government retains certain rights in this software.
10 //
11 // Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
12 // See https://kokkos.org/LICENSE for license information.
13 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
14 //
15 //@HEADER
16 
17 #ifndef KOKKOS_DYNAMIC_VIEW_HPP
18 #define KOKKOS_DYNAMIC_VIEW_HPP
19 #ifndef KOKKOS_IMPL_PUBLIC_INCLUDE
20 #define KOKKOS_IMPL_PUBLIC_INCLUDE
21 #define KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_DYNAMICVIEW
22 #endif
23 
24 #include <cstdio>
25 
26 #include <Kokkos_Core.hpp>
27 #include <impl/Kokkos_Error.hpp>
28 
29 namespace Kokkos {
30 namespace Experimental {
31 
32 namespace Impl {
33 
37 template <typename MemorySpace, typename ValueType>
38 struct ChunkedArrayManager {
39  using value_type = ValueType;
40  using pointer_type = ValueType*;
41  using track_type = Kokkos::Impl::SharedAllocationTracker;
42 
43  ChunkedArrayManager() = default;
44  ChunkedArrayManager(ChunkedArrayManager const&) = default;
45  ChunkedArrayManager(ChunkedArrayManager&&) = default;
46  ChunkedArrayManager& operator=(ChunkedArrayManager&&) = default;
47  ChunkedArrayManager& operator=(const ChunkedArrayManager&) = default;
48 
49  template <typename Space, typename Value>
50  friend struct ChunkedArrayManager;
51 
52  template <typename Space, typename Value>
53  inline ChunkedArrayManager(const ChunkedArrayManager<Space, Value>& rhs)
54  : m_valid(rhs.m_valid),
55  m_chunk_max(rhs.m_chunk_max),
56  m_chunks((ValueType**)(rhs.m_chunks)),
57  m_track(rhs.m_track),
58  m_chunk_size(rhs.m_chunk_size) {
59  static_assert(
61  "Incompatible ChunkedArrayManager copy construction");
62  }
63 
64  ChunkedArrayManager(const unsigned arg_chunk_max,
65  const unsigned arg_chunk_size)
66  : m_chunk_max(arg_chunk_max), m_chunk_size(arg_chunk_size) {}
67 
68  private:
69  struct ACCESSIBLE_TAG {};
70  struct INACCESSIBLE_TAG {};
71 
72  ChunkedArrayManager(ACCESSIBLE_TAG, pointer_type* arg_chunks,
73  const unsigned arg_chunk_max)
74  : m_valid(true), m_chunk_max(arg_chunk_max), m_chunks(arg_chunks) {}
75 
76  ChunkedArrayManager(INACCESSIBLE_TAG, const unsigned arg_chunk_max,
77  const unsigned arg_chunk_size)
78  : m_chunk_max(arg_chunk_max), m_chunk_size(arg_chunk_size) {}
79 
80  public:
81  template <typename Space, typename Enable_ = void>
82  struct IsAccessibleFrom;
83 
84  template <typename Space>
85  struct IsAccessibleFrom<
86  Space, typename std::enable_if_t<Kokkos::Impl::MemorySpaceAccess<
87  MemorySpace, Space>::accessible>> : std::true_type {};
88 
89  template <typename Space>
90  struct IsAccessibleFrom<
91  Space, typename std::enable_if_t<!Kokkos::Impl::MemorySpaceAccess<
92  MemorySpace, Space>::accessible>> : std::false_type {};
93 
94  template <typename Space>
95  static ChunkedArrayManager<Space, ValueType> create_mirror(
96  ChunkedArrayManager<MemorySpace, ValueType> const& other,
97  std::enable_if_t<IsAccessibleFrom<Space>::value>* = nullptr) {
98  return ChunkedArrayManager<Space, ValueType>{
99  ACCESSIBLE_TAG{}, other.m_chunks, other.m_chunk_max};
100  }
101 
102  template <typename Space>
103  static ChunkedArrayManager<Space, ValueType> create_mirror(
104  ChunkedArrayManager<MemorySpace, ValueType> const& other,
105  std::enable_if_t<!IsAccessibleFrom<Space>::value>* = nullptr) {
106  using tag_type =
107  typename ChunkedArrayManager<Space, ValueType>::INACCESSIBLE_TAG;
108  return ChunkedArrayManager<Space, ValueType>{tag_type{}, other.m_chunk_max,
109  other.m_chunk_size};
110  }
111 
112  public:
113  void allocate_device(const std::string& label) {
114  if (m_chunks == nullptr) {
115  m_chunks = reinterpret_cast<pointer_type*>(MemorySpace().allocate(
116  label.c_str(), (sizeof(pointer_type) * (m_chunk_max + 2))));
117  }
118  }
119 
120  void initialize() {
121  for (unsigned i = 0; i < m_chunk_max + 2; i++) {
122  m_chunks[i] = nullptr;
123  }
124  m_valid = true;
125  }
126 
127  private:
130  template <typename Space>
131  struct Destroy {
132  Destroy() = default;
133  Destroy(Destroy&&) = default;
134  Destroy(const Destroy&) = default;
135  Destroy& operator=(Destroy&&) = default;
136  Destroy& operator=(const Destroy&) = default;
137 
138  Destroy(std::string label, value_type** arg_chunk,
139  const unsigned arg_chunk_max, const unsigned arg_chunk_size,
140  value_type** arg_linked)
141  : m_label(label),
142  m_chunks(arg_chunk),
143  m_linked(arg_linked),
144  m_chunk_max(arg_chunk_max),
145  m_chunk_size(arg_chunk_size) {}
146 
147  void execute() {
148  // Destroy the array of chunk pointers.
149  // Two entries beyond the max chunks are allocation counters.
150  uintptr_t const len =
151  *reinterpret_cast<uintptr_t*>(m_chunks + m_chunk_max);
152  for (unsigned i = 0; i < len; i++) {
153  Space().deallocate(m_label.c_str(), m_chunks[i],
154  sizeof(value_type) * m_chunk_size);
155  }
156  // Destroy the linked allocation if we have one.
157  if (m_linked != nullptr) {
158  Space().deallocate(m_label.c_str(), m_linked,
159  (sizeof(value_type*) * (m_chunk_max + 2)));
160  }
161  }
162 
163  void destroy_shared_allocation() { execute(); }
164 
165  std::string m_label;
166  value_type** m_chunks = nullptr;
167  value_type** m_linked = nullptr;
168  unsigned m_chunk_max;
169  unsigned m_chunk_size;
170  };
171 
172  public:
173  template <typename Space>
174  void allocate_with_destroy(const std::string& label,
175  pointer_type* linked_allocation = nullptr) {
176  using destroy_type = Destroy<Space>;
177  using record_type =
178  Kokkos::Impl::SharedAllocationRecord<MemorySpace, destroy_type>;
179 
180  // Allocate + 2 extra slots so that *m_chunk[m_chunk_max] ==
181  // num_chunks_alloc and *m_chunk[m_chunk_max+1] == extent This must match in
182  // Destroy's execute(...) method
183  record_type* const record = record_type::allocate(
184  MemorySpace(), label, (sizeof(pointer_type) * (m_chunk_max + 2)));
185  m_chunks = static_cast<pointer_type*>(record->data());
186  m_track.assign_allocated_record_to_uninitialized(record);
187 
188  record->m_destroy = destroy_type(label, m_chunks, m_chunk_max, m_chunk_size,
189  linked_allocation);
190  }
191 
192  pointer_type* get_ptr() const { return m_chunks; }
193 
194  template <typename OtherMemorySpace, typename ExecutionSpace>
195  void deep_copy_to(
196  const ExecutionSpace& exec_space,
197  ChunkedArrayManager<OtherMemorySpace, ValueType> const& other) const {
198  if (other.m_chunks != m_chunks) {
199  Kokkos::Impl::DeepCopy<OtherMemorySpace, MemorySpace, ExecutionSpace>(
200  exec_space, other.m_chunks, m_chunks,
201  sizeof(pointer_type) * (m_chunk_max + 2));
202  }
203  }
204 
205  KOKKOS_INLINE_FUNCTION
206  pointer_type* operator+(int i) const { return m_chunks + i; }
207 
208  KOKKOS_INLINE_FUNCTION
209  pointer_type& operator[](int i) const { return m_chunks[i]; }
210 
211  track_type const& track() const { return m_track; }
212 
213  KOKKOS_INLINE_FUNCTION
214  bool valid() const { return m_valid; }
215 
216  private:
217  bool m_valid = false;
218  unsigned m_chunk_max = 0;
219  pointer_type* m_chunks = nullptr;
220  track_type m_track;
221  unsigned m_chunk_size = 0;
222 };
223 
224 } /* end namespace Impl */
225 
230 template <typename DataType, typename... P>
231 class DynamicView : public Kokkos::ViewTraits<DataType, P...> {
232  public:
233  using traits = Kokkos::ViewTraits<DataType, P...>;
234 
235  using value_type = typename traits::value_type;
236  using device_space = typename traits::memory_space;
237  using host_space =
238  typename Kokkos::Impl::HostMirror<device_space>::Space::memory_space;
239  using device_accessor = Impl::ChunkedArrayManager<device_space, value_type>;
240  using host_accessor = Impl::ChunkedArrayManager<host_space, value_type>;
241 
242  private:
243  template <class, class...>
244  friend class DynamicView;
245 
246  using track_type = Kokkos::Impl::SharedAllocationTracker;
247 
248  static_assert(traits::rank == 1 && traits::rank_dynamic == 1,
249  "DynamicView must be rank-one");
250 
251  // It is assumed that the value_type is trivially copyable;
252  // when this is not the case, potential problems can occur.
253  static_assert(std::is_void<typename traits::specialize>::value,
254  "DynamicView only implemented for non-specialized View type");
255 
256  private:
257  device_accessor m_chunks;
258  host_accessor m_chunks_host;
259  unsigned m_chunk_shift; // ceil(log2(m_chunk_size))
260  unsigned m_chunk_mask; // m_chunk_size - 1
261  unsigned m_chunk_max; // number of entries in the chunk array - each pointing
262  // to a chunk of extent == m_chunk_size entries
263  unsigned m_chunk_size; // 2 << (m_chunk_shift - 1)
264 
265  public:
266  //----------------------------------------------------------------------
267 
269  using array_type =
270  DynamicView<typename traits::data_type, typename traits::device_type>;
271 
273  using const_type = DynamicView<typename traits::const_data_type,
274  typename traits::device_type>;
275 
277  using non_const_type = DynamicView<typename traits::non_const_data_type,
278  typename traits::device_type>;
279 
281  using HostMirror = DynamicView;
282 
284  using uniform_device =
285  Kokkos::Device<typename traits::device_type::execution_space,
286  Kokkos::AnonymousSpace>;
287  using uniform_type = array_type;
288  using uniform_const_type = const_type;
289  using uniform_runtime_type = array_type;
290  using uniform_runtime_const_type = const_type;
291  using uniform_nomemspace_type =
292  DynamicView<typename traits::data_type, uniform_device>;
293  using uniform_const_nomemspace_type =
294  DynamicView<typename traits::const_data_type, uniform_device>;
295  using uniform_runtime_nomemspace_type =
296  DynamicView<typename traits::data_type, uniform_device>;
297  using uniform_runtime_const_nomemspace_type =
298  DynamicView<typename traits::const_data_type, uniform_device>;
299 
300  //----------------------------------------------------------------------
301 
302  enum { Rank = 1 };
303 
304  KOKKOS_INLINE_FUNCTION
305  size_t allocation_extent() const noexcept {
306  uintptr_t n =
307  *reinterpret_cast<const uintptr_t*>(m_chunks_host + m_chunk_max);
308  return (n << m_chunk_shift);
309  }
310 
311  KOKKOS_INLINE_FUNCTION
312  size_t chunk_size() const noexcept { return m_chunk_size; }
313 
314  KOKKOS_INLINE_FUNCTION
315  size_t chunk_max() const noexcept { return m_chunk_max; }
316 
317  KOKKOS_INLINE_FUNCTION
318  size_t size() const noexcept {
319  size_t extent_0 =
320  *reinterpret_cast<const size_t*>(m_chunks_host + m_chunk_max + 1);
321  return extent_0;
322  }
323 
324  template <typename iType>
325  KOKKOS_INLINE_FUNCTION size_t extent(const iType& r) const {
326  return r == 0 ? size() : 1;
327  }
328 
329  template <typename iType>
330  KOKKOS_INLINE_FUNCTION size_t extent_int(const iType& r) const {
331  return r == 0 ? size() : 1;
332  }
333 
334  KOKKOS_INLINE_FUNCTION constexpr size_t stride_0() const { return 0; }
335  KOKKOS_INLINE_FUNCTION constexpr size_t stride_1() const { return 0; }
336  KOKKOS_INLINE_FUNCTION constexpr size_t stride_2() const { return 0; }
337  KOKKOS_INLINE_FUNCTION constexpr size_t stride_3() const { return 0; }
338  KOKKOS_INLINE_FUNCTION constexpr size_t stride_4() const { return 0; }
339  KOKKOS_INLINE_FUNCTION constexpr size_t stride_5() const { return 0; }
340  KOKKOS_INLINE_FUNCTION constexpr size_t stride_6() const { return 0; }
341  KOKKOS_INLINE_FUNCTION constexpr size_t stride_7() const { return 0; }
342 
343  template <typename iType>
344  KOKKOS_INLINE_FUNCTION void stride(iType* const s) const {
345  *s = 0;
346  }
347 
348  //----------------------------------------
349  // Allocation tracking properties
350 
351  KOKKOS_INLINE_FUNCTION
352  int use_count() const { return m_chunks_host.track().use_count(); }
353 
354  inline const std::string label() const {
355  return m_chunks_host.track().template get_label<host_space>();
356  }
357 
358  //----------------------------------------------------------------------
359  // Range span is the span which contains all members.
360 
361  using reference_type = typename traits::value_type&;
362  using pointer_type = typename traits::value_type*;
363 
364  enum {
365  reference_type_is_lvalue_reference =
366  std::is_lvalue_reference<reference_type>::value
367  };
368 
369  KOKKOS_INLINE_FUNCTION constexpr bool span_is_contiguous() const {
370  return false;
371  }
372  KOKKOS_INLINE_FUNCTION constexpr size_t span() const { return 0; }
373  KOKKOS_INLINE_FUNCTION constexpr pointer_type data() const { return 0; }
374 
375  //----------------------------------------
376 
377  template <typename I0, class... Args>
378  KOKKOS_INLINE_FUNCTION reference_type
379  operator()(const I0& i0, const Args&... /*args*/) const {
380  static_assert(Kokkos::Impl::are_integral<I0, Args...>::value,
381  "Indices must be integral type");
382 
383  Kokkos::Impl::runtime_check_memory_access_violation<
384  typename traits::memory_space>(
385  "Kokkos::DynamicView ERROR: attempt to access inaccessible memory "
386  "space");
387 
388  // Which chunk is being indexed.
389  const uintptr_t ic = uintptr_t(i0) >> m_chunk_shift;
390 
391 #if defined(KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK)
392  const uintptr_t n = *reinterpret_cast<uintptr_t*>(m_chunks + m_chunk_max);
393  if (n <= ic) Kokkos::abort("Kokkos::DynamicView array bounds error");
394 #endif
395 
396  typename traits::value_type** const ch = m_chunks + ic;
397  return (*ch)[i0 & m_chunk_mask];
398  }
399 
400  //----------------------------------------
404  template <typename IntType>
405  inline void resize_serial(IntType const& n) {
406  using local_value_type = typename traits::value_type;
407  using value_pointer_type = local_value_type*;
408 
409  const uintptr_t NC =
410  (n + m_chunk_mask) >>
411  m_chunk_shift; // New total number of chunks needed for resize
412 
413  if (m_chunk_max < NC) {
414  Kokkos::abort("DynamicView::resize_serial exceeded maximum size");
415  }
416 
417  // *m_chunks[m_chunk_max] stores the current number of chunks being used
418  uintptr_t* const pc =
419  reinterpret_cast<uintptr_t*>(m_chunks_host + m_chunk_max);
420  std::string _label = m_chunks_host.track().template get_label<host_space>();
421 
422  if (*pc < NC) {
423  while (*pc < NC) {
424  m_chunks_host[*pc] =
425  reinterpret_cast<value_pointer_type>(device_space().allocate(
426  _label.c_str(), sizeof(local_value_type) << m_chunk_shift));
427  ++*pc;
428  }
429  } else {
430  while (NC + 1 <= *pc) {
431  --*pc;
432  device_space().deallocate(_label.c_str(), m_chunks_host[*pc],
433  sizeof(local_value_type) << m_chunk_shift);
434  m_chunks_host[*pc] = nullptr;
435  }
436  }
437  // *m_chunks_host[m_chunk_max+1] stores the 'extent' requested by resize
438  *(pc + 1) = n;
439 
440  typename device_space::execution_space exec{};
441  m_chunks_host.deep_copy_to(exec, m_chunks);
442  exec.fence(
443  "DynamicView::resize_serial: Fence after copying chunks to the device");
444  }
445 
446  KOKKOS_INLINE_FUNCTION bool is_allocated() const {
447  if (m_chunks_host.valid()) {
448  // *m_chunks_host[m_chunk_max] stores the current number of chunks being
449  // used
450  uintptr_t* const pc =
451  reinterpret_cast<uintptr_t*>(m_chunks_host + m_chunk_max);
452  return (*(pc + 1) > 0);
453  } else {
454  return false;
455  }
456  }
457 
458  KOKKOS_FUNCTION const device_accessor& impl_get_chunks() const {
459  return m_chunks;
460  }
461 
462  KOKKOS_FUNCTION device_accessor& impl_get_chunks() { return m_chunks; }
463 
464  //----------------------------------------------------------------------
465 
466  ~DynamicView() = default;
467  DynamicView() = default;
468  DynamicView(DynamicView&&) = default;
469  DynamicView(const DynamicView&) = default;
470  DynamicView& operator=(DynamicView&&) = default;
471  DynamicView& operator=(const DynamicView&) = default;
472 
473  template <class RT, class... RP>
474  DynamicView(const DynamicView<RT, RP...>& rhs)
475  : m_chunks(rhs.m_chunks),
476  m_chunks_host(rhs.m_chunks_host),
477  m_chunk_shift(rhs.m_chunk_shift),
478  m_chunk_mask(rhs.m_chunk_mask),
479  m_chunk_max(rhs.m_chunk_max),
480  m_chunk_size(rhs.m_chunk_size) {
481  using SrcTraits = typename DynamicView<RT, RP...>::traits;
482  using Mapping = Kokkos::Impl::ViewMapping<traits, SrcTraits, void>;
483  static_assert(Mapping::is_assignable,
484  "Incompatible DynamicView copy construction");
485  }
486 
493  template <class... Prop>
494  DynamicView(const Kokkos::Impl::ViewCtorProp<Prop...>& arg_prop,
495  const unsigned min_chunk_size,
496  const unsigned max_extent)
497  : // The chunk size is guaranteed to be a power of two
498  m_chunk_shift(Kokkos::Impl::integral_power_of_two_that_contains(
499  min_chunk_size)) // div ceil(log2(min_chunk_size))
500  ,
501  m_chunk_mask((1 << m_chunk_shift) - 1) // mod
502  ,
503  m_chunk_max((max_extent + m_chunk_mask) >>
504  m_chunk_shift) // max num pointers-to-chunks in array
505  ,
506  m_chunk_size(2 << (m_chunk_shift - 1)) {
507  m_chunks = device_accessor(m_chunk_max, m_chunk_size);
508 
509  const std::string& label =
510  Kokkos::Impl::get_property<Kokkos::Impl::LabelTag>(arg_prop);
511 
512  if (device_accessor::template IsAccessibleFrom<host_space>::value) {
513  m_chunks.template allocate_with_destroy<device_space>(label);
514  m_chunks.initialize();
515  m_chunks_host =
516  device_accessor::template create_mirror<host_space>(m_chunks);
517  } else {
518  m_chunks.allocate_device(label);
519  m_chunks_host =
520  device_accessor::template create_mirror<host_space>(m_chunks);
521  m_chunks_host.template allocate_with_destroy<device_space>(
522  label, m_chunks.get_ptr());
523  m_chunks_host.initialize();
524 
525  using alloc_prop_input = Kokkos::Impl::ViewCtorProp<Prop...>;
526 
527  auto arg_prop_copy = ::Kokkos::Impl::with_properties_if_unset(
528  arg_prop, typename device_space::execution_space{});
529 
530  const auto& exec =
531  Kokkos::Impl::get_property<Kokkos::Impl::ExecutionSpaceTag>(
532  arg_prop_copy);
533  m_chunks_host.deep_copy_to(exec, m_chunks);
534  if (!alloc_prop_input::has_execution_space)
535  exec.fence(
536  "DynamicView::DynamicView(): Fence after copying chunks to the "
537  "device");
538  }
539  }
540 
541  DynamicView(const std::string& arg_label, const unsigned min_chunk_size,
542  const unsigned max_extent)
543  : DynamicView(Kokkos::view_alloc(arg_label), min_chunk_size, max_extent) {
544  }
545 };
546 
547 } // namespace Experimental
548 
549 template <class>
550 struct is_dynamic_view : public std::false_type {};
551 
552 template <class D, class... P>
553 struct is_dynamic_view<Kokkos::Experimental::DynamicView<D, P...>>
554  : public std::true_type {};
555 
556 template <class T>
557 inline constexpr bool is_dynamic_view_v = is_dynamic_view<T>::value;
558 
559 } // namespace Kokkos
560 
561 namespace Kokkos {
562 
563 namespace Impl {
564 
565 // Deduce Mirror Types
566 template <class Space, class T, class... P>
567 struct MirrorDynamicViewType {
568  // The incoming view_type
569  using src_view_type = typename Kokkos::Experimental::DynamicView<T, P...>;
570  // The memory space for the mirror view
571  using memory_space = typename Space::memory_space;
572  // Check whether it is the same memory space
573  enum {
574  is_same_memspace =
575  std::is_same<memory_space, typename src_view_type::memory_space>::value
576  };
577  // The array_layout
578  using array_layout = typename src_view_type::array_layout;
579  // The data type (we probably want it non-const since otherwise we can't even
580  // deep_copy to it.)
581  using data_type = typename src_view_type::non_const_data_type;
582  // The destination view type if it is not the same memory space
583  using dest_view_type =
585  // If it is the same memory_space return the existing view_type
586  // This will also keep the unmanaged trait if necessary
587  using view_type =
588  std::conditional_t<is_same_memspace, src_view_type, dest_view_type>;
589 };
590 } // namespace Impl
591 
592 namespace Impl {
593 template <class T, class... P, class... ViewCtorArgs>
594 inline auto create_mirror(
596  const Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop,
597  std::enable_if_t<!Impl::ViewCtorProp<ViewCtorArgs...>::has_memory_space>* =
598  nullptr) {
599  using alloc_prop_input = Impl::ViewCtorProp<ViewCtorArgs...>;
600 
601  static_assert(
602  !alloc_prop_input::has_label,
603  "The view constructor arguments passed to Kokkos::create_mirror "
604  "must not include a label!");
605  static_assert(
606  !alloc_prop_input::has_pointer,
607  "The view constructor arguments passed to Kokkos::create_mirror must "
608  "not include a pointer!");
609  static_assert(
610  !alloc_prop_input::allow_padding,
611  "The view constructor arguments passed to Kokkos::create_mirror must "
612  "not explicitly allow padding!");
613 
614  auto prop_copy = Impl::with_properties_if_unset(
615  arg_prop, std::string(src.label()).append("_mirror"));
616 
618  prop_copy, src.chunk_size(), src.chunk_max() * src.chunk_size());
619 
620  ret.resize_serial(src.extent(0));
621 
622  return ret;
623 }
624 
625 template <class T, class... P, class... ViewCtorArgs>
626 inline auto create_mirror(
628  const Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop,
629  std::enable_if_t<Impl::ViewCtorProp<ViewCtorArgs...>::has_memory_space>* =
630  nullptr) {
631  using alloc_prop_input = Impl::ViewCtorProp<ViewCtorArgs...>;
632 
633  static_assert(
634  !alloc_prop_input::has_label,
635  "The view constructor arguments passed to Kokkos::create_mirror "
636  "must not include a label!");
637  static_assert(
638  !alloc_prop_input::has_pointer,
639  "The view constructor arguments passed to Kokkos::create_mirror must "
640  "not include a pointer!");
641  static_assert(
642  !alloc_prop_input::allow_padding,
643  "The view constructor arguments passed to Kokkos::create_mirror must "
644  "not explicitly allow padding!");
645 
646  using MemorySpace = typename alloc_prop_input::memory_space;
647  auto prop_copy = Impl::with_properties_if_unset(
648  arg_prop, std::string(src.label()).append("_mirror"));
649 
650  auto ret = typename Kokkos::Impl::MirrorDynamicViewType<
651  MemorySpace, T, P...>::view_type(prop_copy, src.chunk_size(),
652  src.chunk_max() * src.chunk_size());
653 
654  ret.resize_serial(src.extent(0));
655 
656  return ret;
657 }
658 } // namespace Impl
659 
660 // Create a mirror in host space
661 template <class T, class... P>
662 inline auto create_mirror(
664  return Impl::create_mirror(src, Impl::ViewCtorProp<>{});
665 }
666 
667 template <class T, class... P>
668 inline auto create_mirror(
669  Kokkos::Impl::WithoutInitializing_t wi,
671  return Impl::create_mirror(src, Kokkos::view_alloc(wi));
672 }
673 
674 // Create a mirror in a new space
675 template <class Space, class T, class... P>
676 inline auto create_mirror(
677  const Space&, const Kokkos::Experimental::DynamicView<T, P...>& src) {
678  return Impl::create_mirror(
679  src, Kokkos::view_alloc(typename Space::memory_space{}));
680 }
681 
682 template <class Space, class T, class... P>
683 typename Kokkos::Impl::MirrorDynamicViewType<Space, T, P...>::view_type
684 create_mirror(Kokkos::Impl::WithoutInitializing_t wi, const Space&,
686  return Impl::create_mirror(
687  src, Kokkos::view_alloc(wi, typename Space::memory_space{}));
688 }
689 
690 template <class T, class... P, class... ViewCtorArgs>
691 inline auto create_mirror(
692  const Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop,
694  return Impl::create_mirror(src, arg_prop);
695 }
696 
697 namespace Impl {
698 
699 template <class T, class... P, class... ViewCtorArgs>
700 inline std::enable_if_t<
701  !Impl::ViewCtorProp<ViewCtorArgs...>::has_memory_space &&
702  (std::is_same<
703  typename Kokkos::Experimental::DynamicView<T, P...>::memory_space,
705  T, P...>::HostMirror::memory_space>::value &&
706  std::is_same<
707  typename Kokkos::Experimental::DynamicView<T, P...>::data_type,
709  T, P...>::HostMirror::data_type>::value),
711 create_mirror_view(const Kokkos::Experimental::DynamicView<T, P...>& src,
712  const Impl::ViewCtorProp<ViewCtorArgs...>&) {
713  return src;
714 }
715 
716 template <class T, class... P, class... ViewCtorArgs>
717 inline std::enable_if_t<
718  !Impl::ViewCtorProp<ViewCtorArgs...>::has_memory_space &&
719  !(std::is_same<
720  typename Kokkos::Experimental::DynamicView<T, P...>::memory_space,
722  T, P...>::HostMirror::memory_space>::value &&
723  std::is_same<
724  typename Kokkos::Experimental::DynamicView<T, P...>::data_type,
726  T, P...>::HostMirror::data_type>::value),
728 create_mirror_view(const Kokkos::Experimental::DynamicView<T, P...>& src,
729  const Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop) {
730  return Kokkos::create_mirror(arg_prop, src);
731 }
732 
733 template <class T, class... P, class... ViewCtorArgs,
734  class = std::enable_if_t<
735  Impl::ViewCtorProp<ViewCtorArgs...>::has_memory_space>>
736 std::enable_if_t<Impl::MirrorDynamicViewType<
737  typename Impl::ViewCtorProp<ViewCtorArgs...>::memory_space,
738  T, P...>::is_same_memspace,
739  typename Impl::MirrorDynamicViewType<
740  typename Impl::ViewCtorProp<ViewCtorArgs...>::memory_space,
741  T, P...>::view_type>
742 create_mirror_view(const Kokkos::Experimental::DynamicView<T, P...>& src,
743  const Impl::ViewCtorProp<ViewCtorArgs...>&) {
744  return src;
745 }
746 
747 template <class T, class... P, class... ViewCtorArgs,
748  class = std::enable_if_t<
749  Impl::ViewCtorProp<ViewCtorArgs...>::has_memory_space>>
750 std::enable_if_t<!Impl::MirrorDynamicViewType<
751  typename Impl::ViewCtorProp<ViewCtorArgs...>::memory_space,
752  T, P...>::is_same_memspace,
753  typename Impl::MirrorDynamicViewType<
754  typename Impl::ViewCtorProp<ViewCtorArgs...>::memory_space,
755  T, P...>::view_type>
756 create_mirror_view(const Kokkos::Experimental::DynamicView<T, P...>& src,
757  const Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop) {
758  return Kokkos::Impl::create_mirror(src, arg_prop);
759 }
760 } // namespace Impl
761 
762 // Create a mirror view in host space
763 template <class T, class... P>
764 inline auto create_mirror_view(
765  const typename Kokkos::Experimental::DynamicView<T, P...>& src) {
766  return Impl::create_mirror_view(src, Impl::ViewCtorProp<>{});
767 }
768 
769 template <class T, class... P>
770 inline auto create_mirror_view(
771  Kokkos::Impl::WithoutInitializing_t wi,
772  const typename Kokkos::Experimental::DynamicView<T, P...>& src) {
773  return Impl::create_mirror_view(src, Kokkos::view_alloc(wi));
774 }
775 
776 // Create a mirror in a new space
777 template <class Space, class T, class... P>
778 inline auto create_mirror_view(
779  const Space&, const Kokkos::Experimental::DynamicView<T, P...>& src) {
780  return Impl::create_mirror_view(src,
781  view_alloc(typename Space::memory_space{}));
782 }
783 
784 template <class Space, class T, class... P>
785 inline auto create_mirror_view(
786  Kokkos::Impl::WithoutInitializing_t wi, const Space&,
788  return Impl::create_mirror_view(
789  src, Kokkos::view_alloc(wi, typename Space::memory_space{}));
790 }
791 
792 template <class T, class... P, class... ViewCtorArgs>
793 inline auto create_mirror_view(
794  const Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop,
796  return Impl::create_mirror_view(src, arg_prop);
797 }
798 
799 template <class T, class... DP, class... SP>
800 inline void deep_copy(const Kokkos::Experimental::DynamicView<T, DP...>& dst,
802  using dst_type = Kokkos::Experimental::DynamicView<T, DP...>;
803  using src_type = Kokkos::Experimental::DynamicView<T, SP...>;
804 
805  using dst_execution_space = typename ViewTraits<T, DP...>::execution_space;
806  using src_execution_space = typename ViewTraits<T, SP...>::execution_space;
807  using dst_memory_space = typename ViewTraits<T, DP...>::memory_space;
808  using src_memory_space = typename ViewTraits<T, SP...>::memory_space;
809 
810  constexpr bool DstExecCanAccessSrc =
811  Kokkos::SpaceAccessibility<dst_execution_space,
812  src_memory_space>::accessible;
813  constexpr bool SrcExecCanAccessDst =
814  Kokkos::SpaceAccessibility<src_execution_space,
815  dst_memory_space>::accessible;
816 
817  if (DstExecCanAccessSrc)
818  Kokkos::Impl::ViewRemap<dst_type, src_type, dst_execution_space>(dst, src);
819  else if (SrcExecCanAccessDst)
820  Kokkos::Impl::ViewRemap<dst_type, src_type, src_execution_space>(dst, src);
821  else
822  src.impl_get_chunks().deep_copy_to(dst_execution_space{},
823  dst.impl_get_chunks());
824  Kokkos::fence("Kokkos::deep_copy(DynamicView)");
825 }
826 
827 template <class ExecutionSpace, class T, class... DP, class... SP>
828 inline void deep_copy(const ExecutionSpace& exec,
831  using dst_type = Kokkos::Experimental::DynamicView<T, DP...>;
832  using src_type = Kokkos::Experimental::DynamicView<T, SP...>;
833 
834  using dst_execution_space = typename ViewTraits<T, DP...>::execution_space;
835  using src_execution_space = typename ViewTraits<T, SP...>::execution_space;
836  using dst_memory_space = typename ViewTraits<T, DP...>::memory_space;
837  using src_memory_space = typename ViewTraits<T, SP...>::memory_space;
838 
839  constexpr bool DstExecCanAccessSrc =
840  Kokkos::SpaceAccessibility<dst_execution_space,
841  src_memory_space>::accessible;
842  constexpr bool SrcExecCanAccessDst =
843  Kokkos::SpaceAccessibility<src_execution_space,
844  dst_memory_space>::accessible;
845 
846  // FIXME use execution space
847  if (DstExecCanAccessSrc)
848  Kokkos::Impl::ViewRemap<dst_type, src_type, dst_execution_space>(dst, src);
849  else if (SrcExecCanAccessDst)
850  Kokkos::Impl::ViewRemap<dst_type, src_type, src_execution_space>(dst, src);
851  else
852  src.impl_get_chunks().deep_copy_to(exec, dst.impl_get_chunks());
853 }
854 
855 template <class T, class... DP, class... SP>
856 inline void deep_copy(const View<T, DP...>& dst,
858  using dst_type = View<T, DP...>;
859  using src_type = Kokkos::Experimental::DynamicView<T, SP...>;
860 
861  using dst_execution_space = typename ViewTraits<T, DP...>::execution_space;
862  using src_memory_space = typename ViewTraits<T, SP...>::memory_space;
863 
864  enum {
865  DstExecCanAccessSrc =
866  Kokkos::SpaceAccessibility<dst_execution_space,
867  src_memory_space>::accessible
868  };
869 
870  if (DstExecCanAccessSrc) {
871  // Copying data between views in accessible memory spaces and either
872  // non-contiguous or incompatible shape.
873  Kokkos::Impl::ViewRemap<dst_type, src_type>(dst, src);
874  Kokkos::fence("Kokkos::deep_copy(DynamicView)");
875  } else {
876  Kokkos::Impl::throw_runtime_exception(
877  "deep_copy given views that would require a temporary allocation");
878  }
879 }
880 
881 template <class T, class... DP, class... SP>
882 inline void deep_copy(const Kokkos::Experimental::DynamicView<T, DP...>& dst,
883  const View<T, SP...>& src) {
884  using dst_type = Kokkos::Experimental::DynamicView<T, DP...>;
885  using src_type = View<T, SP...>;
886 
887  using dst_execution_space = typename ViewTraits<T, DP...>::execution_space;
888  using src_memory_space = typename ViewTraits<T, SP...>::memory_space;
889 
890  enum {
891  DstExecCanAccessSrc =
892  Kokkos::SpaceAccessibility<dst_execution_space,
893  src_memory_space>::accessible
894  };
895 
896  if (DstExecCanAccessSrc) {
897  // Copying data between views in accessible memory spaces and either
898  // non-contiguous or incompatible shape.
899  Kokkos::Impl::ViewRemap<dst_type, src_type>(dst, src);
900  Kokkos::fence("Kokkos::deep_copy(DynamicView)");
901  } else {
902  Kokkos::Impl::throw_runtime_exception(
903  "deep_copy given views that would require a temporary allocation");
904  }
905 }
906 
907 namespace Impl {
908 template <class Arg0, class... DP, class... SP>
909 struct CommonSubview<Kokkos::Experimental::DynamicView<DP...>,
910  Kokkos::Experimental::DynamicView<SP...>, 1, Arg0> {
911  using DstType = Kokkos::Experimental::DynamicView<DP...>;
912  using SrcType = Kokkos::Experimental::DynamicView<SP...>;
913  using dst_subview_type = DstType;
914  using src_subview_type = SrcType;
915  dst_subview_type dst_sub;
916  src_subview_type src_sub;
917  CommonSubview(const DstType& dst, const SrcType& src, const Arg0& /*arg0*/)
918  : dst_sub(dst), src_sub(src) {}
919 };
920 
921 template <class... DP, class SrcType, class Arg0>
922 struct CommonSubview<Kokkos::Experimental::DynamicView<DP...>, SrcType, 1,
923  Arg0> {
924  using DstType = Kokkos::Experimental::DynamicView<DP...>;
925  using dst_subview_type = DstType;
926  using src_subview_type = typename Kokkos::Subview<SrcType, Arg0>;
927  dst_subview_type dst_sub;
928  src_subview_type src_sub;
929  CommonSubview(const DstType& dst, const SrcType& src, const Arg0& arg0)
930  : dst_sub(dst), src_sub(src, arg0) {}
931 };
932 
933 template <class DstType, class... SP, class Arg0>
934 struct CommonSubview<DstType, Kokkos::Experimental::DynamicView<SP...>, 1,
935  Arg0> {
936  using SrcType = Kokkos::Experimental::DynamicView<SP...>;
937  using dst_subview_type = typename Kokkos::Subview<DstType, Arg0>;
938  using src_subview_type = SrcType;
939  dst_subview_type dst_sub;
940  src_subview_type src_sub;
941  CommonSubview(const DstType& dst, const SrcType& src, const Arg0& arg0)
942  : dst_sub(dst, arg0), src_sub(src) {}
943 };
944 
945 template <class... DP, class ViewTypeB, class Layout, class ExecSpace,
946  typename iType>
947 struct ViewCopy<Kokkos::Experimental::DynamicView<DP...>, ViewTypeB, Layout,
948  ExecSpace, 1, iType> {
950  ViewTypeB b;
951 
953 
954  ViewCopy(const Kokkos::Experimental::DynamicView<DP...>& a_,
955  const ViewTypeB& b_)
956  : a(a_), b(b_) {
957  Kokkos::parallel_for("Kokkos::ViewCopy-1D", policy_type(0, b.extent(0)),
958  *this);
959  }
960 
961  KOKKOS_INLINE_FUNCTION
962  void operator()(const iType& i0) const { a(i0) = b(i0); };
963 };
964 
965 template <class... DP, class... SP, class Layout, class ExecSpace,
966  typename iType>
967 struct ViewCopy<Kokkos::Experimental::DynamicView<DP...>,
968  Kokkos::Experimental::DynamicView<SP...>, Layout, ExecSpace, 1,
969  iType> {
972 
974 
975  ViewCopy(const Kokkos::Experimental::DynamicView<DP...>& a_,
977  : a(a_), b(b_) {
978  const iType n = std::min(a.extent(0), b.extent(0));
979  Kokkos::parallel_for("Kokkos::ViewCopy-1D", policy_type(0, n), *this);
980  }
981 
982  KOKKOS_INLINE_FUNCTION
983  void operator()(const iType& i0) const { a(i0) = b(i0); };
984 };
985 
986 } // namespace Impl
987 
988 template <class... ViewCtorArgs, class T, class... P>
989 auto create_mirror_view_and_copy(
990  const Impl::ViewCtorProp<ViewCtorArgs...>&,
992  std::enable_if_t<
993  std::is_void<typename ViewTraits<T, P...>::specialize>::value &&
994  Impl::MirrorDynamicViewType<
995  typename Impl::ViewCtorProp<ViewCtorArgs...>::memory_space, T,
996  P...>::is_same_memspace>* = nullptr) {
997  using alloc_prop_input = Impl::ViewCtorProp<ViewCtorArgs...>;
998  static_assert(
999  alloc_prop_input::has_memory_space,
1000  "The view constructor arguments passed to "
1001  "Kokkos::create_mirror_view_and_copy must include a memory space!");
1002  static_assert(!alloc_prop_input::has_pointer,
1003  "The view constructor arguments passed to "
1004  "Kokkos::create_mirror_view_and_copy must "
1005  "not include a pointer!");
1006  static_assert(!alloc_prop_input::allow_padding,
1007  "The view constructor arguments passed to "
1008  "Kokkos::create_mirror_view_and_copy must "
1009  "not explicitly allow padding!");
1010 
1011  // same behavior as deep_copy(src, src)
1012  if (!alloc_prop_input::has_execution_space)
1013  fence(
1014  "Kokkos::create_mirror_view_and_copy: fence before returning src view");
1015  return src;
1016 }
1017 
1018 template <class... ViewCtorArgs, class T, class... P>
1019 auto create_mirror_view_and_copy(
1020  const Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop,
1022  std::enable_if_t<
1023  std::is_void<typename ViewTraits<T, P...>::specialize>::value &&
1024  !Impl::MirrorDynamicViewType<
1025  typename Impl::ViewCtorProp<ViewCtorArgs...>::memory_space, T,
1026  P...>::is_same_memspace>* = nullptr) {
1027  using alloc_prop_input = Impl::ViewCtorProp<ViewCtorArgs...>;
1028  static_assert(
1029  alloc_prop_input::has_memory_space,
1030  "The view constructor arguments passed to "
1031  "Kokkos::create_mirror_view_and_copy must include a memory space!");
1032  static_assert(!alloc_prop_input::has_pointer,
1033  "The view constructor arguments passed to "
1034  "Kokkos::create_mirror_view_and_copy must "
1035  "not include a pointer!");
1036  static_assert(!alloc_prop_input::allow_padding,
1037  "The view constructor arguments passed to "
1038  "Kokkos::create_mirror_view_and_copy must "
1039  "not explicitly allow padding!");
1040  using Space = typename alloc_prop_input::memory_space;
1041  using Mirror =
1042  typename Impl::MirrorDynamicViewType<Space, T, P...>::view_type;
1043 
1044  auto arg_prop_copy = Impl::with_properties_if_unset(
1045  arg_prop, std::string{}, WithoutInitializing,
1046  typename Space::execution_space{});
1047 
1048  std::string& label = Impl::get_property<Impl::LabelTag>(arg_prop_copy);
1049  if (label.empty()) label = src.label();
1050  auto mirror = typename Mirror::non_const_type(
1051  arg_prop_copy, src.chunk_size(), src.chunk_max() * src.chunk_size());
1052  mirror.resize_serial(src.extent(0));
1053  if constexpr (alloc_prop_input::has_execution_space) {
1054  deep_copy(Impl::get_property<Impl::ExecutionSpaceTag>(arg_prop_copy),
1055  mirror, src);
1056  } else
1057  deep_copy(mirror, src);
1058  return mirror;
1059 }
1060 
1061 template <class Space, class T, class... P>
1062 auto create_mirror_view_and_copy(
1063  const Space&, const Kokkos::Experimental::DynamicView<T, P...>& src,
1064  std::string const& name = "") {
1065  return create_mirror_view_and_copy(
1066  Kokkos::view_alloc(typename Space::memory_space{}, name), src);
1067 }
1068 
1069 } // namespace Kokkos
1070 
1071 #ifdef KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_DYNAMICVIEW
1072 #undef KOKKOS_IMPL_PUBLIC_INCLUDE
1073 #undef KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_DYNAMICVIEW
1074 #endif
1075 #endif /* #ifndef KOKKOS_DYNAMIC_VIEW_HPP */
DynamicView< typename traits::data_type, typename traits::device_type > array_type
Dynamic views are restricted to rank-one and no layout. Resize only occurs on host outside of paralle...
Can AccessSpace access MemorySpace ?
Kokkos::Device< typename traits::device_type::execution_space, Kokkos::AnonymousSpace > uniform_device
DynamicView< typename traits::const_data_type, typename traits::device_type > const_type
DynamicView< typename traits::non_const_data_type, typename traits::device_type > non_const_type
void resize_serial(IntType const &n)
Execution policy for work over a range of an integral type.
Traits class for accessing attributes of a View.
Access relationship between DstMemorySpace and SrcMemorySpace.