Tpetra parallel linear algebra  Version of the Day
Tpetra_withLocalAccess_MultiVector.hpp
Go to the documentation of this file.
1 /*
2 // @HEADER
3 // ***********************************************************************
4 //
5 // Tpetra: Templated Linear Algebra Services Package
6 // Copyright (2008) Sandia Corporation
7 //
8 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
9 // the U.S. Government retains certain rights in this software.
10 //
11 // Redistribution and use in source and binary forms, with or without
12 // modification, are permitted provided that the following conditions are
13 // met:
14 //
15 // 1. Redistributions of source code must retain the above copyright
16 // notice, this list of conditions and the following disclaimer.
17 //
18 // 2. Redistributions in binary form must reproduce the above copyright
19 // notice, this list of conditions and the following disclaimer in the
20 // documentation and/or other materials provided with the distribution.
21 //
22 // 3. Neither the name of the Corporation nor the names of the
23 // contributors may be used to endorse or promote products derived from
24 // this software without specific prior written permission.
25 //
26 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 //
38 // ************************************************************************
39 // @HEADER
40 */
41 
42 #ifndef TPETRA_WITHLOCALACCESS_MULTIVECTOR_HPP
43 #define TPETRA_WITHLOCALACCESS_MULTIVECTOR_HPP
44 
46 #include "Tpetra_MultiVector.hpp"
47 #include "Tpetra_Vector.hpp"
48 #include <memory>
49 
53 
54 namespace Tpetra {
55  namespace Details {
56 
57  // We need these forward declarations so that LocalAccess knows
58  // these partial specializations exist, and doesn't just defer to
59  // the generic empty version.
60 
61  template<class SC, class LO, class GO, class NT, class ... Args>
62  struct GetMasterLocalObject<
63  LocalAccess<Tpetra::MultiVector<SC, LO, GO, NT>, Args...>
64  >;
65  template<class SC, class LO, class GO, class NT, class ... Args>
66  struct GetMasterLocalObject<
67  LocalAccess<Tpetra::Vector<SC, LO, GO, NT>, Args...>
68  >;
69 
70  template<class SC, class LO, class GO, class NT, class ... Args>
71  struct GetNonowningLocalObject<
72  LocalAccess<Tpetra::MultiVector<SC, LO, GO, NT>, Args...>
73  >;
74  template<class SC, class LO, class GO, class NT, class ... Args>
75  struct GetNonowningLocalObject<
76  LocalAccess<Tpetra::Vector<SC, LO, GO, NT>, Args...>
77  >;
78 
80 
81  template<class Space>
82  struct is_host_space {
83  // Space=CudaSpace: false.
84  // Space=CudaUVMSpace: false.
85  // Space=CudaHostPinnedSpace: true.
86  // Space=HostSpace: true.
87  //
88  // Space=Cuda: true.
89  // Space=OpenMP: false.
90  // Space=Serial: false.
91  // space=Threads: false.
92  static constexpr bool value =
93  std::is_same<typename Space::execution_space::memory_space,
94  Kokkos::HostSpace>::value;
95  };
96 
98 
100  template<class SC, class LO, class GO, class NT, class ... Args>
102  LocalAccess<Tpetra::MultiVector<SC, LO, GO, NT>, Args...>
103  >
104  {
105  private:
107 
108  public:
109  using local_access_type =
111 
112  private:
113  using execution_space =
114  typename local_access_type::execution_space;
115  static_assert(
116  Kokkos::Impl::is_execution_space<execution_space>::value,
117  "LocalAccess<Args...>::execution_space is not a valid "
118  "Kokkos execution space.");
119 
120  using memory_space = typename local_access_type::memory_space;
121  static_assert(
122  Kokkos::Impl::is_memory_space<memory_space>::value,
123  "LocalAccess<Args...>::memory_space is not a valid "
124  "Kokkos memory space.");
125 
126  using access_mode = typename local_access_type::access_mode;
127  static_assert(
128  is_access_mode<access_mode>::value,
129  "LocalAccess<Args...>::access_mode is not an Access "
130  "type.");
131 
132  // FIXME (mfh 22 Oct 2018, 25 Apr 2019) Need to make sure that
133  // the execution space matches. If not, we would need to
134  // allocate a new View, and then we should actually make the
135  // std::unique_ptr's destructor "copy back." This is why
136  // master_local_object_type (see below) is a
137  // std::unique_ptr<Kokkos::View<...>>, not just a
138  // Kokkos::View<...>.
139  //
140  // mfh 01 May 2019: For now, we avoid allocation and copy back,
141  // by using only the Views available in the MV's DualView.
142  using dual_view_type =
144 
145  public:
146  // This alias is for the Tpetra::MultiVector specialization of
147  // GetNonowningLocalObject. withLocalAccess itself does not
148  // need this to be public.
149  //
150  // Owning View type is always a View of nonconst. If you own
151  // the data, you need to be able to modify them.
152  using master_local_view_type = typename std::conditional<
153  is_host_space<execution_space>::value,
154  typename dual_view_type::t_host,
155  typename dual_view_type::t_dev>::type;
156 
157  static_assert(
158  static_cast<int>(master_local_view_type::Rank) == 2,
159  "Rank of master_local_view_type must be 2. "
160  "Please report this bug to the Tpetra developers.");
161 
162  private:
163  static master_local_view_type
164  getOwningPreActions(local_access_type& LA)
165  {
166  if (! LA.isValid()) { // return "null" Kokkos::View
167  return master_local_view_type();
168  }
169  else {
170  using access_mode = typename local_access_type::access_mode;
171  constexpr bool is_write_only =
172  std::is_same<access_mode, write_only>::value;
173  if (is_write_only) {
174  LA.G_.clear_sync_state();
175  }
176 
177  // Given that Tpetra::(Multi)Vector currently uses
178  // Kokkos::DualView, here is how get() must behave:
179  //
180  // - LA's memory space tells us which allocation to view.
181  //
182  // - LA's execution space tells us whether we need to fence.
183  //
184  // - If LA's execution space equals the MultiVector's
185  // execution space, then there is no need to fence, no
186  // matter what the requested memory space is.
187  //
188  // - Else, if LA's execution space is a host space, but
189  // the MultiVector needs sync to host, then we must
190  // fence the MultiVector's (device) execution space, to
191  // ensure that device kernels aren't concurrently
192  // modifying the MultiVector's local data.
193  // Tpetra::MultiVector::fence (should) do that for us,
194  // via Kokkos::DualView::fence.
195 
196  // It's easier to use an execution space than a memory space
197  // in sync<Space>. Otherwise, DualView of CudaUVMSpace
198  // complains that HostSpace is not one of its two memory
199  // spaces. (Both the device and the host Views of a
200  // DualView of CudaUVMSpace have memory_space =
201  // CudaUVMSpace.) Furthermore, this handles the case where
202  // Kokkos::DefaultHostExecutionSpace != the MultiVector's
203  // execution space, but the latter is still a host space
204  // (e.g., Kokkos::OpenMP vs. Kokkos::Serial).
205 
206  if (LA.G_.template need_sync<execution_space>()) {
207  LA.G_.template sync<execution_space>();
208  }
209 
210  constexpr bool is_read_only =
211  std::is_same<access_mode, read_only>::value;
212  if (! is_read_only) {
213  LA.G_.template modify<execution_space>();
214  }
215 
216  // See note about "copy back" above.
217  auto G_lcl_2d =
218  LA.G_.template getLocalView<execution_space>();
219  // This converts the View to const if applicable.
220  return master_local_view_type(G_lcl_2d);
221  }
222  }
223 
224  public:
225  // This alias is required by withLocalAccess.
226  // using master_local_object_type = std::unique_ptr<
227  // master_local_view_type,
228  // typename impl_type::deleter_type<master_local_view_type>>;
229  using master_local_object_type = std::unique_ptr<
230  master_local_view_type>;
231 
232  // This method is required by withLocalAccess.
233  static master_local_object_type
234  get(local_access_type LA)
235  {
236  auto G_lcl_2d = getOwningPreActions(LA);
237  // Once we can use C++14, switch to std::make_unique.
238  // return master_local_object_type(
239  // new master_local_view_type(G_lcl_2d),
240  // impl_type::getOwningPostActions(LA, G_lcl_2d));
241  return master_local_object_type(
242  new master_local_view_type(G_lcl_2d));
243  }
244  };
245 
246  static_assert(
247  Kokkos::is_view<
250  >::master_local_view_type
251  >::value, "Missing GetMasterLocalObject specialization");
252 
253  static_assert(
254  Kokkos::is_view<
256  LocalAccess<Tpetra::MultiVector<>, Kokkos::HostSpace, read_only>
257  >::master_local_view_type
258  >::value, "Missing GetMasterLocalObject specialization");
259 
261 
263  template<class SC, class LO, class GO, class NT, class ... Args>
265  LocalAccess<Tpetra::Vector<SC, LO, GO, NT>, Args...>
266  >
267  {
268  private:
270 
271  public:
272  using local_access_type =
274 
275  private:
276  using execution_space =
277  typename local_access_type::execution_space;
278  static_assert(
279  Kokkos::Impl::is_execution_space<execution_space>::value,
280  "LocalAccess<Args...>::execution_space is not a valid "
281  "Kokkos execution space.");
282 
283  using memory_space = typename local_access_type::memory_space;
284  static_assert(
285  Kokkos::Impl::is_memory_space<memory_space>::value,
286  "LocalAccess<Args...>::memory_space is not a valid "
287  "Kokkos memory space.");
288 
289  using access_mode = typename local_access_type::access_mode;
290  static_assert(
291  is_access_mode<access_mode>::value,
292  "LocalAccess<Args...>::access_mode is not an Access "
293  "type.");
294 
295  // FIXME (mfh 22 Oct 2018, 25 Apr 2019) Need to make sure that
296  // the execution space matches. If not, we would need to
297  // allocate a new View, and then we should actually make the
298  // std::unique_ptr's destructor "copy back." This is why
299  // master_local_object_type (see below) is a
300  // std::unique_ptr<Kokkos::View<...>>, not just a
301  // Kokkos::View<...>.
302  //
303  // mfh 01 May 2019: For now, we avoid allocation and copy back,
304  // by using only the Views available in the MV's DualView.
305  using dual_view_type =
307 
308  // Owning View type is always a View of nonconst. If you own
309  // the data, you need to be able to modify them.
310  using master_local_view_2d_type = typename std::conditional<
311  is_host_space<execution_space>::value,
312  typename dual_view_type::t_host,
313  typename dual_view_type::t_dev>::type;
314 
315  public:
316  // This alias is for the Tpetra::Vector specialization of
317  // GetNonowningLocalObject. withLocalAccess itself does not
318  // need this to be public.
319  using master_local_view_type = decltype(
320  Kokkos::subview(master_local_view_2d_type(),
321  Kokkos::ALL(), 0));
322 
323  static_assert(
324  static_cast<int>(master_local_view_type::Rank) == 1,
325  "Rank of master_local_view_type must be 1. "
326  "Please report this bug to the Tpetra developers.");
327 
328  private:
329  static master_local_view_2d_type
330  getOwningPreActions(local_access_type& LA)
331  {
332  if (! LA.isValid()) { // return "null" Kokkos::View
333  return master_local_view_2d_type();
334  }
335  else {
336  using access_mode = typename local_access_type::access_mode;
337  constexpr bool is_write_only =
338  std::is_same<access_mode, write_only>::value;
339  if (is_write_only) {
340  LA.G_.clear_sync_state();
341  }
342 
343  if (LA.G_.template need_sync<execution_space>()) {
344  LA.G_.template sync<execution_space>();
345  }
346 
347  constexpr bool is_read_only =
348  std::is_same<access_mode, read_only>::value;
349  if (! is_read_only) {
350  LA.G_.template modify<execution_space>();
351  }
352 
353  // See note about "copy back" above.
354  auto G_lcl_2d =
355  LA.G_.template getLocalView<execution_space>();
356  // This converts the View to const if applicable.
357  return master_local_view_2d_type(G_lcl_2d);
358  }
359  }
360 
361  public:
362  // This alias is required by withLocalAccess.
363  // using master_local_object_type = std::unique_ptr<
364  // master_local_view_type,
365  // typename impl_type::deleter_type<master_local_view_type>>;
366  using master_local_object_type = std::unique_ptr<
367  master_local_view_type>;
368 
369  // This method is required by withLocalAccess.
370  static master_local_object_type
371  get(local_access_type LA)
372  {
373  master_local_view_2d_type G_lcl_2d = getOwningPreActions(LA);
374  master_local_view_type G_lcl_1d =
375  Kokkos::subview(G_lcl_2d, Kokkos::ALL(), 0);
376  // Once we can use C++14, switch to std::make_unique.
377  // return master_local_object_type(
378  // new master_local_view_type(G_lcl_1d),
379  // impl_type::getOwningPostActions(LA, G_lcl_2d));
380 
381  return master_local_object_type(
382  new master_local_view_type(G_lcl_1d));
383  }
384  };
385 
386  static_assert(
387  Kokkos::is_view<
390  >::master_local_view_type
391  >::value, "Missing GetMasterLocalObject specialization");
392 
393  static_assert(
394  Kokkos::is_view<
396  LocalAccess<Tpetra::Vector<>, Kokkos::HostSpace, read_only>
397  >::master_local_view_type
398  >::value, "Missing GetMasterLocalObject specialization");
399 
400 
402 
405  template<class SC, class LO, class GO, class NT, class ... Args>
407  LocalAccess<Tpetra::MultiVector<SC, LO, GO, NT>, Args...>
408  >
409  {
410  private:
412  public:
413  using local_access_type =
415 
416  private:
417  using access_mode = typename local_access_type::access_mode;
418  static_assert(is_access_mode<access_mode>::value,
419  "Please report this bug to the Tpetra developers.");
420 
421  using master_local_view_type =
423  master_local_view_type;
424  static_assert(
425  static_cast<int>(master_local_view_type::Rank) == 2,
426  "Rank of master_local_view_type must be 2.");
427 
428  // master_local_view_type::non_const_data_type is
429  // MV::impl_scalar_type**, where
430  // MV = Tpetra::MultiVector<SC, LO, GO, NT>.
431  using output_data_type = typename std::conditional<
432  std::is_same<access_mode, read_only>::value,
433  typename master_local_view_type::const_data_type,
434  typename master_local_view_type::non_const_data_type>::type;
435 
436  public:
437  using master_local_object_type =
439  master_local_object_type;
440  using nonowning_local_object_type =
441  Kokkos::View<output_data_type,
442  typename master_local_view_type::array_layout,
443  typename master_local_view_type::device_type,
444  Kokkos::MemoryTraits<Kokkos::Unmanaged> >;
445 
446  static nonowning_local_object_type
447  get(local_access_type /* LA */,
448  const master_local_object_type& M)
449  {
450  master_local_view_type* viewPtr = M.get();
451  return viewPtr == nullptr ?
452  nonowning_local_object_type() :
453  nonowning_local_object_type(*viewPtr);
454  }
455  };
456 
458 
461  template<class SC, class LO, class GO, class NT, class ... Args>
463  LocalAccess<Tpetra::Vector<SC, LO, GO, NT>, Args...>
464  >
465  {
466  private:
468  public:
469  using local_access_type =
471 
472  private:
473  using access_mode = typename local_access_type::access_mode;
474  static_assert(is_access_mode<access_mode>::value,
475  "Please report this bug to the Tpetra developers.");
476 
477  using master_local_view_type =
479  master_local_view_type;
480  static_assert(
481  static_cast<int>(master_local_view_type::Rank) == 1,
482  "Rank of master_local_view_type must be 1.");
483 
484  // input_view_type::non_const_data_type is V::impl_scalar_type*,
485  // where V = Tpetra::Vector<SC, LO, GO, NT>.
486  using output_data_type = typename std::conditional<
487  std::is_same<access_mode, read_only>::value,
488  typename master_local_view_type::const_data_type,
489  typename master_local_view_type::non_const_data_type>::type;
490 
491  public:
492  using master_local_object_type =
494  master_local_object_type;
495  using nonowning_local_object_type =
496  Kokkos::View<output_data_type,
497  typename master_local_view_type::array_layout,
498  typename master_local_view_type::device_type,
499  Kokkos::MemoryTraits<Kokkos::Unmanaged> >;
500 
501  static nonowning_local_object_type
502  get (local_access_type /* LA */,
503  const master_local_object_type& M)
504  {
505  master_local_view_type* viewPtr = M.get();
506  return viewPtr == nullptr ?
507  nonowning_local_object_type() :
508  nonowning_local_object_type(*viewPtr);
509  }
510  };
511 
512  } // namespace Details
513 } // namespace Tpetra
514 
515 #endif // TPETRA_WITHLOCALACCESS_MULTIVECTOR_HPP
Declaration and definition of Tpetra::withLocalAccess; declaration of helper classes for users to spe...
Tag class for declaring access intent.
Declaration of access intent for a global object.
global_object_type & G_
Reference to the global object whose data the user will access.
bool isValid() const
Is access supposed to be valid?
One or more distributed dense vectors.
Kokkos::DualView< impl_scalar_type **, Kokkos::LayoutLeft, execution_space > dual_view_type
Kokkos::DualView specialization used by this class.
A distributed dense vector.
base_type::dual_view_type dual_view_type
Kokkos::DualView specialization used by this class.
Implementation details of Tpetra.
Namespace Tpetra contains the class and methods constituting the Tpetra library.
Mapping from LocalAccess to the "master" local object type.
Mapping from "master" local object type to the nonowning "local view" type that users see (as argumen...