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
30 #include <Kokkos_Core.hpp>
31 #include <impl/Kokkos_Error.hpp>
73 #ifdef KOKKOS_ENABLE_CUDA
75 inline const Kokkos::Cuda& get_cuda_space(
const Kokkos::Cuda& in) {
return in; }
77 inline const Kokkos::Cuda& get_cuda_space() {
78 return *Kokkos::Impl::cuda_get_deep_copy_space();
81 template <
typename NonCudaExecSpace>
82 inline const Kokkos::Cuda& get_cuda_space(
const NonCudaExecSpace&) {
83 return get_cuda_space();
86 #endif // KOKKOS_ENABLE_CUDA
90 #ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
91 template <
class DataType,
class Arg1Type = void,
class Arg2Type = void,
92 class Arg3Type =
void>
95 template <
class DataType,
class... Properties>
100 struct is_dual_view :
public std::false_type {};
102 template <
class DT,
class... DP>
103 struct is_dual_view<DualView<DT, DP...>> :
public std::true_type {};
105 template <
class DT,
class... DP>
106 struct is_dual_view<const DualView<DT, DP...>> :
public std::true_type {};
109 inline constexpr
bool is_dual_view_v = is_dual_view<T>::value;
111 #ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
112 template <
class DataType,
class Arg1Type,
class Arg2Type,
class Arg3Type>
113 class DualView :
public ViewTraits<DataType, Arg1Type, Arg2Type, Arg3Type> {
114 template <
class,
class,
class,
class>
116 template <
class DataType,
class... Properties>
117 class DualView :
public ViewTraits<DataType, Properties...> {
118 template <
class,
class...>
120 friend class DualView;
125 #ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
126 using traits = ViewTraits<DataType, Arg1Type, Arg2Type, Arg3Type>;
128 using traits = ViewTraits<DataType, Properties...>;
132 using host_mirror_space =
typename traits::host_mirror_space;
135 #ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
136 using t_dev = View<typename traits::data_type, Arg1Type, Arg2Type, Arg3Type>;
138 using t_dev =
View<
typename traits::data_type, Properties...>;
143 using t_host =
typename t_dev::HostMirror;
147 #ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
149 View<typename traits::const_data_type, Arg1Type, Arg2Type, Arg3Type>;
151 using t_dev_const =
View<
typename traits::const_data_type, Properties...>;
156 using t_host_const =
typename t_dev_const::HostMirror;
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>>;
167 using t_host_const_randomread =
typename t_dev_const_randomread::HostMirror;
171 View<
typename traits::data_type,
typename traits::array_layout,
172 typename traits::device_type, MemoryUnmanaged>;
176 View<
typename t_host::data_type,
typename t_host::array_layout,
177 typename t_host::device_type, MemoryUnmanaged>;
180 using t_dev_const_um =
181 View<
typename traits::const_data_type,
typename traits::array_layout,
182 typename traits::device_type, MemoryUnmanaged>;
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>;
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>>;
198 using t_host_const_randomread_um =
199 typename t_dev_const_randomread_um::HostMirror;
208 using t_modified_flags = View<unsigned int[2], LayoutLeft, Kokkos::HostSpace>;
209 t_modified_flags modified_flags;
230 DualView() =
default;
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)
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))
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 if constexpr (Impl::ViewCtorProp<P...>::sequential_host_init) {
280 h_view = t_host(arg_prop, n0, n1, n2, n3, n4, n5, n6, n7);
281 static_assert(Impl::ViewCtorProp<P...>::initialize,
282 "DualView: SequentialHostInit isn't compatible with "
283 "WithoutInitializing!");
284 static_assert(!Impl::ViewCtorProp<P...>::has_execution_space,
285 "DualView: SequentialHostInit isn't compatible with "
286 "providing an execution space instance!");
288 d_view = Kokkos::create_mirror_view_and_copy(
289 typename traits::memory_space{}, h_view);
291 d_view = t_dev(arg_prop, n0, n1, n2, n3, n4, n5, n6, n7);
294 if constexpr (Kokkos::Impl::has_type<Impl::WithoutInitializing_t,
297 Kokkos::create_mirror_view(Kokkos::WithoutInitializing, d_view);
299 h_view = Kokkos::create_mirror_view(d_view);
304 template <typename DT, typename... DP>
305 DualView(const DualView<DT, DP...>& src)
306 : modified_flags(src.modified_flags),
308 h_view(src.h_view) {}
311 template <
class DT,
class... DP,
class Arg0,
class... Args>
312 DualView(
const DualView<DT, DP...>& src,
const Arg0& arg0, Args... args)
313 : modified_flags(src.modified_flags),
314 d_view(Kokkos::subview(src.d_view, arg0, args...)),
315 h_view(Kokkos::subview(src.h_view, arg0, args...)) {}
327 DualView(
const t_dev& d_view_,
const t_host& h_view_)
328 : modified_flags(t_modified_flags(
"DualView::modified_flags")),
331 if (
int(d_view.rank) !=
int(h_view.rank) ||
332 d_view.extent(0) != h_view.extent(0) ||
333 d_view.extent(1) != h_view.extent(1) ||
334 d_view.extent(2) != h_view.extent(2) ||
335 d_view.extent(3) != h_view.extent(3) ||
336 d_view.extent(4) != h_view.extent(4) ||
337 d_view.extent(5) != h_view.extent(5) ||
338 d_view.extent(6) != h_view.extent(6) ||
339 d_view.extent(7) != h_view.extent(7) ||
340 d_view.stride_0() != h_view.stride_0() ||
341 d_view.stride_1() != h_view.stride_1() ||
342 d_view.stride_2() != h_view.stride_2() ||
343 d_view.stride_3() != h_view.stride_3() ||
344 d_view.stride_4() != h_view.stride_4() ||
345 d_view.stride_5() != h_view.stride_5() ||
346 d_view.stride_6() != h_view.stride_6() ||
347 d_view.stride_7() != h_view.stride_7() ||
348 d_view.span() != h_view.span()) {
349 Kokkos::Impl::throw_runtime_exception(
350 "DualView constructed with incompatible views");
354 struct impl_dualview_is_single_device {
356 value = std::is_same_v<
typename t_dev::device_type,
357 typename t_host::device_type>
362 template <
typename Device>
363 struct impl_device_matches_tdev_device {
364 enum :
bool { value = std::is_same_v<typename t_dev::device_type, Device> };
367 template <
typename Device>
368 struct impl_device_matches_thost_device {
370 value = std::is_same_v<typename t_host::device_type, Device>
375 template <
typename Device>
376 struct impl_device_matches_thost_exec {
378 value = std::is_same_v<typename t_host::execution_space, Device>
383 template <
typename Device>
384 struct impl_device_matches_tdev_exec {
386 value = std::is_same_v<typename t_dev::execution_space, Device>
391 template <
typename Device>
392 struct impl_device_matches_tdev_memory_space {
394 value = std::is_same_v<
typename t_dev::memory_space,
395 typename Device::memory_space>
420 template <
class Device>
421 KOKKOS_FUNCTION
auto view()
const {
422 if constexpr (std::is_same_v<Device, typename Device::memory_space>) {
423 if constexpr (std::is_same_v<
typename Device::memory_space,
424 typename t_dev::memory_space>) {
427 static_assert(std::is_same_v<
typename Device::memory_space,
428 typename t_host::memory_space>,
429 "The template argument is a memory space but doesn't "
430 "match either of DualView's memory spaces!");
434 if constexpr (std::is_same_v<Device, typename Device::execution_space>) {
435 if constexpr (std::is_same_v<
typename Device::execution_space,
436 typename t_dev::execution_space>) {
439 static_assert(std::is_same_v<
typename Device::execution_space,
440 typename t_host::execution_space>,
441 "The template argument is an execution space but "
442 "doesn't match either of DualView's execution spaces!");
446 static_assert(std::is_same_v<Device, typename Device::device_type>,
447 "The template argument is neither a memory space, "
448 "execution space, or device!");
449 if constexpr (std::is_same_v<Device, typename t_dev::device_type>)
452 static_assert(std::is_same_v<Device, typename t_host::device_type>,
453 "The template argument is a device but "
454 "doesn't match either of DualView's devices!");
459 #ifdef KOKKOS_COMPILER_INTEL
460 __builtin_unreachable();
464 KOKKOS_INLINE_FUNCTION
465 t_host view_host()
const {
return h_view; }
467 KOKKOS_INLINE_FUNCTION
468 t_dev view_device()
const {
return d_view; }
470 KOKKOS_INLINE_FUNCTION constexpr
bool is_allocated()
const {
471 return (d_view.is_allocated() && h_view.is_allocated());
474 template <
class Device>
475 static int get_device_side() {
476 constexpr
bool device_is_memspace =
477 std::is_same_v<Device, typename Device::memory_space>;
478 constexpr
bool device_is_execspace =
479 std::is_same_v<Device, typename Device::execution_space>;
480 constexpr
bool device_exec_is_t_dev_exec =
481 std::is_same_v<
typename Device::execution_space,
482 typename t_dev::execution_space>;
483 constexpr
bool device_mem_is_t_dev_mem =
484 std::is_same_v<
typename Device::memory_space,
485 typename t_dev::memory_space>;
486 constexpr
bool device_exec_is_t_host_exec =
487 std::is_same_v<
typename Device::execution_space,
488 typename t_host::execution_space>;
489 constexpr
bool device_mem_is_t_host_mem =
490 std::is_same_v<
typename Device::memory_space,
491 typename t_host::memory_space>;
492 constexpr
bool device_is_t_host_device =
493 std::is_same_v<
typename Device::execution_space,
494 typename t_host::device_type>;
495 constexpr
bool device_is_t_dev_device =
496 std::is_same_v<
typename Device::memory_space,
497 typename t_host::device_type>;
500 device_is_t_dev_device || device_is_t_host_device ||
501 (device_is_memspace &&
502 (device_mem_is_t_dev_mem || device_mem_is_t_host_mem)) ||
503 (device_is_execspace &&
504 (device_exec_is_t_dev_exec || device_exec_is_t_host_exec)) ||
505 ((!device_is_execspace && !device_is_memspace) &&
506 ((device_mem_is_t_dev_mem || device_mem_is_t_host_mem) ||
507 (device_exec_is_t_dev_exec || device_exec_is_t_host_exec))),
508 "Template parameter to .sync() must exactly match one of the "
509 "DualView's device types or one of the execution or memory spaces");
512 if (device_is_t_dev_device)
514 else if (device_is_t_host_device)
517 if (device_is_memspace) {
518 if (device_mem_is_t_dev_mem) dev = 1;
519 if (device_mem_is_t_host_mem) dev = 0;
520 if (device_mem_is_t_host_mem && device_mem_is_t_dev_mem) dev = -1;
522 if (device_is_execspace) {
523 if (device_exec_is_t_dev_exec) dev = 1;
524 if (device_exec_is_t_host_exec) dev = 0;
525 if (device_exec_is_t_host_exec && device_exec_is_t_dev_exec) dev = -1;
527 if (!device_is_execspace && !device_is_memspace) {
528 if (device_mem_is_t_dev_mem) dev = 1;
529 if (device_mem_is_t_host_mem) dev = 0;
530 if (device_mem_is_t_host_mem && device_mem_is_t_dev_mem) dev = -1;
531 if (device_exec_is_t_dev_exec) dev = 1;
532 if (device_exec_is_t_host_exec) dev = 0;
533 if (device_exec_is_t_host_exec && device_exec_is_t_dev_exec) dev = -1;
538 static constexpr
const int view_header_size = 128;
539 void impl_report_host_sync() const noexcept {
540 if (Kokkos::Tools::Experimental::get_callbacks().sync_dual_view !=
542 Kokkos::Tools::syncDualView(
544 reinterpret_cast<void*
>(
reinterpret_cast<uintptr_t
>(h_view.data()) -
549 void impl_report_device_sync() const noexcept {
550 if (Kokkos::Tools::Experimental::get_callbacks().sync_dual_view !=
552 Kokkos::Tools::syncDualView(
554 reinterpret_cast<void*
>(
reinterpret_cast<uintptr_t
>(d_view.data()) -
578 template <
class Device,
class... Args>
579 void sync_impl(std::true_type, Args
const&... args) {
580 if (modified_flags.data() ==
nullptr)
return;
582 int dev = get_device_side<Device>();
585 if ((modified_flags(0) > 0) && (modified_flags(0) >= modified_flags(1))) {
586 #ifdef KOKKOS_ENABLE_CUDA
587 if (std::is_same<
typename t_dev::memory_space,
588 Kokkos::CudaUVMSpace>::value) {
589 if (d_view.data() == h_view.data())
590 Kokkos::Impl::cuda_prefetch_pointer(
591 Impl::get_cuda_space(args...), d_view.data(),
592 sizeof(
typename t_dev::value_type) * d_view.span(),
true);
596 deep_copy(args..., d_view, h_view);
597 modified_flags(0) = modified_flags(1) = 0;
598 impl_report_device_sync();
602 if ((modified_flags(1) > 0) && (modified_flags(1) >= modified_flags(0))) {
603 #ifdef KOKKOS_ENABLE_CUDA
604 if (std::is_same<
typename t_dev::memory_space,
605 Kokkos::CudaUVMSpace>::value) {
606 if (d_view.data() == h_view.data())
607 Kokkos::Impl::cuda_prefetch_pointer(
608 Impl::get_cuda_space(args...), d_view.data(),
609 sizeof(
typename t_dev::value_type) * d_view.span(),
false);
613 deep_copy(args..., h_view, d_view);
614 modified_flags(0) = modified_flags(1) = 0;
615 impl_report_host_sync();
618 if constexpr (std::is_same<
typename t_host::memory_space,
619 typename t_dev::memory_space>::value) {
620 typename t_dev::execution_space().fence(
621 "Kokkos::DualView<>::sync: fence after syncing DualView");
622 typename t_host::execution_space().fence(
623 "Kokkos::DualView<>::sync: fence after syncing DualView");
627 template <
class Device>
628 void sync(
const std::enable_if_t<
629 (std::is_same_v<
typename traits::data_type,
630 typename traits::non_const_data_type>) ||
631 (std::is_same_v<Device, int>),
633 sync_impl<Device>(std::true_type{});
636 template <
class Device,
class ExecutionSpace>
637 void sync(
const ExecutionSpace& exec,
638 const std::enable_if_t<
639 (std::is_same_v<
typename traits::data_type,
640 typename traits::non_const_data_type>) ||
641 (std::is_same_v<Device, int>),
643 sync_impl<Device>(std::true_type{}, exec);
647 template <
class Device,
class... Args>
648 void sync_impl(std::false_type, Args
const&...) {
649 if (modified_flags.data() ==
nullptr)
return;
651 int dev = get_device_side<Device>();
654 if ((modified_flags(0) > 0) && (modified_flags(0) >= modified_flags(1))) {
655 Impl::throw_runtime_exception(
656 "Calling sync on a DualView with a const datatype.");
658 impl_report_device_sync();
661 if ((modified_flags(1) > 0) && (modified_flags(1) >= modified_flags(0))) {
662 Impl::throw_runtime_exception(
663 "Calling sync on a DualView with a const datatype.");
665 impl_report_host_sync();
669 template <
class Device>
670 void sync(
const std::enable_if_t<
671 (!std::is_same_v<
typename traits::data_type,
672 typename traits::non_const_data_type>) ||
673 (std::is_same_v<Device, int>),
675 sync_impl<Device>(std::false_type{});
677 template <
class Device,
class ExecutionSpace>
678 void sync(
const ExecutionSpace& exec,
679 const std::enable_if_t<
680 (!std::is_same_v<
typename traits::data_type,
681 typename traits::non_const_data_type>) ||
682 (std::is_same_v<Device, int>),
684 sync_impl<Device>(std::false_type{}, exec);
688 template <
typename... Args>
689 void sync_host_impl(Args
const&... args) {
690 if (!std::is_same<
typename traits::data_type,
691 typename traits::non_const_data_type>::value)
692 Impl::throw_runtime_exception(
693 "Calling sync_host on a DualView with a const datatype.");
694 if (modified_flags.data() ==
nullptr)
return;
695 if (modified_flags(1) > modified_flags(0)) {
696 #ifdef KOKKOS_ENABLE_CUDA
697 if (std::is_same<
typename t_dev::memory_space,
698 Kokkos::CudaUVMSpace>::value) {
699 if (d_view.data() == h_view.data())
700 Kokkos::Impl::cuda_prefetch_pointer(
701 Impl::get_cuda_space(args...), d_view.data(),
702 sizeof(
typename t_dev::value_type) * d_view.span(),
false);
706 deep_copy(args..., h_view, d_view);
707 modified_flags(1) = modified_flags(0) = 0;
708 impl_report_host_sync();
712 template <
class ExecSpace>
713 void sync_host(
const ExecSpace& exec) {
714 sync_host_impl(exec);
716 void sync_host() { sync_host_impl(); }
719 template <
typename... Args>
720 void sync_device_impl(Args
const&... args) {
721 if (!std::is_same<
typename traits::data_type,
722 typename traits::non_const_data_type>::value)
723 Impl::throw_runtime_exception(
724 "Calling sync_device on a DualView with a const datatype.");
725 if (modified_flags.data() ==
nullptr)
return;
726 if (modified_flags(0) > modified_flags(1)) {
727 #ifdef KOKKOS_ENABLE_CUDA
728 if (std::is_same<
typename t_dev::memory_space,
729 Kokkos::CudaUVMSpace>::value) {
730 if (d_view.data() == h_view.data())
731 Kokkos::Impl::cuda_prefetch_pointer(
732 Impl::get_cuda_space(args...), d_view.data(),
733 sizeof(
typename t_dev::value_type) * d_view.span(),
true);
737 deep_copy(args..., d_view, h_view);
738 modified_flags(1) = modified_flags(0) = 0;
739 impl_report_device_sync();
743 template <
class ExecSpace>
744 void sync_device(
const ExecSpace& exec) {
745 sync_device_impl(exec);
747 void sync_device() { sync_device_impl(); }
749 template <
class Device>
750 bool need_sync()
const {
751 if (modified_flags.data() ==
nullptr)
return false;
752 int dev = get_device_side<Device>();
755 if ((modified_flags(0) > 0) && (modified_flags(0) >= modified_flags(1))) {
760 if ((modified_flags(1) > 0) && (modified_flags(1) >= modified_flags(0))) {
767 inline bool need_sync_host()
const {
768 if (modified_flags.data() ==
nullptr)
return false;
769 return modified_flags(0) < modified_flags(1);
772 inline bool need_sync_device()
const {
773 if (modified_flags.data() ==
nullptr)
return false;
774 return modified_flags(1) < modified_flags(0);
776 void impl_report_device_modification() {
777 if (Kokkos::Tools::Experimental::get_callbacks().modify_dual_view !=
779 Kokkos::Tools::modifyDualView(
781 reinterpret_cast<void*
>(
reinterpret_cast<uintptr_t
>(d_view.data()) -
786 void impl_report_host_modification() {
787 if (Kokkos::Tools::Experimental::get_callbacks().modify_dual_view !=
789 Kokkos::Tools::modifyDualView(
791 reinterpret_cast<void*
>(
reinterpret_cast<uintptr_t
>(h_view.data()) -
801 template <
class Device,
class Dummy = DualView,
802 std::enable_if_t<!Dummy::impl_dualview_is_single_device::value>* =
805 if (modified_flags.data() ==
nullptr) {
806 modified_flags = t_modified_flags(
"DualView::modified_flags");
809 int dev = get_device_side<Device>();
814 (modified_flags(1) > modified_flags(0) ? modified_flags(1)
815 : modified_flags(0)) +
817 impl_report_device_modification();
822 (modified_flags(1) > modified_flags(0) ? modified_flags(1)
823 : modified_flags(0)) +
825 impl_report_host_modification();
828 #ifdef KOKKOS_ENABLE_DEBUG_DUALVIEW_MODIFY_CHECK
829 if (modified_flags(0) && modified_flags(1)) {
830 std::string msg =
"Kokkos::DualView::modify ERROR: ";
831 msg +=
"Concurrent modification of host and device views ";
832 msg +=
"in DualView \"";
833 msg += d_view.label();
835 Kokkos::abort(msg.c_str());
841 class Device,
class Dummy = DualView,
842 std::enable_if_t<Dummy::impl_dualview_is_single_device::value>* =
nullptr>
847 template <
class Dummy = DualView,
848 std::enable_if_t<!Dummy::impl_dualview_is_single_device::value>* =
850 inline void modify_host() {
851 if (modified_flags.data() !=
nullptr) {
853 (modified_flags(1) > modified_flags(0) ? modified_flags(1)
854 : modified_flags(0)) +
856 impl_report_host_modification();
857 #ifdef KOKKOS_ENABLE_DEBUG_DUALVIEW_MODIFY_CHECK
858 if (modified_flags(0) && modified_flags(1)) {
859 std::string msg =
"Kokkos::DualView::modify_host ERROR: ";
860 msg +=
"Concurrent modification of host and device views ";
861 msg +=
"in DualView \"";
862 msg += d_view.label();
864 Kokkos::abort(msg.c_str());
871 class Dummy = DualView,
872 std::enable_if_t<Dummy::impl_dualview_is_single_device::value>* =
nullptr>
873 inline void modify_host() {
877 template <
class Dummy = DualView,
878 std::enable_if_t<!Dummy::impl_dualview_is_single_device::value>* =
880 inline void modify_device() {
881 if (modified_flags.data() !=
nullptr) {
883 (modified_flags(1) > modified_flags(0) ? modified_flags(1)
884 : modified_flags(0)) +
886 impl_report_device_modification();
887 #ifdef KOKKOS_ENABLE_DEBUG_DUALVIEW_MODIFY_CHECK
888 if (modified_flags(0) && modified_flags(1)) {
889 std::string msg =
"Kokkos::DualView::modify_device ERROR: ";
890 msg +=
"Concurrent modification of host and device views ";
891 msg +=
"in DualView \"";
892 msg += d_view.label();
894 Kokkos::abort(msg.c_str());
901 class Dummy = DualView,
902 std::enable_if_t<Dummy::impl_dualview_is_single_device::value>* =
nullptr>
903 inline void modify_device() {
907 inline void clear_sync_state() {
908 if (modified_flags.data() !=
nullptr)
909 modified_flags(1) = modified_flags(0) = 0;
921 template <
class... ViewCtorArgs>
922 void impl_realloc(
const size_t n0,
const size_t n1,
const size_t n2,
923 const size_t n3,
const size_t n4,
const size_t n5,
924 const size_t n6,
const size_t n7,
925 const Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop) {
926 using alloc_prop_input = Impl::ViewCtorProp<ViewCtorArgs...>;
928 static_assert(!alloc_prop_input::has_label,
929 "The view constructor arguments passed to Kokkos::realloc "
930 "must not include a label!");
932 !alloc_prop_input::has_pointer,
933 "The view constructor arguments passed to Kokkos::realloc must "
934 "not include a pointer!");
936 !alloc_prop_input::has_memory_space,
937 "The view constructor arguments passed to Kokkos::realloc must "
938 "not include a memory space instance!");
940 const size_t new_extents[8] = {n0, n1, n2, n3, n4, n5, n6, n7};
941 const bool sizeMismatch =
942 Impl::size_mismatch(h_view, h_view.rank_dynamic, new_extents);
945 if constexpr (alloc_prop_input::sequential_host_init) {
946 static_assert(alloc_prop_input::initialize,
947 "DualView: SequentialHostInit isn't compatible with "
948 "WithoutInitializing!");
949 ::Kokkos::realloc(arg_prop, h_view, n0, n1, n2, n3, n4, n5, n6, n7);
951 create_mirror_view_and_copy(
typename t_dev::memory_space(), h_view);
953 ::Kokkos::realloc(arg_prop, d_view, n0, n1, n2, n3, n4, n5, n6, n7);
954 if constexpr (alloc_prop_input::initialize) {
955 h_view = create_mirror_view(
typename t_host::memory_space(), d_view);
957 h_view = create_mirror_view(Kokkos::WithoutInitializing,
958 typename t_host::memory_space(), d_view);
961 }
else if constexpr (alloc_prop_input::initialize) {
962 if constexpr (alloc_prop_input::has_execution_space) {
963 const auto& exec_space =
964 Impl::get_property<Impl::ExecutionSpaceTag>(arg_prop);
965 ::Kokkos::deep_copy(exec_space, d_view,
typename t_dev::value_type{});
967 ::Kokkos::deep_copy(d_view,
typename t_dev::value_type{});
971 if (modified_flags.data() ==
nullptr) {
972 modified_flags = t_modified_flags(
"DualView::modified_flags");
974 modified_flags(1) = modified_flags(0) = 0;
977 template <
class... ViewCtorArgs>
978 void realloc(
const Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop,
979 const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
980 const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
981 const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
982 const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
983 const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
984 const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
985 const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
986 const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG) {
987 impl_realloc(n0, n1, n2, n3, n4, n5, n6, n7, arg_prop);
990 void realloc(
const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
991 const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
992 const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
993 const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
994 const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
995 const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
996 const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
997 const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG) {
998 impl_realloc(n0, n1, n2, n3, n4, n5, n6, n7, Impl::ViewCtorProp<>{});
1001 template <
typename I>
1002 std::enable_if_t<Impl::is_view_ctor_property<I>::value> realloc(
1003 const I& arg_prop,
const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1004 const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1005 const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1006 const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1007 const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1008 const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1009 const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1010 const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG) {
1011 impl_realloc(n0, n1, n2, n3, n4, n5, n6, n7, Kokkos::view_alloc(arg_prop));
1018 template <
class... ViewCtorArgs>
1019 void impl_resize(
const Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop,
1020 const size_t n0,
const size_t n1,
const size_t n2,
1021 const size_t n3,
const size_t n4,
const size_t n5,
1022 const size_t n6,
const size_t n7) {
1023 using alloc_prop_input = Impl::ViewCtorProp<ViewCtorArgs...>;
1025 static_assert(!alloc_prop_input::has_label,
1026 "The view constructor arguments passed to Kokkos::resize "
1027 "must not include a label!");
1029 !alloc_prop_input::has_pointer,
1030 "The view constructor arguments passed to Kokkos::resize must "
1031 "not include a pointer!");
1033 !alloc_prop_input::has_memory_space,
1034 "The view constructor arguments passed to Kokkos::resize must "
1035 "not include a memory space instance!");
1037 const size_t new_extents[8] = {n0, n1, n2, n3, n4, n5, n6, n7};
1038 const bool sizeMismatch =
1039 Impl::size_mismatch(h_view, h_view.rank_dynamic, new_extents);
1041 if (modified_flags.data() ==
nullptr) {
1042 modified_flags = t_modified_flags(
"DualView::modified_flags");
1045 [[maybe_unused]]
auto resize_on_device = [&](
const auto& properties) {
1048 ::Kokkos::resize(properties, d_view, n0, n1, n2, n3, n4, n5, n6, n7);
1052 resync_host(properties);
1055 ++modified_flags(1);
1059 [[maybe_unused]]
auto resize_on_host = [&](
const auto& properties) {
1062 ::Kokkos::resize(properties, h_view, n0, n1, n2, n3, n4, n5, n6, n7);
1066 resync_device(properties);
1069 ++modified_flags(0);
1073 if constexpr (alloc_prop_input::sequential_host_init) {
1074 static_assert(alloc_prop_input::initialize,
1075 "DualView: SequentialHostInit isn't compatible with "
1076 "WithoutInitializing!");
1077 static_assert(!alloc_prop_input::has_execution_space,
1078 "DualView: SequentialHostInit isn't compatible with "
1079 "providing an execution space instance!");
1082 sync<typename t_host::memory_space>();
1083 ::Kokkos::resize(arg_prop, h_view, n0, n1, n2, n3, n4, n5, n6, n7);
1085 create_mirror_view_and_copy(
typename t_dev::memory_space(), h_view);
1088 }
else if constexpr (alloc_prop_input::has_execution_space) {
1089 using ExecSpace =
typename alloc_prop_input::execution_space;
1090 const auto& exec_space =
1091 Impl::get_property<Impl::ExecutionSpaceTag>(arg_prop);
1092 constexpr
bool exec_space_can_access_device =
1093 SpaceAccessibility<ExecSpace,
1094 typename t_dev::memory_space>::accessible;
1095 constexpr
bool exec_space_can_access_host =
1096 SpaceAccessibility<ExecSpace,
1097 typename t_host::memory_space>::accessible;
1098 static_assert(exec_space_can_access_device || exec_space_can_access_host);
1099 if constexpr (exec_space_can_access_device) {
1100 sync<typename t_dev::memory_space>(exec_space);
1101 resize_on_device(arg_prop);
1104 if constexpr (exec_space_can_access_host) {
1105 sync<typename t_host::memory_space>(exec_space);
1106 resize_on_host(arg_prop);
1110 if (modified_flags(1) >= modified_flags(0)) {
1111 resize_on_device(arg_prop);
1113 resize_on_host(arg_prop);
1122 template <
class... ViewCtorArgs>
1123 inline void resync_host(Impl::ViewCtorProp<ViewCtorArgs...>
const&) {
1124 using alloc_prop_input = Impl::ViewCtorProp<ViewCtorArgs...>;
1126 if constexpr (alloc_prop_input::initialize) {
1127 h_view = create_mirror_view(
typename t_host::memory_space(), d_view);
1129 h_view = create_mirror_view(Kokkos::WithoutInitializing,
1130 typename t_host::memory_space(), d_view);
1137 template <
class... ViewCtorArgs>
1138 inline void resync_device(Impl::ViewCtorProp<ViewCtorArgs...>
const&) {
1139 using alloc_prop_input = Impl::ViewCtorProp<ViewCtorArgs...>;
1141 if constexpr (alloc_prop_input::initialize) {
1142 d_view = create_mirror_view(
typename t_dev::memory_space(), h_view);
1145 d_view = create_mirror_view(Kokkos::WithoutInitializing,
1146 typename t_dev::memory_space(), h_view);
1151 void resize(
const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1152 const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1153 const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1154 const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1155 const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1156 const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1157 const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1158 const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG) {
1159 impl_resize(Impl::ViewCtorProp<>{}, n0, n1, n2, n3, n4, n5, n6, n7);
1162 template <
class... ViewCtorArgs>
1163 void resize(
const Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop,
1164 const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1165 const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1166 const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1167 const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1168 const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1169 const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1170 const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1171 const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG) {
1172 impl_resize(arg_prop, n0, n1, n2, n3, n4, n5, n6, n7);
1176 std::enable_if_t<Impl::is_view_ctor_property<I>::value> resize(
1177 const I& arg_prop,
const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1178 const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1179 const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1180 const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1181 const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1182 const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1183 const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1184 const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG) {
1185 impl_resize(Kokkos::view_alloc(arg_prop), n0, n1, n2, n3, n4, n5, n6, n7);
1193 KOKKOS_INLINE_FUNCTION constexpr
size_t span()
const {
return d_view.span(); }
1195 KOKKOS_INLINE_FUNCTION
bool span_is_contiguous()
const {
1196 return d_view.span_is_contiguous();
1200 template <
typename iType>
1201 void stride(iType* stride_)
const {
1202 d_view.stride(stride_);
1205 template <
typename iType>
1206 KOKKOS_INLINE_FUNCTION constexpr std::enable_if_t<std::is_integral_v<iType>,
1208 extent(
const iType& r)
const {
1209 return d_view.extent(r);
1212 template <
typename iType>
1213 KOKKOS_INLINE_FUNCTION constexpr std::enable_if_t<std::is_integral_v<iType>,
1215 extent_int(
const iType& r)
const {
1216 return static_cast<int>(d_view.extent(r));
1236 template <
class D,
class... P>
1237 struct V2DV<
View<D, P...>> {
1238 using type = DualView<D, P...>;
1242 template <
class DataType,
class... Properties,
class... Args>
1243 auto subview(
const DualView<DataType, Properties...>& src, Args&&... args) {
1245 using deduce_subview_type =
1246 decltype(subview(std::declval<View<DataType, Properties...>>(),
1247 std::forward<Args>(args)...));
1249 return typename Impl::V2DV<deduce_subview_type>::type(
1250 src, std::forward<Args>(args)...);
1264 template <
class DT,
class... DP,
class ST,
class... SP>
1265 void deep_copy(DualView<DT, DP...>& dst,
const DualView<ST, SP...>& src) {
1266 if (src.need_sync_device()) {
1267 deep_copy(dst.h_view, src.h_view);
1270 deep_copy(dst.d_view, src.d_view);
1271 dst.modify_device();
1275 template <
class ExecutionSpace,
class DT,
class... DP,
class ST,
class... SP>
1276 void deep_copy(
const ExecutionSpace& exec, DualView<DT, DP...>& dst,
1277 const DualView<ST, SP...>& src) {
1278 if (src.need_sync_device()) {
1279 deep_copy(exec, dst.h_view, src.h_view);
1282 deep_copy(exec, dst.d_view, src.d_view);
1283 dst.modify_device();
1298 template <
class... Properties,
class... Args>
1299 void resize(DualView<Properties...>& dv, Args&&... args) noexcept(
1300 noexcept(dv.resize(std::forward<Args>(args)...))) {
1301 dv.resize(std::forward<Args>(args)...);
1304 template <
class... ViewCtorArgs,
class... Properties,
class... Args>
1306 const Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop,
1307 DualView<Properties...>& dv,
1308 Args&&... args) noexcept(noexcept(dv.resize(arg_prop,
1309 std::forward<Args>(args)...))) {
1310 dv.resize(arg_prop, std::forward<Args>(args)...);
1313 template <
class I,
class... Properties,
class... Args>
1314 std::enable_if_t<Impl::is_view_ctor_property<I>::value> resize(
1315 const I& arg_prop, DualView<Properties...>& dv,
1316 Args&&... args) noexcept(noexcept(dv.resize(arg_prop,
1317 std::forward<Args>(args)...))) {
1318 dv.resize(arg_prop, std::forward<Args>(args)...);
1321 template <
class... ViewCtorArgs,
class... Properties,
class... Args>
1322 void realloc(
const Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop,
1323 DualView<Properties...>& dv,
1324 Args&&... args) noexcept(noexcept(dv
1325 .realloc(std::forward<Args>(
1327 dv.realloc(arg_prop, std::forward<Args>(args)...);
1330 template <
class... Properties,
class... Args>
1331 void realloc(DualView<Properties...>& dv, Args&&... args) noexcept(
1332 noexcept(dv.realloc(std::forward<Args>(args)...))) {
1333 dv.realloc(std::forward<Args>(args)...);
1336 template <
class I,
class... Properties,
class... Args>
1337 std::enable_if_t<Impl::is_view_ctor_property<I>::value> realloc(
1338 const I& arg_prop, DualView<Properties...>& dv,
1339 Args&&... args) noexcept(noexcept(dv.realloc(arg_prop,
1342 dv.realloc(arg_prop, std::forward<Args>(args)...);
1347 #ifdef KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_DUALVIEW
1348 #undef KOKKOS_IMPL_PUBLIC_INCLUDE
1349 #undef KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_DUALVIEW