140class WrappedDualView {
143 using DVT = DualViewType;
144 using t_host =
typename DualViewType::t_host;
145 using t_dev =
typename DualViewType::t_dev;
147 using HostType =
typename t_host::device_type;
148 using DeviceType =
typename t_dev::device_type;
151 static constexpr bool dualViewHasNonConstData = !impl::hasConstData<DualViewType>::value;
152 static constexpr bool deviceMemoryIsHostAccessible =
153 Kokkos::SpaceAccessibility<Kokkos::DefaultHostExecutionSpace, typename t_dev::memory_space>::accessible;
158 WrappedDualView(DualViewType dualV)
159 : originalDualView(dualV),
160 dualView(originalDualView)
168 WrappedDualView(DualViewType dualV,DualViewType origDualV)
169 : originalDualView(origDualV),
174 WrappedDualView(
const t_dev deviceView) {
175 TEUCHOS_TEST_FOR_EXCEPTION(
176 deviceView.data() !=
nullptr && deviceView.use_count() == 0,
177 std::invalid_argument,
178 "Tpetra::Details::WrappedDualView: cannot construct with a device view that\n"
179 "does not own its memory (i.e. constructed with a raw pointer and dimensions)\n"
180 "because the WrappedDualView needs to assume ownership of the memory.");
184 if(deviceView.use_count() != 0)
186 hostView = Kokkos::create_mirror_view(
187 Kokkos::WithoutInitializing,
188 typename t_host::memory_space(),
191 originalDualView = DualViewType(deviceView, hostView);
192 originalDualView.clear_sync_state();
193 originalDualView.modify_device();
194 dualView = originalDualView;
198 WrappedDualView(
const WrappedDualView parent,
int offset,
int numEntries) {
199 originalDualView = parent.originalDualView;
200 dualView = getSubview(parent.dualView, offset, numEntries);
205 WrappedDualView(
const WrappedDualView parent,
const Kokkos::pair<size_t,size_t>& rowRng,
const Kokkos::ALL_t& colRng) {
206 originalDualView = parent.originalDualView;
207 dualView = getSubview2D(parent.dualView,rowRng,colRng);
210 WrappedDualView(
const WrappedDualView parent,
const Kokkos::ALL_t &rowRng,
const Kokkos::pair<size_t,size_t>& colRng) {
211 originalDualView = parent.originalDualView;
212 dualView = getSubview2D(parent.dualView,rowRng,colRng);
215 WrappedDualView(
const WrappedDualView parent,
const Kokkos::pair<size_t,size_t>& rowRng,
const Kokkos::pair<size_t,size_t>& colRng) {
216 originalDualView = parent.originalDualView;
217 dualView = getSubview2D(parent.dualView,rowRng,colRng);
220 size_t extent(
const int i)
const {
221 return dualView.h_view.extent(i);
224 void stride(
size_t * stride_)
const {
225 dualView.stride(stride_);
229 size_t origExtent(
const int i)
const {
230 return originalDualView.h_view.extent(i);
233 const char * label()
const {
234 return dualView.d_view.label();
238 typename t_host::const_type
239 getHostView(Access::ReadOnlyStruct
240 DEBUG_UVM_REMOVAL_ARGUMENT
243 DEBUG_UVM_REMOVAL_PRINT_CALLER(
"getHostViewReadOnly");
244 if(needsSyncPath()) {
245 throwIfDeviceViewAlive();
246 impl::sync_host(originalDualView);
248 return dualView.view_host();
252 getHostView(Access::ReadWriteStruct
253 DEBUG_UVM_REMOVAL_ARGUMENT
256 DEBUG_UVM_REMOVAL_PRINT_CALLER(
"getHostViewReadWrite");
257 static_assert(dualViewHasNonConstData,
258 "ReadWrite views are not available for DualView with const data");
259 if(needsSyncPath()) {
260 throwIfDeviceViewAlive();
261 impl::sync_host(originalDualView);
262 originalDualView.modify_host();
265 return dualView.view_host();
269 getHostView(Access::OverwriteAllStruct
270 DEBUG_UVM_REMOVAL_ARGUMENT
273 DEBUG_UVM_REMOVAL_PRINT_CALLER(
"getHostViewOverwriteAll");
274 static_assert(dualViewHasNonConstData,
275 "OverwriteAll views are not available for DualView with const data");
277 return getHostView(Access::ReadWrite);
279 if(needsSyncPath()) {
280 throwIfDeviceViewAlive();
281 if (deviceMemoryIsHostAccessible) Kokkos::fence();
282 dualView.clear_sync_state();
283 dualView.modify_host();
285 return dualView.view_host();
288 typename t_dev::const_type
289 getDeviceView(Access::ReadOnlyStruct
290 DEBUG_UVM_REMOVAL_ARGUMENT
293 DEBUG_UVM_REMOVAL_PRINT_CALLER(
"getDeviceViewReadOnly");
294 if(needsSyncPath()) {
295 throwIfHostViewAlive();
296 impl::sync_device(originalDualView);
298 return dualView.view_device();
302 getDeviceView(Access::ReadWriteStruct
303 DEBUG_UVM_REMOVAL_ARGUMENT
306 DEBUG_UVM_REMOVAL_PRINT_CALLER(
"getDeviceViewReadWrite");
307 static_assert(dualViewHasNonConstData,
308 "ReadWrite views are not available for DualView with const data");
309 if(needsSyncPath()) {
310 throwIfHostViewAlive();
311 impl::sync_device(originalDualView);
312 originalDualView.modify_device();
314 return dualView.view_device();
318 getDeviceView(Access::OverwriteAllStruct
319 DEBUG_UVM_REMOVAL_ARGUMENT
322 DEBUG_UVM_REMOVAL_PRINT_CALLER(
"getDeviceViewOverwriteAll");
323 static_assert(dualViewHasNonConstData,
324 "OverwriteAll views are not available for DualView with const data");
326 return getDeviceView(Access::ReadWrite);
328 if(needsSyncPath()) {
329 throwIfHostViewAlive();
330 if (deviceMemoryIsHostAccessible) Kokkos::fence();
331 dualView.clear_sync_state();
332 dualView.modify_device();
334 return dualView.view_device();
337 template<
class TargetDeviceType>
338 typename std::remove_reference<decltype(std::declval<DualViewType>().template view<TargetDeviceType>())>::type::const_type
339 getView (Access::ReadOnlyStruct s DEBUG_UVM_REMOVAL_ARGUMENT)
const {
340 using ReturnViewType =
typename std::remove_reference<decltype(std::declval<DualViewType>().template view<TargetDeviceType>())>::type::const_type;
341 using ReturnDeviceType =
typename ReturnViewType::device_type;
342 constexpr bool returnDevice = std::is_same<ReturnDeviceType, DeviceType>::value;
344 DEBUG_UVM_REMOVAL_PRINT_CALLER(
"getView<Device>ReadOnly");
345 if(needsSyncPath()) {
346 throwIfHostViewAlive();
347 impl::sync_device(originalDualView);
351 DEBUG_UVM_REMOVAL_PRINT_CALLER(
"getView<Host>ReadOnly");
352 if(needsSyncPath()) {
353 throwIfDeviceViewAlive();
354 impl::sync_host(originalDualView);
358 return dualView.template view<TargetDeviceType>();
362 template<
class TargetDeviceType>
363 typename std::remove_reference<decltype(std::declval<DualViewType>().template view<TargetDeviceType>())>::type
364 getView (Access::ReadWriteStruct s DEBUG_UVM_REMOVAL_ARGUMENT)
const {
365 using ReturnViewType =
typename std::remove_reference<decltype(std::declval<DualViewType>().template view<TargetDeviceType>())>::type;
366 using ReturnDeviceType =
typename ReturnViewType::device_type;
367 constexpr bool returnDevice = std::is_same<ReturnDeviceType, DeviceType>::value;
370 DEBUG_UVM_REMOVAL_PRINT_CALLER(
"getView<Device>ReadWrite");
371 static_assert(dualViewHasNonConstData,
372 "ReadWrite views are not available for DualView with const data");
373 if(needsSyncPath()) {
374 throwIfHostViewAlive();
375 impl::sync_device(originalDualView);
376 originalDualView.modify_device();
380 DEBUG_UVM_REMOVAL_PRINT_CALLER(
"getView<Host>ReadWrite");
381 static_assert(dualViewHasNonConstData,
382 "ReadWrite views are not available for DualView with const data");
383 if(needsSyncPath()) {
384 throwIfDeviceViewAlive();
385 impl::sync_host(originalDualView);
386 originalDualView.modify_host();
390 return dualView.template view<TargetDeviceType>();
394 template<
class TargetDeviceType>
395 typename std::remove_reference<decltype(std::declval<DualViewType>().template view<TargetDeviceType>())>::type
396 getView (Access::OverwriteAllStruct s DEBUG_UVM_REMOVAL_ARGUMENT)
const {
397 using ReturnViewType =
typename std::remove_reference<decltype(std::declval<DualViewType>().template view<TargetDeviceType>())>::type;
398 using ReturnDeviceType =
typename ReturnViewType::device_type;
401 return getView<TargetDeviceType>(Access::ReadWrite);
403 constexpr bool returnDevice = std::is_same<ReturnDeviceType, DeviceType>::value;
406 DEBUG_UVM_REMOVAL_PRINT_CALLER(
"getView<Device>OverwriteAll");
407 static_assert(dualViewHasNonConstData,
408 "OverwriteAll views are not available for DualView with const data");
409 if(needsSyncPath()) {
410 throwIfHostViewAlive();
411 dualView.clear_sync_state();
412 dualView.modify_host();
416 DEBUG_UVM_REMOVAL_PRINT_CALLER(
"getView<Host>OverwriteAll");
417 static_assert(dualViewHasNonConstData,
418 "OverwriteAll views are not available for DualView with const data");
419 if(needsSyncPath()) {
420 throwIfDeviceViewAlive();
421 dualView.clear_sync_state();
422 dualView.modify_device();
426 return dualView.template view<TargetDeviceType>();
430 typename t_host::const_type
431 getHostSubview(
int offset,
int numEntries, Access::ReadOnlyStruct
432 DEBUG_UVM_REMOVAL_ARGUMENT
435 DEBUG_UVM_REMOVAL_PRINT_CALLER(
"getHostSubviewReadOnly");
436 if(needsSyncPath()) {
437 throwIfDeviceViewAlive();
438 impl::sync_host(originalDualView);
440 return getSubview(dualView.view_host(), offset, numEntries);
444 getHostSubview(
int offset,
int numEntries, Access::ReadWriteStruct
445 DEBUG_UVM_REMOVAL_ARGUMENT
448 DEBUG_UVM_REMOVAL_PRINT_CALLER(
"getHostSubviewReadWrite");
449 static_assert(dualViewHasNonConstData,
450 "ReadWrite views are not available for DualView with const data");
451 if(needsSyncPath()) {
452 throwIfDeviceViewAlive();
453 impl::sync_host(originalDualView);
454 originalDualView.modify_host();
456 return getSubview(dualView.view_host(), offset, numEntries);
460 getHostSubview(
int offset,
int numEntries, Access::OverwriteAllStruct
461 DEBUG_UVM_REMOVAL_ARGUMENT
464 DEBUG_UVM_REMOVAL_PRINT_CALLER(
"getHostSubviewOverwriteAll");
465 static_assert(dualViewHasNonConstData,
466 "OverwriteAll views are not available for DualView with const data");
467 return getHostSubview(offset, numEntries, Access::ReadWrite);
470 typename t_dev::const_type
471 getDeviceSubview(
int offset,
int numEntries, Access::ReadOnlyStruct
472 DEBUG_UVM_REMOVAL_ARGUMENT
475 DEBUG_UVM_REMOVAL_PRINT_CALLER(
"getDeviceSubviewReadOnly");
476 if(needsSyncPath()) {
477 throwIfHostViewAlive();
478 impl::sync_device(originalDualView);
480 return getSubview(dualView.view_device(), offset, numEntries);
484 getDeviceSubview(
int offset,
int numEntries, Access::ReadWriteStruct
485 DEBUG_UVM_REMOVAL_ARGUMENT
488 DEBUG_UVM_REMOVAL_PRINT_CALLER(
"getDeviceSubviewReadWrite");
489 static_assert(dualViewHasNonConstData,
490 "ReadWrite views are not available for DualView with const data");
491 if(needsSyncPath()) {
492 throwIfHostViewAlive();
493 impl::sync_device(originalDualView);
494 originalDualView.modify_device();
496 return getSubview(dualView.view_device(), offset, numEntries);
500 getDeviceSubview(
int offset,
int numEntries, Access::OverwriteAllStruct
501 DEBUG_UVM_REMOVAL_ARGUMENT
504 DEBUG_UVM_REMOVAL_PRINT_CALLER(
"getDeviceSubviewOverwriteAll");
505 static_assert(dualViewHasNonConstData,
506 "OverwriteAll views are not available for DualView with const data");
507 return getDeviceSubview(offset, numEntries, Access::ReadWrite);
512 typename t_host::HostMirror getHostCopy()
const {
513 auto X_dev = dualView.view_host();
514 if(X_dev.span_is_contiguous()) {
515 auto mirror = Kokkos::create_mirror_view(X_dev);
516 Kokkos::deep_copy(mirror,X_dev);
520 auto X_contig = Tpetra::Details::TempView::toLayout<decltype(X_dev), Kokkos::LayoutLeft>(X_dev);
521 auto mirror = Kokkos::create_mirror_view(X_contig);
522 Kokkos::deep_copy(mirror,X_contig);
527 typename t_dev::HostMirror getDeviceCopy()
const {
528 auto X_dev = dualView.view_device();
529 if(X_dev.span_is_contiguous()) {
530 auto mirror = Kokkos::create_mirror_view(X_dev);
531 Kokkos::deep_copy(mirror,X_dev);
535 auto X_contig = Tpetra::Details::TempView::toLayout<decltype(X_dev), Kokkos::LayoutLeft>(X_dev);
536 auto mirror = Kokkos::create_mirror_view(X_contig);
537 Kokkos::deep_copy(mirror,X_contig);
543 bool is_valid_host()
const {
544 return dualView.view_host().size() == 0 || dualView.view_host().data();
547 bool is_valid_device()
const {
548 return dualView.view_device().size() == 0 || dualView.view_device().data();
552 bool need_sync_host()
const {
553 return originalDualView.need_sync_host();
556 bool need_sync_device()
const {
557 return originalDualView.need_sync_device();
560 int host_view_use_count()
const {
561 return originalDualView.h_view.use_count();
564 int device_view_use_count()
const {
565 return originalDualView.d_view.use_count();
571 template<
typename SC,
typename LO,
typename GO,
typename NO>
572 friend class ::Tpetra::MultiVector;
578 DualViewType getOriginalDualView()
const {
579 return originalDualView;
582 DualViewType getDualView()
const {
586 template <
typename ViewType>
587 ViewType getSubview(ViewType view,
int offset,
int numEntries)
const {
588 return Kokkos::subview(view, Kokkos::pair<int, int>(offset, offset+numEntries));
591 template <
typename ViewType,
typename int_type>
592 ViewType getSubview2D(ViewType view, Kokkos::pair<int_type,int_type> offset0,
const Kokkos::ALL_t&)
const {
593 return Kokkos::subview(view,offset0,Kokkos::ALL());
596 template <
typename ViewType,
typename int_type>
597 ViewType getSubview2D(ViewType view,
const Kokkos::ALL_t&, Kokkos::pair<int_type,int_type> offset1)
const {
598 return Kokkos::subview(view,Kokkos::ALL(),offset1);
601 template <
typename ViewType,
typename int_type>
602 ViewType getSubview2D(ViewType view, Kokkos::pair<int_type,int_type> offset0, Kokkos::pair<int_type,int_type> offset1)
const {
603 return Kokkos::subview(view,offset0,offset1);
606 bool memoryIsAliased()
const {
607 return deviceMemoryIsHostAccessible && dualView.h_view.data() == dualView.d_view.data();
627 bool needsSyncPath()
const {
632#ifdef KOKKOS_ENABLE_CUDA
633 return std::is_same<typename t_dev::memory_space,Kokkos::CudaUVMSpace>::value || !memoryIsAliased();
634#elif defined(KOKKOS_ENABLE_SYCL)
635 return std::is_same<typename t_dev::memory_space,Kokkos::Experimental::SYCLSharedUSMSpace>::value || !memoryIsAliased();
637 return !memoryIsAliased();
642 void throwIfViewsAreDifferentSizes()
const {
645 if(dualView.d_view.size() != dualView.h_view.size()) {
646 std::ostringstream msg;
647 msg <<
"Tpetra::Details::WrappedDualView (name = " << dualView.d_view.label()
648 <<
"; host and device views are different sizes: "
649 << dualView.h_view.size() <<
" vs " <<dualView.h_view.size();
650 throw std::runtime_error(msg.str());
654 void throwIfHostViewAlive()
const {
655 throwIfViewsAreDifferentSizes();
656 if (dualView.h_view.use_count() > dualView.d_view.use_count()) {
657 std::ostringstream msg;
658 msg <<
"Tpetra::Details::WrappedDualView (name = " << dualView.d_view.label()
659 <<
"; host use_count = " << dualView.h_view.use_count()
660 <<
"; device use_count = " << dualView.d_view.use_count() <<
"): "
661 <<
"Cannot access data on device while a host view is alive";
662 throw std::runtime_error(msg.str());
666 void throwIfDeviceViewAlive()
const {
667 throwIfViewsAreDifferentSizes();
668 if (dualView.d_view.use_count() > dualView.h_view.use_count()) {
669 std::ostringstream msg;
670 msg <<
"Tpetra::Details::WrappedDualView (name = " << dualView.d_view.label()
671 <<
"; host use_count = " << dualView.h_view.use_count()
672 <<
"; device use_count = " << dualView.d_view.use_count() <<
"): "
673 <<
"Cannot access data on host while a device view is alive";
674 throw std::runtime_error(msg.str());
679 return originalDualView.h_view != dualView.h_view;
682 mutable DualViewType originalDualView;
683 mutable DualViewType dualView;