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 "Kokkos_Complex.hpp"
55 #include <sstream>
56 #include <stdexcept>
57 #include <type_traits>
58 
59 namespace Tpetra {
60 namespace Details {
61 
62 //
63 // Implementation details for copyConvert (see below).
64 // Users should skip over this anonymous namespace.
65 //
66 namespace { // (anonymous)
67 
68  template<class OutputValueType,
69  class InputValueType>
70  struct ConvertValue {
71  static KOKKOS_INLINE_FUNCTION void
72  convert (OutputValueType& dst, const InputValueType& src) {
73  // This looks trivial, but it actually invokes OutputValueType's
74  // constructor, so that needs to be marked as a __host__
75  // __device__ function (e.g., via the KOKKOS_FUNCTION or
76  // KOKKOS_INLINE_FUNCTION macros).
77  dst = OutputValueType (src);
78  }
79  };
80 
81  template<class RealType>
82  struct ConvertValue<RealType, Kokkos::complex<RealType> > {
83  static KOKKOS_INLINE_FUNCTION void
84  convert (RealType& dst, const Kokkos::complex<RealType>& src) {
85  // RealType's constructor needs to be marked as a __host__
86  // __device__ function (e.g., via the KOKKOS_FUNCTION or
87  // KOKKOS_INLINE_FUNCTION macros).
88  dst = RealType (src.real ());
89  }
90  };
91 
96  template<class OutputViewType,
97  class InputViewType>
98  class CopyConvertFunctor {
99  private:
100  OutputViewType dst_;
101  InputViewType src_;
102 
103  public:
104  typedef typename std::decay<decltype (dst_[0])>::type output_type;
105  typedef typename OutputViewType::size_type index_type;
106 
107  CopyConvertFunctor (const OutputViewType& dst, const InputViewType& src) :
108  dst_ (dst),
109  src_ (src)
110  {
111  // NOTE (mfh 29 Jan 2016): See kokkos/kokkos#178 for why we use
112  // a memory space, rather than an execution space, as the first
113  // argument of VerifyExecutionCanAccessMemorySpace.
114  static_assert (Kokkos::Impl::VerifyExecutionCanAccessMemorySpace<
115  typename OutputViewType::memory_space,
116  typename InputViewType::memory_space>::value,
117  "CopyConvertFunctor (implements copyConvert): Output "
118  "View's space must be able to access the input View's "
119  "memory space.");
120  static_assert (OutputViewType::Rank == 1 && InputViewType::Rank == 1,
121  "CopyConvertFunctor (implements copyConvert): "
122  "OutputViewType and InputViewType must be rank-1 "
123  "Kokkos::View specializations.");
124  }
125 
126  KOKKOS_INLINE_FUNCTION void
127  operator () (const index_type& i) const {
128  using input_type = typename std::decay<decltype (src_[i])>::type;
129  ConvertValue<output_type, input_type>::convert (dst_(i), src_(i));
130  }
131  };
132 
154  template<class OutputViewType,
155  class InputViewType,
156  const bool canUseKokkosDeepCopy =
157  std::is_same<typename OutputViewType::array_layout,
158  typename InputViewType::array_layout>::value &&
159  std::is_same<typename OutputViewType::non_const_value_type,
160  typename InputViewType::non_const_value_type>::value,
161  const bool outputExecSpaceCanAccessInputMemSpace =
162  Kokkos::Impl::VerifyExecutionCanAccessMemorySpace<
163  typename OutputViewType::memory_space,
164  typename InputViewType::memory_space>::value>
165  struct CopyConvertImpl {
166  static void run (const OutputViewType& dst, const InputViewType& src);
167  };
168 
169  // Specialization for canUseKokkosDeepCopy = true:
170  //
171  // If both input and output Views have the same layout, and both
172  // input and output have the same type, then we can use
173  // Kokkos::deep_copy directly. It doesn't matter whether the output
174  // execution space can access the input memory space:
175  // Kokkos::deep_copy takes care of the details.
176  template<class OutputViewType,
177  class InputViewType,
178  const bool outputExecSpaceCanAccessInputMemSpace>
179  struct CopyConvertImpl<OutputViewType, InputViewType,
180  true, outputExecSpaceCanAccessInputMemSpace> {
181  static void run (const OutputViewType& dst, const InputViewType& src) {
182  static_assert (std::is_same<typename OutputViewType::non_const_value_type,
183  typename InputViewType::non_const_value_type>::value,
184  "CopyConvertImpl (implementation of copyConvert): In order"
185  " to call this specialization, the input and output must "
186  "use the same offset type.");
187  static_assert (OutputViewType::Rank == 1 && InputViewType::Rank == 1,
188  "CopyConvertImpl (implementation of copyConvert): "
189  "OutputViewType and InputViewType must be rank-1 "
190  "Kokkos::View specializations.");
191  static_assert (std::is_same<typename OutputViewType::array_layout,
192  typename InputViewType::array_layout>::value,
193  "CopyConvertImpl (implementation of copyConvert): In order"
194  " to call this specialization, src and dst must have the "
195  "the same array_layout.");
196  Kokkos::deep_copy (dst, src);
197  }
198  };
199 
200  // Specialization for canUseKokkosDeepCopy = false and
201  // outputExecSpaceCanAccessInputMemSpace = true:
202  //
203  // If the output execution space can access the input memory space,
204  // then we can use CopyConvertFunctor directly.
205  template<class OutputViewType,
206  class InputViewType>
207  struct CopyConvertImpl<OutputViewType,
208  InputViewType,
209  false,
210  true> {
211  static void run (const OutputViewType& dst, const InputViewType& src) {
212  static_assert (! std::is_same<typename OutputViewType::array_layout,
213  typename InputViewType::array_layout>::value ||
214  ! std::is_same<typename OutputViewType::non_const_value_type,
215  typename InputViewType::non_const_value_type>::value,
216  "CopyConvertImpl (implementation of copyConvert): We "
217  "should not be calling this specialization if "
218  "OutputViewType and InputViewType have the same entry "
219  "and layout types.");
220  static_assert (OutputViewType::Rank == 1 && InputViewType::Rank == 1,
221  "CopyConvertImpl (implementation of copyConvert): "
222  "OutputViewType and InputViewType must both be rank-1 "
223  "Kokkos::View types.");
224  // NOTE (mfh 29 Jan 2016): See kokkos/kokkos#178 for why we use
225  // a memory space, rather than an execution space, as the first
226  // argument of VerifyExecutionCanAccessMemorySpace.
227  static_assert (Kokkos::Impl::VerifyExecutionCanAccessMemorySpace<
228  typename OutputViewType::memory_space,
229  typename InputViewType::memory_space>::value,
230  "CopyConvertImpl (implements copyConvert): In order to "
231  "call this specialization, the output View's space must "
232  "be able to access the input View's memory space.");
233 
234  typedef CopyConvertFunctor<OutputViewType, InputViewType> functor_type;
235  typedef typename OutputViewType::execution_space execution_space;
236  typedef typename OutputViewType::size_type index_type;
237  typedef Kokkos::RangePolicy<execution_space, index_type> range_type;
238  Kokkos::parallel_for (range_type (0, dst.extent (0)),
239  functor_type (dst, src));
240  }
241  };
242 
243  // Specialization for canUseKokkosDeepCopy = false and
244  // outputExecSpaceCanAccessInputMemSpace = false.
245  //
246  // If the output execution space canNOT access the input memory
247  // space, then we can't use CopyConvertFunctor directly. Instead,
248  // tell Kokkos to copy the input View's data into the output View's
249  // memory space _first_. Since the offset types are different for
250  // this specialization, we can't just call Kokkos::deep_copy
251  // directly between the input and output Views of offsets; that
252  // wouldn't compile.
253  //
254  // This case can and does come up in practice: If the output View's
255  // execution space is Cuda, it cannot currently access host memory
256  // (that's the opposite direction from what UVM allows).
257  // Furthermore, that case specifically requires overflow checking,
258  // since (as of 28 Jan 2016 at least) Kokkos::Cuda uses a smaller
259  // offset type than Kokkos' host spaces.
260  template<class OutputViewType,
261  class InputViewType>
262  struct CopyConvertImpl<OutputViewType,
263  InputViewType,
264  false,
265  false> {
266  static void run (const OutputViewType& dst, const InputViewType& src) {
267  const bool canUseKokkosDeepCopy =
268  std::is_same<typename OutputViewType::array_layout,
269  typename InputViewType::array_layout>::value &&
270  std::is_same<typename OutputViewType::non_const_value_type,
271  typename InputViewType::non_const_value_type>::value;
272  static_assert (! canUseKokkosDeepCopy,
273  "CopyConvertImpl (implementation of copyConvert): We "
274  "should not be calling this specialization if we could "
275  "have used Kokkos::deep_copy instead.");
276  static_assert (OutputViewType::Rank == 1 && InputViewType::Rank == 1,
277  "CopyConvertImpl (implementation of copyConvert): "
278  "OutputViewType and InputViewType must both be rank-1 "
279  "Kokkos::View types.");
280 
281  using Kokkos::ViewAllocateWithoutInitializing;
282  typedef Kokkos::View<typename InputViewType::non_const_value_type*,
283  typename InputViewType::array_layout,
284  typename OutputViewType::device_type> output_space_copy_type;
285  output_space_copy_type
286  outputSpaceCopy (ViewAllocateWithoutInitializing ("outputSpace"),
287  src.extent (0));
288  Kokkos::deep_copy (outputSpaceCopy, src);
289 
290  // The output View's execution space can access
291  // outputSpaceCopy's data, so we can run the functor now.
292  typedef CopyConvertFunctor<OutputViewType,
293  output_space_copy_type> functor_type;
294  typedef typename OutputViewType::execution_space execution_space;
295  typedef typename OutputViewType::size_type index_type;
296  typedef Kokkos::RangePolicy<execution_space, index_type> range_type;
297  Kokkos::parallel_for (range_type (0, dst.extent (0)),
298  functor_type (dst, outputSpaceCopy));
299  }
300  };
301 } // namespace (anonymous)
302 
311 template<class OutputViewType,
312  class InputViewType>
313 void
314 copyConvert (const OutputViewType& dst,
315  const InputViewType& src)
316 {
317  static_assert (Kokkos::Impl::is_view<OutputViewType>::value,
318  "OutputViewType (the type of dst) must be a Kokkos::View.");
319  static_assert (Kokkos::Impl::is_view<InputViewType>::value,
320  "InputViewType (the type of src) must be a Kokkos::View.");
321  static_assert (std::is_same<typename OutputViewType::value_type,
322  typename OutputViewType::non_const_value_type>::value,
323  "OutputViewType (the type of dst) must be a nonconst Kokkos::View.");
324  static_assert (static_cast<int> (OutputViewType::rank) == 1,
325  "OutputViewType (the type of dst) must be a rank-1 Kokkos::View.");
326  static_assert (static_cast<int> (InputViewType::rank) == 1,
327  "InputViewType (the type of src) must be a rank-1 Kokkos::View.");
328  if (dst.extent (0) != src.extent (0)) {
329  std::ostringstream os;
330  os << "Tpetra::Details::copyConvert: "
331  << "dst.extent(0) = " << dst.extent (0)
332  << " != src.extent(0) = " << src.extent (0)
333  << ".";
334  throw std::invalid_argument (os.str ());
335  }
336  // Canonicalize the View types in order to avoid redundant instantiations.
337  typedef typename OutputViewType::non_const_type output_view_type;
338  typedef typename InputViewType::const_type input_view_type;
339  CopyConvertImpl<output_view_type, input_view_type>::run (dst, src);
340 }
341 
342 } // namespace Details
343 } // namespace Tpetra
344 
345 #endif // TPETRA_DETAILS_COPYCONVERT_HPP
Details
Implementation details of Tpetra.
Tpetra::Details::copyConvert
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....
Definition: Tpetra_Details_copyConvert.hpp:314
Tpetra
Namespace Tpetra contains the class and methods constituting the Tpetra library.
Tpetra::deep_copy
void deep_copy(MultiVector< DS, DL, DG, DN > &dst, const MultiVector< SS, SL, SG, SN > &src)
Copy the contents of the MultiVector src into dst.
Definition: Tpetra_MultiVector_decl.hpp:2453