VTK-m  2.0
ParallelSortOpenMP.h
Go to the documentation of this file.
1 //============================================================================
2 // Copyright (c) Kitware, Inc.
3 // All rights reserved.
4 // See LICENSE.txt for details.
5 //
6 // This software is distributed WITHOUT ANY WARRANTY; without even
7 // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
8 // PURPOSE. See the above copyright notice for more information.
9 //============================================================================
10 
14 
15 #include <vtkm/BinaryPredicates.h>
16 #include <vtkm/cont/ArrayHandle.h>
19 
20 #include <omp.h>
21 
22 namespace vtkm
23 {
24 namespace cont
25 {
26 namespace openmp
27 {
28 namespace sort
29 {
30 
31 // Forward declare entry points (See stack overflow discussion 7255281 --
32 // templated overloads of template functions are not specialization, and will
33 // be resolved during the first phase of two part lookup).
34 template <typename T, typename Container, class BinaryCompare>
36 template <typename T, typename StorageT, typename U, typename StorageU, class BinaryCompare>
39  BinaryCompare);
40 
41 // Quicksort values:
42 template <typename HandleType, class BinaryCompare>
43 void parallel_sort(HandleType& values,
44  BinaryCompare binary_compare,
45  vtkm::cont::internal::radix::PSortTag)
46 {
47  vtkm::cont::Token token;
48 
49  auto portal = values.PrepareForInPlace(DeviceAdapterTagOpenMP(), token);
50  auto iter = vtkm::cont::ArrayPortalToIteratorBegin(portal);
51  vtkm::Id2 range(0, values.GetNumberOfValues());
52 
53  using IterType = typename std::decay<decltype(iter)>::type;
55 
56  Sorter sorter(iter, binary_compare);
57  sorter.Execute(range);
58 }
59 
60 // Radix sort values:
61 template <typename T, typename StorageT, class BinaryCompare>
63  BinaryCompare binary_compare,
64  vtkm::cont::internal::radix::RadixSortTag)
65 {
66  auto c = vtkm::cont::internal::radix::get_std_compare(binary_compare, T{});
67  vtkm::cont::Token token;
68  auto valuesPortal = values.PrepareForInPlace(vtkm::cont::DeviceAdapterTagOpenMP{}, token);
69  radix::parallel_radix_sort(
70  valuesPortal.GetIteratorBegin(), static_cast<std::size_t>(values.GetNumberOfValues()), c);
71 }
72 
73 // Value sort -- static switch between quicksort & radix sort
74 template <typename T, typename Container, class BinaryCompare>
75 void parallel_sort(vtkm::cont::ArrayHandle<T, Container>& values, BinaryCompare binary_compare)
76 {
77  using namespace vtkm::cont::internal::radix;
78  using SortAlgorithmTag = typename sort_tag_type<T, Container, BinaryCompare>::type;
79 
80  parallel_sort(values, binary_compare, SortAlgorithmTag{});
81 }
82 
83 // Quicksort by key:
84 template <typename T, typename StorageT, typename U, typename StorageU, class BinaryCompare>
87  BinaryCompare binary_compare,
88  vtkm::cont::internal::radix::PSortTag)
89 {
91  constexpr bool larger_than_64bits = sizeof(U) > sizeof(vtkm::Int64);
92  if (larger_than_64bits)
93  {
96 
97  using ValueType = vtkm::cont::ArrayHandle<U, StorageU>;
98  using IndexType = vtkm::cont::ArrayHandle<vtkm::Id>;
100 
101  IndexType indexArray;
102  ValueType valuesScattered;
103  const vtkm::Id size = values.GetNumberOfValues();
104 
105  // Generate an in-memory index array:
106  {
107  vtkm::cont::Token token;
108  auto handle = ArrayHandleIndex(keys.GetNumberOfValues());
109  auto inputPortal = handle.PrepareForInput(DeviceAdapterTagOpenMP(), token);
110  auto outputPortal =
111  indexArray.PrepareForOutput(keys.GetNumberOfValues(), DeviceAdapterTagOpenMP(), token);
112  openmp::CopyHelper(inputPortal, outputPortal, 0, 0, keys.GetNumberOfValues());
113  }
114 
115  // Sort the keys and indices:
116  ZipHandleType zipHandle = vtkm::cont::make_ArrayHandleZip(keys, indexArray);
117  parallel_sort(zipHandle,
118  vtkm::cont::internal::KeyCompare<T, vtkm::Id, BinaryCompare>(binary_compare),
119  vtkm::cont::internal::radix::PSortTag());
120 
121  // Permute the values to their sorted locations:
122  {
123  vtkm::cont::Token token;
124  auto valuesInPortal = values.PrepareForInput(DeviceAdapterTagOpenMP(), token);
125  auto indexPortal = indexArray.PrepareForInput(DeviceAdapterTagOpenMP(), token);
126  auto valuesOutPortal =
127  valuesScattered.PrepareForOutput(size, DeviceAdapterTagOpenMP(), token);
128 
129  VTKM_OPENMP_DIRECTIVE(parallel for
130  default(none)
131  firstprivate(valuesInPortal, indexPortal, valuesOutPortal)
132  schedule(static)
134  for (vtkm::Id i = 0; i < size; ++i)
135  {
136  valuesOutPortal.Set(i, valuesInPortal.Get(indexPortal.Get(i)));
137  }
138  }
139 
140  // Copy the values back into the input array:
141  {
142  vtkm::cont::Token token;
143  auto inputPortal = valuesScattered.PrepareForInput(DeviceAdapterTagOpenMP(), token);
144  auto outputPortal = values.PrepareForOutput(
145  valuesScattered.GetNumberOfValues(), DeviceAdapterTagOpenMP(), token);
146  openmp::CopyHelper(inputPortal, outputPortal, 0, 0, size);
147  }
148  }
149  else
150  {
151  using ValueType = vtkm::cont::ArrayHandle<U, StorageU>;
153 
154  ZipHandleType zipHandle = vtkm::cont::make_ArrayHandleZip(keys, values);
155  parallel_sort(zipHandle,
156  vtkm::cont::internal::KeyCompare<T, U, BinaryCompare>(binary_compare),
157  vtkm::cont::internal::radix::PSortTag{});
158  }
159 }
160 
161 // Radix sort by key:
162 template <typename T, typename StorageT, typename StorageU, class BinaryCompare>
165  BinaryCompare binary_compare,
166  vtkm::cont::internal::radix::RadixSortTag)
167 {
168  using namespace vtkm::cont::internal::radix;
169  auto c = get_std_compare(binary_compare, T{});
170  vtkm::cont::Token token;
171  auto keysPortal = keys.PrepareForInPlace(vtkm::cont::DeviceAdapterTagOpenMP{}, token);
172  auto valuesPortal = values.PrepareForInPlace(vtkm::cont::DeviceAdapterTagOpenMP{}, token);
173  radix::parallel_radix_sort_key_values(keysPortal.GetIteratorBegin(),
174  valuesPortal.GetIteratorBegin(),
175  static_cast<std::size_t>(keys.GetNumberOfValues()),
176  c);
177 }
178 template <typename T, typename StorageT, typename U, typename StorageU, class BinaryCompare>
181  BinaryCompare binary_compare,
182  vtkm::cont::internal::radix::RadixSortTag)
183 {
188 
189  IndexType indexArray;
190  ValueType valuesScattered;
191  const vtkm::Id size = values.GetNumberOfValues();
192 
193  {
194  vtkm::cont::Token token;
195  auto handle = ArrayHandleIndex(keys.GetNumberOfValues());
196  auto inputPortal = handle.PrepareForInput(DeviceAdapterTagOpenMP(), token);
197  auto outputPortal =
198  indexArray.PrepareForOutput(keys.GetNumberOfValues(), DeviceAdapterTagOpenMP(), token);
199  openmp::CopyHelper(inputPortal, outputPortal, 0, 0, keys.GetNumberOfValues());
200  }
201 
202  const vtkm::Id valuesBytes = static_cast<vtkm::Id>(sizeof(T)) * keys.GetNumberOfValues();
203  if (valuesBytes > static_cast<vtkm::Id>(vtkm::cont::internal::radix::MIN_BYTES_FOR_PARALLEL))
204  {
205  parallel_sort_bykey(keys, indexArray, binary_compare);
206  }
207  else
208  {
209  ZipHandleType zipHandle = vtkm::cont::make_ArrayHandleZip(keys, indexArray);
210  parallel_sort(zipHandle,
211  vtkm::cont::internal::KeyCompare<T, vtkm::Id, BinaryCompare>(binary_compare),
212  vtkm::cont::internal::radix::PSortTag());
213  }
214 
215  // Permute the values to their sorted locations:
216  {
217  vtkm::cont::Token token;
218  auto valuesInPortal = values.PrepareForInput(DeviceAdapterTagOpenMP(), token);
219  auto indexPortal = indexArray.PrepareForInput(DeviceAdapterTagOpenMP(), token);
220  auto valuesOutPortal = valuesScattered.PrepareForOutput(size, DeviceAdapterTagOpenMP(), token);
221 
222  VTKM_OPENMP_DIRECTIVE(parallel for
223  default(none)
224  firstprivate(valuesInPortal, indexPortal, valuesOutPortal)
226  schedule(static))
227  for (vtkm::Id i = 0; i < size; ++i)
228  {
229  valuesOutPortal.Set(i, valuesInPortal.Get(indexPortal.Get(i)));
230  }
231  }
232 
233  {
234  vtkm::cont::Token token;
235  auto inputPortal = valuesScattered.PrepareForInput(DeviceAdapterTagOpenMP(), token);
236  auto outputPortal =
237  values.PrepareForOutput(valuesScattered.GetNumberOfValues(), DeviceAdapterTagOpenMP(), token);
238  openmp::CopyHelper(inputPortal, outputPortal, 0, 0, valuesScattered.GetNumberOfValues());
239  }
240 }
241 
242 // Sort by key -- static switch between radix and quick sort:
243 template <typename T, typename StorageT, typename U, typename StorageU, class BinaryCompare>
246  BinaryCompare binary_compare)
247 {
248  using namespace vtkm::cont::internal::radix;
249  using SortAlgorithmTag =
250  typename sortbykey_tag_type<T, U, StorageT, StorageU, BinaryCompare>::type;
251  parallel_sort_bykey(keys, values, binary_compare, SortAlgorithmTag{});
252 }
253 }
254 }
255 }
256 } // end namespace vtkm::cont::openmp::sort
vtkm::cont::ArrayPortalToIteratorBegin
VTKM_SUPPRESS_EXEC_WARNINGS VTKM_EXEC_CONT vtkm::cont::ArrayPortalToIterators< PortalType >::IteratorType ArrayPortalToIteratorBegin(const PortalType &portal)
Convenience function for converting an ArrayPortal to a begin iterator.
Definition: ArrayPortalToIterators.h:178
ParallelRadixSortOpenMP.h
ParallelQuickSortOpenMP.h
vtkm::cont::ArrayHandle::GetNumberOfValues
VTKM_CONT vtkm::Id GetNumberOfValues() const
Returns the number of entries in the array.
Definition: ArrayHandle.h:448
vtkm::cont::ArrayHandle
Manages an array-worth of data.
Definition: ArrayHandle.h:283
ArrayHandle.h
vtkm
Groups connected points that have the same field value.
Definition: Atomic.h:19
vtkm::cont::ArrayHandle::PrepareForInput
VTKM_CONT ReadPortalType PrepareForInput(vtkm::cont::DeviceAdapterId device, vtkm::cont::Token &token) const
Prepares this array to be used as an input to an operation in the execution environment.
Definition: ArrayHandle.h:574
FunctorsOpenMP.h
vtkm::cont::ArrayHandle::PrepareForInPlace
VTKM_CONT WritePortalType PrepareForInPlace(vtkm::cont::DeviceAdapterId device, vtkm::cont::Token &token) const
Prepares this array to be used in an in-place operation (both as input and output) in the execution e...
Definition: ArrayHandle.h:593
vtkm::Id
vtkm::Int32 Id
Represents an ID (index into arrays).
Definition: Types.h:191
ArrayHandleZip.h
vtkm::cont::Token
A token to hold the scope of an ArrayHandle or other object.
Definition: Token.h:35
vtkm::cont::openmp::sort::parallel_sort
void parallel_sort(vtkm::cont::ArrayHandle< T, Container > &, BinaryCompare)
Definition: ParallelSortOpenMP.h:75
vtkm::cont::ArrayHandleZip
ArrayHandleZip is a specialization of ArrayHandle.
Definition: ArrayHandleZip.h:251
ArrayHandleIndex.h
vtkm::cont::make_ArrayHandleZip
VTKM_CONT vtkm::cont::ArrayHandleZip< FirstHandleType, SecondHandleType > make_ArrayHandleZip(const FirstHandleType &first, const SecondHandleType &second)
A convenience function for creating an ArrayHandleZip.
Definition: ArrayHandleZip.h:288
VTKM_OPENMP_DIRECTIVE
#define VTKM_OPENMP_DIRECTIVE(directive)
Definition: FunctorsOpenMP.h:37
VTKM_OPENMP_SHARED_CONST
#define VTKM_OPENMP_SHARED_CONST(...)
Definition: FunctorsOpenMP.h:49
vtkm::Vec< vtkm::Id, 2 >
vtkm::cont::openmp::sort::quick::QuickSorter
Definition: ParallelQuickSortOpenMP.h:35
vtkm::cont::ArrayHandle::PrepareForOutput
VTKM_CONT WritePortalType PrepareForOutput(vtkm::Id numberOfValues, vtkm::cont::DeviceAdapterId device, vtkm::cont::Token &token) const
Prepares (allocates) this array to be used as an output from an operation in the execution environmen...
Definition: ArrayHandle.h:613
BinaryPredicates.h
vtkm::cont::openmp::sort::parallel_sort_bykey
void parallel_sort_bykey(vtkm::cont::ArrayHandle< T, StorageT > &, vtkm::cont::ArrayHandle< U, StorageU > &, BinaryCompare)
Definition: ParallelSortOpenMP.h:244
vtkm::cont::ArrayHandleIndex
An implicit array handle containing the its own indices.
Definition: ArrayHandleIndex.h:54