Kokkos Core Kernels Package Version of the Day
Loading...
Searching...
No Matches
Kokkos_DualView.hpp
Go to the documentation of this file.
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
22
23#ifndef KOKKOS_DUALVIEW_HPP
24#define KOKKOS_DUALVIEW_HPP
25#ifndef KOKKOS_IMPL_PUBLIC_INCLUDE
26#define KOKKOS_IMPL_PUBLIC_INCLUDE
27#define KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_DUALVIEW
28#endif
29
30#include <Kokkos_Core.hpp>
31#include <impl/Kokkos_Error.hpp>
32
33namespace Kokkos {
34
35/* \class DualView
36 * \brief Container to manage mirroring a Kokkos::View that lives
37 * in device memory with a Kokkos::View that lives in host memory.
38 *
39 * This class provides capabilities to manage data which exists in two
40 * memory spaces at the same time. It keeps views of the same layout
41 * on two memory spaces as well as modified flags for both
42 * allocations. Users are responsible for setting the modified flags
43 * manually if they change the data in either memory space, by calling
44 * the sync() method templated on the device where they modified the
45 * data. Users may synchronize data by calling the modify() function,
46 * templated on the device towards which they want to synchronize
47 * (i.e., the target of the one-way copy operation).
48 *
49 * The DualView class also provides convenience methods such as
50 * realloc, resize and capacity which call the appropriate methods of
51 * the underlying Kokkos::View objects.
52 *
53 * The four template arguments are the same as those of Kokkos::View.
54 * (Please refer to that class' documentation for a detailed
55 * description.)
56 *
57 * \tparam DataType The type of the entries stored in the container.
58 *
59 * \tparam Layout The array's layout in memory.
60 *
61 * \tparam Device The Kokkos Device type. If its memory space is
62 * not the same as the host's memory space, then DualView will
63 * contain two separate Views: one in device memory, and one in
64 * host memory. Otherwise, DualView will only store one View.
65 *
66 * \tparam MemoryTraits (optional) The user's intended memory access
67 * behavior. Please see the documentation of Kokkos::View for
68 * examples. The default suffices for most users.
69 */
70
71namespace Impl {
72
73#ifdef KOKKOS_ENABLE_CUDA
74
75inline const Kokkos::Cuda& get_cuda_space(const Kokkos::Cuda& in) { return in; }
76
77inline const Kokkos::Cuda& get_cuda_space() {
78 return *Kokkos::Impl::cuda_get_deep_copy_space();
79}
80
81template <typename NonCudaExecSpace>
82inline const Kokkos::Cuda& get_cuda_space(const NonCudaExecSpace&) {
83 return get_cuda_space();
84}
85
86#endif // KOKKOS_ENABLE_CUDA
87
88} // namespace Impl
89
90#ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
91template <class DataType, class Arg1Type = void, class Arg2Type = void,
92 class Arg3Type = void>
93class DualView;
94#else
95template <class DataType, class... Properties>
96class DualView;
97#endif
98
99template <class>
100struct is_dual_view : public std::false_type {};
101
102template <class DT, class... DP>
103struct is_dual_view<DualView<DT, DP...>> : public std::true_type {};
104
105template <class DT, class... DP>
106struct is_dual_view<const DualView<DT, DP...>> : public std::true_type {};
107
108template <class T>
109inline constexpr bool is_dual_view_v = is_dual_view<T>::value;
110
111#ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
112template <class DataType, class Arg1Type, class Arg2Type, class Arg3Type>
113class DualView : public ViewTraits<DataType, Arg1Type, Arg2Type, Arg3Type> {
114 template <class, class, class, class>
115#else
116template <class DataType, class... Properties>
117class DualView : public ViewTraits<DataType, Properties...> {
118 template <class, class...>
119#endif
120 friend class DualView;
121
122 public:
124
125#ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
126 using traits = ViewTraits<DataType, Arg1Type, Arg2Type, Arg3Type>;
127#else
128 using traits = ViewTraits<DataType, Properties...>;
129#endif
130
132 using host_mirror_space = typename traits::host_mirror_space;
133
135#ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
136 using t_dev = View<typename traits::data_type, Arg1Type, Arg2Type, Arg3Type>;
137#else
138 using t_dev = View<typename traits::data_type, Properties...>;
139#endif
140
143 using t_host = typename t_dev::HostMirror;
144
147#ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
148 using t_dev_const =
149 View<typename traits::const_data_type, Arg1Type, Arg2Type, Arg3Type>;
150#else
151 using t_dev_const = View<typename traits::const_data_type, Properties...>;
152#endif
153
156 using t_host_const = typename t_dev_const::HostMirror;
157
159 using t_dev_const_randomread =
160 View<typename traits::const_data_type, typename traits::array_layout,
161 typename traits::device_type,
162 Kokkos::MemoryTraits<Kokkos::RandomAccess>>;
163
167 using t_host_const_randomread = typename t_dev_const_randomread::HostMirror;
168
170 using t_dev_um =
171 View<typename traits::data_type, typename traits::array_layout,
172 typename traits::device_type, MemoryUnmanaged>;
173
175 using t_host_um =
176 View<typename t_host::data_type, typename t_host::array_layout,
177 typename t_host::device_type, MemoryUnmanaged>;
178
180 using t_dev_const_um =
181 View<typename traits::const_data_type, typename traits::array_layout,
182 typename traits::device_type, MemoryUnmanaged>;
183
185 using t_host_const_um =
186 View<typename t_host::const_data_type, typename t_host::array_layout,
187 typename t_host::device_type, MemoryUnmanaged>;
188
190 using t_dev_const_randomread_um =
191 View<typename t_host::const_data_type, typename t_host::array_layout,
192 typename t_host::device_type,
193 Kokkos::MemoryTraits<Kokkos::Unmanaged | Kokkos::RandomAccess>>;
194
198 using t_host_const_randomread_um =
200
202
204
205 protected:
206 // modified_flags[0] -> host
207 // modified_flags[1] -> device
208 using t_modified_flags = View<unsigned int[2], LayoutLeft, Kokkos::HostSpace>;
209 t_modified_flags modified_flags;
210
211 public:
213
214 // Moved this specifically after modified_flags to resolve an alignment issue
215 // on MSVC/NVCC
217
218 t_dev d_view;
219 t_host h_view;
221
223
224
230 DualView() = default;
231
241 DualView(const std::string& label,
242 const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
243 const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
244 const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
245 const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
246 const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
247 const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
248 const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
249 const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG)
250 : modified_flags(
251 Kokkos::view_alloc(typename t_modified_flags::execution_space{},
252 "DualView::modified_flags")),
253 d_view(label, n0, n1, n2, n3, n4, n5, n6, n7),
254 h_view(create_mirror_view(d_view)) // without UVM, host View mirrors
255 {}
256
267 template <class... P>
268 DualView(const Impl::ViewCtorProp<P...>& arg_prop,
269 std::enable_if_t<!Impl::ViewCtorProp<P...>::has_pointer,
270 size_t> const n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
271 const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
272 const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
273 const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
274 const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
275 const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
276 const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
277 const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG)
278 : modified_flags(t_modified_flags("DualView::modified_flags")),
279 d_view(arg_prop, n0, n1, n2, n3, n4, n5, n6, n7) {
280 // without UVM, host View mirrors
281 if constexpr (Kokkos::Impl::has_type<Impl::WithoutInitializing_t,
282 P...>::value)
283 h_view = Kokkos::create_mirror_view(Kokkos::WithoutInitializing, d_view);
284 else
285 h_view = Kokkos::create_mirror_view(d_view);
286 }
287
289 template <typename DT, typename... DP>
290 DualView(const DualView<DT, DP...>& src)
291 : modified_flags(src.modified_flags),
292 d_view(src.d_view),
293 h_view(src.h_view) {}
294
296 template <class DT, class... DP, class Arg0, class... Args>
297 DualView(const DualView<DT, DP...>& src, const Arg0& arg0, Args... args)
298 : modified_flags(src.modified_flags),
299 d_view(Kokkos::subview(src.d_view, arg0, args...)),
300 h_view(Kokkos::subview(src.h_view, arg0, args...)) {}
301
312 DualView(const t_dev& d_view_, const t_host& h_view_)
313 : modified_flags(t_modified_flags("DualView::modified_flags")),
314 d_view(d_view_),
315 h_view(h_view_) {
316 if (int(d_view.rank) != int(h_view.rank) ||
317 d_view.extent(0) != h_view.extent(0) ||
318 d_view.extent(1) != h_view.extent(1) ||
319 d_view.extent(2) != h_view.extent(2) ||
320 d_view.extent(3) != h_view.extent(3) ||
321 d_view.extent(4) != h_view.extent(4) ||
322 d_view.extent(5) != h_view.extent(5) ||
323 d_view.extent(6) != h_view.extent(6) ||
324 d_view.extent(7) != h_view.extent(7) ||
325 d_view.stride_0() != h_view.stride_0() ||
326 d_view.stride_1() != h_view.stride_1() ||
327 d_view.stride_2() != h_view.stride_2() ||
328 d_view.stride_3() != h_view.stride_3() ||
329 d_view.stride_4() != h_view.stride_4() ||
330 d_view.stride_5() != h_view.stride_5() ||
331 d_view.stride_6() != h_view.stride_6() ||
332 d_view.stride_7() != h_view.stride_7() ||
333 d_view.span() != h_view.span()) {
334 Kokkos::Impl::throw_runtime_exception(
335 "DualView constructed with incompatible views");
336 }
337 }
338 // does the DualView have only one device
339 struct impl_dualview_is_single_device {
340 enum : bool {
341 value = std::is_same<typename t_dev::device_type,
342 typename t_host::device_type>::value
343 };
344 };
345
346 // does the given device match the device of t_dev?
347 template <typename Device>
348 struct impl_device_matches_tdev_device {
349 enum : bool {
350 value = std::is_same<typename t_dev::device_type, Device>::value
351 };
352 };
353 // does the given device match the device of t_host?
354 template <typename Device>
355 struct impl_device_matches_thost_device {
356 enum : bool {
357 value = std::is_same<typename t_host::device_type, Device>::value
358 };
359 };
360
361 // does the given device match the execution space of t_host?
362 template <typename Device>
363 struct impl_device_matches_thost_exec {
364 enum : bool {
365 value = std::is_same<typename t_host::execution_space, Device>::value
366 };
367 };
368
369 // does the given device match the execution space of t_dev?
370 template <typename Device>
371 struct impl_device_matches_tdev_exec {
372 enum : bool {
373 value = std::is_same<typename t_dev::execution_space, Device>::value
374 };
375 };
376
377 // does the given device's memory space match the memory space of t_dev?
378 template <typename Device>
379 struct impl_device_matches_tdev_memory_space {
380 enum : bool {
381 value = std::is_same<typename t_dev::memory_space,
382 typename Device::memory_space>::value
383 };
384 };
385
387
389
412 template <class Device>
413 KOKKOS_INLINE_FUNCTION const typename std::conditional_t<
414 impl_device_matches_tdev_device<Device>::value, t_dev,
415 typename std::conditional_t<
416 impl_device_matches_thost_device<Device>::value, t_host,
417 typename std::conditional_t<
418 impl_device_matches_thost_exec<Device>::value, t_host,
419 typename std::conditional_t<
420 impl_device_matches_tdev_exec<Device>::value, t_dev,
421 typename std::conditional_t<
422 impl_device_matches_tdev_memory_space<Device>::value,
423 t_dev, t_host>>>>>
424 view() const {
425 constexpr bool device_is_memspace =
426 std::is_same<Device, typename Device::memory_space>::value;
427 constexpr bool device_is_execspace =
428 std::is_same<Device, typename Device::execution_space>::value;
429 constexpr bool device_exec_is_t_dev_exec =
430 std::is_same<typename Device::execution_space,
431 typename t_dev::execution_space>::value;
432 constexpr bool device_mem_is_t_dev_mem =
433 std::is_same<typename Device::memory_space,
434 typename t_dev::memory_space>::value;
435 constexpr bool device_exec_is_t_host_exec =
436 std::is_same<typename Device::execution_space,
437 typename t_host::execution_space>::value;
438 constexpr bool device_mem_is_t_host_mem =
439 std::is_same<typename Device::memory_space,
440 typename t_host::memory_space>::value;
441 constexpr bool device_is_t_host_device =
442 std::is_same<typename Device::execution_space,
443 typename t_host::device_type>::value;
444 constexpr bool device_is_t_dev_device =
445 std::is_same<typename Device::memory_space,
446 typename t_host::device_type>::value;
447
448 static_assert(
449 device_is_t_dev_device || device_is_t_host_device ||
450 (device_is_memspace &&
451 (device_mem_is_t_dev_mem || device_mem_is_t_host_mem)) ||
452 (device_is_execspace &&
453 (device_exec_is_t_dev_exec || device_exec_is_t_host_exec)) ||
454 ((!device_is_execspace && !device_is_memspace) &&
455 ((device_mem_is_t_dev_mem || device_mem_is_t_host_mem) ||
456 (device_exec_is_t_dev_exec || device_exec_is_t_host_exec))),
457 "Template parameter to .view() must exactly match one of the "
458 "DualView's device types or one of the execution or memory spaces");
459
460 return Impl::if_c<std::is_same<typename t_dev::memory_space,
461 typename Device::memory_space>::value,
462 t_dev, t_host>::select(d_view, h_view);
463 }
464
465 KOKKOS_INLINE_FUNCTION
466 t_host view_host() const { return h_view; }
467
468 KOKKOS_INLINE_FUNCTION
469 t_dev view_device() const { return d_view; }
470
471 KOKKOS_INLINE_FUNCTION constexpr bool is_allocated() const {
472 return (d_view.is_allocated() && h_view.is_allocated());
473 }
474
475 template <class Device>
476 static int get_device_side() {
477 constexpr bool device_is_memspace =
478 std::is_same<Device, typename Device::memory_space>::value;
479 constexpr bool device_is_execspace =
480 std::is_same<Device, typename Device::execution_space>::value;
481 constexpr bool device_exec_is_t_dev_exec =
482 std::is_same<typename Device::execution_space,
483 typename t_dev::execution_space>::value;
484 constexpr bool device_mem_is_t_dev_mem =
485 std::is_same<typename Device::memory_space,
486 typename t_dev::memory_space>::value;
487 constexpr bool device_exec_is_t_host_exec =
488 std::is_same<typename Device::execution_space,
489 typename t_host::execution_space>::value;
490 constexpr bool device_mem_is_t_host_mem =
491 std::is_same<typename Device::memory_space,
492 typename t_host::memory_space>::value;
493 constexpr bool device_is_t_host_device =
494 std::is_same<typename Device::execution_space,
495 typename t_host::device_type>::value;
496 constexpr bool device_is_t_dev_device =
497 std::is_same<typename Device::memory_space,
498 typename t_host::device_type>::value;
499
500 static_assert(
501 device_is_t_dev_device || device_is_t_host_device ||
502 (device_is_memspace &&
503 (device_mem_is_t_dev_mem || device_mem_is_t_host_mem)) ||
504 (device_is_execspace &&
505 (device_exec_is_t_dev_exec || device_exec_is_t_host_exec)) ||
506 ((!device_is_execspace && !device_is_memspace) &&
507 ((device_mem_is_t_dev_mem || device_mem_is_t_host_mem) ||
508 (device_exec_is_t_dev_exec || device_exec_is_t_host_exec))),
509 "Template parameter to .sync() must exactly match one of the "
510 "DualView's device types or one of the execution or memory spaces");
511
512 int dev = -1;
513 if (device_is_t_dev_device)
514 dev = 1;
515 else if (device_is_t_host_device)
516 dev = 0;
517 else {
518 if (device_is_memspace) {
519 if (device_mem_is_t_dev_mem) dev = 1;
520 if (device_mem_is_t_host_mem) dev = 0;
521 if (device_mem_is_t_host_mem && device_mem_is_t_dev_mem) dev = -1;
522 }
523 if (device_is_execspace) {
524 if (device_exec_is_t_dev_exec) dev = 1;
525 if (device_exec_is_t_host_exec) dev = 0;
526 if (device_exec_is_t_host_exec && device_exec_is_t_dev_exec) dev = -1;
527 }
528 if (!device_is_execspace && !device_is_memspace) {
529 if (device_mem_is_t_dev_mem) dev = 1;
530 if (device_mem_is_t_host_mem) dev = 0;
531 if (device_mem_is_t_host_mem && device_mem_is_t_dev_mem) dev = -1;
532 if (device_exec_is_t_dev_exec) dev = 1;
533 if (device_exec_is_t_host_exec) dev = 0;
534 if (device_exec_is_t_host_exec && device_exec_is_t_dev_exec) dev = -1;
535 }
536 }
537 return dev;
538 }
539 static constexpr const int view_header_size = 128;
540 void impl_report_host_sync() const noexcept {
541 if (Kokkos::Tools::Experimental::get_callbacks().sync_dual_view !=
542 nullptr) {
543 Kokkos::Tools::syncDualView(
544 h_view.label(),
545 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(h_view.data()) -
546 view_header_size),
547 false);
548 }
549 }
550 void impl_report_device_sync() const noexcept {
551 if (Kokkos::Tools::Experimental::get_callbacks().sync_dual_view !=
552 nullptr) {
553 Kokkos::Tools::syncDualView(
554 d_view.label(),
555 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(d_view.data()) -
556 view_header_size),
557 true);
558 }
559 }
560
578 // deliberately passing args by cref as they're used multiple times
579 template <class Device, class... Args>
580 void sync_impl(std::true_type, Args const&... args) {
581 if (modified_flags.data() == nullptr) return;
582
583 int dev = get_device_side<Device>();
584
585 if (dev == 1) { // if Device is the same as DualView's device type
586 if ((modified_flags(0) > 0) && (modified_flags(0) >= modified_flags(1))) {
587#ifdef KOKKOS_ENABLE_CUDA
588 if (std::is_same<typename t_dev::memory_space,
589 Kokkos::CudaUVMSpace>::value) {
590 if (d_view.data() == h_view.data())
591 Kokkos::Impl::cuda_prefetch_pointer(
592 Impl::get_cuda_space(args...), d_view.data(),
593 sizeof(typename t_dev::value_type) * d_view.span(), true);
594 }
595#endif
596
597 deep_copy(args..., d_view, h_view);
598 modified_flags(0) = modified_flags(1) = 0;
599 impl_report_device_sync();
600 }
601 }
602 if (dev == 0) { // hopefully Device is the same as DualView's host type
603 if ((modified_flags(1) > 0) && (modified_flags(1) >= modified_flags(0))) {
604#ifdef KOKKOS_ENABLE_CUDA
605 if (std::is_same<typename t_dev::memory_space,
606 Kokkos::CudaUVMSpace>::value) {
607 if (d_view.data() == h_view.data())
608 Kokkos::Impl::cuda_prefetch_pointer(
609 Impl::get_cuda_space(args...), d_view.data(),
610 sizeof(typename t_dev::value_type) * d_view.span(), false);
611 }
612#endif
613
614 deep_copy(args..., h_view, d_view);
615 modified_flags(0) = modified_flags(1) = 0;
616 impl_report_host_sync();
617 }
618 }
619 if constexpr (std::is_same<typename t_host::memory_space,
620 typename t_dev::memory_space>::value) {
621 typename t_dev::execution_space().fence(
622 "Kokkos::DualView<>::sync: fence after syncing DualView");
623 typename t_host::execution_space().fence(
624 "Kokkos::DualView<>::sync: fence after syncing DualView");
625 }
626 }
627
628 template <class Device>
629 void sync(const std::enable_if_t<
630 (std::is_same<typename traits::data_type,
631 typename traits::non_const_data_type>::value) ||
632 (std::is_same<Device, int>::value),
633 int>& = 0) {
634 sync_impl<Device>(std::true_type{});
635 }
636
637 template <class Device, class ExecutionSpace>
638 void sync(const ExecutionSpace& exec,
639 const std::enable_if_t<
640 (std::is_same<typename traits::data_type,
641 typename traits::non_const_data_type>::value) ||
642 (std::is_same<Device, int>::value),
643 int>& = 0) {
644 sync_impl<Device>(std::true_type{}, exec);
645 }
646
647 // deliberately passing args by cref as they're used multiple times
648 template <class Device, class... Args>
649 void sync_impl(std::false_type, Args const&...) {
650 if (modified_flags.data() == nullptr) return;
651
652 int dev = get_device_side<Device>();
653
654 if (dev == 1) { // if Device is the same as DualView's device type
655 if ((modified_flags(0) > 0) && (modified_flags(0) >= modified_flags(1))) {
656 Impl::throw_runtime_exception(
657 "Calling sync on a DualView with a const datatype.");
658 }
659 impl_report_device_sync();
660 }
661 if (dev == 0) { // hopefully Device is the same as DualView's host type
662 if ((modified_flags(1) > 0) && (modified_flags(1) >= modified_flags(0))) {
663 Impl::throw_runtime_exception(
664 "Calling sync on a DualView with a const datatype.");
665 }
666 impl_report_host_sync();
667 }
668 }
669
670 template <class Device>
671 void sync(const std::enable_if_t<
672 (!std::is_same<typename traits::data_type,
673 typename traits::non_const_data_type>::value) ||
674 (std::is_same<Device, int>::value),
675 int>& = 0) {
676 sync_impl<Device>(std::false_type{});
677 }
678 template <class Device, class ExecutionSpace>
679 void sync(const ExecutionSpace& exec,
680 const std::enable_if_t<
681 (!std::is_same<typename traits::data_type,
682 typename traits::non_const_data_type>::value) ||
683 (std::is_same<Device, int>::value),
684 int>& = 0) {
685 sync_impl<Device>(std::false_type{}, exec);
686 }
687
688 // deliberately passing args by cref as they're used multiple times
689 template <typename... Args>
690 void sync_host_impl(Args const&... args) {
691 if (!std::is_same<typename traits::data_type,
692 typename traits::non_const_data_type>::value)
693 Impl::throw_runtime_exception(
694 "Calling sync_host on a DualView with a const datatype.");
695 if (modified_flags.data() == nullptr) return;
696 if (modified_flags(1) > modified_flags(0)) {
697#ifdef KOKKOS_ENABLE_CUDA
698 if (std::is_same<typename t_dev::memory_space,
699 Kokkos::CudaUVMSpace>::value) {
700 if (d_view.data() == h_view.data())
701 Kokkos::Impl::cuda_prefetch_pointer(
702 Impl::get_cuda_space(args...), d_view.data(),
703 sizeof(typename t_dev::value_type) * d_view.span(), false);
704 }
705#endif
706
707 deep_copy(args..., h_view, d_view);
708 modified_flags(1) = modified_flags(0) = 0;
709 impl_report_host_sync();
710 }
711 }
712
713 template <class ExecSpace>
714 void sync_host(const ExecSpace& exec) {
715 sync_host_impl(exec);
716 }
717 void sync_host() { sync_host_impl(); }
718
719 // deliberately passing args by cref as they're used multiple times
720 template <typename... Args>
721 void sync_device_impl(Args const&... args) {
722 if (!std::is_same<typename traits::data_type,
723 typename traits::non_const_data_type>::value)
724 Impl::throw_runtime_exception(
725 "Calling sync_device on a DualView with a const datatype.");
726 if (modified_flags.data() == nullptr) return;
727 if (modified_flags(0) > modified_flags(1)) {
728#ifdef KOKKOS_ENABLE_CUDA
729 if (std::is_same<typename t_dev::memory_space,
730 Kokkos::CudaUVMSpace>::value) {
731 if (d_view.data() == h_view.data())
732 Kokkos::Impl::cuda_prefetch_pointer(
733 Impl::get_cuda_space(args...), d_view.data(),
734 sizeof(typename t_dev::value_type) * d_view.span(), true);
735 }
736#endif
737
738 deep_copy(args..., d_view, h_view);
739 modified_flags(1) = modified_flags(0) = 0;
740 impl_report_device_sync();
741 }
742 }
743
744 template <class ExecSpace>
745 void sync_device(const ExecSpace& exec) {
746 sync_device_impl(exec);
747 }
748 void sync_device() { sync_device_impl(); }
749
750 template <class Device>
751 bool need_sync() const {
752 if (modified_flags.data() == nullptr) return false;
753 int dev = get_device_side<Device>();
754
755 if (dev == 1) { // if Device is the same as DualView's device type
756 if ((modified_flags(0) > 0) && (modified_flags(0) >= modified_flags(1))) {
757 return true;
758 }
759 }
760 if (dev == 0) { // hopefully Device is the same as DualView's host type
761 if ((modified_flags(1) > 0) && (modified_flags(1) >= modified_flags(0))) {
762 return true;
763 }
764 }
765 return false;
766 }
767
768 inline bool need_sync_host() const {
769 if (modified_flags.data() == nullptr) return false;
770 return modified_flags(0) < modified_flags(1);
771 }
772
773 inline bool need_sync_device() const {
774 if (modified_flags.data() == nullptr) return false;
775 return modified_flags(1) < modified_flags(0);
776 }
777 void impl_report_device_modification() {
778 if (Kokkos::Tools::Experimental::get_callbacks().modify_dual_view !=
779 nullptr) {
780 Kokkos::Tools::modifyDualView(
781 d_view.label(),
782 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(d_view.data()) -
783 view_header_size),
784 true);
785 }
786 }
787 void impl_report_host_modification() {
788 if (Kokkos::Tools::Experimental::get_callbacks().modify_dual_view !=
789 nullptr) {
790 Kokkos::Tools::modifyDualView(
791 h_view.label(),
792 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(h_view.data()) -
793 view_header_size),
794 false);
795 }
796 }
802 template <class Device, class Dummy = DualView,
803 std::enable_if_t<!Dummy::impl_dualview_is_single_device::value>* =
804 nullptr>
805 void modify() {
806 if (modified_flags.data() == nullptr) {
807 modified_flags = t_modified_flags("DualView::modified_flags");
808 }
809
810 int dev = get_device_side<Device>();
811
812 if (dev == 1) { // if Device is the same as DualView's device type
813 // Increment the device's modified count.
814 modified_flags(1) =
815 (modified_flags(1) > modified_flags(0) ? modified_flags(1)
816 : modified_flags(0)) +
817 1;
818 impl_report_device_modification();
819 }
820 if (dev == 0) { // hopefully Device is the same as DualView's host type
821 // Increment the host's modified count.
822 modified_flags(0) =
823 (modified_flags(1) > modified_flags(0) ? modified_flags(1)
824 : modified_flags(0)) +
825 1;
826 impl_report_host_modification();
827 }
828
829#ifdef KOKKOS_ENABLE_DEBUG_DUALVIEW_MODIFY_CHECK
830 if (modified_flags(0) && modified_flags(1)) {
831 std::string msg = "Kokkos::DualView::modify ERROR: ";
832 msg += "Concurrent modification of host and device views ";
833 msg += "in DualView \"";
834 msg += d_view.label();
835 msg += "\"\n";
836 Kokkos::abort(msg.c_str());
837 }
838#endif
839 }
840
841 template <
842 class Device, class Dummy = DualView,
843 std::enable_if_t<Dummy::impl_dualview_is_single_device::value>* = nullptr>
844 void modify() {
845 return;
846 }
847
848 template <class Dummy = DualView,
849 std::enable_if_t<!Dummy::impl_dualview_is_single_device::value>* =
850 nullptr>
851 inline void modify_host() {
852 if (modified_flags.data() != nullptr) {
853 modified_flags(0) =
854 (modified_flags(1) > modified_flags(0) ? modified_flags(1)
855 : modified_flags(0)) +
856 1;
857 impl_report_host_modification();
858#ifdef KOKKOS_ENABLE_DEBUG_DUALVIEW_MODIFY_CHECK
859 if (modified_flags(0) && modified_flags(1)) {
860 std::string msg = "Kokkos::DualView::modify_host ERROR: ";
861 msg += "Concurrent modification of host and device views ";
862 msg += "in DualView \"";
863 msg += d_view.label();
864 msg += "\"\n";
865 Kokkos::abort(msg.c_str());
866 }
867#endif
868 }
869 }
870
871 template <
872 class Dummy = DualView,
873 std::enable_if_t<Dummy::impl_dualview_is_single_device::value>* = nullptr>
874 inline void modify_host() {
875 return;
876 }
877
878 template <class Dummy = DualView,
879 std::enable_if_t<!Dummy::impl_dualview_is_single_device::value>* =
880 nullptr>
881 inline void modify_device() {
882 if (modified_flags.data() != nullptr) {
883 modified_flags(1) =
884 (modified_flags(1) > modified_flags(0) ? modified_flags(1)
885 : modified_flags(0)) +
886 1;
887 impl_report_device_modification();
888#ifdef KOKKOS_ENABLE_DEBUG_DUALVIEW_MODIFY_CHECK
889 if (modified_flags(0) && modified_flags(1)) {
890 std::string msg = "Kokkos::DualView::modify_device ERROR: ";
891 msg += "Concurrent modification of host and device views ";
892 msg += "in DualView \"";
893 msg += d_view.label();
894 msg += "\"\n";
895 Kokkos::abort(msg.c_str());
896 }
897#endif
898 }
899 }
900
901 template <
902 class Dummy = DualView,
903 std::enable_if_t<Dummy::impl_dualview_is_single_device::value>* = nullptr>
904 inline void modify_device() {
905 return;
906 }
907
908 inline void clear_sync_state() {
909 if (modified_flags.data() != nullptr)
910 modified_flags(1) = modified_flags(0) = 0;
911 }
912
914
916
922 template <class... ViewCtorArgs>
923 void impl_realloc(const size_t n0, const size_t n1, const size_t n2,
924 const size_t n3, const size_t n4, const size_t n5,
925 const size_t n6, const size_t n7,
926 const Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop) {
927 using alloc_prop_input = Impl::ViewCtorProp<ViewCtorArgs...>;
928
929 static_assert(!alloc_prop_input::has_label,
930 "The view constructor arguments passed to Kokkos::realloc "
931 "must not include a label!");
932 static_assert(
933 !alloc_prop_input::has_pointer,
934 "The view constructor arguments passed to Kokkos::realloc must "
935 "not include a pointer!");
936 static_assert(
937 !alloc_prop_input::has_memory_space,
938 "The view constructor arguments passed to Kokkos::realloc must "
939 "not include a memory space instance!");
940
941 const size_t new_extents[8] = {n0, n1, n2, n3, n4, n5, n6, n7};
942 const bool sizeMismatch =
943 Impl::size_mismatch(h_view, h_view.rank_dynamic, new_extents);
944
945 if (sizeMismatch) {
946 ::Kokkos::realloc(arg_prop, d_view, n0, n1, n2, n3, n4, n5, n6, n7);
947 if (alloc_prop_input::initialize) {
948 h_view = create_mirror_view(typename t_host::memory_space(), d_view);
949 } else {
950 h_view = create_mirror_view(Kokkos::WithoutInitializing,
951 typename t_host::memory_space(), d_view);
952 }
953 } else if (alloc_prop_input::initialize) {
954 if constexpr (alloc_prop_input::has_execution_space) {
955 const auto& exec_space =
956 Impl::get_property<Impl::ExecutionSpaceTag>(arg_prop);
957 ::Kokkos::deep_copy(exec_space, d_view, typename t_dev::value_type{});
958 } else
959 ::Kokkos::deep_copy(d_view, typename t_dev::value_type{});
960 }
961
962 /* Reset dirty flags */
963 if (modified_flags.data() == nullptr) {
964 modified_flags = t_modified_flags("DualView::modified_flags");
965 } else
966 modified_flags(1) = modified_flags(0) = 0;
967 }
968
969 template <class... ViewCtorArgs>
970 void realloc(const Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop,
971 const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
972 const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
973 const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
974 const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
975 const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
976 const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
977 const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
978 const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG) {
979 impl_realloc(n0, n1, n2, n3, n4, n5, n6, n7, arg_prop);
980 }
981
982 void realloc(const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
983 const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
984 const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
985 const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
986 const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
987 const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
988 const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
989 const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG) {
990 impl_realloc(n0, n1, n2, n3, n4, n5, n6, n7, Impl::ViewCtorProp<>{});
991 }
992
993 template <typename I>
994 std::enable_if_t<Impl::is_view_ctor_property<I>::value> realloc(
995 const I& arg_prop, const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
996 const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
997 const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
998 const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
999 const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1000 const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1001 const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1002 const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG) {
1003 impl_realloc(n0, n1, n2, n3, n4, n5, n6, n7, Kokkos::view_alloc(arg_prop));
1004 }
1005
1010 template <class... ViewCtorArgs>
1011 void impl_resize(const Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop,
1012 const size_t n0, const size_t n1, const size_t n2,
1013 const size_t n3, const size_t n4, const size_t n5,
1014 const size_t n6, const size_t n7) {
1015 using alloc_prop_input = Impl::ViewCtorProp<ViewCtorArgs...>;
1016
1017 static_assert(!alloc_prop_input::has_label,
1018 "The view constructor arguments passed to Kokkos::resize "
1019 "must not include a label!");
1020 static_assert(
1021 !alloc_prop_input::has_pointer,
1022 "The view constructor arguments passed to Kokkos::resize must "
1023 "not include a pointer!");
1024 static_assert(
1025 !alloc_prop_input::has_memory_space,
1026 "The view constructor arguments passed to Kokkos::resize must "
1027 "not include a memory space instance!");
1028
1029 const size_t new_extents[8] = {n0, n1, n2, n3, n4, n5, n6, n7};
1030 const bool sizeMismatch =
1031 Impl::size_mismatch(h_view, h_view.rank_dynamic, new_extents);
1032
1033 if (modified_flags.data() == nullptr) {
1034 modified_flags = t_modified_flags("DualView::modified_flags");
1035 }
1036
1037 [[maybe_unused]] auto resize_on_device = [&](const auto& properties) {
1038 /* Resize on Device */
1039 if (sizeMismatch) {
1040 ::Kokkos::resize(properties, d_view, n0, n1, n2, n3, n4, n5, n6, n7);
1041 if (alloc_prop_input::initialize) {
1042 h_view = create_mirror_view(typename t_host::memory_space(), d_view);
1043 } else {
1044 h_view = create_mirror_view(Kokkos::WithoutInitializing,
1045 typename t_host::memory_space(), d_view);
1046 }
1047
1048 /* Mark Device copy as modified */
1049 ++modified_flags(1);
1050 }
1051 };
1052
1053 [[maybe_unused]] auto resize_on_host = [&](const auto& properties) {
1054 /* Resize on Host */
1055 if (sizeMismatch) {
1056 ::Kokkos::resize(properties, h_view, n0, n1, n2, n3, n4, n5, n6, n7);
1057 if (alloc_prop_input::initialize) {
1058 d_view = create_mirror_view(typename t_dev::memory_space(), h_view);
1059
1060 } else {
1061 d_view = create_mirror_view(Kokkos::WithoutInitializing,
1062 typename t_dev::memory_space(), h_view);
1063 }
1064
1065 /* Mark Host copy as modified */
1066 ++modified_flags(0);
1067 }
1068 };
1069
1070 constexpr bool has_execution_space = alloc_prop_input::has_execution_space;
1071
1072 if constexpr (has_execution_space) {
1073 using ExecSpace = typename alloc_prop_input::execution_space;
1074 const auto& exec_space =
1075 Impl::get_property<Impl::ExecutionSpaceTag>(arg_prop);
1076 constexpr bool exec_space_can_access_device =
1077 SpaceAccessibility<ExecSpace,
1078 typename t_dev::memory_space>::accessible;
1079 constexpr bool exec_space_can_access_host =
1080 SpaceAccessibility<ExecSpace,
1081 typename t_host::memory_space>::accessible;
1082 static_assert(exec_space_can_access_device || exec_space_can_access_host);
1083 if constexpr (exec_space_can_access_device) {
1084 sync<typename t_dev::memory_space>(exec_space);
1085 resize_on_device(arg_prop);
1086 return;
1087 }
1088 if constexpr (exec_space_can_access_host) {
1089 sync<typename t_host::memory_space>(exec_space);
1090 resize_on_host(arg_prop);
1091 return;
1092 }
1093 } else {
1094 if (modified_flags(1) >= modified_flags(0)) {
1095 resize_on_device(arg_prop);
1096 } else {
1097 resize_on_host(arg_prop);
1098 }
1099 }
1100 }
1101
1102 void resize(const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1103 const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1104 const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1105 const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1106 const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1107 const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1108 const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1109 const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG) {
1110 impl_resize(Impl::ViewCtorProp<>{}, n0, n1, n2, n3, n4, n5, n6, n7);
1111 }
1112
1113 template <class... ViewCtorArgs>
1114 void resize(const Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop,
1115 const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1116 const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1117 const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1118 const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1119 const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1120 const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1121 const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1122 const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG) {
1123 impl_resize(arg_prop, n0, n1, n2, n3, n4, n5, n6, n7);
1124 }
1125
1126 template <class I>
1127 std::enable_if_t<Impl::is_view_ctor_property<I>::value> resize(
1128 const I& arg_prop, const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1129 const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1130 const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1131 const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1132 const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1133 const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1134 const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1135 const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG) {
1136 impl_resize(Kokkos::view_alloc(arg_prop), n0, n1, n2, n3, n4, n5, n6, n7);
1137 }
1138
1140
1142
1144 KOKKOS_INLINE_FUNCTION constexpr size_t span() const { return d_view.span(); }
1145
1146 KOKKOS_INLINE_FUNCTION bool span_is_contiguous() const {
1147 return d_view.span_is_contiguous();
1148 }
1149
1151 template <typename iType>
1152 void stride(iType* stride_) const {
1153 d_view.stride(stride_);
1154 }
1155
1156 template <typename iType>
1157 KOKKOS_INLINE_FUNCTION constexpr std::enable_if_t<
1158 std::is_integral<iType>::value, size_t>
1159 extent(const iType& r) const {
1160 return d_view.extent(r);
1161 }
1162
1163 template <typename iType>
1164 KOKKOS_INLINE_FUNCTION constexpr std::enable_if_t<
1165 std::is_integral<iType>::value, int>
1166 extent_int(const iType& r) const {
1167 return static_cast<int>(d_view.extent(r));
1168 }
1169
1171};
1172
1173} // namespace Kokkos
1174
1175//----------------------------------------------------------------------------
1176//----------------------------------------------------------------------------
1177//
1178// Partial specializations of Kokkos::subview() for DualView objects.
1179//
1180
1181namespace Kokkos {
1182namespace Impl {
1183
1184template <class V>
1185struct V2DV;
1186
1187template <class D, class... P>
1188struct V2DV<View<D, P...>> {
1189 using type = DualView<D, P...>;
1190};
1191} /* namespace Impl */
1192
1193template <class DataType, class... Properties, class... Args>
1194auto subview(const DualView<DataType, Properties...>& src, Args&&... args) {
1195 // leverage Kokkos::View facilities to deduce the properties of the subview
1196 using deduce_subview_type =
1197 decltype(subview(std::declval<View<DataType, Properties...>>(),
1198 std::forward<Args>(args)...));
1199 // map it back to dual view
1200 return typename Impl::V2DV<deduce_subview_type>::type(
1201 src, std::forward<Args>(args)...);
1202}
1203
1204} /* namespace Kokkos */
1205
1206//----------------------------------------------------------------------------
1207//----------------------------------------------------------------------------
1208
1209namespace Kokkos {
1210
1211//
1212// Partial specialization of Kokkos::deep_copy() for DualView objects.
1213//
1214
1215template <class DT, class... DP, class ST, class... SP>
1216void deep_copy(DualView<DT, DP...>& dst, const DualView<ST, SP...>& src) {
1217 if (src.need_sync_device()) {
1218 deep_copy(dst.h_view, src.h_view);
1219 dst.modify_host();
1220 } else {
1221 deep_copy(dst.d_view, src.d_view);
1222 dst.modify_device();
1223 }
1224}
1225
1226template <class ExecutionSpace, class DT, class... DP, class ST, class... SP>
1227void deep_copy(const ExecutionSpace& exec, DualView<DT, DP...>& dst,
1228 const DualView<ST, SP...>& src) {
1229 if (src.need_sync_device()) {
1230 deep_copy(exec, dst.h_view, src.h_view);
1231 dst.modify_host();
1232 } else {
1233 deep_copy(exec, dst.d_view, src.d_view);
1234 dst.modify_device();
1235 }
1236}
1237
1238} // namespace Kokkos
1239
1240//----------------------------------------------------------------------------
1241//----------------------------------------------------------------------------
1242
1243namespace Kokkos {
1244
1245//
1246// Non-member resize and realloc
1247//
1248
1249template <class... Properties, class... Args>
1250void resize(DualView<Properties...>& dv, Args&&... args) noexcept(
1251 noexcept(dv.resize(std::forward<Args>(args)...))) {
1252 dv.resize(std::forward<Args>(args)...);
1253}
1254
1255template <class... ViewCtorArgs, class... Properties, class... Args>
1256void resize(
1257 const Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop,
1258 DualView<Properties...>& dv,
1259 Args&&... args) noexcept(noexcept(dv.resize(arg_prop,
1260 std::forward<Args>(args)...))) {
1261 dv.resize(arg_prop, std::forward<Args>(args)...);
1262}
1263
1264template <class I, class... Properties, class... Args>
1265std::enable_if_t<Impl::is_view_ctor_property<I>::value> resize(
1266 const I& arg_prop, DualView<Properties...>& dv,
1267 Args&&... args) noexcept(noexcept(dv.resize(arg_prop,
1268 std::forward<Args>(args)...))) {
1269 dv.resize(arg_prop, std::forward<Args>(args)...);
1270}
1271
1272template <class... ViewCtorArgs, class... Properties, class... Args>
1273void realloc(const Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop,
1274 DualView<Properties...>& dv,
1275 Args&&... args) noexcept(noexcept(dv
1276 .realloc(std::forward<Args>(
1277 args)...))) {
1278 dv.realloc(arg_prop, std::forward<Args>(args)...);
1279}
1280
1281template <class... Properties, class... Args>
1282void realloc(DualView<Properties...>& dv, Args&&... args) noexcept(
1283 noexcept(dv.realloc(std::forward<Args>(args)...))) {
1284 dv.realloc(std::forward<Args>(args)...);
1285}
1286
1287template <class I, class... Properties, class... Args>
1288std::enable_if_t<Impl::is_view_ctor_property<I>::value> realloc(
1289 const I& arg_prop, DualView<Properties...>& dv,
1290 Args&&... args) noexcept(noexcept(dv.realloc(arg_prop,
1291 std::forward<Args>(
1292 args)...))) {
1293 dv.realloc(arg_prop, std::forward<Args>(args)...);
1294}
1295
1296} // end namespace Kokkos
1297
1298#ifdef KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_DUALVIEW
1299#undef KOKKOS_IMPL_PUBLIC_INCLUDE
1300#undef KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_DUALVIEW
1301#endif
1302#endif
View to an array of data.
View< typename traits::non_const_data_type, typename traits::array_layout, Device< DefaultHostExecutionSpace, typename traits::host_mirror_space::memory_space >, typename traits::hooks_policy > HostMirror
ScopeGuard Some user scope issues have been identified with some Kokkos::finalize calls; ScopeGuard a...
Traits class for accessing attributes of a View.