Kokkos Core Kernels Package  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
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 
33 namespace 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 
71 namespace Impl {
72 
73 #ifdef KOKKOS_ENABLE_CUDA
74 
75 inline const Kokkos::Cuda& get_cuda_space(const Kokkos::Cuda& in) { return in; }
76 
77 inline const Kokkos::Cuda& get_cuda_space() {
78  return *Kokkos::Impl::cuda_get_deep_copy_space();
79 }
80 
81 template <typename NonCudaExecSpace>
82 inline 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
91 template <class DataType, class Arg1Type = void, class Arg2Type = void,
92  class Arg3Type = void>
93 class DualView;
94 #else
95 template <class DataType, class... Properties>
96 class DualView;
97 #endif
98 
99 template <class>
100 struct is_dual_view : public std::false_type {};
101 
102 template <class DT, class... DP>
103 struct is_dual_view<DualView<DT, DP...>> : public std::true_type {};
104 
105 template <class DT, class... DP>
106 struct is_dual_view<const DualView<DT, DP...>> : public std::true_type {};
107 
108 template <class T>
109 inline constexpr bool is_dual_view_v = is_dual_view<T>::value;
110 
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>
115 #else
116 template <class DataType, class... Properties>
117 class 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:
212  // does the DualView have only one device
213  static constexpr bool impl_dualview_is_single_device =
214  std::is_same_v<typename t_dev::device_type, typename t_host::device_type>;
216 
217 #ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
218  public:
219 #else
220  private:
221 #endif
222 
223  // Moved this specifically after modified_flags to resolve an alignment issue
224  // on MSVC/NVCC
226 
227  t_dev d_view;
228  t_host h_view;
230 
231  public:
233 
234 
239  DualView() = default;
240 
250  DualView(const std::string& label,
251  const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
252  const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
253  const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
254  const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
255  const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
256  const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
257  const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
258  const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG)
259  : modified_flags(
260  Kokkos::view_alloc(typename t_modified_flags::execution_space{},
261  "DualView::modified_flags")),
262  d_view(label, n0, n1, n2, n3, n4, n5, n6, n7),
263  h_view(create_mirror_view(d_view)) // without UVM, host View mirrors
264  {}
265 
276  template <class... P>
277  DualView(const Impl::ViewCtorProp<P...>& arg_prop,
278  std::enable_if_t<!Impl::ViewCtorProp<P...>::has_pointer,
279  size_t> const n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
280  const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
281  const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
282  const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
283  const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
284  const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
285  const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
286  const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG)
287  : modified_flags(t_modified_flags("DualView::modified_flags")) {
288  if constexpr (Impl::ViewCtorProp<P...>::sequential_host_init) {
289  h_view = t_host(arg_prop, n0, n1, n2, n3, n4, n5, n6, n7);
290  static_assert(Impl::ViewCtorProp<P...>::initialize,
291  "DualView: SequentialHostInit isn't compatible with "
292  "WithoutInitializing!");
293  static_assert(!Impl::ViewCtorProp<P...>::has_execution_space,
294  "DualView: SequentialHostInit isn't compatible with "
295  "providing an execution space instance!");
296 
297  d_view = Kokkos::create_mirror_view_and_copy(
298  typename traits::memory_space{}, h_view);
299  } else {
300  d_view = t_dev(arg_prop, n0, n1, n2, n3, n4, n5, n6, n7);
301 
302  // without UVM, host View mirrors
303  if constexpr (Kokkos::Impl::has_type<Impl::WithoutInitializing_t,
304  P...>::value)
305  h_view =
306  Kokkos::create_mirror_view(Kokkos::WithoutInitializing, d_view);
307  else
308  h_view = Kokkos::create_mirror_view(d_view);
309  }
310  }
311 
313  template <typename DT, typename... DP>
314  DualView(const DualView<DT, DP...>& src)
315  : modified_flags(src.modified_flags),
316  d_view(src.d_view),
317  h_view(src.h_view) {}
318 
320  template <class DT, class... DP, class Arg0, class... Args>
321  DualView(const DualView<DT, DP...>& src, const Arg0& arg0, Args... args)
322  : modified_flags(src.modified_flags),
323  d_view(Kokkos::subview(src.d_view, arg0, args...)),
324  h_view(Kokkos::subview(src.h_view, arg0, args...)) {}
325 
336  DualView(const t_dev& d_view_, const t_host& h_view_)
337  : modified_flags(t_modified_flags("DualView::modified_flags")),
338  d_view(d_view_),
339  h_view(h_view_) {
340  if (int(d_view.rank) != int(h_view.rank) ||
341  [&]() {
342  // This has a false positive in clang-tidy
343  // NOLINTNEXTLINE(bugprone-inc-dec-in-conditions)
344  for (size_t r = 0; r < d_view.rank(); ++r) {
345  if (d_view.extent(r) != h_view.extent(r) ||
346  d_view.stride(r) != h_view.stride(r))
347  return true;
348  }
349  return false;
350  }() ||
351  d_view.span() != h_view.span()) {
352  Kokkos::Impl::throw_runtime_exception(
353  "DualView constructed with incompatible views");
354  }
356  typename t_dev::memory_space>::accessible &&
357  (d_view.data() != h_view.data()))
358  Kokkos::abort(
359  "DualView storing one View constructed from two different Views");
360  }
361 
363 
365 
383  template <class Device>
384  KOKKOS_FUNCTION auto view() const {
385  if constexpr (std::is_same_v<Device, typename Device::memory_space>) {
386  if constexpr (std::is_same_v<typename Device::memory_space,
387  typename t_dev::memory_space>) {
388  return d_view;
389  } else {
390  static_assert(std::is_same_v<typename Device::memory_space,
391  typename t_host::memory_space>,
392  "The template argument is a memory space but doesn't "
393  "match either of DualView's memory spaces!");
394  return h_view;
395  }
396  } else {
397  if constexpr (std::is_same_v<Device, typename Device::execution_space>) {
398  if constexpr (std::is_same_v<typename Device::execution_space,
399  typename t_dev::execution_space>) {
400  return d_view;
401  } else {
402  static_assert(std::is_same_v<typename Device::execution_space,
403  typename t_host::execution_space>,
404  "The template argument is an execution space but "
405  "doesn't match either of DualView's execution spaces!");
406  return h_view;
407  }
408  } else {
409  static_assert(std::is_same_v<Device, typename Device::device_type>,
410  "The template argument is neither a memory space, "
411  "execution space, or device!");
412  if constexpr (std::is_same_v<Device, typename t_dev::device_type>)
413  return d_view;
414  else {
415  static_assert(std::is_same_v<Device, typename t_host::device_type>,
416  "The template argument is a device but "
417  "doesn't match either of DualView's devices!");
418  return h_view;
419  }
420  }
421  }
422  }
423 
424 #ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
425  KOKKOS_INLINE_FUNCTION
426  t_host view_host() const { return h_view; }
427 
428  KOKKOS_INLINE_FUNCTION
429  t_dev view_device() const { return d_view; }
430 #else
431  KOKKOS_INLINE_FUNCTION
432  const t_host& view_host() const { return h_view; }
433 
434  KOKKOS_INLINE_FUNCTION
435  const t_dev& view_device() const { return d_view; }
436 #endif
437 
438  KOKKOS_INLINE_FUNCTION constexpr bool is_allocated() const {
439  return (d_view.is_allocated() && h_view.is_allocated());
440  }
441 
442  template <class Device>
443  static int get_device_side() {
444  constexpr bool device_is_memspace =
445  std::is_same_v<Device, typename Device::memory_space>;
446  constexpr bool device_is_execspace =
447  std::is_same_v<Device, typename Device::execution_space>;
448  constexpr bool device_exec_is_t_dev_exec =
449  std::is_same_v<typename Device::execution_space,
450  typename t_dev::execution_space>;
451  constexpr bool device_mem_is_t_dev_mem =
452  std::is_same_v<typename Device::memory_space,
453  typename t_dev::memory_space>;
454  constexpr bool device_exec_is_t_host_exec =
455  std::is_same_v<typename Device::execution_space,
456  typename t_host::execution_space>;
457  constexpr bool device_mem_is_t_host_mem =
458  std::is_same_v<typename Device::memory_space,
459  typename t_host::memory_space>;
460  constexpr bool device_is_t_host_device =
461  std::is_same_v<typename Device::execution_space,
462  typename t_host::device_type>;
463  constexpr bool device_is_t_dev_device =
464  std::is_same_v<typename Device::memory_space,
465  typename t_host::device_type>;
466 
467  static_assert(
468  device_is_t_dev_device || device_is_t_host_device ||
469  (device_is_memspace &&
470  (device_mem_is_t_dev_mem || device_mem_is_t_host_mem)) ||
471  (device_is_execspace &&
472  (device_exec_is_t_dev_exec || device_exec_is_t_host_exec)) ||
473  ((!device_is_execspace && !device_is_memspace) &&
474  ((device_mem_is_t_dev_mem || device_mem_is_t_host_mem) ||
475  (device_exec_is_t_dev_exec || device_exec_is_t_host_exec))),
476  "Template parameter to .sync() must exactly match one of the "
477  "DualView's device types or one of the execution or memory spaces");
478 
479  int dev = -1;
480  if (device_is_t_dev_device)
481  dev = 1;
482  else if (device_is_t_host_device)
483  dev = 0;
484  else {
485  if (device_is_memspace) {
486  if (device_mem_is_t_dev_mem) dev = 1;
487  if (device_mem_is_t_host_mem) dev = 0;
488  if (device_mem_is_t_host_mem && device_mem_is_t_dev_mem) dev = -1;
489  }
490  if (device_is_execspace) {
491  if (device_exec_is_t_dev_exec) dev = 1;
492  if (device_exec_is_t_host_exec) dev = 0;
493  if (device_exec_is_t_host_exec && device_exec_is_t_dev_exec) dev = -1;
494  }
495  if (!device_is_execspace && !device_is_memspace) {
496  if (device_mem_is_t_dev_mem) dev = 1;
497  if (device_mem_is_t_host_mem) dev = 0;
498  if (device_mem_is_t_host_mem && device_mem_is_t_dev_mem) dev = -1;
499  if (device_exec_is_t_dev_exec) dev = 1;
500  if (device_exec_is_t_host_exec) dev = 0;
501  if (device_exec_is_t_host_exec && device_exec_is_t_dev_exec) dev = -1;
502  }
503  }
504  return dev;
505  }
506  static constexpr const int view_header_size = 128;
507  void impl_report_host_sync() const noexcept {
508  if (Kokkos::Tools::Experimental::get_callbacks().sync_dual_view !=
509  nullptr) {
510  Kokkos::Tools::syncDualView(
511  h_view.label(),
512  reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(h_view.data()) -
513  view_header_size),
514  false);
515  }
516  }
517  void impl_report_device_sync() const noexcept {
518  if (Kokkos::Tools::Experimental::get_callbacks().sync_dual_view !=
519  nullptr) {
520  Kokkos::Tools::syncDualView(
521  d_view.label(),
522  reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(d_view.data()) -
523  view_header_size),
524  true);
525  }
526  }
527 
545  // deliberately passing args by cref as they're used multiple times
546  template <class Device, class... Args>
547  void sync_impl(std::true_type, Args const&... args) {
548  if (modified_flags.data() == nullptr) return;
549 
550  int dev = get_device_side<Device>();
551 
552  if (dev == 1) { // if Device is the same as DualView's device type
553  if ((modified_flags(0) > 0) && (modified_flags(0) >= modified_flags(1))) {
554 #ifdef KOKKOS_ENABLE_CUDA
555  if (std::is_same<typename t_dev::memory_space,
556  Kokkos::CudaUVMSpace>::value) {
557  if (d_view.data() == h_view.data())
558  Kokkos::Impl::cuda_prefetch_pointer(
559  Impl::get_cuda_space(args...), d_view.data(),
560  sizeof(typename t_dev::value_type) * d_view.span(), true);
561  }
562 #endif
563 
564  deep_copy(args..., d_view, h_view);
565  modified_flags(0) = modified_flags(1) = 0;
566  impl_report_device_sync();
567  }
568  }
569  if (dev == 0) { // hopefully Device is the same as DualView's host type
570  if ((modified_flags(1) > 0) && (modified_flags(1) >= modified_flags(0))) {
571 #ifdef KOKKOS_ENABLE_CUDA
572  if (std::is_same<typename t_dev::memory_space,
573  Kokkos::CudaUVMSpace>::value) {
574  if (d_view.data() == h_view.data())
575  Kokkos::Impl::cuda_prefetch_pointer(
576  Impl::get_cuda_space(args...), d_view.data(),
577  sizeof(typename t_dev::value_type) * d_view.span(), false);
578  }
579 #endif
580 
581  deep_copy(args..., h_view, d_view);
582  modified_flags(0) = modified_flags(1) = 0;
583  impl_report_host_sync();
584  }
585  }
586  if constexpr (std::is_same_v<typename t_host::memory_space,
587  typename t_dev::memory_space>) {
588  typename t_dev::execution_space().fence(
589  "Kokkos::DualView<>::sync: fence after syncing DualView");
590  typename t_host::execution_space().fence(
591  "Kokkos::DualView<>::sync: fence after syncing DualView");
592  }
593  }
594 
595  template <class Device>
596  void sync() {
597  if constexpr (impl_dualview_is_single_device) {
598  // FIXME_DUALVIEW_ASYNCHRONOUS_BACKENDS
599  // Kokkos::fence(
600  // "Kokkos::DualView: fence for sync with host-accessible memory
601  // space");
602  return;
603  } else {
604  sync_impl<Device>(
605  typename std::is_same<typename traits::data_type,
606  typename traits::non_const_data_type>::type{});
607  }
608  }
609 
610  template <class Device, class ExecutionSpace>
611  void sync([[maybe_unused]] const ExecutionSpace& exec) {
612  if constexpr (impl_dualview_is_single_device)
613  return;
614  else {
615  sync_impl<Device>(
616  typename std::is_same<typename traits::data_type,
617  typename traits::non_const_data_type>::type{},
618  exec);
619  }
620  }
621 
622  // deliberately passing args by cref as they're used multiple times
623  template <class Device, class... Args>
624  void sync_impl(std::false_type, Args const&...) {
625  if (modified_flags.data() == nullptr) return;
626 
627  int dev = get_device_side<Device>();
628 
629  if (dev == 1) { // if Device is the same as DualView's device type
630  if ((modified_flags(0) > 0) && (modified_flags(0) >= modified_flags(1))) {
631  Impl::throw_runtime_exception(
632  "Calling sync on a DualView with a const datatype.");
633  }
634  impl_report_device_sync();
635  }
636  if (dev == 0) { // hopefully Device is the same as DualView's host type
637  if ((modified_flags(1) > 0) && (modified_flags(1) >= modified_flags(0))) {
638  Impl::throw_runtime_exception(
639  "Calling sync on a DualView with a const datatype.");
640  }
641  impl_report_host_sync();
642  }
643  }
644 
645  // deliberately passing args by cref as they're used multiple times
646  template <typename... Args>
647  void sync_host_impl(Args const&... args) {
648  if (!std::is_same_v<typename traits::data_type,
649  typename traits::non_const_data_type>)
650  Impl::throw_runtime_exception(
651  "Calling sync_host on a DualView with a const datatype.");
652  if (modified_flags.data() == nullptr) return;
653  if (modified_flags(1) > modified_flags(0)) {
654 #ifdef KOKKOS_ENABLE_CUDA
655  if (std::is_same<typename t_dev::memory_space,
656  Kokkos::CudaUVMSpace>::value) {
657  if (d_view.data() == h_view.data())
658  Kokkos::Impl::cuda_prefetch_pointer(
659  Impl::get_cuda_space(args...), d_view.data(),
660  sizeof(typename t_dev::value_type) * d_view.span(), false);
661  }
662 #endif
663 
664  deep_copy(args..., h_view, d_view);
665  modified_flags(1) = modified_flags(0) = 0;
666  impl_report_host_sync();
667  }
668  }
669 
670  template <class ExecSpace>
671  void sync_host([[maybe_unused]] const ExecSpace& exec) {
672  if constexpr (impl_dualview_is_single_device)
673  return;
674  else
675  sync_host_impl(exec);
676  }
677  void sync_host() {
678  if constexpr (impl_dualview_is_single_device) {
679  // FIXME_DUALVIEW_ASYNCHRONOUS_BACKENDS
680  // Kokkos::fence(
681  // "Kokkos::DualView: fence for sync_host with host-accessible
682  // memory " "space");
683  return;
684  } else
685  sync_host_impl();
686  }
687 
688  // deliberately passing args by cref as they're used multiple times
689  template <typename... Args>
690  void sync_device_impl(Args const&... args) {
691  if (!std::is_same_v<typename traits::data_type,
692  typename traits::non_const_data_type>)
693  Impl::throw_runtime_exception(
694  "Calling sync_device on a DualView with a const datatype.");
695  if (modified_flags.data() == nullptr) return;
696  if (modified_flags(0) > modified_flags(1)) {
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(), true);
704  }
705 #endif
706 
707  deep_copy(args..., d_view, h_view);
708  modified_flags(1) = modified_flags(0) = 0;
709  impl_report_device_sync();
710  }
711  }
712 
713  template <class ExecSpace>
714  void sync_device([[maybe_unused]] const ExecSpace& exec) {
715  if constexpr (impl_dualview_is_single_device)
716  return;
717  else
718  sync_device_impl(exec);
719  }
720  void sync_device() {
721  if constexpr (impl_dualview_is_single_device) {
722  // FIXME_DUALVIEW_ASYNCHRONOUS_BACKENDS
723  // Kokkos::fence(
724  // "Kokkos::DualView: fence for sync_device with host-accessible
725  // memory " "space");
726  return;
727  } else
728  sync_device_impl();
729  }
730 
731  template <class Device>
732  bool need_sync() const {
733  if (modified_flags.data() == nullptr) return false;
734  int dev = get_device_side<Device>();
735 
736  if (dev == 1) { // if Device is the same as DualView's device type
737  if ((modified_flags(0) > 0) && (modified_flags(0) >= modified_flags(1))) {
738  return true;
739  }
740  }
741  if (dev == 0) { // hopefully Device is the same as DualView's host type
742  if ((modified_flags(1) > 0) && (modified_flags(1) >= modified_flags(0))) {
743  return true;
744  }
745  }
746  return false;
747  }
748 
749  inline bool need_sync_host() const {
750  if (modified_flags.data() == nullptr) return false;
751  return modified_flags(0) < modified_flags(1);
752  }
753 
754  inline bool need_sync_device() const {
755  if (modified_flags.data() == nullptr) return false;
756  return modified_flags(1) < modified_flags(0);
757  }
758  void impl_report_device_modification() {
759  if (Kokkos::Tools::Experimental::get_callbacks().modify_dual_view !=
760  nullptr) {
761  Kokkos::Tools::modifyDualView(
762  d_view.label(),
763  reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(d_view.data()) -
764  view_header_size),
765  true);
766  }
767  }
768  void impl_report_host_modification() {
769  if (Kokkos::Tools::Experimental::get_callbacks().modify_dual_view !=
770  nullptr) {
771  Kokkos::Tools::modifyDualView(
772  h_view.label(),
773  reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(h_view.data()) -
774  view_header_size),
775  false);
776  }
777  }
783  template <class Device>
784  void modify() {
785  if constexpr (impl_dualview_is_single_device) {
786  return;
787  } else {
788  if (modified_flags.data() == nullptr) return;
789 
790  int dev = get_device_side<Device>();
791 
792  if (dev == 1) { // if Device is the same as DualView's device type
793  // Increment the device's modified count.
794  modified_flags(1) =
795  (modified_flags(1) > modified_flags(0) ? modified_flags(1)
796  : modified_flags(0)) +
797  1;
798  impl_report_device_modification();
799  }
800  if (dev == 0) { // hopefully Device is the same as DualView's host type
801  // Increment the host's modified count.
802  modified_flags(0) =
803  (modified_flags(1) > modified_flags(0) ? modified_flags(1)
804  : modified_flags(0)) +
805  1;
806  impl_report_host_modification();
807  }
808 
809  if (modified_flags(0) && modified_flags(1)) {
810  std::string msg = "Kokkos::DualView::modify ERROR: ";
811  msg += "Concurrent modification of host and device views ";
812  msg += "in DualView \"";
813  msg += d_view.label();
814  msg += "\"\n";
815  Kokkos::abort(msg.c_str());
816  }
817  }
818  }
819 
820  inline void modify_host() {
821  if constexpr (impl_dualview_is_single_device) {
822  return;
823  } else {
824  if (modified_flags.data() != nullptr) {
825  modified_flags(0) =
826  (modified_flags(1) > modified_flags(0) ? modified_flags(1)
827  : modified_flags(0)) +
828  1;
829  impl_report_host_modification();
830  if (modified_flags(0) && modified_flags(1)) {
831  std::string msg = "Kokkos::DualView::modify_host 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  }
839  }
840  }
841 
842  inline void modify_device() {
843  if constexpr (impl_dualview_is_single_device) {
844  return;
845  } else {
846  if (modified_flags.data() != nullptr) {
847  modified_flags(1) =
848  (modified_flags(1) > modified_flags(0) ? modified_flags(1)
849  : modified_flags(0)) +
850  1;
851  impl_report_device_modification();
852  if (modified_flags(0) && modified_flags(1)) {
853  std::string msg = "Kokkos::DualView::modify_device ERROR: ";
854  msg += "Concurrent modification of host and device views ";
855  msg += "in DualView \"";
856  msg += d_view.label();
857  msg += "\"\n";
858  Kokkos::abort(msg.c_str());
859  }
860  }
861  }
862  }
863 
864  inline void clear_sync_state() {
865  if (modified_flags.data() != nullptr)
866  modified_flags(1) = modified_flags(0) = 0;
867  }
868 
870 
872 
878  template <class... ViewCtorArgs>
879  void impl_realloc(const size_t n0, const size_t n1, const size_t n2,
880  const size_t n3, const size_t n4, const size_t n5,
881  const size_t n6, const size_t n7,
882  const Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop) {
883  using alloc_prop_input = Impl::ViewCtorProp<ViewCtorArgs...>;
884 
885  static_assert(!alloc_prop_input::has_label,
886  "The view constructor arguments passed to Kokkos::realloc "
887  "must not include a label!");
888  static_assert(
889  !alloc_prop_input::has_pointer,
890  "The view constructor arguments passed to Kokkos::realloc must "
891  "not include a pointer!");
892  static_assert(
893  !alloc_prop_input::has_memory_space,
894  "The view constructor arguments passed to Kokkos::realloc must "
895  "not include a memory space instance!");
896 
897  const size_t new_extents[8] = {n0, n1, n2, n3, n4, n5, n6, n7};
898  const bool sizeMismatch =
899  Impl::size_mismatch(h_view, h_view.rank_dynamic, new_extents);
900 
901  if (sizeMismatch) {
902  if constexpr (alloc_prop_input::sequential_host_init) {
903  static_assert(alloc_prop_input::initialize,
904  "DualView: SequentialHostInit isn't compatible with "
905  "WithoutInitializing!");
906  ::Kokkos::realloc(arg_prop, h_view, n0, n1, n2, n3, n4, n5, n6, n7);
907  d_view =
908  create_mirror_view_and_copy(typename t_dev::memory_space(), h_view);
909  } else {
910  ::Kokkos::realloc(arg_prop, d_view, n0, n1, n2, n3, n4, n5, n6, n7);
911  if constexpr (alloc_prop_input::initialize) {
912  h_view = create_mirror_view(typename t_host::memory_space(), d_view);
913  } else {
914  h_view = create_mirror_view(Kokkos::WithoutInitializing,
915  typename t_host::memory_space(), d_view);
916  }
917  }
918  } else if constexpr (alloc_prop_input::initialize) {
919  if constexpr (alloc_prop_input::has_execution_space) {
920  const auto& exec_space =
921  Impl::get_property<Impl::ExecutionSpaceTag>(arg_prop);
922  ::Kokkos::deep_copy(exec_space, d_view, typename t_dev::value_type{});
923  } else
924  ::Kokkos::deep_copy(d_view, typename t_dev::value_type{});
925  }
926 
927  /* Reset dirty flags */
928  if (modified_flags.data() == nullptr) {
929  modified_flags = t_modified_flags("DualView::modified_flags");
930  } else
931  modified_flags(1) = modified_flags(0) = 0;
932  }
933 
934  template <class... ViewCtorArgs>
935  void realloc(const Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop,
936  const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
937  const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
938  const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
939  const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
940  const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
941  const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
942  const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
943  const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG) {
944  impl_realloc(n0, n1, n2, n3, n4, n5, n6, n7, arg_prop);
945  }
946 
947  void realloc(const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
948  const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
949  const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
950  const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
951  const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
952  const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
953  const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
954  const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG) {
955  impl_realloc(n0, n1, n2, n3, n4, n5, n6, n7, Impl::ViewCtorProp<>{});
956  }
957 
958  template <typename I>
959  std::enable_if_t<Impl::is_view_ctor_property<I>::value> realloc(
960  const I& arg_prop, const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
961  const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
962  const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
963  const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
964  const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
965  const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
966  const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
967  const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG) {
968  impl_realloc(n0, n1, n2, n3, n4, n5, n6, n7, Kokkos::view_alloc(arg_prop));
969  }
970 
975  template <class... ViewCtorArgs>
976  void impl_resize(const Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop,
977  const size_t n0, const size_t n1, const size_t n2,
978  const size_t n3, const size_t n4, const size_t n5,
979  const size_t n6, const size_t n7) {
980  using alloc_prop_input = Impl::ViewCtorProp<ViewCtorArgs...>;
981 
982  static_assert(!alloc_prop_input::has_label,
983  "The view constructor arguments passed to Kokkos::resize "
984  "must not include a label!");
985  static_assert(
986  !alloc_prop_input::has_pointer,
987  "The view constructor arguments passed to Kokkos::resize must "
988  "not include a pointer!");
989  static_assert(
990  !alloc_prop_input::has_memory_space,
991  "The view constructor arguments passed to Kokkos::resize must "
992  "not include a memory space instance!");
993 
994  const size_t new_extents[8] = {n0, n1, n2, n3, n4, n5, n6, n7};
995  const bool sizeMismatch =
996  Impl::size_mismatch(h_view, h_view.rank_dynamic, new_extents);
997 
998  if (modified_flags.data() == nullptr) {
999  modified_flags = t_modified_flags("DualView::modified_flags");
1000  }
1001 
1002  [[maybe_unused]] auto resize_on_device = [&](const auto& properties) {
1003  /* Resize on Device */
1004  if (sizeMismatch) {
1005  ::Kokkos::resize(properties, d_view, n0, n1, n2, n3, n4, n5, n6, n7);
1006  // this part of the lambda was relocated in a method as it contains a
1007  // `if constexpr`. In some cases, both branches were evaluated
1008  // leading to a compile error
1009  resync_host(properties);
1010 
1011  /* Mark Device copy as modified */
1012  ++modified_flags(1);
1013  }
1014  };
1015 
1016  [[maybe_unused]] auto resize_on_host = [&](const auto& properties) {
1017  /* Resize on Host */
1018  if (sizeMismatch) {
1019  ::Kokkos::resize(properties, h_view, n0, n1, n2, n3, n4, n5, n6, n7);
1020  // this part of the lambda was relocated in a method as it contains a
1021  // `if constexpr`. In some cases, both branches were evaluated
1022  // leading to a compile error
1023  resync_device(properties);
1024 
1025  /* Mark Host copy as modified */
1026  ++modified_flags(0);
1027  }
1028  };
1029 
1030  if constexpr (alloc_prop_input::sequential_host_init) {
1031  static_assert(alloc_prop_input::initialize,
1032  "DualView: SequentialHostInit isn't compatible with "
1033  "WithoutInitializing!");
1034  static_assert(!alloc_prop_input::has_execution_space,
1035  "DualView: SequentialHostInit isn't compatible with "
1036  "providing an execution space instance!");
1037 
1038  if (sizeMismatch) {
1039  sync<typename t_host::memory_space>();
1040  ::Kokkos::resize(arg_prop, h_view, n0, n1, n2, n3, n4, n5, n6, n7);
1041  d_view =
1042  create_mirror_view_and_copy(typename t_dev::memory_space(), h_view);
1043  }
1044  return;
1045  } else if constexpr (alloc_prop_input::has_execution_space) {
1046  using ExecSpace = typename alloc_prop_input::execution_space;
1047  const auto& exec_space =
1048  Impl::get_property<Impl::ExecutionSpaceTag>(arg_prop);
1049  constexpr bool exec_space_can_access_device =
1050  SpaceAccessibility<ExecSpace,
1051  typename t_dev::memory_space>::accessible;
1052  constexpr bool exec_space_can_access_host =
1053  SpaceAccessibility<ExecSpace,
1054  typename t_host::memory_space>::accessible;
1055  static_assert(exec_space_can_access_device || exec_space_can_access_host);
1056  if constexpr (exec_space_can_access_device) {
1057  sync<typename t_dev::memory_space>(exec_space);
1058  resize_on_device(arg_prop);
1059  return;
1060  }
1061  if constexpr (exec_space_can_access_host) {
1062  sync<typename t_host::memory_space>(exec_space);
1063  resize_on_host(arg_prop);
1064  return;
1065  }
1066  } else {
1067  if (modified_flags(1) >= modified_flags(0)) {
1068  resize_on_device(arg_prop);
1069  } else {
1070  resize_on_host(arg_prop);
1071  }
1072  }
1073  }
1074 
1075  private:
1076  // resync host mirror from device
1077  // this code was relocated from a lambda as it contains a `if constexpr`.
1078  // In some cases, both branches were evaluated, leading to a compile error
1079  template <class... ViewCtorArgs>
1080  inline void resync_host(Impl::ViewCtorProp<ViewCtorArgs...> const&) {
1081  using alloc_prop_input = Impl::ViewCtorProp<ViewCtorArgs...>;
1082 
1083  if constexpr (alloc_prop_input::initialize) {
1084  h_view = create_mirror_view(typename t_host::memory_space(), d_view);
1085  } else {
1086  h_view = create_mirror_view(Kokkos::WithoutInitializing,
1087  typename t_host::memory_space(), d_view);
1088  }
1089  }
1090 
1091  // resync device mirror from host
1092  // this code was relocated from a lambda as it contains a `if constexpr`
1093  // In some cases, both branches were evaluated leading to a compile error
1094  template <class... ViewCtorArgs>
1095  inline void resync_device(Impl::ViewCtorProp<ViewCtorArgs...> const&) {
1096  using alloc_prop_input = Impl::ViewCtorProp<ViewCtorArgs...>;
1097 
1098  if constexpr (alloc_prop_input::initialize) {
1099  d_view = create_mirror_view(typename t_dev::memory_space(), h_view);
1100 
1101  } else {
1102  d_view = create_mirror_view(Kokkos::WithoutInitializing,
1103  typename t_dev::memory_space(), h_view);
1104  }
1105  }
1106 
1107  public:
1108  void resize(const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1109  const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1110  const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1111  const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1112  const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1113  const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1114  const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1115  const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG) {
1116  impl_resize(Impl::ViewCtorProp<>{}, n0, n1, n2, n3, n4, n5, n6, n7);
1117  }
1118 
1119  template <class... ViewCtorArgs>
1120  void resize(const Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop,
1121  const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1122  const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1123  const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1124  const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1125  const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1126  const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1127  const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1128  const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG) {
1129  impl_resize(arg_prop, n0, n1, n2, n3, n4, n5, n6, n7);
1130  }
1131 
1132  template <class I>
1133  std::enable_if_t<Impl::is_view_ctor_property<I>::value> resize(
1134  const I& arg_prop, const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1135  const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1136  const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1137  const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1138  const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1139  const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1140  const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1141  const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG) {
1142  impl_resize(Kokkos::view_alloc(arg_prop), n0, n1, n2, n3, n4, n5, n6, n7);
1143  }
1144 
1146 
1148 
1150  KOKKOS_INLINE_FUNCTION constexpr size_t span() const { return d_view.span(); }
1151 
1152  KOKKOS_INLINE_FUNCTION bool span_is_contiguous() const {
1153  return d_view.span_is_contiguous();
1154  }
1155 
1157  template <typename iType>
1158  void stride(iType* stride_) const {
1159  d_view.stride(stride_);
1160  }
1161 
1162  template <typename iType>
1163  KOKKOS_INLINE_FUNCTION constexpr std::enable_if_t<std::is_integral_v<iType>,
1164  size_t>
1165  extent(const iType& r) const {
1166  return d_view.extent(r);
1167  }
1168 
1169  template <typename iType>
1170  KOKKOS_INLINE_FUNCTION constexpr std::enable_if_t<std::is_integral_v<iType>,
1171  int>
1172  extent_int(const iType& r) const {
1173  return static_cast<int>(d_view.extent(r));
1174  }
1175 
1177 };
1178 
1179 } // namespace Kokkos
1180 
1181 //----------------------------------------------------------------------------
1182 //----------------------------------------------------------------------------
1183 //
1184 // Partial specializations of Kokkos::subview() for DualView objects.
1185 //
1186 
1187 namespace Kokkos {
1188 namespace Impl {
1189 
1190 template <class V>
1191 struct V2DV;
1192 
1193 template <class D, class... P>
1194 struct V2DV<View<D, P...>> {
1195  using type = DualView<D, P...>;
1196 };
1197 } /* namespace Impl */
1198 
1199 template <class DataType, class... Properties, class... Args>
1200 auto subview(const DualView<DataType, Properties...>& src, Args&&... args) {
1201  // leverage Kokkos::View facilities to deduce the properties of the subview
1202  using deduce_subview_type =
1203  decltype(subview(std::declval<View<DataType, Properties...>>(),
1204  std::forward<Args>(args)...));
1205  // map it back to dual view
1206  return typename Impl::V2DV<deduce_subview_type>::type(
1207  src, std::forward<Args>(args)...);
1208 }
1209 
1210 } /* namespace Kokkos */
1211 
1212 //----------------------------------------------------------------------------
1213 //----------------------------------------------------------------------------
1214 
1215 namespace Kokkos {
1216 
1217 //
1218 // Partial specialization of Kokkos::deep_copy() for DualView objects.
1219 //
1220 
1221 template <class DT, class... DP, class ST, class... SP>
1222 void deep_copy(DualView<DT, DP...>& dst, const DualView<ST, SP...>& src) {
1223  if (src.need_sync_device()) {
1224  deep_copy(dst.view_host(), src.view_host());
1225  dst.modify_host();
1226  } else {
1227  deep_copy(dst.view_device(), src.view_device());
1228  dst.modify_device();
1229  }
1230 }
1231 
1232 template <class ExecutionSpace, class DT, class... DP, class ST, class... SP>
1233 void deep_copy(const ExecutionSpace& exec, DualView<DT, DP...>& dst,
1234  const DualView<ST, SP...>& src) {
1235  if (src.need_sync_device()) {
1236  deep_copy(exec, dst.view_host(), src.view_host());
1237  dst.modify_host();
1238  } else {
1239  deep_copy(exec, dst.view_device(), src.view_device());
1240  dst.modify_device();
1241  }
1242 }
1243 
1244 } // namespace Kokkos
1245 
1246 //----------------------------------------------------------------------------
1247 //----------------------------------------------------------------------------
1248 
1249 namespace Kokkos {
1250 
1251 //
1252 // Non-member resize and realloc
1253 //
1254 
1255 template <class... Properties, class... Args>
1256 void resize(DualView<Properties...>& dv, Args&&... args) noexcept(
1257  noexcept(dv.resize(std::forward<Args>(args)...))) {
1258  dv.resize(std::forward<Args>(args)...);
1259 }
1260 
1261 template <class... ViewCtorArgs, class... Properties, class... Args>
1262 void resize(
1263  const Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop,
1264  DualView<Properties...>& dv,
1265  Args&&... args) noexcept(noexcept(dv.resize(arg_prop,
1266  std::forward<Args>(args)...))) {
1267  dv.resize(arg_prop, std::forward<Args>(args)...);
1268 }
1269 
1270 template <class I, class... Properties, class... Args>
1271 std::enable_if_t<Impl::is_view_ctor_property<I>::value> resize(
1272  const I& arg_prop, DualView<Properties...>& dv,
1273  Args&&... args) noexcept(noexcept(dv.resize(arg_prop,
1274  std::forward<Args>(args)...))) {
1275  dv.resize(arg_prop, std::forward<Args>(args)...);
1276 }
1277 
1278 template <class... ViewCtorArgs, class... Properties, class... Args>
1279 void realloc(const Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop,
1280  DualView<Properties...>& dv,
1281  Args&&... args) noexcept(noexcept(dv
1282  .realloc(std::forward<Args>(
1283  args)...))) {
1284  dv.realloc(arg_prop, std::forward<Args>(args)...);
1285 }
1286 
1287 template <class... Properties, class... Args>
1288 void realloc(DualView<Properties...>& dv, Args&&... args) noexcept(
1289  noexcept(dv.realloc(std::forward<Args>(args)...))) {
1290  dv.realloc(std::forward<Args>(args)...);
1291 }
1292 
1293 template <class I, class... Properties, class... Args>
1294 std::enable_if_t<Impl::is_view_ctor_property<I>::value> realloc(
1295  const I& arg_prop, DualView<Properties...>& dv,
1296  Args&&... args) noexcept(noexcept(dv.realloc(arg_prop,
1297  std::forward<Args>(
1298  args)...))) {
1299  dv.realloc(arg_prop, std::forward<Args>(args)...);
1300 }
1301 
1302 } // end namespace Kokkos
1303 
1304 #ifdef KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_DUALVIEW
1305 #undef KOKKOS_IMPL_PUBLIC_INCLUDE
1306 #undef KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_DUALVIEW
1307 #endif
1308 #endif
Can AccessSpace access MemorySpace ?
Memory management for host memory.