Viskores  1.0
ParallelSortOpenMP.h
Go to the documentation of this file.
1 //============================================================================
2 // The contents of this file are covered by the Viskores license. See
3 // LICENSE.txt for details.
4 //
5 // By contributing to this file, all contributors agree to the Developer
6 // Certificate of Origin Version 1.1 (DCO 1.1) as stated in DCO.txt.
7 //============================================================================
8 
9 //============================================================================
10 // Copyright (c) Kitware, Inc.
11 // All rights reserved.
12 // See LICENSE.txt for details.
13 //
14 // This software is distributed WITHOUT ANY WARRANTY; without even
15 // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
16 // PURPOSE. See the above copyright notice for more information.
17 //============================================================================
18 
22 
27 
28 #include <omp.h>
29 
30 namespace viskores
31 {
32 namespace cont
33 {
34 namespace openmp
35 {
36 namespace sort
37 {
38 
39 // Forward declare entry points (See stack overflow discussion 7255281 --
40 // templated overloads of template functions are not specialization, and will
41 // be resolved during the first phase of two part lookup).
42 template <typename T, typename Container, class BinaryCompare>
44 template <typename T, typename StorageT, typename U, typename StorageU, class BinaryCompare>
47  BinaryCompare);
48 
49 // Quicksort values:
50 template <typename HandleType, class BinaryCompare>
51 void parallel_sort(HandleType& values,
52  BinaryCompare binary_compare,
53  viskores::cont::internal::radix::PSortTag)
54 {
56 
57  auto portal = values.PrepareForInPlace(DeviceAdapterTagOpenMP(), token);
59  viskores::Id2 range(0, values.GetNumberOfValues());
60 
61  using IterType = typename std::decay<decltype(iter)>::type;
63 
64  Sorter sorter(iter, binary_compare);
65  sorter.Execute(range);
66 }
67 
68 // Radix sort values:
69 template <typename T, typename StorageT, class BinaryCompare>
71  BinaryCompare binary_compare,
72  viskores::cont::internal::radix::RadixSortTag)
73 {
74  auto c = viskores::cont::internal::radix::get_std_compare(binary_compare, T{});
76  auto valuesPortal = values.PrepareForInPlace(viskores::cont::DeviceAdapterTagOpenMP{}, token);
78  valuesPortal.GetIteratorBegin(), static_cast<std::size_t>(values.GetNumberOfValues()), c);
79 }
80 
81 // Value sort -- static switch between quicksort & radix sort
82 template <typename T, typename Container, class BinaryCompare>
83 void parallel_sort(viskores::cont::ArrayHandle<T, Container>& values, BinaryCompare binary_compare)
84 {
85  using namespace viskores::cont::internal::radix;
86  using SortAlgorithmTag = typename sort_tag_type<T, Container, BinaryCompare>::type;
87 
88  parallel_sort(values, binary_compare, SortAlgorithmTag{});
89 }
90 
91 // Quicksort by key:
92 template <typename T, typename StorageT, typename U, typename StorageU, class BinaryCompare>
95  BinaryCompare binary_compare,
96  viskores::cont::internal::radix::PSortTag)
97 {
99  constexpr bool larger_than_64bits = sizeof(U) > sizeof(viskores::Int64);
100  if (larger_than_64bits)
101  {
104 
108 
109  IndexType indexArray;
110  ValueType valuesScattered;
111  const viskores::Id size = values.GetNumberOfValues();
112 
113  // Generate an in-memory index array:
114  {
115  viskores::cont::Token token;
116  auto handle = ArrayHandleIndex(keys.GetNumberOfValues());
117  auto inputPortal = handle.PrepareForInput(DeviceAdapterTagOpenMP(), token);
118  auto outputPortal =
119  indexArray.PrepareForOutput(keys.GetNumberOfValues(), DeviceAdapterTagOpenMP(), token);
120  openmp::CopyHelper(inputPortal, outputPortal, 0, 0, keys.GetNumberOfValues());
121  }
122 
123  // Sort the keys and indices:
124  ZipHandleType zipHandle = viskores::cont::make_ArrayHandleZip(keys, indexArray);
126  zipHandle,
127  viskores::cont::internal::KeyCompare<T, viskores::Id, BinaryCompare>(binary_compare),
128  viskores::cont::internal::radix::PSortTag());
129 
130  // Permute the values to their sorted locations:
131  {
132  viskores::cont::Token token;
133  auto valuesInPortal = values.PrepareForInput(DeviceAdapterTagOpenMP(), token);
134  auto indexPortal = indexArray.PrepareForInput(DeviceAdapterTagOpenMP(), token);
135  auto valuesOutPortal =
136  valuesScattered.PrepareForOutput(size, DeviceAdapterTagOpenMP(), token);
137 
138  VISKORES_OPENMP_DIRECTIVE(parallel for
139  default(none)
140  firstprivate(valuesInPortal, indexPortal, valuesOutPortal)
141  schedule(static)
143  for (viskores::Id i = 0; i < size; ++i)
144  {
145  valuesOutPortal.Set(i, valuesInPortal.Get(indexPortal.Get(i)));
146  }
147  }
148 
149  // Copy the values back into the input array:
150  {
151  viskores::cont::Token token;
152  auto inputPortal = valuesScattered.PrepareForInput(DeviceAdapterTagOpenMP(), token);
153  auto outputPortal = values.PrepareForOutput(
154  valuesScattered.GetNumberOfValues(), DeviceAdapterTagOpenMP(), token);
155  openmp::CopyHelper(inputPortal, outputPortal, 0, 0, size);
156  }
157  }
158  else
159  {
162 
163  ZipHandleType zipHandle = viskores::cont::make_ArrayHandleZip(keys, values);
164  parallel_sort(zipHandle,
165  viskores::cont::internal::KeyCompare<T, U, BinaryCompare>(binary_compare),
166  viskores::cont::internal::radix::PSortTag{});
167  }
168 }
169 
170 // Radix sort by key:
171 template <typename T, typename StorageT, typename StorageU, class BinaryCompare>
174  BinaryCompare binary_compare,
175  viskores::cont::internal::radix::RadixSortTag)
176 {
177  using namespace viskores::cont::internal::radix;
178  auto c = get_std_compare(binary_compare, T{});
179  viskores::cont::Token token;
180  auto keysPortal = keys.PrepareForInPlace(viskores::cont::DeviceAdapterTagOpenMP{}, token);
181  auto valuesPortal = values.PrepareForInPlace(viskores::cont::DeviceAdapterTagOpenMP{}, token);
182  radix::parallel_radix_sort_key_values(keysPortal.GetIteratorBegin(),
183  valuesPortal.GetIteratorBegin(),
184  static_cast<std::size_t>(keys.GetNumberOfValues()),
185  c);
186 }
187 template <typename T, typename StorageT, typename U, typename StorageU, class BinaryCompare>
190  BinaryCompare binary_compare,
191  viskores::cont::internal::radix::RadixSortTag)
192 {
197 
198  IndexType indexArray;
199  ValueType valuesScattered;
200  const viskores::Id size = values.GetNumberOfValues();
201 
202  {
203  viskores::cont::Token token;
204  auto handle = ArrayHandleIndex(keys.GetNumberOfValues());
205  auto inputPortal = handle.PrepareForInput(DeviceAdapterTagOpenMP(), token);
206  auto outputPortal =
207  indexArray.PrepareForOutput(keys.GetNumberOfValues(), DeviceAdapterTagOpenMP(), token);
208  openmp::CopyHelper(inputPortal, outputPortal, 0, 0, keys.GetNumberOfValues());
209  }
210 
211  const viskores::Id valuesBytes = static_cast<viskores::Id>(sizeof(T)) * keys.GetNumberOfValues();
212  if (valuesBytes >
213  static_cast<viskores::Id>(viskores::cont::internal::radix::MIN_BYTES_FOR_PARALLEL))
214  {
215  parallel_sort_bykey(keys, indexArray, binary_compare);
216  }
217  else
218  {
219  ZipHandleType zipHandle = viskores::cont::make_ArrayHandleZip(keys, indexArray);
221  zipHandle,
222  viskores::cont::internal::KeyCompare<T, viskores::Id, BinaryCompare>(binary_compare),
223  viskores::cont::internal::radix::PSortTag());
224  }
225 
226  // Permute the values to their sorted locations:
227  {
228  viskores::cont::Token token;
229  auto valuesInPortal = values.PrepareForInput(DeviceAdapterTagOpenMP(), token);
230  auto indexPortal = indexArray.PrepareForInput(DeviceAdapterTagOpenMP(), token);
231  auto valuesOutPortal = valuesScattered.PrepareForOutput(size, DeviceAdapterTagOpenMP(), token);
232 
233  VISKORES_OPENMP_DIRECTIVE(parallel for
234  default(none)
235  firstprivate(valuesInPortal, indexPortal, valuesOutPortal)
237  schedule(static))
238  for (viskores::Id i = 0; i < size; ++i)
239  {
240  valuesOutPortal.Set(i, valuesInPortal.Get(indexPortal.Get(i)));
241  }
242  }
243 
244  {
245  viskores::cont::Token token;
246  auto inputPortal = valuesScattered.PrepareForInput(DeviceAdapterTagOpenMP(), token);
247  auto outputPortal =
248  values.PrepareForOutput(valuesScattered.GetNumberOfValues(), DeviceAdapterTagOpenMP(), token);
249  openmp::CopyHelper(inputPortal, outputPortal, 0, 0, valuesScattered.GetNumberOfValues());
250  }
251 }
252 
253 // Sort by key -- static switch between radix and quick sort:
254 template <typename T, typename StorageT, typename U, typename StorageU, class BinaryCompare>
257  BinaryCompare binary_compare)
258 {
259  using namespace viskores::cont::internal::radix;
260  using SortAlgorithmTag =
261  typename sortbykey_tag_type<T, U, StorageT, StorageU, BinaryCompare>::type;
262  parallel_sort_bykey(keys, values, binary_compare, SortAlgorithmTag{});
263 }
264 }
265 }
266 }
267 } // end namespace viskores::cont::openmp::sort
ParallelRadixSortOpenMP.h
ParallelQuickSortOpenMP.h
ArrayHandle.h
viskores::cont::openmp::sort::parallel_sort_bykey
void parallel_sort_bykey(viskores::cont::ArrayHandle< T, StorageT > &, viskores::cont::ArrayHandle< U, StorageU > &, BinaryCompare)
Definition: ParallelSortOpenMP.h:255
viskores::cont::ArrayHandle::PrepareForInput
ReadPortalType PrepareForInput(viskores::cont::DeviceAdapterId device, viskores::cont::Token &token) const
Prepares this array to be used as an input to an operation in the execution environment.
Definition: ArrayHandle.h:615
viskores::cont::make_ArrayHandleZip
viskores::cont::ArrayHandleZip< FirstHandleType, SecondHandleType > make_ArrayHandleZip(const FirstHandleType &first, const SecondHandleType &second)
A convenience function for creating an ArrayHandleZip.
Definition: ArrayHandleZip.h:300
viskores::cont::ArrayHandle
Manages an array-worth of data.
Definition: ArrayHandle.h:313
FunctorsOpenMP.h
VISKORES_OPENMP_DIRECTIVE
#define VISKORES_OPENMP_DIRECTIVE(directive)
Definition: FunctorsOpenMP.h:45
viskores::cont::ArrayHandleZip
ArrayHandleZip is a specialization of ArrayHandle.
Definition: ArrayHandleZip.h:263
viskores::cont::DeviceAdapterTagOpenMP
Tag for a device adapter that uses OpenMP compiler extensions to run algorithms on multiple threads.
Definition: DeviceAdapterTagOpenMP.h:35
ArrayHandleZip.h
viskores::Int64
signed long long Int64
Base type to use for 64-bit signed integer numbers.
Definition: Types.h:212
viskores::cont::openmp::sort::radix::parallel_radix_sort
void parallel_radix_sort(short int *data, size_t num_elems, const std::greater< short int > &comp)
viskores::Id
viskores::Int64 Id
Base type to use to index arrays.
Definition: Types.h:235
viskores::cont::openmp::sort::parallel_sort
void parallel_sort(viskores::cont::ArrayHandle< T, Container > &, BinaryCompare)
Definition: ParallelSortOpenMP.h:83
viskores
Groups connected points that have the same field value.
Definition: Atomic.h:27
viskores::cont::ArrayHandle::PrepareForInPlace
WritePortalType PrepareForInPlace(viskores::cont::DeviceAdapterId device, viskores::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:634
ArrayHandleIndex.h
viskores::cont::ArrayPortalToIteratorBegin
viskores::cont::ArrayPortalToIterators< PortalType >::IteratorType ArrayPortalToIteratorBegin(const PortalType &portal)
Convenience function for converting an ArrayPortal to a begin iterator.
Definition: ArrayPortalToIterators.h:189
viskores::cont::ArrayHandle::GetNumberOfValues
viskores::Id GetNumberOfValues() const
Returns the number of entries in the array.
Definition: ArrayHandle.h:482
viskores::cont::openmp::sort::quick::QuickSorter
Definition: ParallelQuickSortOpenMP.h:43
viskores::cont::ArrayHandle::PrepareForOutput
WritePortalType PrepareForOutput(viskores::Id numberOfValues, viskores::cont::DeviceAdapterId device, viskores::cont::Token &token) const
Prepares (allocates) this array to be used as an output from an operation in the execution environmen...
Definition: ArrayHandle.h:654
viskores::cont::openmp::sort::radix::parallel_radix_sort_key_values
VISKORES_CONT_EXPORT void parallel_radix_sort_key_values(short int *keys, viskores::Id *vals, size_t num_elems, const std::greater< short int > &comp)
BinaryPredicates.h
viskores::Vec< viskores::Id, 2 >
viskores::cont::Token
A token to hold the scope of an ArrayHandle or other object.
Definition: Token.h:43
viskores::cont::ArrayHandleIndex
An implicit array handle containing the its own indices.
Definition: ArrayHandleIndex.h:64
VISKORES_OPENMP_SHARED_CONST
#define VISKORES_OPENMP_SHARED_CONST(...)
Definition: FunctorsOpenMP.h:57