OpenFPM_pdata  4.1.0
Project that contain the implementation of distributed structures
sort_ofp.cuh
1 /*
2  * sort_ofp.cuh
3  *
4  * Created on: Aug 23, 2019
5  * Author: i-bird
6  */
7 
8 #ifndef SORT_OFP_CUH_
9 #define SORT_OFP_CUH_
10 
11 
12 #ifdef __NVCC__
13 
14 #include "util/cuda_launch.hpp"
15 
16 #if CUDART_VERSION >= 11000
17  #ifndef CUDA_ON_CPU
18  // Here we have for sure CUDA >= 11
19  #ifdef __HIP__
20  #include "hipcub/hipcub.hpp"
21  #else
22  #include "cub/cub.cuh"
23  #endif
24  #ifndef SORT_WITH_CUB
25  #define SORT_WITH_CUB
26  #endif
27  #endif
28 #else
29  // Here we have old CUDA
30  #include "cub_old/cub.cuh"
31  #include "util/cuda/moderngpu/kernel_mergesort.hxx"
32 #endif
33 
34 #include "util/cuda/ofp_context.hxx"
35 
36 template<typename key_t, typename val_t>
37 struct key_val_ref;
38 
39 template<typename key_t, typename val_t>
40 struct key_val
41 {
42  key_t key;
43  val_t val;
44 
45  key_val(const key_t & k, const val_t & v)
46  :key(k),val(v)
47  {}
48 
49  key_val(const key_val_ref<key_t,val_t> & tmp)
50  {
51  this->operator=(tmp);
52  }
53 
54  bool operator<(const key_val & tmp) const
55  {
56  return key < tmp.key;
57  }
58 
59  bool operator>(const key_val & tmp) const
60  {
61  return key > tmp.key;
62  }
63 
64  key_val & operator=(const key_val_ref<key_t,val_t> & tmp)
65  {
66  key = tmp.key;
67  val = tmp.val;
68 
69  return *this;
70  }
71 };
72 
73 
74 template<typename key_t, typename val_t>
75 struct key_val_ref
76 {
77  key_t & key;
78  val_t & val;
79 
80  key_val_ref(key_t & k, val_t & v)
81  :key(k),val(v)
82  {}
83 
84  key_val_ref(key_val_ref<key_t,val_t> && tmp)
85  :key(tmp.key),val(tmp.val)
86  {}
87 
88  key_val_ref & operator=(const key_val<key_t,val_t> & tmp)
89  {
90  key = tmp.key;
91  val = tmp.val;
92 
93  return *this;
94  }
95 
96  key_val_ref & operator=(const key_val_ref<key_t,val_t> & tmp)
97  {
98  key = tmp.key;
99  val = tmp.val;
100 
101  return *this;
102  }
103 
104  bool operator<(const key_val_ref<key_t,val_t> & tmp)
105  {
106  return key < tmp.key;
107  }
108 
109  bool operator>(const key_val_ref<key_t,val_t> & tmp)
110  {
111  return key > tmp.key;
112  }
113 
114  bool operator<(const key_val<key_t,val_t> & tmp)
115  {
116  return key < tmp.key;
117  }
118 
119  bool operator>(const key_val<key_t,val_t> & tmp)
120  {
121  return key > tmp.key;
122  }
123 };
124 
125 
126 template<typename key_t, typename val_t>
127 struct key_val_it
128 {
129  key_t * key;
130  val_t * val;
131 
132 
133  key_val_it & operator+=(int delta)
134  {
135  key += delta;
136  val += delta;
137  return *this;
138  }
139 
140  bool operator==(const key_val_it & tmp)
141  {
142  return (key == tmp.key && val == tmp.val);
143  }
144 
145  key_val_ref<key_t,val_t> operator*()
146  {
147  return key_val_ref<key_t,val_t>(*key,*val);
148  }
149 
150  key_val_ref<key_t,val_t> operator[](int i)
151  {
152  return key_val_ref<key_t,val_t>(*key,*val);
153  }
154 
155  key_val_it operator+(size_t count) const
156  {
157  key_val_it tmp(key+count,val+count);
158 
159  return tmp;
160  }
161 
162 
163  size_t operator-(key_val_it & tmp) const
164  {
165  return key - tmp.key;
166  }
167 
168  key_val_it operator-(size_t count) const
169  {
170  key_val_it tmp(key-count,val-count);
171 
172  return tmp;
173  }
174 
175  key_val_it & operator++()
176  {
177  ++key;
178  ++val;
179 
180  return *this;
181  }
182 
183  key_val_it operator++(int)
184  {
185  key_val_it temp = *this;
186  ++*this;
187  return temp;
188  }
189 
190  key_val_it & operator--()
191  {
192  --key;
193  --val;
194 
195  return *this;
196  }
197 
198  bool operator!=(const key_val_it & tmp) const
199  {
200  return key != tmp.key && val != tmp.val;
201  }
202 
203  bool operator<(const key_val_it & tmp) const
204  {
205  return key < tmp.key;
206  }
207 
208  bool operator>(const key_val_it & tmp) const
209  {
210  return key > tmp.key;
211  }
212 
213  bool operator>=(const key_val_it & tmp) const
214  {
215  return key >= tmp.key;
216  }
217 
218  key_val_it<key_t,val_t> & operator=(key_val_it<key_t,val_t> & tmp)
219  {
220  key = tmp.key;
221  val = tmp.val;
222 
223  return *this;
224  }
225 
226  key_val_it() {}
227 
228  key_val_it(const key_val_it<key_t,val_t> & tmp)
229  :key(tmp.key),val(tmp.val)
230  {}
231 
232  key_val_it(key_t * key, val_t * val)
233  :key(key),val(val)
234  {}
235 };
236 
237 template<typename key_t, typename val_t>
238 void swap(key_val_ref<key_t,val_t> a, key_val_ref<key_t,val_t> b)
239 {
240  key_t kt = a.key;
241  a.key = b.key;
242  b.key = kt;
243 
244  val_t vt = a.val;
245  a.val = b.val;
246  b.val = vt;
247 }
248 
249 namespace std
250 {
251  template<typename key_t, typename val_t>
252  struct iterator_traits<key_val_it<key_t,val_t>>
253  {
254  typedef size_t difference_type; //almost always ptrdiff_t
255  typedef key_val<key_t,val_t> value_type; //almost always T
256  typedef key_val<key_t,val_t> & reference; //almost always T& or const T&
257  typedef key_val<key_t,val_t> & pointer; //almost always T* or const T*
258  typedef std::random_access_iterator_tag iterator_category; //usually std::forward_iterator_tag or similar
259  };
260 }
261 
262 
263 namespace openfpm
264 {
265  template<typename key_t, typename val_t,
266  typename comp_t>
267  void sort(key_t* keys_input, val_t* vals_input, int count,
268  comp_t comp, mgpu::ofp_context_t& context)
269  {
270 #ifdef CUDA_ON_CPU
271 
272  key_val_it<key_t,val_t> kv(keys_input,vals_input);
273 
274  std::sort(kv,kv+count,comp);
275 
276 #else
277 
278  #ifdef SORT_WITH_CUB
279 
280  #ifdef __HIP__
281 
282  void *d_temp_storage = NULL;
283  size_t temp_storage_bytes = 0;
284 
285  auto & temporal2 = context.getTemporalCUB2();
286  temporal2.resize(sizeof(key_t)*count);
287 
288  auto & temporal3 = context.getTemporalCUB3();
289  temporal3.resize(sizeof(val_t)*count);
290 
291  if (std::is_same<mgpu::template less_t<key_t>,comp_t>::value == true)
292  {
293  hipcub::DeviceRadixSort::SortPairs(d_temp_storage,
294  temp_storage_bytes,
295  keys_input,
296  (key_t *)temporal2.template getDeviceBuffer<0>(),
297  vals_input,
298  (val_t *)temporal3.template getDeviceBuffer<0>(),
299  count);
300 
301  auto & temporal = context.getTemporalCUB();
302  temporal.resize(temp_storage_bytes);
303 
304  d_temp_storage = temporal.template getDeviceBuffer<0>();
305 
306  // Run
307  hipcub::DeviceRadixSort::SortPairs(d_temp_storage,
308  temp_storage_bytes,
309  keys_input,
310  (key_t *)temporal2.template getDeviceBuffer<0>(),
311  vals_input,
312  (val_t *)temporal3.template getDeviceBuffer<0>(),
313  count);
314  }
315  else if (std::is_same<mgpu::template greater_t<key_t>,comp_t>::value == true)
316  {
317  hipcub::DeviceRadixSort::SortPairsDescending(d_temp_storage,
318  temp_storage_bytes,
319  keys_input,
320  (key_t *)temporal2.template getDeviceBuffer<0>(),
321  vals_input,
322  (val_t *)temporal3.template getDeviceBuffer<0>(),
323  count);
324 
325  auto & temporal = context.getTemporalCUB();
326  temporal.resize(temp_storage_bytes);
327 
328  d_temp_storage = temporal.template getDeviceBuffer<0>();
329 
330  // Run
331  hipcub::DeviceRadixSort::SortPairsDescending(d_temp_storage,
332  temp_storage_bytes,
333  keys_input,
334  (key_t *)temporal2.template getDeviceBuffer<0>(),
335  vals_input,
336  (val_t *)temporal3.template getDeviceBuffer<0>(),
337  count);
338  }
339 
340  cudaMemcpy(keys_input,temporal2.getDeviceBuffer<0>(),sizeof(key_t)*count,cudaMemcpyDeviceToDevice);
341  cudaMemcpy(vals_input,temporal3.getDeviceBuffer<0>(),sizeof(val_t)*count,cudaMemcpyDeviceToDevice);
342 
343 
344  #else
345 
346  void *d_temp_storage = NULL;
347  size_t temp_storage_bytes = 0;
348 
349  auto & temporal2 = context.getTemporalCUB2();
350  temporal2.resize(sizeof(key_t)*count);
351 
352  auto & temporal3 = context.getTemporalCUB3();
353  temporal3.resize(sizeof(val_t)*count);
354 
355  if (std::is_same<mgpu::template less_t<key_t>,comp_t>::value == true)
356  {
357  cub::DeviceRadixSort::SortPairs(d_temp_storage,
358  temp_storage_bytes,
359  keys_input,
360  (key_t *)temporal2.template getDeviceBuffer<0>(),
361  vals_input,
362  (val_t *)temporal3.template getDeviceBuffer<0>(),
363  count);
364 
365  auto & temporal = context.getTemporalCUB();
366  temporal.resize(temp_storage_bytes);
367 
368  d_temp_storage = temporal.template getDeviceBuffer<0>();
369 
370  // Run
371  cub::DeviceRadixSort::SortPairs(d_temp_storage,
372  temp_storage_bytes,
373  keys_input,
374  (key_t *)temporal2.template getDeviceBuffer<0>(),
375  vals_input,
376  (val_t *)temporal3.template getDeviceBuffer<0>(),
377  count);
378  }
379  else if (std::is_same<mgpu::template greater_t<key_t>,comp_t>::value == true)
380  {
382  temp_storage_bytes,
383  keys_input,
384  (key_t *)temporal2.template getDeviceBuffer<0>(),
385  vals_input,
386  (val_t *)temporal3.template getDeviceBuffer<0>(),
387  count);
388 
389  auto & temporal = context.getTemporalCUB();
390  temporal.resize(temp_storage_bytes);
391 
392  d_temp_storage = temporal.template getDeviceBuffer<0>();
393 
394  // Run
396  temp_storage_bytes,
397  keys_input,
398  (key_t *)temporal2.template getDeviceBuffer<0>(),
399  vals_input,
400  (val_t *)temporal3.template getDeviceBuffer<0>(),
401  count);
402  }
403 
404  cudaMemcpy(keys_input,temporal2.getDeviceBuffer<0>(),sizeof(key_t)*count,cudaMemcpyDeviceToDevice);
405  cudaMemcpy(vals_input,temporal3.getDeviceBuffer<0>(),sizeof(val_t)*count,cudaMemcpyDeviceToDevice);
406 
407  #endif
408 
409  #else
410  mgpu::mergesort(keys_input,vals_input,count,comp,context);
411  #endif
412 
413 #endif
414  }
415 }
416 
417 #endif
418 
419 
420 #endif /* SORT_OFP_CUH_ */
convert a type into constant type
Definition: aggregate.hpp:292
static CUB_RUNTIME_FUNCTION cudaError_t SortPairsDescending(void *d_temp_storage, size_t &temp_storage_bytes, const KeyT *d_keys_in, KeyT *d_keys_out, const ValueT *d_values_in, ValueT *d_values_out, int num_items, int begin_bit=0, int end_bit=sizeof(KeyT) *8, cudaStream_t stream=0, bool debug_synchronous=false)
Sorts key-value pairs into descending order. (~2N auxiliary storage required).
static CUB_RUNTIME_FUNCTION cudaError_t SortPairs(void *d_temp_storage, size_t &temp_storage_bytes, const KeyT *d_keys_in, KeyT *d_keys_out, const ValueT *d_values_in, ValueT *d_values_out, int num_items, int begin_bit=0, int end_bit=sizeof(KeyT) *8, cudaStream_t stream=0, bool debug_synchronous=false)
Sorts key-value pairs into ascending order. (~2N auxiliary storage required)