Kokkos Core Kernels Package Version of the Day
Loading...
Searching...
No Matches
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
29namespace Kokkos {
30namespace Experimental {
31
32namespace Impl {
33
37template <typename MemorySpace, typename ValueType>
38struct 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(
60 Kokkos::Impl::MemorySpaceAccess<MemorySpace, Space>::assignable,
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
230template <typename DataType, typename... P>
231class 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;
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_v<typename traits::specialize>,
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
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
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_v<reference_type>
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
549template <class>
550struct is_dynamic_view : public std::false_type {};
551
552template <class D, class... P>
553struct is_dynamic_view<Kokkos::Experimental::DynamicView<D, P...>>
554 : public std::true_type {};
555
556template <class T>
557inline constexpr bool is_dynamic_view_v = is_dynamic_view<T>::value;
558
559} // namespace Kokkos
560
561namespace Kokkos {
562
563namespace Impl {
564
565// Deduce Mirror Types
566template <class Space, class T, class... P>
567struct 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_v<memory_space, typename src_view_type::memory_space>
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 =
584 Kokkos::Experimental::DynamicView<data_type, array_layout, Space>;
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
592namespace Impl {
593
594// create a mirror
595// private interface that accepts arbitrary view constructor args passed by a
596// view_alloc
597template <class T, class... P, class... ViewCtorArgs>
598inline auto create_mirror(const Kokkos::Experimental::DynamicView<T, P...>& src,
599 const Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop) {
600 using alloc_prop_input = Impl::ViewCtorProp<ViewCtorArgs...>;
601 check_view_ctor_args_create_mirror<ViewCtorArgs...>();
602
603 auto prop_copy = Impl::with_properties_if_unset(
604 arg_prop, std::string(src.label()).append("_mirror"));
605
606 if constexpr (Impl::ViewCtorProp<ViewCtorArgs...>::has_memory_space) {
607 using MemorySpace = typename alloc_prop_input::memory_space;
608
609 auto ret = typename Kokkos::Impl::MirrorDynamicViewType<
610 MemorySpace, T, P...>::view_type(prop_copy, src.chunk_size(),
611 src.chunk_max() * src.chunk_size());
612
613 ret.resize_serial(src.extent(0));
614
615 return ret;
616 } else {
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#if defined(KOKKOS_COMPILER_INTEL) || \
625 (defined(KOKKOS_COMPILER_NVCC) && KOKKOS_COMPILER_NVCC >= 1130 && \
626 !defined(KOKKOS_COMPILER_MSVC))
627 __builtin_unreachable();
628#endif
629}
630
631} // namespace Impl
632
633// public interface
634template <class T, class... P,
635 typename Enable = std::enable_if_t<
636 std::is_void_v<typename ViewTraits<T, P...>::specialize>>>
637inline auto create_mirror(
638 const Kokkos::Experimental::DynamicView<T, P...>& src) {
639 return Impl::create_mirror(src, Impl::ViewCtorProp<>{});
640}
641
642// public interface that accepts a without initializing flag
643template <class T, class... P,
644 typename Enable = std::enable_if_t<
645 std::is_void_v<typename ViewTraits<T, P...>::specialize>>>
646inline auto create_mirror(
647 Kokkos::Impl::WithoutInitializing_t wi,
648 const Kokkos::Experimental::DynamicView<T, P...>& src) {
649 return Impl::create_mirror(src, Kokkos::view_alloc(wi));
650}
651
652// public interface that accepts a space
653template <class Space, class T, class... P,
654 typename Enable = std::enable_if_t<
655 Kokkos::is_space<Space>::value &&
656 std::is_void_v<typename ViewTraits<T, P...>::specialize>>>
657inline auto create_mirror(
658 const Space&, const Kokkos::Experimental::DynamicView<T, P...>& src) {
659 return Impl::create_mirror(
660 src, Kokkos::view_alloc(typename Space::memory_space{}));
661}
662
663// public interface that accepts a space and a without initializing flag
664template <class Space, class T, class... P,
665 typename Enable = std::enable_if_t<
666 Kokkos::is_space<Space>::value &&
667 std::is_void_v<typename ViewTraits<T, P...>::specialize>>>
668inline auto create_mirror(
669 Kokkos::Impl::WithoutInitializing_t wi, const Space&,
670 const Kokkos::Experimental::DynamicView<T, P...>& src) {
671 return Impl::create_mirror(
672 src, Kokkos::view_alloc(wi, typename Space::memory_space{}));
673}
674
675// public interface that accepts arbitrary view constructor args passed by a
676// view_alloc
677template <class T, class... P, class... ViewCtorArgs,
678 typename Enable = std::enable_if_t<
679 std::is_void_v<typename ViewTraits<T, P...>::specialize>>>
680inline auto create_mirror(
681 const Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop,
682 const Kokkos::Experimental::DynamicView<T, P...>& src) {
683 return Impl::create_mirror(src, arg_prop);
684}
685
686namespace Impl {
687
688// create a mirror view
689// private interface that accepts arbitrary view constructor args passed by a
690// view_alloc
691template <class T, class... P, class... ViewCtorArgs>
692inline auto create_mirror_view(
693 const Kokkos::Experimental::DynamicView<T, P...>& src,
694 [[maybe_unused]] const Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop) {
695 if constexpr (!Impl::ViewCtorProp<ViewCtorArgs...>::has_memory_space) {
696 if constexpr (std::is_same_v<typename Kokkos::Experimental::DynamicView<
697 T, P...>::memory_space,
698 typename Kokkos::Experimental::DynamicView<
699 T, P...>::HostMirror::memory_space> &&
700 std::is_same_v<typename Kokkos::Experimental::DynamicView<
701 T, P...>::data_type,
702 typename Kokkos::Experimental::DynamicView<
703 T, P...>::HostMirror::data_type>) {
704 return
706 } else {
707 return Kokkos::Impl::choose_create_mirror(src, arg_prop);
708 }
709 } else {
710 if constexpr (Impl::MirrorDynamicViewType<
711 typename Impl::ViewCtorProp<
712 ViewCtorArgs...>::memory_space,
713 T, P...>::is_same_memspace) {
714 return typename Impl::MirrorDynamicViewType<
715 typename Impl::ViewCtorProp<ViewCtorArgs...>::memory_space, T,
716 P...>::view_type(src);
717 } else {
718 return Kokkos::Impl::choose_create_mirror(src, arg_prop);
719 }
720 }
721#if defined(KOKKOS_COMPILER_INTEL) || \
722 (defined(KOKKOS_COMPILER_NVCC) && KOKKOS_COMPILER_NVCC >= 1130 && \
723 !defined(KOKKOS_COMPILER_MSVC))
724 __builtin_unreachable();
725#endif
726}
727
728} // namespace Impl
729
730// public interface
731template <class T, class... P>
732inline auto create_mirror_view(
733 const typename Kokkos::Experimental::DynamicView<T, P...>& src) {
734 return Impl::create_mirror_view(src, Impl::ViewCtorProp<>{});
735}
736
737// public interface that accepts a without initializing flag
738template <class T, class... P>
739inline auto create_mirror_view(
740 Kokkos::Impl::WithoutInitializing_t wi,
741 const typename Kokkos::Experimental::DynamicView<T, P...>& src) {
742 return Impl::create_mirror_view(src, Kokkos::view_alloc(wi));
743}
744
745// public interface that accepts a space
746template <class Space, class T, class... P,
747 class Enable = std::enable_if_t<Kokkos::is_space<Space>::value>>
748inline auto create_mirror_view(
749 const Space&, const Kokkos::Experimental::DynamicView<T, P...>& src) {
750 return Impl::create_mirror_view(src,
751 view_alloc(typename Space::memory_space{}));
752}
753
754// public interface that accepts a space and a without initializing flag
755template <class Space, class T, class... P,
756 class Enable = std::enable_if_t<Kokkos::is_space<Space>::value>>
757inline auto create_mirror_view(
758 Kokkos::Impl::WithoutInitializing_t wi, const Space&,
759 const Kokkos::Experimental::DynamicView<T, P...>& src) {
760 return Impl::create_mirror_view(
761 src, Kokkos::view_alloc(wi, typename Space::memory_space{}));
762}
763
764// public interface that accepts arbitrary view constructor args passed by a
765// view_alloc
766template <class T, class... P, class... ViewCtorArgs>
767inline auto create_mirror_view(
768 const Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop,
769 const Kokkos::Experimental::DynamicView<T, P...>& src) {
770 return Impl::create_mirror_view(src, arg_prop);
771}
772
773template <class T, class... DP, class... SP>
774inline void deep_copy(const Kokkos::Experimental::DynamicView<T, DP...>& dst,
775 const Kokkos::Experimental::DynamicView<T, SP...>& src) {
776 using dst_type = Kokkos::Experimental::DynamicView<T, DP...>;
777 using src_type = Kokkos::Experimental::DynamicView<T, SP...>;
778
779 using dst_execution_space = typename ViewTraits<T, DP...>::execution_space;
780 using src_execution_space = typename ViewTraits<T, SP...>::execution_space;
781 using dst_memory_space = typename ViewTraits<T, DP...>::memory_space;
782 using src_memory_space = typename ViewTraits<T, SP...>::memory_space;
783
784 constexpr bool DstExecCanAccessSrc =
785 Kokkos::SpaceAccessibility<dst_execution_space,
786 src_memory_space>::accessible;
787 constexpr bool SrcExecCanAccessDst =
788 Kokkos::SpaceAccessibility<src_execution_space,
789 dst_memory_space>::accessible;
790
791 if (DstExecCanAccessSrc)
792 Kokkos::Impl::ViewRemap<dst_type, src_type, dst_execution_space>(dst, src);
793 else if (SrcExecCanAccessDst)
794 Kokkos::Impl::ViewRemap<dst_type, src_type, src_execution_space>(dst, src);
795 else
796 src.impl_get_chunks().deep_copy_to(dst_execution_space{},
797 dst.impl_get_chunks());
798 Kokkos::fence("Kokkos::deep_copy(DynamicView)");
799}
800
801template <class ExecutionSpace, class T, class... DP, class... SP>
802inline void deep_copy(const ExecutionSpace& exec,
803 const Kokkos::Experimental::DynamicView<T, DP...>& dst,
804 const Kokkos::Experimental::DynamicView<T, SP...>& src) {
805 using dst_type = Kokkos::Experimental::DynamicView<T, DP...>;
806 using src_type = Kokkos::Experimental::DynamicView<T, SP...>;
807
808 using dst_execution_space = typename ViewTraits<T, DP...>::execution_space;
809 using src_execution_space = typename ViewTraits<T, SP...>::execution_space;
810 using dst_memory_space = typename ViewTraits<T, DP...>::memory_space;
811 using src_memory_space = typename ViewTraits<T, SP...>::memory_space;
812
813 constexpr bool DstExecCanAccessSrc =
814 Kokkos::SpaceAccessibility<dst_execution_space,
815 src_memory_space>::accessible;
816 constexpr bool SrcExecCanAccessDst =
817 Kokkos::SpaceAccessibility<src_execution_space,
818 dst_memory_space>::accessible;
819
820 // FIXME use execution space
821 if (DstExecCanAccessSrc)
822 Kokkos::Impl::ViewRemap<dst_type, src_type, dst_execution_space>(dst, src);
823 else if (SrcExecCanAccessDst)
824 Kokkos::Impl::ViewRemap<dst_type, src_type, src_execution_space>(dst, src);
825 else
826 src.impl_get_chunks().deep_copy_to(exec, dst.impl_get_chunks());
827}
828
829template <class T, class... DP, class... SP>
830inline void deep_copy(const View<T, DP...>& dst,
831 const Kokkos::Experimental::DynamicView<T, SP...>& src) {
832 using dst_type = View<T, DP...>;
833 using src_type = Kokkos::Experimental::DynamicView<T, SP...>;
834
835 using dst_execution_space = typename ViewTraits<T, DP...>::execution_space;
836 using src_memory_space = typename ViewTraits<T, SP...>::memory_space;
837
838 constexpr bool DstExecCanAccessSrc =
839 Kokkos::SpaceAccessibility<dst_execution_space,
840 src_memory_space>::accessible;
841 static_assert(
842 DstExecCanAccessSrc,
843 "deep_copy given views that would require a temporary allocation");
844
845 // Copying data between views in accessible memory spaces and either
846 // non-contiguous or incompatible shape.
847 Kokkos::Impl::ViewRemap<dst_type, src_type>(dst, src);
848 Kokkos::fence("Kokkos::deep_copy(DynamicView)");
849}
850
851template <class T, class... DP, class... SP>
852inline void deep_copy(const Kokkos::Experimental::DynamicView<T, DP...>& dst,
853 const View<T, SP...>& src) {
854 using dst_type = Kokkos::Experimental::DynamicView<T, DP...>;
855 using src_type = View<T, SP...>;
856
857 using dst_execution_space = typename ViewTraits<T, DP...>::execution_space;
858 using src_memory_space = typename ViewTraits<T, SP...>::memory_space;
859
860 constexpr bool DstExecCanAccessSrc =
861 Kokkos::SpaceAccessibility<dst_execution_space,
862 src_memory_space>::accessible;
863 static_assert(
864 DstExecCanAccessSrc,
865 "deep_copy given views that would require a temporary allocation");
866
867 // Copying data between views in accessible memory spaces and either
868 // non-contiguous or incompatible shape.
869 Kokkos::Impl::ViewRemap<dst_type, src_type>(dst, src);
870 Kokkos::fence("Kokkos::deep_copy(DynamicView)");
871}
872
873namespace Impl {
874template <class Arg0, class... DP, class... SP>
875struct CommonSubview<Kokkos::Experimental::DynamicView<DP...>,
876 Kokkos::Experimental::DynamicView<SP...>, 1, Arg0> {
877 using DstType = Kokkos::Experimental::DynamicView<DP...>;
878 using SrcType = Kokkos::Experimental::DynamicView<SP...>;
879 using dst_subview_type = DstType;
880 using src_subview_type = SrcType;
881 dst_subview_type dst_sub;
882 src_subview_type src_sub;
883 CommonSubview(const DstType& dst, const SrcType& src, const Arg0& /*arg0*/)
884 : dst_sub(dst), src_sub(src) {}
885};
886
887template <class... DP, class SrcType, class Arg0>
888struct CommonSubview<Kokkos::Experimental::DynamicView<DP...>, SrcType, 1,
889 Arg0> {
890 using DstType = Kokkos::Experimental::DynamicView<DP...>;
891 using dst_subview_type = DstType;
892 using src_subview_type = typename Kokkos::Subview<SrcType, Arg0>;
893 dst_subview_type dst_sub;
894 src_subview_type src_sub;
895 CommonSubview(const DstType& dst, const SrcType& src, const Arg0& arg0)
896 : dst_sub(dst), src_sub(src, arg0) {}
897};
898
899template <class DstType, class... SP, class Arg0>
900struct CommonSubview<DstType, Kokkos::Experimental::DynamicView<SP...>, 1,
901 Arg0> {
902 using SrcType = Kokkos::Experimental::DynamicView<SP...>;
903 using dst_subview_type = typename Kokkos::Subview<DstType, Arg0>;
904 using src_subview_type = SrcType;
905 dst_subview_type dst_sub;
906 src_subview_type src_sub;
907 CommonSubview(const DstType& dst, const SrcType& src, const Arg0& arg0)
908 : dst_sub(dst, arg0), src_sub(src) {}
909};
910
911template <class... DP, class ViewTypeB, class Layout, class ExecSpace,
912 typename iType>
913struct ViewCopy<Kokkos::Experimental::DynamicView<DP...>, ViewTypeB, Layout,
914 ExecSpace, 1, iType> {
915 Kokkos::Experimental::DynamicView<DP...> a;
916 ViewTypeB b;
917
918 using policy_type = Kokkos::RangePolicy<ExecSpace, Kokkos::IndexType<iType>>;
919
920 ViewCopy(const Kokkos::Experimental::DynamicView<DP...>& a_,
921 const ViewTypeB& b_)
922 : a(a_), b(b_) {
923 Kokkos::parallel_for("Kokkos::ViewCopy-1D", policy_type(0, b.extent(0)),
924 *this);
925 }
926
927 KOKKOS_INLINE_FUNCTION
928 void operator()(const iType& i0) const { a(i0) = b(i0); };
929};
930
931template <class... DP, class... SP, class Layout, class ExecSpace,
932 typename iType>
933struct ViewCopy<Kokkos::Experimental::DynamicView<DP...>,
934 Kokkos::Experimental::DynamicView<SP...>, Layout, ExecSpace, 1,
935 iType> {
936 Kokkos::Experimental::DynamicView<DP...> a;
937 Kokkos::Experimental::DynamicView<SP...> b;
938
939 using policy_type = Kokkos::RangePolicy<ExecSpace, Kokkos::IndexType<iType>>;
940
941 ViewCopy(const Kokkos::Experimental::DynamicView<DP...>& a_,
942 const Kokkos::Experimental::DynamicView<SP...>& b_)
943 : a(a_), b(b_) {
944 const iType n = std::min(a.extent(0), b.extent(0));
945 Kokkos::parallel_for("Kokkos::ViewCopy-1D", policy_type(0, n), *this);
946 }
947
948 KOKKOS_INLINE_FUNCTION
949 void operator()(const iType& i0) const { a(i0) = b(i0); };
950};
951
952} // namespace Impl
953
954// create a mirror view and deep copy it
955// public interface that accepts arbitrary view constructor args passed by a
956// view_alloc
957template <class... ViewCtorArgs, class T, class... P,
958 class Enable = std::enable_if_t<
959 std::is_void_v<typename ViewTraits<T, P...>::specialize>>>
960auto create_mirror_view_and_copy(
961 [[maybe_unused]] const Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop,
962 const Kokkos::Experimental::DynamicView<T, P...>& src) {
963 using alloc_prop_input = Impl::ViewCtorProp<ViewCtorArgs...>;
964
965 Impl::check_view_ctor_args_create_mirror_view_and_copy<ViewCtorArgs...>();
966
967 if constexpr (Impl::MirrorDynamicViewType<
968 typename Impl::ViewCtorProp<ViewCtorArgs...>::memory_space,
969 T, P...>::is_same_memspace) {
970 // same behavior as deep_copy(src, src)
971 if constexpr (!alloc_prop_input::has_execution_space)
972 fence(
973 "Kokkos::create_mirror_view_and_copy: fence before returning src "
974 "view");
975 return src;
976 } else {
977 using Space = typename alloc_prop_input::memory_space;
978 using Mirror =
979 typename Impl::MirrorDynamicViewType<Space, T, P...>::view_type;
980
981 auto arg_prop_copy = Impl::with_properties_if_unset(
982 arg_prop, std::string{}, WithoutInitializing,
983 typename Space::execution_space{});
984
985 std::string& label = Impl::get_property<Impl::LabelTag>(arg_prop_copy);
986 if (label.empty()) label = src.label();
987 auto mirror = typename Mirror::non_const_type(
988 arg_prop_copy, src.chunk_size(), src.chunk_max() * src.chunk_size());
989 mirror.resize_serial(src.extent(0));
990 if constexpr (alloc_prop_input::has_execution_space) {
991 deep_copy(Impl::get_property<Impl::ExecutionSpaceTag>(arg_prop_copy),
992 mirror, src);
993 } else
994 deep_copy(mirror, src);
995 return mirror;
996 }
997#if defined(KOKKOS_COMPILER_NVCC) && KOKKOS_COMPILER_NVCC >= 1130 && \
998 !defined(KOKKOS_COMPILER_MSVC)
999 __builtin_unreachable();
1000#endif
1001}
1002
1003template <class Space, class T, class... P,
1004 typename Enable = std::enable_if_t<Kokkos::is_space<Space>::value>>
1005auto create_mirror_view_and_copy(
1006 const Space&, const Kokkos::Experimental::DynamicView<T, P...>& src,
1007 std::string const& name = "") {
1008 return create_mirror_view_and_copy(
1009 Kokkos::view_alloc(typename Space::memory_space{}, name), src);
1010}
1011
1012} // namespace Kokkos
1013
1014#ifdef KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_DYNAMICVIEW
1015#undef KOKKOS_IMPL_PUBLIC_INCLUDE
1016#undef KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_DYNAMICVIEW
1017#endif
1018#endif /* #ifndef KOKKOS_DYNAMIC_VIEW_HPP */
Dynamic views are restricted to rank-one and no layout. Resize only occurs on host outside of paralle...
DynamicView(const Kokkos::Impl::ViewCtorProp< Prop... > &arg_prop, const unsigned min_chunk_size, const unsigned max_extent)
Allocation constructor.
DynamicView< typename traits::non_const_data_type, typename traits::device_type > non_const_type
void resize_serial(IntType const &n)
Resizing in serial can grow or shrink the array size up to the maximum number of chunks.
DynamicView< typename traits::data_type, typename traits::device_type > array_type
Compatible view of array of scalar types.
Kokkos::Device< typename traits::device_type::execution_space, Kokkos::AnonymousSpace > uniform_device
DynamicView< typename traits::const_data_type, typename traits::device_type > const_type
ScopeGuard Some user scope issues have been identified with some Kokkos::finalize calls; ScopeGuard a...