40#ifndef TPETRA_DETAILS_WRAPPEDDUALVIEW_HPP
41#define TPETRA_DETAILS_WRAPPEDDUALVIEW_HPP
43#include <Tpetra_Access.hpp>
44#include <Kokkos_DualView.hpp>
45#include "Teuchos_TestForException.hpp"
50#ifdef DEBUG_UVM_REMOVAL
52#define DEBUG_UVM_REMOVAL_ARGUMENT ,const char* callerstr = __builtin_FUNCTION()
54#define DEBUG_UVM_REMOVAL_PRINT_CALLER(fn) \
56 auto envVarSet = std::getenv("TPETRA_UVM_REMOVAL"); \
57 if (envVarSet && (std::strcmp(envVarSet,"1") == 0)) \
58 std::cout << (fn) << " called from " << callerstr \
59 << " host cnt " << dualView.h_view.use_count() \
60 << " device cnt " << dualView.d_view.use_count() \
66#define DEBUG_UVM_REMOVAL_ARGUMENT
67#define DEBUG_UVM_REMOVAL_PRINT_CALLER(fn)
80template <
typename DualViewType>
82 using valueType =
typename DualViewType::value_type;
83 using constValueType =
typename DualViewType::const_value_type;
84 static constexpr bool value = std::is_same<valueType, constValueType>::value;
87template <
typename DualViewType>
88using enableIfConstData = std::enable_if_t<hasConstData<DualViewType>::value>;
90template <
typename DualViewType>
91using enableIfNonConstData = std::enable_if_t<!hasConstData<DualViewType>::value>;
93template <
typename DualViewType>
94enableIfNonConstData<DualViewType>
95sync_host(DualViewType dualView) {
99template <
typename DualViewType>
100enableIfConstData<DualViewType>
101sync_host(DualViewType dualView) { }
103template <
typename DualViewType>
104enableIfNonConstData<DualViewType>
105sync_device(DualViewType dualView) {
106 dualView.sync_device();
109template <
typename DualViewType>
110enableIfConstData<DualViewType>
111sync_device(DualViewType dualView) { }
115template <
typename DualViewType>
116class WrappedDualView {
118 using HostViewType =
typename DualViewType::t_host;
119 using DeviceViewType =
typename DualViewType::t_dev;
122 static constexpr bool dualViewHasNonConstData = !impl::hasConstData<DualViewType>::value;
123 static constexpr bool deviceMemoryIsHostAccessible =
124 Kokkos::SpaceAccessibility<Kokkos::DefaultHostExecutionSpace, typename DeviceViewType::memory_space>::accessible;
129 WrappedDualView(DualViewType dualV)
130 : originalDualView(dualV),
131 dualView(originalDualView)
134 WrappedDualView(
const DeviceViewType deviceView) {
135 TEUCHOS_TEST_FOR_EXCEPTION(
136 deviceView.data() !=
nullptr && deviceView.use_count() == 0,
137 std::invalid_argument,
138 "Tpetra::Details::WrappedDualView: cannot construct with a device view that\n"
139 "does not own its memory (i.e. constructed with a raw pointer and dimensions)\n"
140 "because the WrappedDualView needs to assume ownership of the memory.");
143 HostViewType hostView;
144 if(deviceView.use_count() != 0)
146 hostView = Kokkos::create_mirror_view_and_copy(
147 typename HostViewType::memory_space(),
150 originalDualView = DualViewType(deviceView, hostView);
151 dualView = originalDualView;
154 WrappedDualView(
const WrappedDualView parent,
int offset,
int numEntries) {
155 originalDualView = parent.originalDualView;
156 dualView = getSubview(parent.dualView, offset, numEntries);
159 size_t extent(
const int i)
const {
160 return dualView.extent(i);
163 typename HostViewType::const_type
164 getHostView(Access::ReadOnlyStruct
165 DEBUG_UVM_REMOVAL_ARGUMENT
168 DEBUG_UVM_REMOVAL_PRINT_CALLER(
"getHostViewReadOnly");
169 throwIfDeviceViewAlive();
170 impl::sync_host(originalDualView);
171 return dualView.view_host();
175 getHostView(Access::ReadWriteStruct
176 DEBUG_UVM_REMOVAL_ARGUMENT
179 DEBUG_UVM_REMOVAL_PRINT_CALLER(
"getHostViewReadWrite");
180 static_assert(dualViewHasNonConstData,
181 "ReadWrite views are not available for DualView with const data");
182 throwIfDeviceViewAlive();
183 impl::sync_host(originalDualView);
184 originalDualView.modify_host();
185 return dualView.view_host();
189 getHostView(Access::OverwriteAllStruct
190 DEBUG_UVM_REMOVAL_ARGUMENT
193 DEBUG_UVM_REMOVAL_PRINT_CALLER(
"getHostViewOverwriteAll");
194 static_assert(dualViewHasNonConstData,
195 "OverwriteAll views are not available for DualView with const data");
197 return getHostView(Access::ReadWrite);
199 throwIfDeviceViewAlive();
200 if (deviceMemoryIsHostAccessible) Kokkos::fence();
201 dualView.clear_sync_state();
202 dualView.modify_host();
203 return dualView.view_host();
206 typename DeviceViewType::const_type
207 getDeviceView(Access::ReadOnlyStruct
208 DEBUG_UVM_REMOVAL_ARGUMENT
211 DEBUG_UVM_REMOVAL_PRINT_CALLER(
"getDeviceViewReadOnly");
212 throwIfHostViewAlive();
213 impl::sync_device(originalDualView);
214 return dualView.view_device();
218 getDeviceView(Access::ReadWriteStruct
219 DEBUG_UVM_REMOVAL_ARGUMENT
222 DEBUG_UVM_REMOVAL_PRINT_CALLER(
"getDeviceViewReadWrite");
223 static_assert(dualViewHasNonConstData,
224 "ReadWrite views are not available for DualView with const data");
225 throwIfHostViewAlive();
226 impl::sync_device(originalDualView);
227 originalDualView.modify_device();
228 return dualView.view_device();
232 getDeviceView(Access::OverwriteAllStruct
233 DEBUG_UVM_REMOVAL_ARGUMENT
236 DEBUG_UVM_REMOVAL_PRINT_CALLER(
"getDeviceViewOverwriteAll");
237 static_assert(dualViewHasNonConstData,
238 "OverwriteAll views are not available for DualView with const data");
240 return getDeviceView(Access::ReadWrite);
242 throwIfHostViewAlive();
243 dualView.clear_sync_state();
244 dualView.modify_device();
245 return dualView.view_device();
248 typename HostViewType::const_type
249 getHostSubview(
int offset,
int numEntries, Access::ReadOnlyStruct
250 DEBUG_UVM_REMOVAL_ARGUMENT
253 DEBUG_UVM_REMOVAL_PRINT_CALLER(
"getHostSubviewReadOnly");
254 throwIfDeviceViewAlive();
255 impl::sync_host(originalDualView);
256 return getSubview(dualView.view_host(), offset, numEntries);
260 getHostSubview(
int offset,
int numEntries, Access::ReadWriteStruct
261 DEBUG_UVM_REMOVAL_ARGUMENT
264 DEBUG_UVM_REMOVAL_PRINT_CALLER(
"getHostSubviewReadWrite");
265 static_assert(dualViewHasNonConstData,
266 "ReadWrite views are not available for DualView with const data");
267 throwIfDeviceViewAlive();
268 impl::sync_host(originalDualView);
269 originalDualView.modify_host();
270 return getSubview(dualView.view_host(), offset, numEntries);
274 getHostSubview(
int offset,
int numEntries, Access::OverwriteAllStruct
275 DEBUG_UVM_REMOVAL_ARGUMENT
278 DEBUG_UVM_REMOVAL_PRINT_CALLER(
"getHostSubviewOverwriteAll");
279 static_assert(dualViewHasNonConstData,
280 "OverwriteAll views are not available for DualView with const data");
281 return getHostSubview(offset, numEntries, Access::ReadWrite);
284 typename DeviceViewType::const_type
285 getDeviceSubview(
int offset,
int numEntries, Access::ReadOnlyStruct
286 DEBUG_UVM_REMOVAL_ARGUMENT
289 DEBUG_UVM_REMOVAL_PRINT_CALLER(
"getDeviceSubviewReadOnly");
290 throwIfHostViewAlive();
291 impl::sync_device(originalDualView);
292 return getSubview(dualView.view_device(), offset, numEntries);
296 getDeviceSubview(
int offset,
int numEntries, Access::ReadWriteStruct
297 DEBUG_UVM_REMOVAL_ARGUMENT
300 DEBUG_UVM_REMOVAL_PRINT_CALLER(
"getDeviceSubviewReadWrite");
301 static_assert(dualViewHasNonConstData,
302 "ReadWrite views are not available for DualView with const data");
303 throwIfHostViewAlive();
304 impl::sync_device(originalDualView);
305 originalDualView.modify_device();
306 return getSubview(dualView.view_device(), offset, numEntries);
310 getDeviceSubview(
int offset,
int numEntries, Access::OverwriteAllStruct
311 DEBUG_UVM_REMOVAL_ARGUMENT
314 DEBUG_UVM_REMOVAL_PRINT_CALLER(
"getDeviceSubviewOverwriteAll");
315 static_assert(dualViewHasNonConstData,
316 "OverwriteAll views are not available for DualView with const data");
317 return getDeviceSubview(offset, numEntries, Access::ReadWrite);
321 template <
typename ViewType>
322 ViewType getSubview(ViewType view,
int offset,
int numEntries)
const {
323 return Kokkos::subview(view, Kokkos::pair<int, int>(offset, offset+numEntries));
326 void throwIfHostViewAlive()
const {
327 if( deviceMemoryIsHostAccessible && dualView.h_view.data() == dualView.d_view.data())
return;
329 if (dualView.h_view.use_count() > dualView.d_view.use_count()) {
330 std::ostringstream msg;
331 msg <<
"Tpetra::Details::WrappedDualView (name = " << dualView.d_view.label()
332 <<
"; host use_count = " << dualView.h_view.use_count()
333 <<
"; device use_count = " << dualView.d_view.use_count() <<
"): "
334 <<
"Cannot access data on device while a host view is alive";
335 throw std::runtime_error(msg.str());
339 void throwIfDeviceViewAlive()
const {
340 if(deviceMemoryIsHostAccessible && dualView.h_view.data() == dualView.d_view.data())
return;
342 if (dualView.d_view.use_count() > dualView.h_view.use_count()) {
343 std::ostringstream msg;
344 msg <<
"Tpetra::Details::WrappedDualView (name = " << dualView.d_view.label()
345 <<
"; host use_count = " << dualView.h_view.use_count()
346 <<
"; device use_count = " << dualView.d_view.use_count() <<
"): "
347 <<
"Cannot access data on host while a device view is alive";
348 throw std::runtime_error(msg.str());
353 return originalDualView.h_view != dualView.h_view;
356 mutable DualViewType originalDualView;
357 mutable DualViewType dualView;
Implementation details of Tpetra.
Namespace Tpetra contains the class and methods constituting the Tpetra library.