Tpetra parallel linear algebra Version of the Day
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 <Kokkos_DualView.hpp>
45#include "Teuchos_TestForException.hpp"
46#include <sstream>
47
48// #define DEBUG_UVM_REMOVAL // Works only with gcc > 4.8
49
50#ifdef DEBUG_UVM_REMOVAL
51
52#define DEBUG_UVM_REMOVAL_ARGUMENT ,const char* callerstr = __builtin_FUNCTION()
53
54#define DEBUG_UVM_REMOVAL_PRINT_CALLER(fn) \
55 { \
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() \
61 << std::endl; \
62 }
63
64#else
65
66#define DEBUG_UVM_REMOVAL_ARGUMENT
67#define DEBUG_UVM_REMOVAL_PRINT_CALLER(fn)
68
69#endif
70
72namespace Tpetra {
73
76namespace Details {
77
78namespace impl {
79
80template <typename DualViewType>
81struct hasConstData {
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;
85};
86
87template <typename DualViewType>
88using enableIfConstData = std::enable_if_t<hasConstData<DualViewType>::value>;
89
90template <typename DualViewType>
91using enableIfNonConstData = std::enable_if_t<!hasConstData<DualViewType>::value>;
92
93template <typename DualViewType>
94enableIfNonConstData<DualViewType>
95sync_host(DualViewType dualView) {
96 dualView.sync_host();
97}
98
99template <typename DualViewType>
100enableIfConstData<DualViewType>
101sync_host(DualViewType dualView) { }
102
103template <typename DualViewType>
104enableIfNonConstData<DualViewType>
105sync_device(DualViewType dualView) {
106 dualView.sync_device();
107}
108
109template <typename DualViewType>
110enableIfConstData<DualViewType>
111sync_device(DualViewType dualView) { }
112
113}
114
115template <typename DualViewType>
116class WrappedDualView {
117public:
118 using HostViewType = typename DualViewType::t_host;
119 using DeviceViewType = typename DualViewType::t_dev;
120
121private:
122 static constexpr bool dualViewHasNonConstData = !impl::hasConstData<DualViewType>::value;
123 static constexpr bool deviceMemoryIsHostAccessible =
124 Kokkos::SpaceAccessibility<Kokkos::DefaultHostExecutionSpace, typename DeviceViewType::memory_space>::accessible;
125
126public:
127 WrappedDualView() {}
128
129 WrappedDualView(DualViewType dualV)
130 : originalDualView(dualV),
131 dualView(originalDualView)
132 { }
133
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.");
141 //If the provided view is default-constructed (null, 0 extent, 0 use count),
142 //leave the host mirror default-constructed as well in order to have a matching use count of 0.
143 HostViewType hostView;
144 if(deviceView.use_count() != 0)
145 {
146 hostView = Kokkos::create_mirror_view_and_copy(
147 typename HostViewType::memory_space(),
148 deviceView);
149 }
150 originalDualView = DualViewType(deviceView, hostView);
151 dualView = originalDualView;
152 }
153
154 WrappedDualView(const WrappedDualView parent, int offset, int numEntries) {
155 originalDualView = parent.originalDualView;
156 dualView = getSubview(parent.dualView, offset, numEntries);
157 }
158
159 size_t extent(const int i) const {
160 return dualView.extent(i);
161 }
162
163 typename HostViewType::const_type
164 getHostView(Access::ReadOnlyStruct
165 DEBUG_UVM_REMOVAL_ARGUMENT
166 ) const
167 {
168 DEBUG_UVM_REMOVAL_PRINT_CALLER("getHostViewReadOnly");
169 throwIfDeviceViewAlive();
170 impl::sync_host(originalDualView);
171 return dualView.view_host();
172 }
173
174 HostViewType
175 getHostView(Access::ReadWriteStruct
176 DEBUG_UVM_REMOVAL_ARGUMENT
177 )
178 {
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();
186 }
187
188 HostViewType
189 getHostView(Access::OverwriteAllStruct
190 DEBUG_UVM_REMOVAL_ARGUMENT
191 )
192 {
193 DEBUG_UVM_REMOVAL_PRINT_CALLER("getHostViewOverwriteAll");
194 static_assert(dualViewHasNonConstData,
195 "OverwriteAll views are not available for DualView with const data");
196 if (iAmASubview()) {
197 return getHostView(Access::ReadWrite);
198 }
199 throwIfDeviceViewAlive();
200 if (deviceMemoryIsHostAccessible) Kokkos::fence();
201 dualView.clear_sync_state();
202 dualView.modify_host();
203 return dualView.view_host();
204 }
205
206 typename DeviceViewType::const_type
207 getDeviceView(Access::ReadOnlyStruct
208 DEBUG_UVM_REMOVAL_ARGUMENT
209 ) const
210 {
211 DEBUG_UVM_REMOVAL_PRINT_CALLER("getDeviceViewReadOnly");
212 throwIfHostViewAlive();
213 impl::sync_device(originalDualView);
214 return dualView.view_device();
215 }
216
217 DeviceViewType
218 getDeviceView(Access::ReadWriteStruct
219 DEBUG_UVM_REMOVAL_ARGUMENT
220 )
221 {
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();
229 }
230
231 DeviceViewType
232 getDeviceView(Access::OverwriteAllStruct
233 DEBUG_UVM_REMOVAL_ARGUMENT
234 )
235 {
236 DEBUG_UVM_REMOVAL_PRINT_CALLER("getDeviceViewOverwriteAll");
237 static_assert(dualViewHasNonConstData,
238 "OverwriteAll views are not available for DualView with const data");
239 if (iAmASubview()) {
240 return getDeviceView(Access::ReadWrite);
241 }
242 throwIfHostViewAlive();
243 dualView.clear_sync_state();
244 dualView.modify_device();
245 return dualView.view_device();
246 }
247
248 typename HostViewType::const_type
249 getHostSubview(int offset, int numEntries, Access::ReadOnlyStruct
250 DEBUG_UVM_REMOVAL_ARGUMENT
251 ) const
252 {
253 DEBUG_UVM_REMOVAL_PRINT_CALLER("getHostSubviewReadOnly");
254 throwIfDeviceViewAlive();
255 impl::sync_host(originalDualView);
256 return getSubview(dualView.view_host(), offset, numEntries);
257 }
258
259 HostViewType
260 getHostSubview(int offset, int numEntries, Access::ReadWriteStruct
261 DEBUG_UVM_REMOVAL_ARGUMENT
262 )
263 {
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);
271 }
272
273 HostViewType
274 getHostSubview(int offset, int numEntries, Access::OverwriteAllStruct
275 DEBUG_UVM_REMOVAL_ARGUMENT
276 )
277 {
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);
282 }
283
284 typename DeviceViewType::const_type
285 getDeviceSubview(int offset, int numEntries, Access::ReadOnlyStruct
286 DEBUG_UVM_REMOVAL_ARGUMENT
287 ) const
288 {
289 DEBUG_UVM_REMOVAL_PRINT_CALLER("getDeviceSubviewReadOnly");
290 throwIfHostViewAlive();
291 impl::sync_device(originalDualView);
292 return getSubview(dualView.view_device(), offset, numEntries);
293 }
294
295 DeviceViewType
296 getDeviceSubview(int offset, int numEntries, Access::ReadWriteStruct
297 DEBUG_UVM_REMOVAL_ARGUMENT
298 )
299 {
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);
307 }
308
309 DeviceViewType
310 getDeviceSubview(int offset, int numEntries, Access::OverwriteAllStruct
311 DEBUG_UVM_REMOVAL_ARGUMENT
312 )
313 {
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);
318 }
319
320private:
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));
324 }
325
326 void throwIfHostViewAlive() const {
327 if( deviceMemoryIsHostAccessible && dualView.h_view.data() == dualView.d_view.data()) return;
328
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());
336 }
337 }
338
339 void throwIfDeviceViewAlive() const {
340 if(deviceMemoryIsHostAccessible && dualView.h_view.data() == dualView.d_view.data()) return;
341
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());
349 }
350 }
351
352 bool iAmASubview() {
353 return originalDualView.h_view != dualView.h_view;
354 }
355
356 mutable DualViewType originalDualView;
357 mutable DualViewType dualView;
358};
359
360} // namespace Details
361
362} // namespace Tpetra
363
364#endif
Implementation details of Tpetra.
Namespace Tpetra contains the class and methods constituting the Tpetra library.