120 using t_host =
typename DualViewType::t_host;
121 using t_dev =
typename DualViewType::t_dev;
123 using HostType =
typename t_host::device_type;
124 using DeviceType =
typename t_dev::device_type;
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;
139 : originalDualView(
dualV)
140 , dualView(originalDualView) {}
143 template <
class SrcDualViewType>
145 : originalDualView(src.originalDualView)
146 , dualView(src.dualView) {}
149 template <
class SrcDualViewType>
151 originalDualView = src.originalDualView;
152 dualView = src.dualView;
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.");
176 hostView = Kokkos::create_mirror_view(
177 Kokkos::WithoutInitializing,
178 typename t_host::memory_space(),
181 originalDualView = DualViewType(deviceView, hostView);
182 originalDualView.clear_sync_state();
183 originalDualView.modify_device();
184 dualView = originalDualView;
188 WrappedDualView(
const WrappedDualView parent,
int offset,
int numEntries) {
189 originalDualView = parent.originalDualView;
190 dualView = getSubview(parent.dualView, offset, numEntries);
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);
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);
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);
209 size_t extent(
const int i)
const {
210 return getRawHostView().extent(i);
213 void stride(
size_t* stride_)
const {
214 dualView.stride(stride_);
217 size_t origExtent(
const int i)
const {
218 return getRawHostOriginalView().extent(i);
221 const char* label()
const {
222 return getRawDeviceView().label();
225 typename t_host::const_type
226 getHostView(Access::ReadOnlyStruct
227 DEBUG_UVM_REMOVAL_ARGUMENT)
const {
228 DEBUG_UVM_REMOVAL_PRINT_CALLER(
"getHostViewReadOnly");
230 if (needsSyncPath()) {
231 throwIfDeviceViewAlive();
232 impl::sync_host(originalDualView);
234 return getRawHostView();
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();
249 return getRawHostView();
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");
259 return getHostView(Access::ReadWrite);
261 if (needsSyncPath()) {
262 throwIfDeviceViewAlive();
263 if (deviceMemoryIsHostAccessible) Kokkos::fence(
"WrappedDualView::getHostView");
264 dualView.clear_sync_state();
265 dualView.modify_host();
267 return getRawHostView();
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);
278 return getRawDeviceView();
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();
292 return getRawDeviceView();
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");
302 return getDeviceView(Access::ReadWrite);
304 if (needsSyncPath()) {
305 throwIfHostViewAlive();
306 if (deviceMemoryIsHostAccessible) Kokkos::fence(
"WrappedDualView::getDeviceView");
307 dualView.clear_sync_state();
308 dualView.modify_device();
310 return getRawDeviceView();
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;
320 DEBUG_UVM_REMOVAL_PRINT_CALLER(
"getView<Device>ReadOnly");
321 if (needsSyncPath()) {
322 throwIfHostViewAlive();
323 impl::sync_device(originalDualView);
326 DEBUG_UVM_REMOVAL_PRINT_CALLER(
"getView<Host>ReadOnly");
327 if (needsSyncPath()) {
328 throwIfDeviceViewAlive();
329 impl::sync_host(originalDualView);
333 return dualView.template view<TargetDeviceType>();
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;
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();
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();
363 return dualView.template view<TargetDeviceType>();
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;
373 return getView<TargetDeviceType>(Access::ReadWrite);
375 constexpr bool returnDevice = std::is_same<ReturnDeviceType, DeviceType>::value;
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();
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();
397 return dualView.template view<TargetDeviceType>();
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);
407 return getSubview(getRawHostView(), offset, numEntries);
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();
420 return getSubview(getRawHostView(), offset, numEntries);
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);
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);
438 return getSubview(getRawDeviceView(), offset, numEntries);
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();
451 return getSubview(getRawDeviceView(), offset, numEntries);
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);
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);
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);
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);
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);
492 bool is_valid_host()
const {
493 return getRawHostView().size() == 0 || getRawHostView().data();
496 bool is_valid_device()
const {
497 return getRawDeviceView().size() == 0 || getRawDeviceView().data();
500 bool need_sync_host()
const {
501 return originalDualView.need_sync_host();
504 bool need_sync_device()
const {
505 return originalDualView.need_sync_device();
508 int host_view_use_count()
const {
509 return getRawHostOriginalView().use_count();
512 int device_view_use_count()
const {
513 return getRawDeviceView().use_count();
518 template <
typename SC,
typename LO,
typename GO,
typename NO>
519 friend class ::Tpetra::MultiVector;
522 const auto& getRawHostOriginalView()
const {
523#ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
524 return originalDualView.h_view;
526 return originalDualView.view_host();
530 const auto& getRawDeviceOriginalView()
const {
531#ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
532 return originalDualView.d_view;
534 return originalDualView.view_device();
538 const auto& getRawHostView()
const {
539#ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
540 return dualView.h_view;
542 return dualView.view_host();
546 const auto& getRawDeviceView()
const {
547#ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
548 return dualView.d_view;
550 return dualView.view_device();
557 DualViewType getOriginalDualView()
const {
558 return originalDualView;
561 DualViewType getDualView()
const {
568 DualViewType implGetOriginalDualView()
const {
569 return originalDualView;
572 DualViewType implGetDualView()
const {
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));
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());
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);
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);
597 bool memoryIsAliased()
const {
598 return deviceMemoryIsHostAccessible && getRawHostView().data() == getRawDeviceView().data();
618 bool needsSyncPath()
const {
624 if constexpr (Spaces::is_gpu_exec_space<typename DualViewType::execution_space>()) {
627 if constexpr (!deviceMemoryIsHostAccessible) {
630 return dualView.view_host().data() != dualView.view_device().data();
635 void throwIfViewsAreDifferentSizes()
const {
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());
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());
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());
672 return getRawHostOriginalView() != getRawHostView();
675 mutable DualViewType originalDualView;
676 mutable DualViewType dualView;