Tpetra parallel linear algebra  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Tpetra_Details_computeOffsets.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_DETAILS_COMPUTEOFFSETS_HPP
43 #define TPETRA_DETAILS_COMPUTEOFFSETS_HPP
44 
51 
52 #include "TpetraCore_config.h"
54 #include <limits>
55 #include <type_traits>
56 
57 namespace Tpetra {
58 namespace Details {
59 
60 //
61 // Implementation details for computeOffsetsFromCounts (see below).
62 // Users should skip over this anonymous namespace.
63 //
64 namespace { // (anonymous)
65 
75 template<class OffsetType,
76  class CountType,
77  class SizeType>
78 class ComputeOffsetsFromCounts {
79 public:
80  static_assert (std::is_integral<OffsetType>::value,
81  "OffsetType must be a built-in integer.");
82  static_assert (std::is_integral<CountType>::value,
83  "CountType must be a built-in integer.");
84  static_assert (std::is_integral<SizeType>::value,
85  "SizeType must be a built-in integer.");
86 
87  using offsets_view_type =
88  Kokkos::View<OffsetType*, Kokkos::AnonymousSpace>;
89  using counts_view_type =
90  Kokkos::View<const CountType*, Kokkos::AnonymousSpace>;
91 
97  ComputeOffsetsFromCounts (const offsets_view_type& offsets,
98  const counts_view_type& counts) :
99  offsets_ (offsets),
100  counts_ (counts),
101  size_ (counts.extent (0))
102  {}
103 
105  KOKKOS_INLINE_FUNCTION void
106  operator () (const SizeType i, OffsetType& update,
107  const bool finalPass) const
108  {
109  const auto curVal = (i < size_) ? counts_[i] : OffsetType ();
110  if (finalPass) {
111  offsets_[i] = update;
112  }
113  update += (i < size_) ? curVal : OffsetType ();
114  }
115 
116  template<class ExecutionSpace>
117  static OffsetType
118  run (const ExecutionSpace& execSpace,
119  const offsets_view_type& offsets,
120  const counts_view_type& counts)
121  {
122  const SizeType numCounts (counts.extent (0));
123  using range_type = Kokkos::RangePolicy<ExecutionSpace, SizeType>;
124  range_type range (execSpace, 0, numCounts + SizeType (1));
125  using functor_type =
126  ComputeOffsetsFromCounts<OffsetType, CountType, SizeType>;
127  functor_type functor (offsets, counts);
128  OffsetType total (0);
129  const char funcName[] = "Tpetra::Details::computeOffsetsFromCounts";
130  Kokkos::parallel_scan (range, functor, total, funcName);
131  return total;
132  }
133 
134 private:
136  offsets_view_type offsets_;
138  counts_view_type counts_;
140  SizeType size_;
141 };
142 
152 template<class OffsetType,
153  class CountType,
154  class SizeType>
155 class ComputeOffsetsFromConstantCount {
156 public:
157  static_assert (std::is_integral<OffsetType>::value,
158  "OffsetType must be a built-in integer.");
159  static_assert (std::is_integral<CountType>::value,
160  "CountType must be a built-in integer.");
161  static_assert (std::is_integral<SizeType>::value,
162  "SizeType must be a built-in integer.");
163 
164  using offsets_view_type =
165  Kokkos::View<OffsetType*, Kokkos::AnonymousSpace>;
166 
172  ComputeOffsetsFromConstantCount (const offsets_view_type& offsets,
173  const CountType count) :
174  offsets_ (offsets),
175  count_ (count)
176  {}
177 
179  KOKKOS_INLINE_FUNCTION void
180  operator () (const SizeType i) const
181  {
182  offsets_[i] = count_*i;
183  }
184 
185  template<class ExecutionSpace>
186  static OffsetType
187  run (const ExecutionSpace& execSpace,
188  const offsets_view_type& offsets,
189  const CountType count)
190  {
191  const SizeType numOffsets (offsets.extent (0));
192  using range_type = Kokkos::RangePolicy<ExecutionSpace, SizeType>;
193  range_type range (execSpace, 0, numOffsets);
194  using functor_type =
195  ComputeOffsetsFromConstantCount<OffsetType, CountType, SizeType>;
196  functor_type functor (offsets, count);
197  const OffsetType total = numOffsets*count;
198  const char funcName[] =
199  "Tpetra::Details::computeOffsetsFromConstantCount";
200  Kokkos::parallel_for (range, functor, funcName);
201  return total;
202  }
203 
204 private:
206  offsets_view_type offsets_;
208  CountType count_;
209 };
210 
211 } // namespace (anonymous)
212 
238 template<class ExecutionSpace,
239  class OffsetsViewType,
240  class CountsViewType,
241  class SizeType = typename OffsetsViewType::size_type>
242 typename OffsetsViewType::non_const_value_type
243 computeOffsetsFromCounts (const ExecutionSpace& execSpace,
244  const OffsetsViewType& ptr,
245  const CountsViewType& counts)
246 {
247  static_assert (Kokkos::is_execution_space<ExecutionSpace>::value,
248  "ExecutionSpace must be a Kokkos execution space.");
249  static_assert (Kokkos::Impl::is_view<OffsetsViewType>::value,
250  "OffsetsViewType (the type of ptr) must be a Kokkos::View.");
251  static_assert (Kokkos::Impl::is_view<CountsViewType>::value,
252  "CountsViewType (the type of counts) must be a Kokkos::View.");
253  static_assert (std::is_same<typename OffsetsViewType::value_type,
254  typename OffsetsViewType::non_const_value_type>::value,
255  "OffsetsViewType (the type of ptr) must be a nonconst Kokkos::View.");
256  static_assert (static_cast<int> (OffsetsViewType::rank) == 1,
257  "OffsetsViewType (the type of ptr) must be a rank-1 Kokkos::View.");
258  static_assert (static_cast<int> (CountsViewType::rank) == 1,
259  "CountsViewType (the type of counts) must be a rank-1 Kokkos::View.");
260 
261  using offset_type = typename OffsetsViewType::non_const_value_type;
262  static_assert (std::is_integral<offset_type>::value,
263  "The entries of ptr must be built-in integers.");
264  using count_type = typename CountsViewType::non_const_value_type;
265  static_assert (std::is_integral<count_type>::value,
266  "The entries of counts must be built-in integers.");
267  static_assert (std::is_integral<SizeType>::value,
268  "SizeType must be a built-in integer type.");
269 
270  const char funcName[] = "Tpetra::Details::computeOffsetsFromCounts";
271 
272  const auto numOffsets = ptr.size ();
273  const auto numCounts = counts.size ();
274  offset_type total (0);
275 
276  if (numOffsets != 0) {
277  TEUCHOS_TEST_FOR_EXCEPTION
278  (numCounts >= numOffsets, std::invalid_argument, funcName <<
279  ": counts.size() = " << numCounts << " >= ptr.size() = " <<
280  numOffsets << ".");
281 
282 #ifdef TPETRA_AVOID_PARALLEL_SCAN
283  // KDD 11/25/19 Temporary workaround to the one scan whose behavior
284  // makes a difference for GPU runs. On the GPU platforms, serializing
285  // this scan (via Kokkos' magic) makes the code perform correctly.
286  // This code serializes the scan, without the Kokkos magic, for debugging
287  // on stria. #6345
288  // To use this code, add -DTPETRA_AVOID_PARALLEL_SCAN to CMAKE_CXX_FLAGS
289 
290  Kokkos::View<offset_type*,Kokkos::HostSpace>
291  ptrAPS(Kokkos::ViewAllocateWithoutInitializing("APS_offsets"),
292  numOffsets);
293  Kokkos::View<count_type*,Kokkos::HostSpace>
294  countsAPS(Kokkos::ViewAllocateWithoutInitializing("APS_counts"),
295  numCounts);
296 
297  Kokkos::deep_copy(countsAPS, counts);
298 
299  ptrAPS(0) = 0;
300  for (size_t i = 0; i < numCounts; i++)
301  ptrAPS(i+1) = ptrAPS(i) + countsAPS(i);
302 
303  total = ptrAPS(numCounts);
304 
305  Kokkos::deep_copy(ptr, ptrAPS);
306 
307 #else
308  using Kokkos::AnonymousSpace;
309  using Kokkos::View;
310  View<offset_type*, AnonymousSpace> ptr_a = ptr;
311  View<const count_type*, AnonymousSpace> counts_a;
312 
313  using offsets_device_type = typename OffsetsViewType::device_type;
314  using counts_copy_type = View<count_type*, offsets_device_type>;
315  counts_copy_type counts_copy;
316 
317  using offsets_memory_space =
318  typename offsets_device_type::memory_space;
319  using counts_memory_space = typename CountsViewType::memory_space;
320  constexpr bool countsAccessibleFromOffsetsExecSpace =
321  Kokkos::Impl::VerifyExecutionCanAccessMemorySpace<
322  offsets_memory_space, counts_memory_space>::value;
323  if (countsAccessibleFromOffsetsExecSpace) {
324  // NOTE (mfh 21 Aug 2019) Some compilers have trouble deducing
325  // that operator= works if more than one template argument
326  // differ. If that should happen, introduce an intermediate
327  // type here.
328  counts_a = counts;
329  }
330  else {
331  using Kokkos::view_alloc;
332  using Kokkos::WithoutInitializing;
333  counts_copy = counts_copy_type
334  (view_alloc ("counts_copy", WithoutInitializing), numCounts);
335  Kokkos::deep_copy (counts_copy, counts);
336  counts_a = counts_copy;
337  }
338 
339  using functor_type =
340  ComputeOffsetsFromCounts<offset_type, count_type, SizeType>;
341  total = functor_type::run (execSpace, ptr_a, counts_a);
342 #endif
343  }
344 
345  return total;
346 }
347 
349 template<class OffsetsViewType,
350  class CountsViewType,
351  class SizeType = typename OffsetsViewType::size_type>
352 typename OffsetsViewType::non_const_value_type
353 computeOffsetsFromCounts (const OffsetsViewType& ptr,
354  const CountsViewType& counts)
355 {
356  using execution_space = typename OffsetsViewType::execution_space;
357  return computeOffsetsFromCounts (execution_space (), ptr, counts);
358 }
359 
382 template<class OffsetsViewType,
383  class CountType,
384  class SizeType = typename OffsetsViewType::size_type>
385 typename OffsetsViewType::non_const_value_type
386 computeOffsetsFromConstantCount (const OffsetsViewType& ptr,
387  const CountType count)
388 {
389  static_assert (Kokkos::Impl::is_view<OffsetsViewType>::value,
390  "ptr must be a Kokkos::View.");
391  static_assert (std::is_same<typename OffsetsViewType::value_type,
392  typename OffsetsViewType::non_const_value_type>::value,
393  "ptr must be a nonconst Kokkos::View.");
394  static_assert (static_cast<int> (OffsetsViewType::rank) == 1,
395  "ptr must be a rank-1 Kokkos::View.");
396 
397  using offset_type = typename OffsetsViewType::non_const_value_type;
398  static_assert (std::is_integral<offset_type>::value,
399  "The type of each entry of ptr must be a "
400  "built-in integer.");
401  static_assert (std::is_integral<CountType>::value,
402  "CountType must be a built-in integer.");
403  static_assert (std::is_integral<SizeType>::value,
404  "SizeType must be a built-in integer.");
405 
406  using device_type = typename OffsetsViewType::device_type;
407  using execution_space = typename device_type::execution_space;
408 
409  offset_type total (0);
410  if (ptr.extent (0) != 0) {
411  using CT = CountType;
412  using functor_type =
413  ComputeOffsetsFromConstantCount<offset_type, CT, SizeType>;
414  execution_space execSpace;
415  functor_type::run (execSpace, ptr, count);
416  }
417  return total;
418 }
419 
420 } // namespace Details
421 } // namespace Tpetra
422 
423 #endif // TPETRA_DETAILS_COMPUTEOFFSETS_HPP
counts_view_type counts_
Bucket counts (input argument).
OffsetsViewType::non_const_value_type computeOffsetsFromConstantCount(const OffsetsViewType &ptr, const CountType count)
Compute offsets from a constant count.
offsets_view_type offsets_
Offsets (output argument)
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.
CountType count_
&quot;Count&quot; input argument
SizeType size_
Number of entries in counts_.
OffsetsViewType::non_const_value_type computeOffsetsFromCounts(const ExecutionSpace &execSpace, const OffsetsViewType &ptr, const CountsViewType &counts)
Compute offsets from counts.
Declaration and definition of Tpetra::Details::getEntryOnHost.