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