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
57namespace 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
95namespace Impl {
96
97#ifdef KOKKOS_ENABLE_CUDA
98
99inline const Kokkos::Cuda& get_cuda_space(const Kokkos::Cuda& in) { return in; }
100
101inline const Kokkos::Cuda& get_cuda_space() {
102 return *Kokkos::Impl::cuda_get_deep_copy_space();
103}
104
105template <typename NonCudaExecSpace>
106inline const Kokkos::Cuda& get_cuda_space(const NonCudaExecSpace&) {
107 return get_cuda_space();
108}
109
110#endif // KOKKOS_ENABLE_CUDA
111
112} // namespace Impl
113template <class DataType, class Arg1Type = void, class Arg2Type = void,
114 class Arg3Type = void>
115class 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
980namespace Kokkos {
981namespace Impl {
982
983template <class D, class A1, class A2, class A3, class... Args>
984struct 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
995template <class D, class A1, class A2, class A3, class... Args>
996typename 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
1007namespace Kokkos {
1008
1009//
1010// Partial specialization of Kokkos::deep_copy() for DualView objects.
1011//
1012
1013template <class DT, class DL, class DD, class DM, class ST, class SL, class SD,
1014 class SM>
1015void 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
1027template <class ExecutionSpace, class DT, class DL, class DD, class DM,
1028 class ST, class SL, class SD, class SM>
1029void 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
1047namespace Kokkos {
1048
1049//
1050// Non-member resize and realloc
1051//
1052
1053template <class... Properties, class... Args>
1054void resize(DualView<Properties...>& dv, Args&&... args) noexcept(
1055 noexcept(dv.resize(std::forward<Args>(args)...))) {
1056 dv.resize(std::forward<Args>(args)...);
1057}
1058
1059template <class... Properties, class... Args>
1060void 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.