Tpetra parallel linear algebra Version of the Day
Loading...
Searching...
No Matches
Tpetra_Details_WrappedDualView.hpp
1// @HEADER
2// ***********************************************************************
3//
4// Tpetra: Templated Linear Algebra Services Package
5// Copyright (2008) Sandia Corporation
6//
7// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
8// the U.S. Government retains certain rights in this software.
9//
10// Redistribution and use in source and binary forms, with or without
11// modification, are permitted provided that the following conditions are
12// met:
13//
14// 1. Redistributions of source code must retain the above copyright
15// notice, this list of conditions and the following disclaimer.
16//
17// 2. Redistributions in binary form must reproduce the above copyright
18// notice, this list of conditions and the following disclaimer in the
19// documentation and/or other materials provided with the distribution.
20//
21// 3. Neither the name of the Corporation nor the names of the
22// contributors may be used to endorse or promote products derived from
23// this software without specific prior written permission.
24//
25// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36//
37// ************************************************************************
38// @HEADER
39
40#ifndef TPETRA_DETAILS_WRAPPEDDUALVIEW_HPP
41#define TPETRA_DETAILS_WRAPPEDDUALVIEW_HPP
42
43#include <Tpetra_Access.hpp>
44#include <Tpetra_Details_temporaryViewUtils.hpp>
45#include <Kokkos_DualView.hpp>
46#include "Teuchos_TestForException.hpp"
47#include <sstream>
48
49//#define DEBUG_UVM_REMOVAL // Works only with gcc > 4.8
50
51#ifdef DEBUG_UVM_REMOVAL
52
53#define DEBUG_UVM_REMOVAL_ARGUMENT ,const char* callerstr = __builtin_FUNCTION(),const char * filestr=__builtin_FILE(),const int linnum = __builtin_LINE()
54
55#define DEBUG_UVM_REMOVAL_PRINT_CALLER(fn) \
56 { \
57 auto envVarSet = std::getenv("TPETRA_UVM_REMOVAL"); \
58 if (envVarSet && (std::strcmp(envVarSet,"1") == 0)) \
59 std::cout << (fn) << " called from " << callerstr \
60 << " at " << filestr << ":"<<linnum \
61 << " host cnt " << dualView.h_view.use_count() \
62 << " device cnt " << dualView.d_view.use_count() \
63 << std::endl; \
64 }
65
66#else
67
68#define DEBUG_UVM_REMOVAL_ARGUMENT
69#define DEBUG_UVM_REMOVAL_PRINT_CALLER(fn)
70
71#endif
72
74namespace Tpetra {
75
76 // We really need this forward declaration here for friend to work
77 template<typename SC, typename LO, typename GO, typename NO>
78 class MultiVector;
79
80
83namespace Details {
84
85namespace impl {
86
87template <typename DualViewType>
88struct hasConstData {
89 using valueType = typename DualViewType::value_type;
90 using constValueType = typename DualViewType::const_value_type;
91 static constexpr bool value = std::is_same<valueType, constValueType>::value;
92};
93
94template <typename DualViewType>
95using enableIfConstData = std::enable_if_t<hasConstData<DualViewType>::value>;
96
97template <typename DualViewType>
98using enableIfNonConstData = std::enable_if_t<!hasConstData<DualViewType>::value>;
99
100template <typename DualViewType>
101enableIfNonConstData<DualViewType>
102sync_host(DualViewType dualView) {
103 dualView.sync_host();
104}
105
106template <typename DualViewType>
107enableIfConstData<DualViewType>
108sync_host(DualViewType dualView) { }
109
110template <typename DualViewType>
111enableIfNonConstData<DualViewType>
112sync_device(DualViewType dualView) {
113 dualView.sync_device();
114}
115
116template <typename DualViewType>
117enableIfConstData<DualViewType>
118sync_device(DualViewType dualView) { }
119
120}
121
122
123template <typename DualViewType>
124class WrappedDualView {
125public:
126
127 using DVT = DualViewType;
128 using t_host = typename DualViewType::t_host;
129 using t_dev = typename DualViewType::t_dev;
130
131 using HostType = typename t_host::device_type;
132 using DeviceType = typename t_dev::device_type;
133
134private:
135 static constexpr bool dualViewHasNonConstData = !impl::hasConstData<DualViewType>::value;
136 static constexpr bool deviceMemoryIsHostAccessible =
137 Kokkos::SpaceAccessibility<Kokkos::DefaultHostExecutionSpace, typename t_dev::memory_space>::accessible;
138
139public:
140 WrappedDualView() {}
141
142 WrappedDualView(DualViewType dualV)
143 : originalDualView(dualV),
144 dualView(originalDualView)
145 { }
146
147 // This is an expert-only constructor
148 // For WrappedDualView to manage synchronizations correctly,
149 // it must have an DualView which is not a subview to due the
150 // sync's on. This is what origDualV is for. In this case,
151 // dualV is a subview of origDualV.
152 WrappedDualView(DualViewType dualV,DualViewType origDualV)
153 : originalDualView(origDualV),
154 dualView(dualV)
155 { }
156
157
158 WrappedDualView(const t_dev deviceView) {
159 TEUCHOS_TEST_FOR_EXCEPTION(
160 deviceView.data() != nullptr && deviceView.use_count() == 0,
161 std::invalid_argument,
162 "Tpetra::Details::WrappedDualView: cannot construct with a device view that\n"
163 "does not own its memory (i.e. constructed with a raw pointer and dimensions)\n"
164 "because the WrappedDualView needs to assume ownership of the memory.");
165 //If the provided view is default-constructed (null, 0 extent, 0 use count),
166 //leave the host mirror default-constructed as well in order to have a matching use count of 0.
167 t_host hostView;
168 if(deviceView.use_count() != 0)
169 {
170 hostView = Kokkos::create_mirror_view(
171 Kokkos::WithoutInitializing,
172 typename t_host::memory_space(),
173 deviceView);
174 }
175 originalDualView = DualViewType(deviceView, hostView);
176 originalDualView.clear_sync_state();
177 originalDualView.modify_device();
178 dualView = originalDualView;
179 }
180
181 // 1D View constructors
182 WrappedDualView(const WrappedDualView parent, int offset, int numEntries) {
183 originalDualView = parent.originalDualView;
184 dualView = getSubview(parent.dualView, offset, numEntries);
185 }
186
187
188 // 2D View Constructors
189 WrappedDualView(const WrappedDualView parent,const Kokkos::pair<size_t,size_t>& rowRng, const Kokkos::Impl::ALL_t& colRng) {
190 originalDualView = parent.originalDualView;
191 dualView = getSubview2D(parent.dualView,rowRng,colRng);
192 }
193
194 WrappedDualView(const WrappedDualView parent,const Kokkos::Impl::ALL_t &rowRng, const Kokkos::pair<size_t,size_t>& colRng) {
195 originalDualView = parent.originalDualView;
196 dualView = getSubview2D(parent.dualView,rowRng,colRng);
197 }
198
199 WrappedDualView(const WrappedDualView parent,const Kokkos::pair<size_t,size_t>& rowRng, const Kokkos::pair<size_t,size_t>& colRng) {
200 originalDualView = parent.originalDualView;
201 dualView = getSubview2D(parent.dualView,rowRng,colRng);
202 }
203
204 size_t extent(const int i) const {
205 return dualView.h_view.extent(i);
206 }
207
208 void stride(size_t * stride_) const {
209 dualView.stride(stride_);
210 }
211
212
213 size_t origExtent(const int i) const {
214 return originalDualView.h_view.extent(i);
215 }
216
217 const char * label() const {
218 return dualView.d_view.label();
219 }
220
221
222 typename t_host::const_type
223 getHostView(Access::ReadOnlyStruct
224 DEBUG_UVM_REMOVAL_ARGUMENT
225 ) const
226 {
227 DEBUG_UVM_REMOVAL_PRINT_CALLER("getHostViewReadOnly");
228 if(needsSyncPath()) {
229 throwIfDeviceViewAlive();
230 impl::sync_host(originalDualView);
231 }
232 return dualView.view_host();
233 }
234
235 t_host
236 getHostView(Access::ReadWriteStruct
237 DEBUG_UVM_REMOVAL_ARGUMENT
238 )
239 {
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 dualView.view_host();
250 }
251
252 t_host
253 getHostView(Access::OverwriteAllStruct
254 DEBUG_UVM_REMOVAL_ARGUMENT
255 )
256 {
257 DEBUG_UVM_REMOVAL_PRINT_CALLER("getHostViewOverwriteAll");
258 static_assert(dualViewHasNonConstData,
259 "OverwriteAll views are not available for DualView with const data");
260 if (iAmASubview()) {
261 return getHostView(Access::ReadWrite);
262 }
263 if(needsSyncPath()) {
264 throwIfDeviceViewAlive();
265 if (deviceMemoryIsHostAccessible) Kokkos::fence();
266 dualView.clear_sync_state();
267 dualView.modify_host();
268 }
269 return dualView.view_host();
270 }
271
272 typename t_dev::const_type
273 getDeviceView(Access::ReadOnlyStruct
274 DEBUG_UVM_REMOVAL_ARGUMENT
275 ) const
276 {
277 DEBUG_UVM_REMOVAL_PRINT_CALLER("getDeviceViewReadOnly");
278 if(needsSyncPath()) {
279 throwIfHostViewAlive();
280 impl::sync_device(originalDualView);
281 }
282 return dualView.view_device();
283 }
284
285 t_dev
286 getDeviceView(Access::ReadWriteStruct
287 DEBUG_UVM_REMOVAL_ARGUMENT
288 )
289 {
290 DEBUG_UVM_REMOVAL_PRINT_CALLER("getDeviceViewReadWrite");
291 static_assert(dualViewHasNonConstData,
292 "ReadWrite views are not available for DualView with const data");
293 if(needsSyncPath()) {
294 throwIfHostViewAlive();
295 impl::sync_device(originalDualView);
296 originalDualView.modify_device();
297 }
298 return dualView.view_device();
299 }
300
301 t_dev
302 getDeviceView(Access::OverwriteAllStruct
303 DEBUG_UVM_REMOVAL_ARGUMENT
304 )
305 {
306 DEBUG_UVM_REMOVAL_PRINT_CALLER("getDeviceViewOverwriteAll");
307 static_assert(dualViewHasNonConstData,
308 "OverwriteAll views are not available for DualView with const data");
309 if (iAmASubview()) {
310 return getDeviceView(Access::ReadWrite);
311 }
312 if(needsSyncPath()) {
313 throwIfHostViewAlive();
314 if (deviceMemoryIsHostAccessible) Kokkos::fence();
315 dualView.clear_sync_state();
316 dualView.modify_device();
317 }
318 return dualView.view_device();
319 }
320
321 template<class TargetDeviceType>
322 typename std::remove_reference<decltype(std::declval<DualViewType>().template view<TargetDeviceType>())>::type::const_type
323 getView (Access::ReadOnlyStruct s DEBUG_UVM_REMOVAL_ARGUMENT) const {
324 using ReturnViewType = typename std::remove_reference<decltype(std::declval<DualViewType>().template view<TargetDeviceType>())>::type::const_type;
325 using ReturnDeviceType = typename ReturnViewType::device_type;
326 constexpr bool returnDevice = std::is_same<ReturnDeviceType, DeviceType>::value;
327 if(returnDevice) {
328 DEBUG_UVM_REMOVAL_PRINT_CALLER("getView<Device>ReadOnly");
329 if(needsSyncPath()) {
330 throwIfHostViewAlive();
331 impl::sync_device(originalDualView);
332 }
333 }
334 else {
335 DEBUG_UVM_REMOVAL_PRINT_CALLER("getView<Host>ReadOnly");
336 if(needsSyncPath()) {
337 throwIfDeviceViewAlive();
338 impl::sync_host(originalDualView);
339 }
340 }
341
342 return dualView.template view<TargetDeviceType>();
343 }
344
345
346 template<class TargetDeviceType>
347 typename std::remove_reference<decltype(std::declval<DualViewType>().template view<TargetDeviceType>())>::type
348 getView (Access::ReadWriteStruct s DEBUG_UVM_REMOVAL_ARGUMENT) const {
349 using ReturnViewType = typename std::remove_reference<decltype(std::declval<DualViewType>().template view<TargetDeviceType>())>::type;
350 using ReturnDeviceType = typename ReturnViewType::device_type;
351 constexpr bool returnDevice = std::is_same<ReturnDeviceType, DeviceType>::value;
352
353 if(returnDevice) {
354 DEBUG_UVM_REMOVAL_PRINT_CALLER("getView<Device>ReadWrite");
355 static_assert(dualViewHasNonConstData,
356 "ReadWrite views are not available for DualView with const data");
357 if(needsSyncPath()) {
358 throwIfHostViewAlive();
359 impl::sync_device(originalDualView);
360 originalDualView.modify_device();
361 }
362 }
363 else {
364 DEBUG_UVM_REMOVAL_PRINT_CALLER("getView<Host>ReadWrite");
365 static_assert(dualViewHasNonConstData,
366 "ReadWrite views are not available for DualView with const data");
367 if(needsSyncPath()) {
368 throwIfDeviceViewAlive();
369 impl::sync_host(originalDualView);
370 originalDualView.modify_host();
371 }
372 }
373
374 return dualView.template view<TargetDeviceType>();
375 }
376
377
378 template<class TargetDeviceType>
379 typename std::remove_reference<decltype(std::declval<DualViewType>().template view<TargetDeviceType>())>::type
380 getView (Access::OverwriteAllStruct s DEBUG_UVM_REMOVAL_ARGUMENT) const {
381 using ReturnViewType = typename std::remove_reference<decltype(std::declval<DualViewType>().template view<TargetDeviceType>())>::type;
382 using ReturnDeviceType = typename ReturnViewType::device_type;
383
384 if (iAmASubview())
385 return getView<TargetDeviceType>(Access::ReadWrite);
386
387 constexpr bool returnDevice = std::is_same<ReturnDeviceType, DeviceType>::value;
388
389 if(returnDevice) {
390 DEBUG_UVM_REMOVAL_PRINT_CALLER("getView<Device>OverwriteAll");
391 static_assert(dualViewHasNonConstData,
392 "OverwriteAll views are not available for DualView with const data");
393 if(needsSyncPath()) {
394 throwIfHostViewAlive();
395 dualView.clear_sync_state();
396 dualView.modify_host();
397 }
398 }
399 else {
400 DEBUG_UVM_REMOVAL_PRINT_CALLER("getView<Host>OverwriteAll");
401 static_assert(dualViewHasNonConstData,
402 "OverwriteAll views are not available for DualView with const data");
403 if(needsSyncPath()) {
404 throwIfDeviceViewAlive();
405 dualView.clear_sync_state();
406 dualView.modify_device();
407 }
408 }
409
410 return dualView.template view<TargetDeviceType>();
411 }
412
413
414 typename t_host::const_type
415 getHostSubview(int offset, int numEntries, Access::ReadOnlyStruct
416 DEBUG_UVM_REMOVAL_ARGUMENT
417 ) const
418 {
419 DEBUG_UVM_REMOVAL_PRINT_CALLER("getHostSubviewReadOnly");
420 if(needsSyncPath()) {
421 throwIfDeviceViewAlive();
422 impl::sync_host(originalDualView);
423 }
424 return getSubview(dualView.view_host(), offset, numEntries);
425 }
426
427 t_host
428 getHostSubview(int offset, int numEntries, Access::ReadWriteStruct
429 DEBUG_UVM_REMOVAL_ARGUMENT
430 )
431 {
432 DEBUG_UVM_REMOVAL_PRINT_CALLER("getHostSubviewReadWrite");
433 static_assert(dualViewHasNonConstData,
434 "ReadWrite views are not available for DualView with const data");
435 if(needsSyncPath()) {
436 throwIfDeviceViewAlive();
437 impl::sync_host(originalDualView);
438 originalDualView.modify_host();
439 }
440 return getSubview(dualView.view_host(), offset, numEntries);
441 }
442
443 t_host
444 getHostSubview(int offset, int numEntries, Access::OverwriteAllStruct
445 DEBUG_UVM_REMOVAL_ARGUMENT
446 )
447 {
448 DEBUG_UVM_REMOVAL_PRINT_CALLER("getHostSubviewOverwriteAll");
449 static_assert(dualViewHasNonConstData,
450 "OverwriteAll views are not available for DualView with const data");
451 return getHostSubview(offset, numEntries, Access::ReadWrite);
452 }
453
454 typename t_dev::const_type
455 getDeviceSubview(int offset, int numEntries, Access::ReadOnlyStruct
456 DEBUG_UVM_REMOVAL_ARGUMENT
457 ) const
458 {
459 DEBUG_UVM_REMOVAL_PRINT_CALLER("getDeviceSubviewReadOnly");
460 if(needsSyncPath()) {
461 throwIfHostViewAlive();
462 impl::sync_device(originalDualView);
463 }
464 return getSubview(dualView.view_device(), offset, numEntries);
465 }
466
467 t_dev
468 getDeviceSubview(int offset, int numEntries, Access::ReadWriteStruct
469 DEBUG_UVM_REMOVAL_ARGUMENT
470 )
471 {
472 DEBUG_UVM_REMOVAL_PRINT_CALLER("getDeviceSubviewReadWrite");
473 static_assert(dualViewHasNonConstData,
474 "ReadWrite views are not available for DualView with const data");
475 if(needsSyncPath()) {
476 throwIfHostViewAlive();
477 impl::sync_device(originalDualView);
478 originalDualView.modify_device();
479 }
480 return getSubview(dualView.view_device(), offset, numEntries);
481 }
482
483 t_dev
484 getDeviceSubview(int offset, int numEntries, Access::OverwriteAllStruct
485 DEBUG_UVM_REMOVAL_ARGUMENT
486 )
487 {
488 DEBUG_UVM_REMOVAL_PRINT_CALLER("getDeviceSubviewOverwriteAll");
489 static_assert(dualViewHasNonConstData,
490 "OverwriteAll views are not available for DualView with const data");
491 return getDeviceSubview(offset, numEntries, Access::ReadWrite);
492 }
493
494
495 // Debugging functions to get copies of the view state
496 typename t_host::HostMirror getHostCopy() const {
497 auto X_dev = dualView.view_host();
498 if(X_dev.span_is_contiguous()) {
499 auto mirror = Kokkos::create_mirror_view(X_dev);
500 Kokkos::deep_copy(mirror,X_dev);
501 return mirror;
502 }
503 else {
504 auto X_contig = Tpetra::Details::TempView::toLayout<decltype(X_dev), Kokkos::LayoutLeft>(X_dev);
505 auto mirror = Kokkos::create_mirror_view(X_contig);
506 Kokkos::deep_copy(mirror,X_contig);
507 return mirror;
508 }
509 }
510
511 typename t_dev::HostMirror getDeviceCopy() const {
512 auto X_dev = dualView.view_device();
513 if(X_dev.span_is_contiguous()) {
514 auto mirror = Kokkos::create_mirror_view(X_dev);
515 Kokkos::deep_copy(mirror,X_dev);
516 return mirror;
517 }
518 else {
519 auto X_contig = Tpetra::Details::TempView::toLayout<decltype(X_dev), Kokkos::LayoutLeft>(X_dev);
520 auto mirror = Kokkos::create_mirror_view(X_contig);
521 Kokkos::deep_copy(mirror,X_contig);
522 return mirror;
523 }
524 }
525
526 // Debugging functions for validity checks
527 bool is_valid_host() const {
528 return dualView.view_host().size() == 0 || dualView.view_host().data();
529 }
530
531 bool is_valid_device() const {
532 return dualView.view_device().size() == 0 || dualView.view_device().data();
533 }
534
535
536 bool need_sync_host() const {
537 return originalDualView.need_sync_host();
538 }
539
540 bool need_sync_device() const {
541 return originalDualView.need_sync_device();
542 }
543
544 int host_view_use_count() const {
545 return originalDualView.h_view.use_count();
546 }
547
548 int device_view_use_count() const {
549 return originalDualView.d_view.use_count();
550 }
551
552
553 // MultiVector really needs to get at the raw DualViews,
554 // but we'd very much prefer that users not.
555 template<typename SC, typename LO, typename GO, typename NO>
556 friend class ::Tpetra::MultiVector;
557
558private:
559 // A Kokkos implementation of WrappedDualView will have to make these
560 // functions publically accessable, but in the Tpetra version, we'd
561 // really rather not.
562 DualViewType getOriginalDualView() const {
563 return originalDualView;
564 }
565
566 DualViewType getDualView() const {
567 return dualView;
568 }
569
570 template <typename ViewType>
571 ViewType getSubview(ViewType view, int offset, int numEntries) const {
572 return Kokkos::subview(view, Kokkos::pair<int, int>(offset, offset+numEntries));
573 }
574
575 template <typename ViewType,typename int_type>
576 ViewType getSubview2D(ViewType view, Kokkos::pair<int_type,int_type> offset0, const Kokkos::Impl::ALL_t&) const {
577 return Kokkos::subview(view,offset0,Kokkos::ALL());
578 }
579
580 template <typename ViewType,typename int_type>
581 ViewType getSubview2D(ViewType view, const Kokkos::Impl::ALL_t&, Kokkos::pair<int_type,int_type> offset1) const {
582 return Kokkos::subview(view,Kokkos::ALL(),offset1);
583 }
584
585 template <typename ViewType,typename int_type>
586 ViewType getSubview2D(ViewType view, Kokkos::pair<int_type,int_type> offset0, Kokkos::pair<int_type,int_type> offset1) const {
587 return Kokkos::subview(view,offset0,offset1);
588 }
589
590
591 bool memoryIsAliased() const {
592 return deviceMemoryIsHostAccessible && dualView.h_view.data() == dualView.d_view.data();
593 }
594
595 bool needsSyncPath() const {
596 // needsSyncPath tells us whether we need the "sync path" where we (potentially) fence,
597 // check use counts and take care of sync/modify for the underlying DualView
598 //
599 // The logic is this:
600 // 1) For non-CUDA archtectures where there the host/device pointers are aliased
601 // we don't need the "sync path."
602 // 2) For CUDA, we always need the "sync path" if we're using the CudaUVMSpace (we need to make sure
603 // to fence before reading memory on host) OR if the host/device pointers are aliased.
604 //
605 // Avoiding the "sync path" speeds up calculations on architectures where we can
606 // avoid it (e.g. SerialNode) by not not touching the modify flags.
607 //
608 // Note for the future: Memory spaces that can be addressed on both host and device
609 // that don't otherwise have an intrinsic fencing mechanism will need to trigger the
610 // "sync path"
611
612#ifdef KOKKOS_ENABLE_CUDA
613 return std::is_same<typename t_dev::memory_space,Kokkos::CudaUVMSpace>::value || !memoryIsAliased();
614#else
615 return !memoryIsAliased();
616#endif
617 }
618
619
620 void throwIfViewsAreDifferentSizes() const {
621 // Here we check *size* (the product of extents) rather than each extent individually.
622 // This is mostly designed to catch people resizing one view, but not the other.
623 if(dualView.d_view.size() != dualView.h_view.size()) {
624 std::ostringstream msg;
625 msg << "Tpetra::Details::WrappedDualView (name = " << dualView.d_view.label()
626 << "; host and device views are different sizes: "
627 << dualView.h_view.size() << " vs " <<dualView.h_view.size();
628 throw std::runtime_error(msg.str());
629 }
630 }
631
632 void throwIfHostViewAlive() const {
633 throwIfViewsAreDifferentSizes();
634 if (dualView.h_view.use_count() > dualView.d_view.use_count()) {
635 std::ostringstream msg;
636 msg << "Tpetra::Details::WrappedDualView (name = " << dualView.d_view.label()
637 << "; host use_count = " << dualView.h_view.use_count()
638 << "; device use_count = " << dualView.d_view.use_count() << "): "
639 << "Cannot access data on device while a host view is alive";
640 throw std::runtime_error(msg.str());
641 }
642 }
643
644 void throwIfDeviceViewAlive() const {
645 throwIfViewsAreDifferentSizes();
646 if (dualView.d_view.use_count() > dualView.h_view.use_count()) {
647 std::ostringstream msg;
648 msg << "Tpetra::Details::WrappedDualView (name = " << dualView.d_view.label()
649 << "; host use_count = " << dualView.h_view.use_count()
650 << "; device use_count = " << dualView.d_view.use_count() << "): "
651 << "Cannot access data on host while a device view is alive";
652 throw std::runtime_error(msg.str());
653 }
654 }
655
656 bool iAmASubview() {
657 return originalDualView.h_view != dualView.h_view;
658 }
659
660 mutable DualViewType originalDualView;
661 mutable DualViewType dualView;
662};
663
664} // namespace Details
665
666} // namespace Tpetra
667
668#endif
Implementation details of Tpetra.
Namespace Tpetra contains the class and methods constituting the Tpetra library.