Tpetra parallel linear algebra  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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
Mapping from &quot;master&quot; local object type to the nonowning &quot;local view&quot; type that users see (as argumen...
Declaration of access intent for a global object.
global_object_type & G_
Reference to the global object whose data the user will access.
Kokkos::DualView< impl_scalar_type **, Kokkos::LayoutLeft, execution_space > dual_view_type
Kokkos::DualView specialization used by this class.
One or more distributed dense vectors.
Declaration and definition of Tpetra::withLocalAccess; declaration of helper classes for users to spe...
A distributed dense vector.
bool isValid() const
Is access supposed to be valid?
base_type::dual_view_type dual_view_type
Kokkos::DualView specialization used by this class.
Tag class for declaring access intent.
Mapping from LocalAccess to the &quot;master&quot; local object type.