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 =
199 typename t_dev_const_randomread_um::HostMirror;
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 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!");
287
288 d_view = Kokkos::create_mirror_view_and_copy(
289 typename traits::memory_space{}, h_view);
290 } else {
291 d_view = t_dev(arg_prop, n0, n1, n2, n3, n4, n5, n6, n7);
292
293 // without UVM, host View mirrors
294 if constexpr (Kokkos::Impl::has_type<Impl::WithoutInitializing_t,
295 P...>::value)
296 h_view =
297 Kokkos::create_mirror_view(Kokkos::WithoutInitializing, d_view);
298 else
299 h_view = Kokkos::create_mirror_view(d_view);
300 }
301 }
302
304 template <typename DT, typename... DP>
305 DualView(const DualView<DT, DP...>& src)
306 : modified_flags(src.modified_flags),
307 d_view(src.d_view),
308 h_view(src.h_view) {}
309
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...)) {}
316
327 DualView(const t_dev& d_view_, const t_host& h_view_)
328 : modified_flags(t_modified_flags("DualView::modified_flags")),
329 d_view(d_view_),
330 h_view(h_view_) {
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");
351 }
352 }
353 // does the DualView have only one device
354 struct impl_dualview_is_single_device {
355 enum : bool {
356 value = std::is_same_v<typename t_dev::device_type,
357 typename t_host::device_type>
358 };
359 };
360
361 // does the given device match the device of t_dev?
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> };
365 };
366 // does the given device match the device of t_host?
367 template <typename Device>
368 struct impl_device_matches_thost_device {
369 enum : bool {
370 value = std::is_same_v<typename t_host::device_type, Device>
371 };
372 };
373
374 // does the given device match the execution space of t_host?
375 template <typename Device>
376 struct impl_device_matches_thost_exec {
377 enum : bool {
378 value = std::is_same_v<typename t_host::execution_space, Device>
379 };
380 };
381
382 // does the given device match the execution space of t_dev?
383 template <typename Device>
384 struct impl_device_matches_tdev_exec {
385 enum : bool {
386 value = std::is_same_v<typename t_dev::execution_space, Device>
387 };
388 };
389
390 // does the given device's memory space match the memory space of t_dev?
391 template <typename Device>
392 struct impl_device_matches_tdev_memory_space {
393 enum : bool {
394 value = std::is_same_v<typename t_dev::memory_space,
395 typename Device::memory_space>
396 };
397 };
398
400
402
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>) {
425 return d_view;
426 } else {
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!");
431 return h_view;
432 }
433 } else {
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>) {
437 return d_view;
438 } else {
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!");
443 return h_view;
444 }
445 } else {
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>)
450 return d_view;
451 else {
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!");
455 return h_view;
456 }
457 }
458 }
459#ifdef KOKKOS_COMPILER_INTEL
460 __builtin_unreachable();
461#endif
462 }
463
464 KOKKOS_INLINE_FUNCTION
465 t_host view_host() const { return h_view; }
466
467 KOKKOS_INLINE_FUNCTION
468 t_dev view_device() const { return d_view; }
469
470 KOKKOS_INLINE_FUNCTION constexpr bool is_allocated() const {
471 return (d_view.is_allocated() && h_view.is_allocated());
472 }
473
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>;
498
499 static_assert(
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");
510
511 int dev = -1;
512 if (device_is_t_dev_device)
513 dev = 1;
514 else if (device_is_t_host_device)
515 dev = 0;
516 else {
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;
521 }
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;
526 }
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;
534 }
535 }
536 return dev;
537 }
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 !=
541 nullptr) {
542 Kokkos::Tools::syncDualView(
543 h_view.label(),
544 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(h_view.data()) -
545 view_header_size),
546 false);
547 }
548 }
549 void impl_report_device_sync() const noexcept {
550 if (Kokkos::Tools::Experimental::get_callbacks().sync_dual_view !=
551 nullptr) {
552 Kokkos::Tools::syncDualView(
553 d_view.label(),
554 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(d_view.data()) -
555 view_header_size),
556 true);
557 }
558 }
559
577 // deliberately passing args by cref as they're used multiple times
578 template <class Device, class... Args>
579 void sync_impl(std::true_type, Args const&... args) {
580 if (modified_flags.data() == nullptr) return;
581
582 int dev = get_device_side<Device>();
583
584 if (dev == 1) { // if Device is the same as DualView's device type
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);
593 }
594#endif
595
596 deep_copy(args..., d_view, h_view);
597 modified_flags(0) = modified_flags(1) = 0;
598 impl_report_device_sync();
599 }
600 }
601 if (dev == 0) { // hopefully Device is the same as DualView's host type
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);
610 }
611#endif
612
613 deep_copy(args..., h_view, d_view);
614 modified_flags(0) = modified_flags(1) = 0;
615 impl_report_host_sync();
616 }
617 }
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");
624 }
625 }
626
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>),
632 int>& = 0) {
633 sync_impl<Device>(std::true_type{});
634 }
635
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>),
642 int>& = 0) {
643 sync_impl<Device>(std::true_type{}, exec);
644 }
645
646 // deliberately passing args by cref as they're used multiple times
647 template <class Device, class... Args>
648 void sync_impl(std::false_type, Args const&...) {
649 if (modified_flags.data() == nullptr) return;
650
651 int dev = get_device_side<Device>();
652
653 if (dev == 1) { // if Device is the same as DualView's device type
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.");
657 }
658 impl_report_device_sync();
659 }
660 if (dev == 0) { // hopefully Device is the same as DualView's host type
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.");
664 }
665 impl_report_host_sync();
666 }
667 }
668
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>),
674 int>& = 0) {
675 sync_impl<Device>(std::false_type{});
676 }
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>),
683 int>& = 0) {
684 sync_impl<Device>(std::false_type{}, exec);
685 }
686
687 // deliberately passing args by cref as they're used multiple times
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);
703 }
704#endif
705
706 deep_copy(args..., h_view, d_view);
707 modified_flags(1) = modified_flags(0) = 0;
708 impl_report_host_sync();
709 }
710 }
711
712 template <class ExecSpace>
713 void sync_host(const ExecSpace& exec) {
714 sync_host_impl(exec);
715 }
716 void sync_host() { sync_host_impl(); }
717
718 // deliberately passing args by cref as they're used multiple times
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);
734 }
735#endif
736
737 deep_copy(args..., d_view, h_view);
738 modified_flags(1) = modified_flags(0) = 0;
739 impl_report_device_sync();
740 }
741 }
742
743 template <class ExecSpace>
744 void sync_device(const ExecSpace& exec) {
745 sync_device_impl(exec);
746 }
747 void sync_device() { sync_device_impl(); }
748
749 template <class Device>
750 bool need_sync() const {
751 if (modified_flags.data() == nullptr) return false;
752 int dev = get_device_side<Device>();
753
754 if (dev == 1) { // if Device is the same as DualView's device type
755 if ((modified_flags(0) > 0) && (modified_flags(0) >= modified_flags(1))) {
756 return true;
757 }
758 }
759 if (dev == 0) { // hopefully Device is the same as DualView's host type
760 if ((modified_flags(1) > 0) && (modified_flags(1) >= modified_flags(0))) {
761 return true;
762 }
763 }
764 return false;
765 }
766
767 inline bool need_sync_host() const {
768 if (modified_flags.data() == nullptr) return false;
769 return modified_flags(0) < modified_flags(1);
770 }
771
772 inline bool need_sync_device() const {
773 if (modified_flags.data() == nullptr) return false;
774 return modified_flags(1) < modified_flags(0);
775 }
776 void impl_report_device_modification() {
777 if (Kokkos::Tools::Experimental::get_callbacks().modify_dual_view !=
778 nullptr) {
779 Kokkos::Tools::modifyDualView(
780 d_view.label(),
781 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(d_view.data()) -
782 view_header_size),
783 true);
784 }
785 }
786 void impl_report_host_modification() {
787 if (Kokkos::Tools::Experimental::get_callbacks().modify_dual_view !=
788 nullptr) {
789 Kokkos::Tools::modifyDualView(
790 h_view.label(),
791 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(h_view.data()) -
792 view_header_size),
793 false);
794 }
795 }
801 template <class Device, class Dummy = DualView,
802 std::enable_if_t<!Dummy::impl_dualview_is_single_device::value>* =
803 nullptr>
804 void modify() {
805 if (modified_flags.data() == nullptr) {
806 modified_flags = t_modified_flags("DualView::modified_flags");
807 }
808
809 int dev = get_device_side<Device>();
810
811 if (dev == 1) { // if Device is the same as DualView's device type
812 // Increment the device's modified count.
813 modified_flags(1) =
814 (modified_flags(1) > modified_flags(0) ? modified_flags(1)
815 : modified_flags(0)) +
816 1;
817 impl_report_device_modification();
818 }
819 if (dev == 0) { // hopefully Device is the same as DualView's host type
820 // Increment the host's modified count.
821 modified_flags(0) =
822 (modified_flags(1) > modified_flags(0) ? modified_flags(1)
823 : modified_flags(0)) +
824 1;
825 impl_report_host_modification();
826 }
827
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();
834 msg += "\"\n";
835 Kokkos::abort(msg.c_str());
836 }
837#endif
838 }
839
840 template <
841 class Device, class Dummy = DualView,
842 std::enable_if_t<Dummy::impl_dualview_is_single_device::value>* = nullptr>
843 void modify() {
844 return;
845 }
846
847 template <class Dummy = DualView,
848 std::enable_if_t<!Dummy::impl_dualview_is_single_device::value>* =
849 nullptr>
850 inline void modify_host() {
851 if (modified_flags.data() != nullptr) {
852 modified_flags(0) =
853 (modified_flags(1) > modified_flags(0) ? modified_flags(1)
854 : modified_flags(0)) +
855 1;
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();
863 msg += "\"\n";
864 Kokkos::abort(msg.c_str());
865 }
866#endif
867 }
868 }
869
870 template <
871 class Dummy = DualView,
872 std::enable_if_t<Dummy::impl_dualview_is_single_device::value>* = nullptr>
873 inline void modify_host() {
874 return;
875 }
876
877 template <class Dummy = DualView,
878 std::enable_if_t<!Dummy::impl_dualview_is_single_device::value>* =
879 nullptr>
880 inline void modify_device() {
881 if (modified_flags.data() != nullptr) {
882 modified_flags(1) =
883 (modified_flags(1) > modified_flags(0) ? modified_flags(1)
884 : modified_flags(0)) +
885 1;
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();
893 msg += "\"\n";
894 Kokkos::abort(msg.c_str());
895 }
896#endif
897 }
898 }
899
900 template <
901 class Dummy = DualView,
902 std::enable_if_t<Dummy::impl_dualview_is_single_device::value>* = nullptr>
903 inline void modify_device() {
904 return;
905 }
906
907 inline void clear_sync_state() {
908 if (modified_flags.data() != nullptr)
909 modified_flags(1) = modified_flags(0) = 0;
910 }
911
913
915
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...>;
927
928 static_assert(!alloc_prop_input::has_label,
929 "The view constructor arguments passed to Kokkos::realloc "
930 "must not include a label!");
931 static_assert(
932 !alloc_prop_input::has_pointer,
933 "The view constructor arguments passed to Kokkos::realloc must "
934 "not include a pointer!");
935 static_assert(
936 !alloc_prop_input::has_memory_space,
937 "The view constructor arguments passed to Kokkos::realloc must "
938 "not include a memory space instance!");
939
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);
943
944 if (sizeMismatch) {
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);
950 d_view =
951 create_mirror_view_and_copy(typename t_dev::memory_space(), h_view);
952 } else {
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);
956 } else {
957 h_view = create_mirror_view(Kokkos::WithoutInitializing,
958 typename t_host::memory_space(), d_view);
959 }
960 }
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{});
966 } else
967 ::Kokkos::deep_copy(d_view, typename t_dev::value_type{});
968 }
969
970 /* Reset dirty flags */
971 if (modified_flags.data() == nullptr) {
972 modified_flags = t_modified_flags("DualView::modified_flags");
973 } else
974 modified_flags(1) = modified_flags(0) = 0;
975 }
976
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);
988 }
989
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<>{});
999 }
1000
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));
1012 }
1013
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...>;
1024
1025 static_assert(!alloc_prop_input::has_label,
1026 "The view constructor arguments passed to Kokkos::resize "
1027 "must not include a label!");
1028 static_assert(
1029 !alloc_prop_input::has_pointer,
1030 "The view constructor arguments passed to Kokkos::resize must "
1031 "not include a pointer!");
1032 static_assert(
1033 !alloc_prop_input::has_memory_space,
1034 "The view constructor arguments passed to Kokkos::resize must "
1035 "not include a memory space instance!");
1036
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);
1040
1041 if (modified_flags.data() == nullptr) {
1042 modified_flags = t_modified_flags("DualView::modified_flags");
1043 }
1044
1045 [[maybe_unused]] auto resize_on_device = [&](const auto& properties) {
1046 /* Resize on Device */
1047 if (sizeMismatch) {
1048 ::Kokkos::resize(properties, d_view, n0, n1, n2, n3, n4, n5, n6, n7);
1049 // this part of the lambda was relocated in a method as it contains a
1050 // `if constexpr`. In some cases, both branches were evaluated
1051 // leading to a compile error
1052 resync_host(properties);
1053
1054 /* Mark Device copy as modified */
1055 ++modified_flags(1);
1056 }
1057 };
1058
1059 [[maybe_unused]] auto resize_on_host = [&](const auto& properties) {
1060 /* Resize on Host */
1061 if (sizeMismatch) {
1062 ::Kokkos::resize(properties, h_view, n0, n1, n2, n3, n4, n5, n6, n7);
1063 // this part of the lambda was relocated in a method as it contains a
1064 // `if constexpr`. In some cases, both branches were evaluated
1065 // leading to a compile error
1066 resync_device(properties);
1067
1068 /* Mark Host copy as modified */
1069 ++modified_flags(0);
1070 }
1071 };
1072
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!");
1080
1081 if (sizeMismatch) {
1082 sync<typename t_host::memory_space>();
1083 ::Kokkos::resize(arg_prop, h_view, n0, n1, n2, n3, n4, n5, n6, n7);
1084 d_view =
1085 create_mirror_view_and_copy(typename t_dev::memory_space(), h_view);
1086 }
1087 return;
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);
1102 return;
1103 }
1104 if constexpr (exec_space_can_access_host) {
1105 sync<typename t_host::memory_space>(exec_space);
1106 resize_on_host(arg_prop);
1107 return;
1108 }
1109 } else {
1110 if (modified_flags(1) >= modified_flags(0)) {
1111 resize_on_device(arg_prop);
1112 } else {
1113 resize_on_host(arg_prop);
1114 }
1115 }
1116 }
1117
1118 private:
1119 // resync host mirror from device
1120 // this code was relocated from a lambda as it contains a `if constexpr`.
1121 // In some cases, both branches were evaluated, leading to a compile error
1122 template <class... ViewCtorArgs>
1123 inline void resync_host(Impl::ViewCtorProp<ViewCtorArgs...> const&) {
1124 using alloc_prop_input = Impl::ViewCtorProp<ViewCtorArgs...>;
1125
1126 if constexpr (alloc_prop_input::initialize) {
1127 h_view = create_mirror_view(typename t_host::memory_space(), d_view);
1128 } else {
1129 h_view = create_mirror_view(Kokkos::WithoutInitializing,
1130 typename t_host::memory_space(), d_view);
1131 }
1132 }
1133
1134 // resync device mirror from host
1135 // this code was relocated from a lambda as it contains a `if constexpr`
1136 // In some cases, both branches were evaluated leading to a compile error
1137 template <class... ViewCtorArgs>
1138 inline void resync_device(Impl::ViewCtorProp<ViewCtorArgs...> const&) {
1139 using alloc_prop_input = Impl::ViewCtorProp<ViewCtorArgs...>;
1140
1141 if constexpr (alloc_prop_input::initialize) {
1142 d_view = create_mirror_view(typename t_dev::memory_space(), h_view);
1143
1144 } else {
1145 d_view = create_mirror_view(Kokkos::WithoutInitializing,
1146 typename t_dev::memory_space(), h_view);
1147 }
1148 }
1149
1150 public:
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);
1160 }
1161
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);
1173 }
1174
1175 template <class I>
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);
1186 }
1187
1189
1191
1193 KOKKOS_INLINE_FUNCTION constexpr size_t span() const { return d_view.span(); }
1194
1195 KOKKOS_INLINE_FUNCTION bool span_is_contiguous() const {
1196 return d_view.span_is_contiguous();
1197 }
1198
1200 template <typename iType>
1201 void stride(iType* stride_) const {
1202 d_view.stride(stride_);
1203 }
1204
1205 template <typename iType>
1206 KOKKOS_INLINE_FUNCTION constexpr std::enable_if_t<std::is_integral_v<iType>,
1207 size_t>
1208 extent(const iType& r) const {
1209 return d_view.extent(r);
1210 }
1211
1212 template <typename iType>
1213 KOKKOS_INLINE_FUNCTION constexpr std::enable_if_t<std::is_integral_v<iType>,
1214 int>
1215 extent_int(const iType& r) const {
1216 return static_cast<int>(d_view.extent(r));
1217 }
1218
1220};
1221
1222} // namespace Kokkos
1223
1224//----------------------------------------------------------------------------
1225//----------------------------------------------------------------------------
1226//
1227// Partial specializations of Kokkos::subview() for DualView objects.
1228//
1229
1230namespace Kokkos {
1231namespace Impl {
1232
1233template <class V>
1234struct V2DV;
1235
1236template <class D, class... P>
1237struct V2DV<View<D, P...>> {
1238 using type = DualView<D, P...>;
1239};
1240} /* namespace Impl */
1241
1242template <class DataType, class... Properties, class... Args>
1243auto subview(const DualView<DataType, Properties...>& src, Args&&... args) {
1244 // leverage Kokkos::View facilities to deduce the properties of the subview
1245 using deduce_subview_type =
1246 decltype(subview(std::declval<View<DataType, Properties...>>(),
1247 std::forward<Args>(args)...));
1248 // map it back to dual view
1249 return typename Impl::V2DV<deduce_subview_type>::type(
1250 src, std::forward<Args>(args)...);
1251}
1252
1253} /* namespace Kokkos */
1254
1255//----------------------------------------------------------------------------
1256//----------------------------------------------------------------------------
1257
1258namespace Kokkos {
1259
1260//
1261// Partial specialization of Kokkos::deep_copy() for DualView objects.
1262//
1263
1264template <class DT, class... DP, class ST, class... SP>
1265void 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);
1268 dst.modify_host();
1269 } else {
1270 deep_copy(dst.d_view, src.d_view);
1271 dst.modify_device();
1272 }
1273}
1274
1275template <class ExecutionSpace, class DT, class... DP, class ST, class... SP>
1276void 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);
1280 dst.modify_host();
1281 } else {
1282 deep_copy(exec, dst.d_view, src.d_view);
1283 dst.modify_device();
1284 }
1285}
1286
1287} // namespace Kokkos
1288
1289//----------------------------------------------------------------------------
1290//----------------------------------------------------------------------------
1291
1292namespace Kokkos {
1293
1294//
1295// Non-member resize and realloc
1296//
1297
1298template <class... Properties, class... Args>
1299void resize(DualView<Properties...>& dv, Args&&... args) noexcept(
1300 noexcept(dv.resize(std::forward<Args>(args)...))) {
1301 dv.resize(std::forward<Args>(args)...);
1302}
1303
1304template <class... ViewCtorArgs, class... Properties, class... Args>
1305void resize(
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)...);
1311}
1312
1313template <class I, class... Properties, class... Args>
1314std::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)...);
1319}
1320
1321template <class... ViewCtorArgs, class... Properties, class... Args>
1322void realloc(const Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop,
1323 DualView<Properties...>& dv,
1324 Args&&... args) noexcept(noexcept(dv
1325 .realloc(std::forward<Args>(
1326 args)...))) {
1327 dv.realloc(arg_prop, std::forward<Args>(args)...);
1328}
1329
1330template <class... Properties, class... Args>
1331void realloc(DualView<Properties...>& dv, Args&&... args) noexcept(
1332 noexcept(dv.realloc(std::forward<Args>(args)...))) {
1333 dv.realloc(std::forward<Args>(args)...);
1334}
1335
1336template <class I, class... Properties, class... Args>
1337std::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,
1340 std::forward<Args>(
1341 args)...))) {
1342 dv.realloc(arg_prop, std::forward<Args>(args)...);
1343}
1344
1345} // end namespace Kokkos
1346
1347#ifdef KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_DUALVIEW
1348#undef KOKKOS_IMPL_PUBLIC_INCLUDE
1349#undef KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_DUALVIEW
1350#endif
1351#endif
View
ScopeGuard Some user scope issues have been identified with some Kokkos::finalize calls; ScopeGuard a...