Tpetra parallel linear algebra Version of the Day
Loading...
Searching...
No Matches
Tpetra_Details_WrappedDualView.hpp
1// @HEADER
2// *****************************************************************************
3// Tpetra: Templated Linear Algebra Services Package
4//
5// Copyright 2008 NTESS and the Tpetra contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9
10#ifndef TPETRA_DETAILS_WRAPPEDDUALVIEW_HPP
11#define TPETRA_DETAILS_WRAPPEDDUALVIEW_HPP
12
13#include <Tpetra_Access.hpp>
14#include <Tpetra_Details_temporaryViewUtils.hpp>
15#include <Kokkos_DualView.hpp>
16#include "Teuchos_TestForException.hpp"
18#include "TpetraCore_DLLExportMacro.h"
19#include <sstream>
20
21// #define DEBUG_UVM_REMOVAL // Works only with gcc > 4.8
22
23#ifdef DEBUG_UVM_REMOVAL
24
25#define DEBUG_UVM_REMOVAL_ARGUMENT , const char *callerstr = __builtin_FUNCTION(), const char *filestr = __builtin_FILE(), const int linnum = __builtin_LINE()
26
27#define DEBUG_UVM_REMOVAL_PRINT_CALLER(fn) \
28 { \
29 auto envVarSet = std::getenv("TPETRA_UVM_REMOVAL"); \
30 if (envVarSet && (std::strcmp(envVarSet, "1") == 0)) \
31 std::cout << (fn) << " called from " << callerstr \
32 << " at " << filestr << ":" << linnum \
33 << " host cnt " << getRawHostView().use_count() \
34 << " device cnt " << getRawDeviceView().use_count() \
35 << std::endl; \
36 }
37
38#else
39
40#define DEBUG_UVM_REMOVAL_ARGUMENT
41#define DEBUG_UVM_REMOVAL_PRINT_CALLER(fn)
42
43#endif
44
46namespace Tpetra {
47
48// We really need this forward declaration here for friend to work
49template <typename SC, typename LO, typename GO, typename NO>
50class MultiVector;
51
54namespace Details {
55
56namespace impl {
57
58template <typename DualViewType>
59struct hasConstData {
60 using valueType = typename DualViewType::value_type;
61 using constValueType = typename DualViewType::const_value_type;
62 static constexpr bool value = std::is_same<valueType, constValueType>::value;
63};
64
65template <typename DualViewType>
66using enableIfConstData = std::enable_if_t<hasConstData<DualViewType>::value>;
67
68template <typename DualViewType>
69using enableIfNonConstData = std::enable_if_t<!hasConstData<DualViewType>::value>;
70
71template <typename DualViewType>
72enableIfNonConstData<DualViewType>
73sync_host(DualViewType dualView) {
74 // This will sync, but only if needed
75 dualView.sync_host();
76}
77
78template <typename DualViewType>
79enableIfConstData<DualViewType>
80sync_host(DualViewType dualView) {}
81
82template <typename DualViewType>
83enableIfNonConstData<DualViewType>
84sync_device(DualViewType dualView) {
85 // This will sync, but only if needed
86 dualView.sync_device();
87}
88
89template <typename DualViewType>
90enableIfConstData<DualViewType>
91sync_device(DualViewType dualView) {}
92
93} // namespace impl
94
102
103extern TPETRA_LIB_DLL_EXPORT bool wdvTrackingEnabled;
104
109TPETRA_LIB_DLL_EXPORT void disableWDVTracking();
110
112TPETRA_LIB_DLL_EXPORT void enableWDVTracking();
113
116template <typename DualViewType>
118 public:
119 using DVT = DualViewType;
120 using t_host = typename DualViewType::t_host;
121 using t_dev = typename DualViewType::t_dev;
122
123 using HostType = typename t_host::device_type;
124 using DeviceType = typename t_dev::device_type;
125
126 private:
127 static constexpr bool dualViewHasNonConstData = !impl::hasConstData<DualViewType>::value;
128 static constexpr bool deviceMemoryIsHostAccessible =
129 Kokkos::SpaceAccessibility<Kokkos::DefaultHostExecutionSpace, typename t_dev::memory_space>::accessible;
130
131 private:
132 template <typename>
133 friend class WrappedDualView;
134
135 public:
136 WrappedDualView() {}
137
139 : originalDualView(dualV)
140 , dualView(originalDualView) {}
141
143 template <class SrcDualViewType>
145 : originalDualView(src.originalDualView)
146 , dualView(src.dualView) {}
147
149 template <class SrcDualViewType>
151 originalDualView = src.originalDualView;
152 dualView = src.dualView;
153 return *this;
154 }
155
156 // This is an expert-only constructor
157 // For WrappedDualView to manage synchronizations correctly,
158 // it must have an DualView which is not a subview to due the
159 // sync's on. This is what origDualV is for. In this case,
160 // dualV is a subview of origDualV.
162 : originalDualView(origDualV)
163 , dualView(dualV) {}
164
165 WrappedDualView(const t_dev deviceView) {
167 deviceView.data() != nullptr && deviceView.use_count() == 0,
168 std::invalid_argument,
169 "Tpetra::Details::WrappedDualView: cannot construct with a device view that\n"
170 "does not own its memory (i.e. constructed with a raw pointer and dimensions)\n"
171 "because the WrappedDualView needs to assume ownership of the memory.");
172 // If the provided view is default-constructed (null, 0 extent, 0 use count),
173 // leave the host mirror default-constructed as well in order to have a matching use count of 0.
174 t_host hostView;
175 if (deviceView.use_count() != 0) {
176 hostView = Kokkos::create_mirror_view(
177 Kokkos::WithoutInitializing,
178 typename t_host::memory_space(),
179 deviceView);
180 }
181 originalDualView = DualViewType(deviceView, hostView);
182 originalDualView.clear_sync_state();
183 originalDualView.modify_device();
184 dualView = originalDualView;
185 }
186
187 // 1D View constructors
188 WrappedDualView(const WrappedDualView parent, int offset, int numEntries) {
189 originalDualView = parent.originalDualView;
190 dualView = getSubview(parent.dualView, offset, numEntries);
191 }
192
193 // 2D View Constructors
194 WrappedDualView(const WrappedDualView parent, const Kokkos::pair<size_t, size_t>& rowRng, const Kokkos::ALL_t& colRng) {
195 originalDualView = parent.originalDualView;
196 dualView = getSubview2D(parent.dualView, rowRng, colRng);
197 }
198
199 WrappedDualView(const WrappedDualView parent, const Kokkos::ALL_t& rowRng, const Kokkos::pair<size_t, size_t>& colRng) {
200 originalDualView = parent.originalDualView;
201 dualView = getSubview2D(parent.dualView, rowRng, colRng);
202 }
203
204 WrappedDualView(const WrappedDualView parent, const Kokkos::pair<size_t, size_t>& rowRng, const Kokkos::pair<size_t, size_t>& colRng) {
205 originalDualView = parent.originalDualView;
206 dualView = getSubview2D(parent.dualView, rowRng, colRng);
207 }
208
209 size_t extent(const int i) const {
210 return getRawHostView().extent(i);
211 }
212
213 void stride(size_t* stride_) const {
214 dualView.stride(stride_);
215 }
216
217 size_t origExtent(const int i) const {
218 return getRawHostOriginalView().extent(i);
219 }
220
221 const char* label() const {
222 return getRawDeviceView().label();
223 }
224
225 typename t_host::const_type
226 getHostView(Access::ReadOnlyStruct
227 DEBUG_UVM_REMOVAL_ARGUMENT) const {
228 DEBUG_UVM_REMOVAL_PRINT_CALLER("getHostViewReadOnly");
229
230 if (needsSyncPath()) {
231 throwIfDeviceViewAlive();
232 impl::sync_host(originalDualView);
233 }
234 return getRawHostView();
235 }
236
237 t_host
238 getHostView(Access::ReadWriteStruct
239 DEBUG_UVM_REMOVAL_ARGUMENT) {
240 DEBUG_UVM_REMOVAL_PRINT_CALLER("getHostViewReadWrite");
241 static_assert(dualViewHasNonConstData,
242 "ReadWrite views are not available for DualView with const data");
243 if (needsSyncPath()) {
244 throwIfDeviceViewAlive();
245 impl::sync_host(originalDualView);
246 originalDualView.modify_host();
247 }
248
249 return getRawHostView();
250 }
251
252 t_host
253 getHostView(Access::OverwriteAllStruct
254 DEBUG_UVM_REMOVAL_ARGUMENT) {
255 DEBUG_UVM_REMOVAL_PRINT_CALLER("getHostViewOverwriteAll");
256 static_assert(dualViewHasNonConstData,
257 "OverwriteAll views are not available for DualView with const data");
258 if (iAmASubview()) {
259 return getHostView(Access::ReadWrite);
260 }
261 if (needsSyncPath()) {
262 throwIfDeviceViewAlive();
263 if (deviceMemoryIsHostAccessible) Kokkos::fence("WrappedDualView::getHostView");
264 dualView.clear_sync_state();
265 dualView.modify_host();
266 }
267 return getRawHostView();
268 }
269
270 typename t_dev::const_type
271 getDeviceView(Access::ReadOnlyStruct
272 DEBUG_UVM_REMOVAL_ARGUMENT) const {
273 DEBUG_UVM_REMOVAL_PRINT_CALLER("getDeviceViewReadOnly");
274 if (needsSyncPath()) {
275 throwIfHostViewAlive();
276 impl::sync_device(originalDualView);
277 }
278 return getRawDeviceView();
279 }
280
281 t_dev
282 getDeviceView(Access::ReadWriteStruct
283 DEBUG_UVM_REMOVAL_ARGUMENT) {
284 DEBUG_UVM_REMOVAL_PRINT_CALLER("getDeviceViewReadWrite");
285 static_assert(dualViewHasNonConstData,
286 "ReadWrite views are not available for DualView with const data");
287 if (needsSyncPath()) {
288 throwIfHostViewAlive();
289 impl::sync_device(originalDualView);
290 originalDualView.modify_device();
291 }
292 return getRawDeviceView();
293 }
294
295 t_dev
296 getDeviceView(Access::OverwriteAllStruct
297 DEBUG_UVM_REMOVAL_ARGUMENT) {
298 DEBUG_UVM_REMOVAL_PRINT_CALLER("getDeviceViewOverwriteAll");
299 static_assert(dualViewHasNonConstData,
300 "OverwriteAll views are not available for DualView with const data");
301 if (iAmASubview()) {
302 return getDeviceView(Access::ReadWrite);
303 }
304 if (needsSyncPath()) {
305 throwIfHostViewAlive();
306 if (deviceMemoryIsHostAccessible) Kokkos::fence("WrappedDualView::getDeviceView");
307 dualView.clear_sync_state();
308 dualView.modify_device();
309 }
310 return getRawDeviceView();
311 }
312
313 template <class TargetDeviceType>
314 typename std::remove_reference<decltype(std::declval<DualViewType>().template view<TargetDeviceType>())>::type::const_type
315 getView(Access::ReadOnlyStruct s DEBUG_UVM_REMOVAL_ARGUMENT) const {
316 using ReturnViewType = typename std::remove_reference<decltype(std::declval<DualViewType>().template view<TargetDeviceType>())>::type::const_type;
317 using ReturnDeviceType = typename ReturnViewType::device_type;
318 constexpr bool returnDevice = std::is_same<ReturnDeviceType, DeviceType>::value;
319 if (returnDevice) {
320 DEBUG_UVM_REMOVAL_PRINT_CALLER("getView<Device>ReadOnly");
321 if (needsSyncPath()) {
322 throwIfHostViewAlive();
323 impl::sync_device(originalDualView);
324 }
325 } else {
326 DEBUG_UVM_REMOVAL_PRINT_CALLER("getView<Host>ReadOnly");
327 if (needsSyncPath()) {
328 throwIfDeviceViewAlive();
329 impl::sync_host(originalDualView);
330 }
331 }
332
333 return dualView.template view<TargetDeviceType>();
334 }
335
336 template <class TargetDeviceType>
337 typename std::remove_reference<decltype(std::declval<DualViewType>().template view<TargetDeviceType>())>::type
338 getView(Access::ReadWriteStruct s DEBUG_UVM_REMOVAL_ARGUMENT) const {
339 using ReturnViewType = typename std::remove_reference<decltype(std::declval<DualViewType>().template view<TargetDeviceType>())>::type;
340 using ReturnDeviceType = typename ReturnViewType::device_type;
341 constexpr bool returnDevice = std::is_same<ReturnDeviceType, DeviceType>::value;
342
343 if (returnDevice) {
344 DEBUG_UVM_REMOVAL_PRINT_CALLER("getView<Device>ReadWrite");
345 static_assert(dualViewHasNonConstData,
346 "ReadWrite views are not available for DualView with const data");
347 if (needsSyncPath()) {
348 throwIfHostViewAlive();
349 impl::sync_device(originalDualView);
350 originalDualView.modify_device();
351 }
352 } else {
353 DEBUG_UVM_REMOVAL_PRINT_CALLER("getView<Host>ReadWrite");
354 static_assert(dualViewHasNonConstData,
355 "ReadWrite views are not available for DualView with const data");
356 if (needsSyncPath()) {
357 throwIfDeviceViewAlive();
358 impl::sync_host(originalDualView);
359 originalDualView.modify_host();
360 }
361 }
362
363 return dualView.template view<TargetDeviceType>();
364 }
365
366 template <class TargetDeviceType>
367 typename std::remove_reference<decltype(std::declval<DualViewType>().template view<TargetDeviceType>())>::type
368 getView(Access::OverwriteAllStruct s DEBUG_UVM_REMOVAL_ARGUMENT) const {
369 using ReturnViewType = typename std::remove_reference<decltype(std::declval<DualViewType>().template view<TargetDeviceType>())>::type;
370 using ReturnDeviceType = typename ReturnViewType::device_type;
371
372 if (iAmASubview())
373 return getView<TargetDeviceType>(Access::ReadWrite);
374
375 constexpr bool returnDevice = std::is_same<ReturnDeviceType, DeviceType>::value;
376
377 if (returnDevice) {
378 DEBUG_UVM_REMOVAL_PRINT_CALLER("getView<Device>OverwriteAll");
379 static_assert(dualViewHasNonConstData,
380 "OverwriteAll views are not available for DualView with const data");
381 if (needsSyncPath()) {
382 throwIfHostViewAlive();
383 dualView.clear_sync_state();
384 dualView.modify_host();
385 }
386 } else {
387 DEBUG_UVM_REMOVAL_PRINT_CALLER("getView<Host>OverwriteAll");
388 static_assert(dualViewHasNonConstData,
389 "OverwriteAll views are not available for DualView with const data");
390 if (needsSyncPath()) {
391 throwIfDeviceViewAlive();
392 dualView.clear_sync_state();
393 dualView.modify_device();
394 }
395 }
396
397 return dualView.template view<TargetDeviceType>();
398 }
399
400 typename t_host::const_type
401 getHostSubview(int offset, int numEntries, Access::ReadOnlyStruct DEBUG_UVM_REMOVAL_ARGUMENT) const {
402 DEBUG_UVM_REMOVAL_PRINT_CALLER("getHostSubviewReadOnly");
403 if (needsSyncPath()) {
404 throwIfDeviceViewAlive();
405 impl::sync_host(originalDualView);
406 }
407 return getSubview(getRawHostView(), offset, numEntries);
408 }
409
410 t_host
411 getHostSubview(int offset, int numEntries, Access::ReadWriteStruct DEBUG_UVM_REMOVAL_ARGUMENT) {
412 DEBUG_UVM_REMOVAL_PRINT_CALLER("getHostSubviewReadWrite");
413 static_assert(dualViewHasNonConstData,
414 "ReadWrite views are not available for DualView with const data");
415 if (needsSyncPath()) {
416 throwIfDeviceViewAlive();
417 impl::sync_host(originalDualView);
418 originalDualView.modify_host();
419 }
420 return getSubview(getRawHostView(), offset, numEntries);
421 }
422
423 t_host
424 getHostSubview(int offset, int numEntries, Access::OverwriteAllStruct DEBUG_UVM_REMOVAL_ARGUMENT) {
425 DEBUG_UVM_REMOVAL_PRINT_CALLER("getHostSubviewOverwriteAll");
426 static_assert(dualViewHasNonConstData,
427 "OverwriteAll views are not available for DualView with const data");
428 return getHostSubview(offset, numEntries, Access::ReadWrite);
429 }
430
431 typename t_dev::const_type
432 getDeviceSubview(int offset, int numEntries, Access::ReadOnlyStruct DEBUG_UVM_REMOVAL_ARGUMENT) const {
433 DEBUG_UVM_REMOVAL_PRINT_CALLER("getDeviceSubviewReadOnly");
434 if (needsSyncPath()) {
435 throwIfHostViewAlive();
436 impl::sync_device(originalDualView);
437 }
438 return getSubview(getRawDeviceView(), offset, numEntries);
439 }
440
441 t_dev
442 getDeviceSubview(int offset, int numEntries, Access::ReadWriteStruct DEBUG_UVM_REMOVAL_ARGUMENT) {
443 DEBUG_UVM_REMOVAL_PRINT_CALLER("getDeviceSubviewReadWrite");
444 static_assert(dualViewHasNonConstData,
445 "ReadWrite views are not available for DualView with const data");
446 if (needsSyncPath()) {
447 throwIfHostViewAlive();
448 impl::sync_device(originalDualView);
449 originalDualView.modify_device();
450 }
451 return getSubview(getRawDeviceView(), offset, numEntries);
452 }
453
454 t_dev
455 getDeviceSubview(int offset, int numEntries, Access::OverwriteAllStruct DEBUG_UVM_REMOVAL_ARGUMENT) {
456 DEBUG_UVM_REMOVAL_PRINT_CALLER("getDeviceSubviewOverwriteAll");
457 static_assert(dualViewHasNonConstData,
458 "OverwriteAll views are not available for DualView with const data");
459 return getDeviceSubview(offset, numEntries, Access::ReadWrite);
460 }
461
462 // Debugging functions to get copies of the view state
463 typename t_host::host_mirror_type getHostCopy() const {
464 auto X_dev = getRawHostView();
465 if (X_dev.span_is_contiguous()) {
466 auto mirror = Kokkos::create_mirror_view(X_dev);
467 Kokkos::deep_copy(mirror, X_dev);
468 return mirror;
469 } else {
470 auto X_contig = Tpetra::Details::TempView::toLayout<decltype(X_dev), Kokkos::LayoutLeft>(X_dev);
471 auto mirror = Kokkos::create_mirror_view(X_contig);
472 Kokkos::deep_copy(mirror, X_contig);
473 return mirror;
474 }
475 }
476
477 typename t_dev::host_mirror_type getDeviceCopy() const {
478 auto X_dev = getRawDeviceView();
479 if (X_dev.span_is_contiguous()) {
480 auto mirror = Kokkos::create_mirror_view(X_dev);
481 Kokkos::deep_copy(mirror, X_dev);
482 return mirror;
483 } else {
484 auto X_contig = Tpetra::Details::TempView::toLayout<decltype(X_dev), Kokkos::LayoutLeft>(X_dev);
485 auto mirror = Kokkos::create_mirror_view(X_contig);
486 Kokkos::deep_copy(mirror, X_contig);
487 return mirror;
488 }
489 }
490
491 // Debugging functions for validity checks
492 bool is_valid_host() const {
493 return getRawHostView().size() == 0 || getRawHostView().data();
494 }
495
496 bool is_valid_device() const {
497 return getRawDeviceView().size() == 0 || getRawDeviceView().data();
498 }
499
500 bool need_sync_host() const {
501 return originalDualView.need_sync_host();
502 }
503
504 bool need_sync_device() const {
505 return originalDualView.need_sync_device();
506 }
507
508 int host_view_use_count() const {
509 return getRawHostOriginalView().use_count();
510 }
511
512 int device_view_use_count() const {
513 return getRawDeviceView().use_count();
514 }
515
516 // MultiVector really needs to get at the raw DualViews,
517 // but we'd very much prefer that users not.
518 template <typename SC, typename LO, typename GO, typename NO>
519 friend class ::Tpetra::MultiVector;
520
521 private:
522 const auto& getRawHostOriginalView() const {
523#ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
524 return originalDualView.h_view;
525#else
526 return originalDualView.view_host();
527#endif
528 }
529
530 const auto& getRawDeviceOriginalView() const {
531#ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
532 return originalDualView.d_view;
533#else
534 return originalDualView.view_device();
535#endif
536 }
537
538 const auto& getRawHostView() const {
539#ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
540 return dualView.h_view;
541#else
542 return dualView.view_host();
543#endif
544 }
545
546 const auto& getRawDeviceView() const {
547#ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
548 return dualView.d_view;
549#else
550 return dualView.view_device();
551#endif
552 }
553
554 // A Kokkos implementation of WrappedDualView will have to make these
555 // functions publically accessable, but in the Tpetra version, we'd
556 // really rather not.
557 DualViewType getOriginalDualView() const {
558 return originalDualView;
559 }
560
561 DualViewType getDualView() const {
562 return dualView;
563 }
564
565 // Stokhos wants to reinterpret Tpetra MV of Stokhos type as
566 // Tpetra MV of scalar type, we need access to the dualView for that
567 public:
568 DualViewType implGetOriginalDualView() const {
569 return originalDualView;
570 }
571
572 DualViewType implGetDualView() const {
573 return dualView;
574 }
575
576 private:
577 template <typename ViewType>
578 ViewType getSubview(ViewType view, int offset, int numEntries) const {
579 return Kokkos::subview(view, Kokkos::pair<int, int>(offset, offset + numEntries));
580 }
581
582 template <typename ViewType, typename int_type>
583 ViewType getSubview2D(ViewType view, Kokkos::pair<int_type, int_type> offset0, const Kokkos::ALL_t&) const {
584 return Kokkos::subview(view, offset0, Kokkos::ALL());
585 }
586
587 template <typename ViewType, typename int_type>
588 ViewType getSubview2D(ViewType view, const Kokkos::ALL_t&, Kokkos::pair<int_type, int_type> offset1) const {
589 return Kokkos::subview(view, Kokkos::ALL(), offset1);
590 }
591
592 template <typename ViewType, typename int_type>
593 ViewType getSubview2D(ViewType view, Kokkos::pair<int_type, int_type> offset0, Kokkos::pair<int_type, int_type> offset1) const {
594 return Kokkos::subview(view, offset0, offset1);
595 }
596
597 bool memoryIsAliased() const {
598 return deviceMemoryIsHostAccessible && getRawHostView().data() == getRawDeviceView().data();
599 }
600
618 bool needsSyncPath() const {
620 return false;
621
622 // We check to see if the memory is not aliased *or* if it is a supported
623 // (heterogeneous memory) accelerator (for shared host/device memory).
624 if constexpr (Spaces::is_gpu_exec_space<typename DualViewType::execution_space>()) {
625 return true;
626 } else {
627 if constexpr (!deviceMemoryIsHostAccessible) {
628 return true;
629 } else {
630 return dualView.view_host().data() != dualView.view_device().data();
631 }
632 }
633 }
634
635 void throwIfViewsAreDifferentSizes() const {
636 // Here we check *size* (the product of extents) rather than each extent individually.
637 // This is mostly designed to catch people resizing one view, but not the other.
638 if (getRawDeviceView().size() != getRawHostView().size()) {
639 std::ostringstream msg;
640 msg << "Tpetra::Details::WrappedDualView (name = " << getRawDeviceView().label()
641 << "; host and device views are different sizes: "
642 << getRawHostView().size() << " vs " << getRawHostView().size();
643 throw std::runtime_error(msg.str());
644 }
645 }
646
647 void throwIfHostViewAlive() const {
648 throwIfViewsAreDifferentSizes();
649 if (getRawHostView().use_count() > getRawDeviceView().use_count()) {
650 std::ostringstream msg;
651 msg << "Tpetra::Details::WrappedDualView (name = " << getRawDeviceView().label()
652 << "; host use_count = " << getRawHostView().use_count()
653 << "; device use_count = " << getRawDeviceView().use_count() << "): "
654 << "Cannot access data on device while a host view is alive";
655 throw std::runtime_error(msg.str());
656 }
657 }
658
659 void throwIfDeviceViewAlive() const {
660 throwIfViewsAreDifferentSizes();
661 if (getRawDeviceView().use_count() > getRawHostView().use_count()) {
662 std::ostringstream msg;
663 msg << "Tpetra::Details::WrappedDualView (name = " << getRawDeviceView().label()
664 << "; host use_count = " << getRawHostView().use_count()
665 << "; device use_count = " << getRawDeviceView().use_count() << "): "
666 << "Cannot access data on host while a device view is alive";
667 throw std::runtime_error(msg.str());
668 }
669 }
670
671 bool iAmASubview() {
672 return getRawHostOriginalView() != getRawHostView();
673 }
674
675 mutable DualViewType originalDualView;
676 mutable DualViewType dualView;
677};
678
679} // namespace Details
680
681} // namespace Tpetra
682
683#endif
Struct that holds views of the contents of a CrsMatrix.
A wrapper around Kokkos::DualView to safely manage data that might be replicated between host and dev...
WrappedDualView & operator=(const WrappedDualView< SrcDualViewType > &src)
Conversion assignment operator.
WrappedDualView(const WrappedDualView< SrcDualViewType > &src)
Conversion copy constructor.
Implementation details of Tpetra.
void disableWDVTracking()
Disable WrappedDualView reference-count tracking and syncing. Call this before entering a host-parall...
TPETRA_LIB_DLL_EXPORT bool wdvTrackingEnabled
Whether WrappedDualView reference count checking is enabled. Initially true. Since the DualView sync ...
void enableWDVTracking()
Enable WrappedDualView reference-count tracking and syncing. Call this after exiting a host-parallel ...
Namespace Tpetra contains the class and methods constituting the Tpetra library.