Kokkos Core Kernels Package  Version of the Day
Kokkos_DualView.hpp
Go to the documentation of this file.
1 /*
2 //@HEADER
3 // ************************************************************************
4 //
5 // Kokkos v. 3.0
6 // Copyright (2020) National Technology & Engineering
7 // Solutions of Sandia, LLC (NTESS).
8 //
9 // Under the terms of Contract DE-NA0003525 with NTESS,
10 // the U.S. Government retains certain rights in this software.
11 //
12 // Redistribution and use in source and binary forms, with or without
13 // modification, are permitted provided that the following conditions are
14 // met:
15 //
16 // 1. Redistributions of source code must retain the above copyright
17 // notice, this list of conditions and the following disclaimer.
18 //
19 // 2. Redistributions in binary form must reproduce the above copyright
20 // notice, this list of conditions and the following disclaimer in the
21 // documentation and/or other materials provided with the distribution.
22 //
23 // 3. Neither the name of the Corporation nor the names of the
24 // contributors may be used to endorse or promote products derived from
25 // this software without specific prior written permission.
26 //
27 // THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
28 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
31 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
32 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
33 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
34 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
35 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
36 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
37 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 //
39 // Questions? Contact Christian R. Trott (crtrott@sandia.gov)
40 //
41 // ************************************************************************
42 //@HEADER
43 */
44 
50 
51 #ifndef KOKKOS_DUALVIEW_HPP
52 #define KOKKOS_DUALVIEW_HPP
53 
54 #include <Kokkos_Core.hpp>
55 #include <impl/Kokkos_Error.hpp>
56 
57 namespace Kokkos {
58 
59 /* \class DualView
60  * \brief Container to manage mirroring a Kokkos::View that lives
61  * in device memory with a Kokkos::View that lives in host memory.
62  *
63  * This class provides capabilities to manage data which exists in two
64  * memory spaces at the same time. It keeps views of the same layout
65  * on two memory spaces as well as modified flags for both
66  * allocations. Users are responsible for setting the modified flags
67  * manually if they change the data in either memory space, by calling
68  * the sync() method templated on the device where they modified the
69  * data. Users may synchronize data by calling the modify() function,
70  * templated on the device towards which they want to synchronize
71  * (i.e., the target of the one-way copy operation).
72  *
73  * The DualView class also provides convenience methods such as
74  * realloc, resize and capacity which call the appropriate methods of
75  * the underlying Kokkos::View objects.
76  *
77  * The four template arguments are the same as those of Kokkos::View.
78  * (Please refer to that class' documentation for a detailed
79  * description.)
80  *
81  * \tparam DataType The type of the entries stored in the container.
82  *
83  * \tparam Layout The array's layout in memory.
84  *
85  * \tparam Device The Kokkos Device type. If its memory space is
86  * not the same as the host's memory space, then DualView will
87  * contain two separate Views: one in device memory, and one in
88  * host memory. Otherwise, DualView will only store one View.
89  *
90  * \tparam MemoryTraits (optional) The user's intended memory access
91  * behavior. Please see the documentation of Kokkos::View for
92  * examples. The default suffices for most users.
93  */
94 
95 namespace Impl {
96 
97 #ifdef KOKKOS_ENABLE_CUDA
98 
99 inline const Kokkos::Cuda& get_cuda_space(const Kokkos::Cuda& in) { return in; }
100 
101 inline const Kokkos::Cuda& get_cuda_space() {
102  return *Kokkos::Impl::cuda_get_deep_copy_space();
103 }
104 
105 template <typename NonCudaExecSpace>
106 inline const Kokkos::Cuda& get_cuda_space(const NonCudaExecSpace&) {
107  return get_cuda_space();
108 }
109 
110 #endif // KOKKOS_ENABLE_CUDA
111 
112 } // namespace Impl
113 template <class DataType, class Arg1Type = void, class Arg2Type = void,
114  class Arg3Type = void>
115 class DualView : public ViewTraits<DataType, Arg1Type, Arg2Type, Arg3Type> {
116  template <class, class, class, class>
117  friend class DualView;
118 
119  public:
121 
122  using traits = ViewTraits<DataType, Arg1Type, Arg2Type, Arg3Type>;
123 
125  using host_mirror_space = typename traits::host_mirror_space;
126 
128  using t_dev = View<typename traits::data_type, Arg1Type, Arg2Type, Arg3Type>;
129 
132  using t_host = typename t_dev::HostMirror;
133 
136  using t_dev_const =
137  View<typename traits::const_data_type, Arg1Type, Arg2Type, Arg3Type>;
138 
141  using t_host_const = typename t_dev_const::HostMirror;
142 
144  using t_dev_const_randomread =
145  View<typename traits::const_data_type, typename traits::array_layout,
146  typename traits::device_type,
147  Kokkos::MemoryTraits<Kokkos::RandomAccess> >;
148 
152  using t_host_const_randomread = typename t_dev_const_randomread::HostMirror;
153 
155  using t_dev_um =
156  View<typename traits::data_type, typename traits::array_layout,
157  typename traits::device_type, MemoryUnmanaged>;
158 
160  using t_host_um =
161  View<typename t_host::data_type, typename t_host::array_layout,
162  typename t_host::device_type, MemoryUnmanaged>;
163 
165  using t_dev_const_um =
166  View<typename traits::const_data_type, typename traits::array_layout,
167  typename traits::device_type, MemoryUnmanaged>;
168 
170  using t_host_const_um =
171  View<typename t_host::const_data_type, typename t_host::array_layout,
172  typename t_host::device_type, MemoryUnmanaged>;
173 
175  using t_dev_const_randomread_um =
176  View<typename t_host::const_data_type, typename t_host::array_layout,
177  typename t_host::device_type,
178  Kokkos::MemoryTraits<Kokkos::Unmanaged | Kokkos::RandomAccess> >;
179 
183  using t_host_const_randomread_um =
185 
187 
189 
190  protected:
191  // modified_flags[0] -> host
192  // modified_flags[1] -> device
193  using t_modified_flags = View<unsigned int[2], LayoutLeft, Kokkos::HostSpace>;
194  t_modified_flags modified_flags;
195 
196  public:
198 
199  // Moved this specifically after modified_flags to resolve an alignment issue
200  // on MSVC/NVCC
202 
203  t_dev d_view;
204  t_host h_view;
206 
208 
209 
215  DualView() = default;
216 
226  DualView(const std::string& label,
227  const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
228  const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
229  const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
230  const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
231  const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
232  const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
233  const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
234  const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG)
235  : modified_flags(t_modified_flags("DualView::modified_flags")),
236  d_view(label, n0, n1, n2, n3, n4, n5, n6, n7),
237  h_view(create_mirror_view(d_view)) // without UVM, host View mirrors
238  {}
239 
250  template <class... P>
251  DualView(const Impl::ViewCtorProp<P...>& arg_prop,
252  typename std::enable_if<!Impl::ViewCtorProp<P...>::has_pointer,
253  size_t>::type const n0 =
254  KOKKOS_IMPL_CTOR_DEFAULT_ARG,
255  const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
256  const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
257  const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
258  const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
259  const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
260  const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
261  const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG)
262  : modified_flags(t_modified_flags("DualView::modified_flags")),
263  d_view(arg_prop, n0, n1, n2, n3, n4, n5, n6, n7),
264  h_view(create_mirror_view(d_view)) // without UVM, host View mirrors
265  {}
266 
268  template <class SS, class LS, class DS, class MS>
269  DualView(const DualView<SS, LS, DS, MS>& src)
270  : modified_flags(src.modified_flags),
271  d_view(src.d_view),
272  h_view(src.h_view) {}
273 
275  template <class SD, class S1, class S2, class S3, class Arg0, class... Args>
276  DualView(const DualView<SD, S1, S2, S3>& src, const Arg0& arg0, Args... args)
277  : modified_flags(src.modified_flags),
278  d_view(Kokkos::subview(src.d_view, arg0, args...)),
279  h_view(Kokkos::subview(src.h_view, arg0, args...)) {}
280 
291  DualView(const t_dev& d_view_, const t_host& h_view_)
292  : modified_flags(t_modified_flags("DualView::modified_flags")),
293  d_view(d_view_),
294  h_view(h_view_) {
295  if (int(d_view.rank) != int(h_view.rank) ||
296  d_view.extent(0) != h_view.extent(0) ||
297  d_view.extent(1) != h_view.extent(1) ||
298  d_view.extent(2) != h_view.extent(2) ||
299  d_view.extent(3) != h_view.extent(3) ||
300  d_view.extent(4) != h_view.extent(4) ||
301  d_view.extent(5) != h_view.extent(5) ||
302  d_view.extent(6) != h_view.extent(6) ||
303  d_view.extent(7) != h_view.extent(7) ||
304  d_view.stride_0() != h_view.stride_0() ||
305  d_view.stride_1() != h_view.stride_1() ||
306  d_view.stride_2() != h_view.stride_2() ||
307  d_view.stride_3() != h_view.stride_3() ||
308  d_view.stride_4() != h_view.stride_4() ||
309  d_view.stride_5() != h_view.stride_5() ||
310  d_view.stride_6() != h_view.stride_6() ||
311  d_view.stride_7() != h_view.stride_7() ||
312  d_view.span() != h_view.span()) {
313  Kokkos::Impl::throw_runtime_exception(
314  "DualView constructed with incompatible views");
315  }
316  }
317  // does the DualView have only one device
318  struct impl_dualview_is_single_device {
319  enum : bool {
320  value = std::is_same<typename t_dev::device_type,
321  typename t_host::device_type>::value
322  };
323  };
324 
325  // does the given device match the device of t_dev?
326  template <typename Device>
327  struct impl_device_matches_tdev_device {
328  enum : bool {
329  value = std::is_same<typename t_dev::device_type, Device>::value
330  };
331  };
332  // does the given device match the device of t_host?
333  template <typename Device>
334  struct impl_device_matches_thost_device {
335  enum : bool {
336  value = std::is_same<typename t_host::device_type, Device>::value
337  };
338  };
339 
340  // does the given device match the execution space of t_host?
341  template <typename Device>
342  struct impl_device_matches_thost_exec {
343  enum : bool {
344  value = std::is_same<typename t_host::execution_space, Device>::value
345  };
346  };
347 
348  // does the given device match the execution space of t_dev?
349  template <typename Device>
350  struct impl_device_matches_tdev_exec {
351  enum : bool {
352  value = std::is_same<typename t_dev::execution_space, Device>::value
353  };
354  };
355 
356  // does the given device's memory space match the memory space of t_dev?
357  template <typename Device>
358  struct impl_device_matches_tdev_memory_space {
359  enum : bool {
360  value = std::is_same<typename t_dev::memory_space,
361  typename Device::memory_space>::value
362  };
363  };
364 
366 
368 
391  template <class Device>
392  KOKKOS_INLINE_FUNCTION const typename std::conditional_t<
393  impl_device_matches_tdev_device<Device>::value, t_dev,
394  typename std::conditional_t<
395  impl_device_matches_thost_device<Device>::value, t_host,
396  typename std::conditional_t<
397  impl_device_matches_thost_exec<Device>::value, t_host,
398  typename std::conditional_t<
399  impl_device_matches_tdev_exec<Device>::value, t_dev,
400  typename std::conditional_t<
401  impl_device_matches_tdev_memory_space<Device>::value,
402  t_dev, t_host> > > > >
403  view() const {
404  constexpr bool device_is_memspace =
405  std::is_same<Device, typename Device::memory_space>::value;
406  constexpr bool device_is_execspace =
407  std::is_same<Device, typename Device::execution_space>::value;
408  constexpr bool device_exec_is_t_dev_exec =
409  std::is_same<typename Device::execution_space,
410  typename t_dev::execution_space>::value;
411  constexpr bool device_mem_is_t_dev_mem =
412  std::is_same<typename Device::memory_space,
413  typename t_dev::memory_space>::value;
414  constexpr bool device_exec_is_t_host_exec =
415  std::is_same<typename Device::execution_space,
416  typename t_host::execution_space>::value;
417  constexpr bool device_mem_is_t_host_mem =
418  std::is_same<typename Device::memory_space,
419  typename t_host::memory_space>::value;
420  constexpr bool device_is_t_host_device =
421  std::is_same<typename Device::execution_space,
422  typename t_host::device_type>::value;
423  constexpr bool device_is_t_dev_device =
424  std::is_same<typename Device::memory_space,
425  typename t_host::device_type>::value;
426 
427  static_assert(
428  device_is_t_dev_device || device_is_t_host_device ||
429  (device_is_memspace &&
430  (device_mem_is_t_dev_mem || device_mem_is_t_host_mem)) ||
431  (device_is_execspace &&
432  (device_exec_is_t_dev_exec || device_exec_is_t_host_exec)) ||
433  ((!device_is_execspace && !device_is_memspace) &&
434  ((device_mem_is_t_dev_mem || device_mem_is_t_host_mem) ||
435  (device_exec_is_t_dev_exec || device_exec_is_t_host_exec))),
436  "Template parameter to .view() must exactly match one of the "
437  "DualView's device types or one of the execution or memory spaces");
438 
439  return Impl::if_c<std::is_same<typename t_dev::memory_space,
440  typename Device::memory_space>::value,
441  t_dev, t_host>::select(d_view, h_view);
442  }
443 
444  KOKKOS_INLINE_FUNCTION
445  t_host view_host() const { return h_view; }
446 
447  KOKKOS_INLINE_FUNCTION
448  t_dev view_device() const { return d_view; }
449 
450  KOKKOS_INLINE_FUNCTION constexpr bool is_allocated() const {
451  return (d_view.is_allocated() && h_view.is_allocated());
452  }
453 
454  template <class Device>
455  static int get_device_side() {
456  constexpr bool device_is_memspace =
457  std::is_same<Device, typename Device::memory_space>::value;
458  constexpr bool device_is_execspace =
459  std::is_same<Device, typename Device::execution_space>::value;
460  constexpr bool device_exec_is_t_dev_exec =
461  std::is_same<typename Device::execution_space,
462  typename t_dev::execution_space>::value;
463  constexpr bool device_mem_is_t_dev_mem =
464  std::is_same<typename Device::memory_space,
465  typename t_dev::memory_space>::value;
466  constexpr bool device_exec_is_t_host_exec =
467  std::is_same<typename Device::execution_space,
468  typename t_host::execution_space>::value;
469  constexpr bool device_mem_is_t_host_mem =
470  std::is_same<typename Device::memory_space,
471  typename t_host::memory_space>::value;
472  constexpr bool device_is_t_host_device =
473  std::is_same<typename Device::execution_space,
474  typename t_host::device_type>::value;
475  constexpr bool device_is_t_dev_device =
476  std::is_same<typename Device::memory_space,
477  typename t_host::device_type>::value;
478 
479  static_assert(
480  device_is_t_dev_device || device_is_t_host_device ||
481  (device_is_memspace &&
482  (device_mem_is_t_dev_mem || device_mem_is_t_host_mem)) ||
483  (device_is_execspace &&
484  (device_exec_is_t_dev_exec || device_exec_is_t_host_exec)) ||
485  ((!device_is_execspace && !device_is_memspace) &&
486  ((device_mem_is_t_dev_mem || device_mem_is_t_host_mem) ||
487  (device_exec_is_t_dev_exec || device_exec_is_t_host_exec))),
488  "Template parameter to .sync() must exactly match one of the "
489  "DualView's device types or one of the execution or memory spaces");
490 
491  int dev = -1;
492  if (device_is_t_dev_device)
493  dev = 1;
494  else if (device_is_t_host_device)
495  dev = 0;
496  else {
497  if (device_is_memspace) {
498  if (device_mem_is_t_dev_mem) dev = 1;
499  if (device_mem_is_t_host_mem) dev = 0;
500  if (device_mem_is_t_host_mem && device_mem_is_t_dev_mem) dev = -1;
501  }
502  if (device_is_execspace) {
503  if (device_exec_is_t_dev_exec) dev = 1;
504  if (device_exec_is_t_host_exec) dev = 0;
505  if (device_exec_is_t_host_exec && device_exec_is_t_dev_exec) dev = -1;
506  }
507  if (!device_is_execspace && !device_is_memspace) {
508  if (device_mem_is_t_dev_mem) dev = 1;
509  if (device_mem_is_t_host_mem) dev = 0;
510  if (device_mem_is_t_host_mem && device_mem_is_t_dev_mem) dev = -1;
511  if (device_exec_is_t_dev_exec) dev = 1;
512  if (device_exec_is_t_host_exec) dev = 0;
513  if (device_exec_is_t_host_exec && device_exec_is_t_dev_exec) dev = -1;
514  }
515  }
516  return dev;
517  }
518  static constexpr const int view_header_size = 128;
519  void impl_report_host_sync() const noexcept {
520  if (Kokkos::Tools::Experimental::get_callbacks().sync_dual_view !=
521  nullptr) {
522  Kokkos::Tools::syncDualView(
523  h_view.label(),
524  reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(h_view.data()) -
525  view_header_size),
526  false);
527  }
528  }
529  void impl_report_device_sync() const noexcept {
530  if (Kokkos::Tools::Experimental::get_callbacks().sync_dual_view !=
531  nullptr) {
532  Kokkos::Tools::syncDualView(
533  d_view.label(),
534  reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(d_view.data()) -
535  view_header_size),
536  true);
537  }
538  }
539 
557  // deliberately passing args by cref as they're used multiple times
558  template <class Device, class... Args>
559  void sync_impl(std::true_type, Args const&... args) {
560  if (modified_flags.data() == nullptr) return;
561 
562  int dev = get_device_side<Device>();
563 
564  if (dev == 1) { // if Device is the same as DualView's device type
565  if ((modified_flags(0) > 0) && (modified_flags(0) >= modified_flags(1))) {
566 #ifdef KOKKOS_ENABLE_CUDA
567  if (std::is_same<typename t_dev::memory_space,
568  Kokkos::CudaUVMSpace>::value) {
569  if (d_view.data() == h_view.data())
570  Kokkos::Impl::cuda_prefetch_pointer(
571  Impl::get_cuda_space(args...), d_view.data(),
572  sizeof(typename t_dev::value_type) * d_view.span(), true);
573  }
574 #endif
575 
576  deep_copy(args..., d_view, h_view);
577  modified_flags(0) = modified_flags(1) = 0;
578  impl_report_device_sync();
579  }
580  }
581  if (dev == 0) { // hopefully Device is the same as DualView's host type
582  if ((modified_flags(1) > 0) && (modified_flags(1) >= modified_flags(0))) {
583 #ifdef KOKKOS_ENABLE_CUDA
584  if (std::is_same<typename t_dev::memory_space,
585  Kokkos::CudaUVMSpace>::value) {
586  if (d_view.data() == h_view.data())
587  Kokkos::Impl::cuda_prefetch_pointer(
588  Impl::get_cuda_space(args...), d_view.data(),
589  sizeof(typename t_dev::value_type) * d_view.span(), false);
590  }
591 #endif
592 
593  deep_copy(args..., h_view, d_view);
594  modified_flags(0) = modified_flags(1) = 0;
595  impl_report_host_sync();
596  }
597  }
598  if (std::is_same<typename t_host::memory_space,
599  typename t_dev::memory_space>::value) {
600  typename t_dev::execution_space().fence();
601  typename t_host::execution_space().fence();
602  }
603  }
604 
605  template <class Device>
606  void sync(const typename std::enable_if<
607  (std::is_same<typename traits::data_type,
608  typename traits::non_const_data_type>::value) ||
609  (std::is_same<Device, int>::value),
610  int>::type& = 0) {
611  sync_impl<Device>(std::true_type{});
612  }
613 
614  template <class Device, class ExecutionSpace>
615  void sync(const ExecutionSpace& exec,
616  const typename std::enable_if<
617  (std::is_same<typename traits::data_type,
618  typename traits::non_const_data_type>::value) ||
619  (std::is_same<Device, int>::value),
620  int>::type& = 0) {
621  sync_impl<Device>(std::true_type{}, exec);
622  }
623 
624  // deliberately passing args by cref as they're used multiple times
625  template <class Device, class... Args>
626  void sync_impl(std::false_type, Args const&...) {
627  if (modified_flags.data() == nullptr) return;
628 
629  int dev = get_device_side<Device>();
630 
631  if (dev == 1) { // if Device is the same as DualView's device type
632  if ((modified_flags(0) > 0) && (modified_flags(0) >= modified_flags(1))) {
633  Impl::throw_runtime_exception(
634  "Calling sync on a DualView with a const datatype.");
635  }
636  impl_report_device_sync();
637  }
638  if (dev == 0) { // hopefully Device is the same as DualView's host type
639  if ((modified_flags(1) > 0) && (modified_flags(1) >= modified_flags(0))) {
640  Impl::throw_runtime_exception(
641  "Calling sync on a DualView with a const datatype.");
642  }
643  impl_report_host_sync();
644  }
645  }
646 
647  template <class Device>
648  void sync(const typename std::enable_if<
649  (!std::is_same<typename traits::data_type,
650  typename traits::non_const_data_type>::value) ||
651  (std::is_same<Device, int>::value),
652  int>::type& = 0) {
653  sync_impl<Device>(std::false_type{});
654  }
655  template <class Device, class ExecutionSpace>
656  void sync(const ExecutionSpace& exec,
657  const typename std::enable_if<
658  (!std::is_same<typename traits::data_type,
659  typename traits::non_const_data_type>::value) ||
660  (std::is_same<Device, int>::value),
661  int>::type& = 0) {
662  sync_impl<Device>(std::false_type{}, exec);
663  }
664 
665  // deliberately passing args by cref as they're used multiple times
666  template <typename... Args>
667  void sync_host_impl(Args const&... args) {
668  if (!std::is_same<typename traits::data_type,
669  typename traits::non_const_data_type>::value)
670  Impl::throw_runtime_exception(
671  "Calling sync_host on a DualView with a const datatype.");
672  if (modified_flags.data() == nullptr) return;
673  if (modified_flags(1) > modified_flags(0)) {
674 #ifdef KOKKOS_ENABLE_CUDA
675  if (std::is_same<typename t_dev::memory_space,
676  Kokkos::CudaUVMSpace>::value) {
677  if (d_view.data() == h_view.data())
678  Kokkos::Impl::cuda_prefetch_pointer(
679  Impl::get_cuda_space(args...), d_view.data(),
680  sizeof(typename t_dev::value_type) * d_view.span(), false);
681  }
682 #endif
683 
684  deep_copy(args..., h_view, d_view);
685  modified_flags(1) = modified_flags(0) = 0;
686  impl_report_host_sync();
687  }
688  }
689 
690  template <class ExecSpace>
691  void sync_host(const ExecSpace& exec) {
692  sync_host_impl(exec);
693  }
694  void sync_host() { sync_host_impl(); }
695 
696  // deliberately passing args by cref as they're used multiple times
697  template <typename... Args>
698  void sync_device_impl(Args const&... args) {
699  if (!std::is_same<typename traits::data_type,
700  typename traits::non_const_data_type>::value)
701  Impl::throw_runtime_exception(
702  "Calling sync_device on a DualView with a const datatype.");
703  if (modified_flags.data() == nullptr) return;
704  if (modified_flags(0) > modified_flags(1)) {
705 #ifdef KOKKOS_ENABLE_CUDA
706  if (std::is_same<typename t_dev::memory_space,
707  Kokkos::CudaUVMSpace>::value) {
708  if (d_view.data() == h_view.data())
709  Kokkos::Impl::cuda_prefetch_pointer(
710  Impl::get_cuda_space(args...), d_view.data(),
711  sizeof(typename t_dev::value_type) * d_view.span(), true);
712  }
713 #endif
714 
715  deep_copy(args..., d_view, h_view);
716  modified_flags(1) = modified_flags(0) = 0;
717  impl_report_device_sync();
718  }
719  }
720 
721  template <class ExecSpace>
722  void sync_device(const ExecSpace& exec) {
723  sync_device_impl(exec);
724  }
725  void sync_device() { sync_device_impl(); }
726 
727  template <class Device>
728  bool need_sync() const {
729  if (modified_flags.data() == nullptr) return false;
730  int dev = get_device_side<Device>();
731 
732  if (dev == 1) { // if Device is the same as DualView's device type
733  if ((modified_flags(0) > 0) && (modified_flags(0) >= modified_flags(1))) {
734  return true;
735  }
736  }
737  if (dev == 0) { // hopefully Device is the same as DualView's host type
738  if ((modified_flags(1) > 0) && (modified_flags(1) >= modified_flags(0))) {
739  return true;
740  }
741  }
742  return false;
743  }
744 
745  inline bool need_sync_host() const {
746  if (modified_flags.data() == nullptr) return false;
747  return modified_flags(0) < modified_flags(1);
748  }
749 
750  inline bool need_sync_device() const {
751  if (modified_flags.data() == nullptr) return false;
752  return modified_flags(1) < modified_flags(0);
753  }
754  void impl_report_device_modification() {
755  if (Kokkos::Tools::Experimental::get_callbacks().modify_dual_view !=
756  nullptr) {
757  Kokkos::Tools::modifyDualView(
758  d_view.label(),
759  reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(d_view.data()) -
760  view_header_size),
761  true);
762  }
763  }
764  void impl_report_host_modification() {
765  if (Kokkos::Tools::Experimental::get_callbacks().modify_dual_view !=
766  nullptr) {
767  Kokkos::Tools::modifyDualView(
768  h_view.label(),
769  reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(h_view.data()) -
770  view_header_size),
771  false);
772  }
773  }
779  template <class Device>
780  void modify() {
781  if (modified_flags.data() == nullptr) return;
782  if (impl_dualview_is_single_device::value) return;
783  int dev = get_device_side<Device>();
784 
785  if (dev == 1) { // if Device is the same as DualView's device type
786  // Increment the device's modified count.
787  modified_flags(1) =
788  (modified_flags(1) > modified_flags(0) ? modified_flags(1)
789  : modified_flags(0)) +
790  1;
791  impl_report_device_modification();
792  }
793  if (dev == 0) { // hopefully Device is the same as DualView's host type
794  // Increment the host's modified count.
795  modified_flags(0) =
796  (modified_flags(1) > modified_flags(0) ? modified_flags(1)
797  : modified_flags(0)) +
798  1;
799  impl_report_host_modification();
800  }
801 
802 #ifdef KOKKOS_ENABLE_DEBUG_DUALVIEW_MODIFY_CHECK
803  if (modified_flags(0) && modified_flags(1)) {
804  std::string msg = "Kokkos::DualView::modify ERROR: ";
805  msg += "Concurrent modification of host and device views ";
806  msg += "in DualView \"";
807  msg += d_view.label();
808  msg += "\"\n";
809  Kokkos::abort(msg.c_str());
810  }
811 #endif
812  }
813 
814  inline void modify_host() {
815  if (impl_dualview_is_single_device::value) return;
816  if (modified_flags.data() != nullptr) {
817  modified_flags(0) =
818  (modified_flags(1) > modified_flags(0) ? modified_flags(1)
819  : modified_flags(0)) +
820  1;
821  impl_report_host_modification();
822 #ifdef KOKKOS_ENABLE_DEBUG_DUALVIEW_MODIFY_CHECK
823  if (modified_flags(0) && modified_flags(1)) {
824  std::string msg = "Kokkos::DualView::modify_host ERROR: ";
825  msg += "Concurrent modification of host and device views ";
826  msg += "in DualView \"";
827  msg += d_view.label();
828  msg += "\"\n";
829  Kokkos::abort(msg.c_str());
830  }
831 #endif
832  }
833  }
834 
835  inline void modify_device() {
836  if (impl_dualview_is_single_device::value) return;
837  if (modified_flags.data() != nullptr) {
838  modified_flags(1) =
839  (modified_flags(1) > modified_flags(0) ? modified_flags(1)
840  : modified_flags(0)) +
841  1;
842  impl_report_device_modification();
843 #ifdef KOKKOS_ENABLE_DEBUG_DUALVIEW_MODIFY_CHECK
844  if (modified_flags(0) && modified_flags(1)) {
845  std::string msg = "Kokkos::DualView::modify_device ERROR: ";
846  msg += "Concurrent modification of host and device views ";
847  msg += "in DualView \"";
848  msg += d_view.label();
849  msg += "\"\n";
850  Kokkos::abort(msg.c_str());
851  }
852 #endif
853  }
854  }
855 
856  inline void clear_sync_state() {
857  if (modified_flags.data() != nullptr)
858  modified_flags(1) = modified_flags(0) = 0;
859  }
860 
862 
864 
870  void realloc(const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
871  const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
872  const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
873  const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
874  const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
875  const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
876  const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
877  const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG) {
878  ::Kokkos::realloc(d_view, n0, n1, n2, n3, n4, n5, n6, n7);
879  h_view = create_mirror_view(d_view);
880 
881  /* Reset dirty flags */
882  if (modified_flags.data() == nullptr) {
883  modified_flags = t_modified_flags("DualView::modified_flags");
884  } else
885  modified_flags(1) = modified_flags(0) = 0;
886  }
887 
892  void resize(const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
893  const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
894  const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
895  const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
896  const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
897  const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
898  const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
899  const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG) {
900  if (modified_flags.data() == nullptr) {
901  modified_flags = t_modified_flags("DualView::modified_flags");
902  }
903  if (modified_flags(1) >= modified_flags(0)) {
904  /* Resize on Device */
905  ::Kokkos::resize(d_view, n0, n1, n2, n3, n4, n5, n6, n7);
906  h_view = create_mirror_view(d_view);
907 
908  /* Mark Device copy as modified */
909  modified_flags(1) = modified_flags(1) + 1;
910 
911  } else {
912  /* Realloc on Device */
913 
914  ::Kokkos::realloc(d_view, n0, n1, n2, n3, n4, n5, n6, n7);
915 
916  const bool sizeMismatch =
917  (h_view.extent(0) != n0) || (h_view.extent(1) != n1) ||
918  (h_view.extent(2) != n2) || (h_view.extent(3) != n3) ||
919  (h_view.extent(4) != n4) || (h_view.extent(5) != n5) ||
920  (h_view.extent(6) != n6) || (h_view.extent(7) != n7);
921  if (sizeMismatch)
922  ::Kokkos::resize(h_view, n0, n1, n2, n3, n4, n5, n6, n7);
923 
924  t_host temp_view = create_mirror_view(d_view);
925 
926  /* Remap on Host */
927  Kokkos::deep_copy(temp_view, h_view);
928 
929  h_view = temp_view;
930 
931  d_view = create_mirror_view(typename t_dev::execution_space(), h_view);
932 
933  /* Mark Host copy as modified */
934  modified_flags(0) = modified_flags(0) + 1;
935  }
936  }
937 
939 
941 
943  KOKKOS_INLINE_FUNCTION constexpr size_t span() const { return d_view.span(); }
944 
945  KOKKOS_INLINE_FUNCTION bool span_is_contiguous() const {
946  return d_view.span_is_contiguous();
947  }
948 
950  template <typename iType>
951  void stride(iType* stride_) const {
952  d_view.stride(stride_);
953  }
954 
955  template <typename iType>
956  KOKKOS_INLINE_FUNCTION constexpr
957  typename std::enable_if<std::is_integral<iType>::value, size_t>::type
958  extent(const iType& r) const {
959  return d_view.extent(r);
960  }
961 
962  template <typename iType>
963  KOKKOS_INLINE_FUNCTION constexpr
964  typename std::enable_if<std::is_integral<iType>::value, int>::type
965  extent_int(const iType& r) const {
966  return static_cast<int>(d_view.extent(r));
967  }
968 
970 };
971 
972 } // namespace Kokkos
973 
974 //----------------------------------------------------------------------------
975 //----------------------------------------------------------------------------
976 //
977 // Partial specializations of Kokkos::subview() for DualView objects.
978 //
979 
980 namespace Kokkos {
981 namespace Impl {
982 
983 template <class D, class A1, class A2, class A3, class... Args>
984 struct DualViewSubview {
985  using dst_traits = typename Kokkos::Impl::ViewMapping<
986  void, Kokkos::ViewTraits<D, A1, A2, A3>, Args...>::traits_type;
987 
988  using type = Kokkos::DualView<
989  typename dst_traits::data_type, typename dst_traits::array_layout,
990  typename dst_traits::device_type, typename dst_traits::memory_traits>;
991 };
992 
993 } /* namespace Impl */
994 
995 template <class D, class A1, class A2, class A3, class... Args>
996 typename Impl::DualViewSubview<D, A1, A2, A3, Args...>::type subview(
997  const DualView<D, A1, A2, A3>& src, Args... args) {
998  return typename Impl::DualViewSubview<D, A1, A2, A3, Args...>::type(src,
999  args...);
1000 }
1001 
1002 } /* namespace Kokkos */
1003 
1004 //----------------------------------------------------------------------------
1005 //----------------------------------------------------------------------------
1006 
1007 namespace Kokkos {
1008 
1009 //
1010 // Partial specialization of Kokkos::deep_copy() for DualView objects.
1011 //
1012 
1013 template <class DT, class DL, class DD, class DM, class ST, class SL, class SD,
1014  class SM>
1015 void deep_copy(
1016  DualView<DT, DL, DD, DM> dst, // trust me, this must not be a reference
1017  const DualView<ST, SL, SD, SM>& src) {
1018  if (src.need_sync_device()) {
1019  deep_copy(dst.h_view, src.h_view);
1020  dst.modify_host();
1021  } else {
1022  deep_copy(dst.d_view, src.d_view);
1023  dst.modify_device();
1024  }
1025 }
1026 
1027 template <class ExecutionSpace, class DT, class DL, class DD, class DM,
1028  class ST, class SL, class SD, class SM>
1029 void deep_copy(
1030  const ExecutionSpace& exec,
1031  DualView<DT, DL, DD, DM> dst, // trust me, this must not be a reference
1032  const DualView<ST, SL, SD, SM>& src) {
1033  if (src.need_sync_device()) {
1034  deep_copy(exec, dst.h_view, src.h_view);
1035  dst.modify_host();
1036  } else {
1037  deep_copy(exec, dst.d_view, src.d_view);
1038  dst.modify_device();
1039  }
1040 }
1041 
1042 } // namespace Kokkos
1043 
1044 //----------------------------------------------------------------------------
1045 //----------------------------------------------------------------------------
1046 
1047 namespace Kokkos {
1048 
1049 //
1050 // Non-member resize and realloc
1051 //
1052 
1053 template <class... Properties, class... Args>
1054 void resize(DualView<Properties...>& dv, Args&&... args) noexcept(
1055  noexcept(dv.resize(std::forward<Args>(args)...))) {
1056  dv.resize(std::forward<Args>(args)...);
1057 }
1058 
1059 template <class... Properties, class... Args>
1060 void realloc(DualView<Properties...>& dv, Args&&... args) noexcept(
1061  noexcept(dv.realloc(std::forward<Args>(args)...))) {
1062  dv.realloc(std::forward<Args>(args)...);
1063 }
1064 
1065 } // end namespace Kokkos
1066 
1067 #endif
View
View< typename traits::non_const_data_type, typename traits::array_layout, Device< DefaultHostExecutionSpace, typename traits::host_mirror_space::memory_space > > HostMirror
Compatible HostMirror view.
Traits class for accessing attributes of a View.
Definition: dummy.cpp:3