Tpetra parallel linear algebra  Version of the Day
Tpetra_Details_copyConvert.hpp
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 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
39 //
40 // ************************************************************************
41 // @HEADER
42 */
43 
44 #ifndef TPETRA_DETAILS_COPYCONVERT_HPP
45 #define TPETRA_DETAILS_COPYCONVERT_HPP
46 
51 
52 #include "TpetraCore_config.h"
53 #include "Kokkos_Core.hpp"
54 #include <sstream>
55 #include <stdexcept>
56 #include <type_traits>
57 
58 namespace Tpetra {
59 namespace Details {
60 
61 //
62 // Implementation details for copyConvert (see below).
63 // Users should skip over this anonymous namespace.
64 //
65 namespace { // (anonymous)
66 
71  template<class OutputViewType,
72  class InputViewType>
73  class CopyConvertFunctor {
74  private:
75  OutputViewType dst_;
76  InputViewType src_;
77 
78  public:
79  typedef typename std::decay<decltype (dst_[0])>::type output_type;
80  typedef typename OutputViewType::size_type index_type;
81 
82  CopyConvertFunctor (const OutputViewType& dst, const InputViewType& src) :
83  dst_ (dst),
84  src_ (src)
85  {
86  // NOTE (mfh 29 Jan 2016): See kokkos/kokkos#178 for why we use
87  // a memory space, rather than an execution space, as the first
88  // argument of VerifyExecutionCanAccessMemorySpace.
89  static_assert (Kokkos::Impl::VerifyExecutionCanAccessMemorySpace<
90  typename OutputViewType::memory_space,
91  typename InputViewType::memory_space>::value,
92  "CopyConvertFunctor (implements copyConvert): Output "
93  "View's space must be able to access the input View's "
94  "memory space.");
95  static_assert (OutputViewType::Rank == 1 && InputViewType::Rank == 1,
96  "CopyConvertFunctor (implements copyConvert): "
97  "OutputViewType and InputViewType must be rank-1 "
98  "Kokkos::View specializations.");
99  }
100 
101  KOKKOS_INLINE_FUNCTION void
102  operator () (const index_type& i) const {
103  // This looks trivial, but it actually invokes output_type's
104  // constructor, so that needs to be marked as a __host__
105  // __device__ function (e.g., via the KOKKOS_FUNCTION or
106  // KOKKOS_INLINE_FUNCTION macros).
107  dst_(i) = output_type (src_(i));
108  }
109  };
110 
132  template<class OutputViewType,
133  class InputViewType,
134  const bool canUseKokkosDeepCopy =
135  std::is_same<typename OutputViewType::array_layout,
136  typename InputViewType::array_layout>::value &&
137  std::is_same<typename OutputViewType::non_const_value_type,
138  typename InputViewType::non_const_value_type>::value,
139  const bool outputExecSpaceCanAccessInputMemSpace =
140  Kokkos::Impl::VerifyExecutionCanAccessMemorySpace<
141  typename OutputViewType::memory_space,
142  typename InputViewType::memory_space>::value>
143  struct CopyConvertImpl {
144  static void run (const OutputViewType& dst, const InputViewType& src);
145  };
146 
147  // Specialization for canUseKokkosDeepCopy = true:
148  //
149  // If both input and output Views have the same layout, and both
150  // input and output have the same type, then we can use
151  // Kokkos::deep_copy directly. It doesn't matter whether the output
152  // execution space can access the input memory space:
153  // Kokkos::deep_copy takes care of the details.
154  template<class OutputViewType,
155  class InputViewType,
156  const bool outputExecSpaceCanAccessInputMemSpace>
157  struct CopyConvertImpl<OutputViewType, InputViewType,
158  true, outputExecSpaceCanAccessInputMemSpace> {
159  static void run (const OutputViewType& dst, const InputViewType& src) {
160  static_assert (std::is_same<typename OutputViewType::non_const_value_type,
161  typename InputViewType::non_const_value_type>::value,
162  "CopyConvertImpl (implementation of copyConvert): In order"
163  " to call this specialization, the input and output must "
164  "use the same offset type.");
165  static_assert (OutputViewType::Rank == 1 && InputViewType::Rank == 1,
166  "CopyConvertImpl (implementation of copyConvert): "
167  "OutputViewType and InputViewType must be rank-1 "
168  "Kokkos::View specializations.");
169  static_assert (std::is_same<typename OutputViewType::array_layout,
170  typename InputViewType::array_layout>::value,
171  "CopyConvertImpl (implementation of copyConvert): In order"
172  " to call this specialization, src and dst must have the "
173  "the same array_layout.");
174  Kokkos::deep_copy (dst, src);
175  }
176  };
177 
178  // Specialization for canUseKokkosDeepCopy = false and
179  // outputExecSpaceCanAccessInputMemSpace = true:
180  //
181  // If the output execution space can access the input memory space,
182  // then we can use CopyConvertFunctor directly.
183  template<class OutputViewType,
184  class InputViewType>
185  struct CopyConvertImpl<OutputViewType,
186  InputViewType,
187  false,
188  true> {
189  static void run (const OutputViewType& dst, const InputViewType& src) {
190  static_assert (! std::is_same<typename OutputViewType::non_const_value_type,
191  typename InputViewType::non_const_value_type>::value,
192  "CopyConvertImpl (implementation of copyConvert): We "
193  "should not be calling this specialization if the entries "
194  "of OutputViewType and InputViewType have the same type.");
195  static_assert (OutputViewType::Rank == 1 && InputViewType::Rank == 1,
196  "CopyConvertImpl (implementation of copyConvert): "
197  "OutputViewType and InputViewType must both be rank-1 "
198  "Kokkos::View types.");
199  // NOTE (mfh 29 Jan 2016): See kokkos/kokkos#178 for why we use
200  // a memory space, rather than an execution space, as the first
201  // argument of VerifyExecutionCanAccessMemorySpace.
202  static_assert (Kokkos::Impl::VerifyExecutionCanAccessMemorySpace<
203  typename OutputViewType::memory_space,
204  typename InputViewType::memory_space>::value,
205  "CopyConvertImpl (implements copyConvert): In order to "
206  "call this specialization, the output View's space must "
207  "be able to access the input View's memory space.");
208 
209  typedef CopyConvertFunctor<OutputViewType, InputViewType> functor_type;
210  typedef typename OutputViewType::execution_space execution_space;
211  typedef typename OutputViewType::size_type index_type;
212  typedef Kokkos::RangePolicy<execution_space, index_type> range_type;
213  Kokkos::parallel_for (range_type (0, dst.dimension_0 ()),
214  functor_type (dst, src));
215  }
216  };
217 
218  // Specialization for canUseKokkosDeepCopy = false and
219  // outputExecSpaceCanAccessInputMemSpace = false.
220  //
221  // If the output execution space canNOT access the input memory
222  // space, then we can't use CopyConvertFunctor directly. Instead,
223  // tell Kokkos to copy the input View's data into the output View's
224  // memory space _first_. Since the offset types are different for
225  // this specialization, we can't just call Kokkos::deep_copy
226  // directly between the input and output Views of offsets; that
227  // wouldn't compile.
228  //
229  // This case can and does come up in practice: If the output View's
230  // execution space is Cuda, it cannot currently access host memory
231  // (that's the opposite direction from what UVM allows).
232  // Furthermore, that case specifically requires overflow checking,
233  // since (as of 28 Jan 2016 at least) Kokkos::Cuda uses a smaller
234  // offset type than Kokkos' host spaces.
235  template<class OutputViewType,
236  class InputViewType>
237  struct CopyConvertImpl<OutputViewType,
238  InputViewType,
239  false,
240  false> {
241  static void run (const OutputViewType& dst, const InputViewType& src) {
242  const bool canUseKokkosDeepCopy =
243  std::is_same<typename OutputViewType::array_layout,
244  typename InputViewType::array_layout>::value &&
245  std::is_same<typename OutputViewType::non_const_value_type,
246  typename InputViewType::non_const_value_type>::value;
247  static_assert (! canUseKokkosDeepCopy,
248  "CopyConvertImpl (implementation of copyConvert): We "
249  "should not be calling this specialization if we could "
250  "have used Kokkos::deep_copy instead.");
251  static_assert (OutputViewType::Rank == 1 && InputViewType::Rank == 1,
252  "CopyConvertImpl (implementation of copyConvert): "
253  "OutputViewType and InputViewType must both be rank-1 "
254  "Kokkos::View types.");
255 
256  using Kokkos::ViewAllocateWithoutInitializing;
257  typedef Kokkos::View<typename InputViewType::non_const_value_type*,
258  typename InputViewType::array_layout,
259  typename OutputViewType::device_type> output_space_copy_type;
260  output_space_copy_type
261  outputSpaceCopy (ViewAllocateWithoutInitializing ("outputSpace"),
262  src.dimension_0 ());
263  Kokkos::deep_copy (outputSpaceCopy, src);
264 
265  // The output View's execution space can access
266  // outputSpaceCopy's data, so we can run the functor now.
267  typedef CopyConvertFunctor<OutputViewType,
268  output_space_copy_type> functor_type;
269  typedef typename OutputViewType::execution_space execution_space;
270  typedef typename OutputViewType::size_type index_type;
271  typedef Kokkos::RangePolicy<execution_space, index_type> range_type;
272  Kokkos::parallel_for (range_type (0, dst.dimension_0 ()),
273  functor_type (dst, outputSpaceCopy));
274  }
275  };
276 } // namespace (anonymous)
277 
286 template<class OutputViewType,
287  class InputViewType>
288 void
289 copyConvert (const OutputViewType& dst,
290  const InputViewType& src)
291 {
292  static_assert (Kokkos::Impl::is_view<OutputViewType>::value,
293  "OutputViewType (the type of dst) must be a Kokkos::View.");
294  static_assert (Kokkos::Impl::is_view<InputViewType>::value,
295  "InputViewType (the type of src) must be a Kokkos::View.");
296  static_assert (std::is_same<typename OutputViewType::value_type,
297  typename OutputViewType::non_const_value_type>::value,
298  "OutputViewType (the type of dst) must be a nonconst Kokkos::View.");
299  static_assert (static_cast<int> (OutputViewType::rank) == 1,
300  "OutputViewType (the type of dst) must be a rank-1 Kokkos::View.");
301  static_assert (static_cast<int> (InputViewType::rank) == 1,
302  "InputViewType (the type of src) must be a rank-1 Kokkos::View.");
303  if (dst.dimension_0 () != src.dimension_0 ()) {
304  std::ostringstream os;
305  os << "Tpetra::Details::copyConvert: "
306  << "dst.dimension_0() = " << dst.dimension_0 ()
307  << " != src.dimension_0() = " << src.dimension_0 ()
308  << ".";
309  throw std::invalid_argument (os.str ());
310  }
311  // Canonicalize the View types in order to avoid redundant instantiations.
312  typedef typename OutputViewType::non_const_type output_view_type;
313  typedef typename InputViewType::const_type input_view_type;
314  CopyConvertImpl<output_view_type, input_view_type>::run (dst, src);
315 }
316 
317 } // namespace Details
318 } // namespace Tpetra
319 
320 #endif // TPETRA_DETAILS_COPYCONVERT_HPP
Namespace Tpetra contains the class and methods constituting the Tpetra library.
void deep_copy(MultiVector< DS, DL, DG, DN, dstClassic > &dst, const MultiVector< SS, SL, SG, SN, srcClassic > &src)
Copy the contents of the MultiVector src into dst.
Implementation details of Tpetra.
void copyConvert(const OutputViewType &dst, const InputViewType &src)
Copy values from the 1-D Kokkos::View src, to the 1-D Kokkos::View dst, of the same length...