00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039 #ifndef _GLIBCXX_PARALLEL_PARTITION_H
00040 #define _GLIBCXX_PARALLEL_PARTITION_H 1
00041
00042 #include <parallel/basic_iterator.h>
00043 #include <parallel/sort.h>
00044 #include <parallel/random_number.h>
00045 #include <bits/stl_algo.h>
00046 #include <parallel/parallel.h>
00047
00048
00049 #define _GLIBCXX_VOLATILE volatile
00050
00051 namespace __gnu_parallel
00052 {
00053
00054
00055
00056
00057
00058
00059 template<typename RandomAccessIterator, typename Predicate>
00060 typename std::iterator_traits<RandomAccessIterator>::difference_type
00061 parallel_partition(RandomAccessIterator begin, RandomAccessIterator end,
00062 Predicate pred, thread_index_t num_threads)
00063 {
00064 typedef std::iterator_traits<RandomAccessIterator> traits_type;
00065 typedef typename traits_type::value_type value_type;
00066 typedef typename traits_type::difference_type difference_type;
00067
00068 difference_type n = end - begin;
00069
00070 _GLIBCXX_CALL(n)
00071
00072 const _Settings& __s = _Settings::get();
00073
00074
00075 _GLIBCXX_VOLATILE difference_type left = 0, right = n - 1;
00076 _GLIBCXX_VOLATILE difference_type leftover_left, leftover_right;
00077 _GLIBCXX_VOLATILE difference_type leftnew, rightnew;
00078
00079 bool* reserved_left = NULL, * reserved_right = NULL;
00080
00081 difference_type chunk_size;
00082
00083 omp_lock_t result_lock;
00084 omp_init_lock(&result_lock);
00085
00086
00087 if(right - left + 1 >= 2 * num_threads * chunk_size)
00088 # pragma omp parallel num_threads(num_threads)
00089 {
00090 # pragma omp single
00091 {
00092 num_threads = omp_get_num_threads();
00093 reserved_left = new bool[num_threads];
00094 reserved_right = new bool[num_threads];
00095
00096 if (__s.partition_chunk_share > 0.0)
00097 chunk_size = std::max<difference_type>(__s.partition_chunk_size,
00098 (double)n * __s.partition_chunk_share
00099 / (double)num_threads);
00100 else
00101 chunk_size = __s.partition_chunk_size;
00102 }
00103
00104 while (right - left + 1 >= 2 * num_threads * chunk_size)
00105 {
00106 # pragma omp single
00107 {
00108 difference_type num_chunks = (right - left + 1) / chunk_size;
00109
00110 for (int r = 0; r < num_threads; ++r)
00111 {
00112 reserved_left[r] = false;
00113 reserved_right[r] = false;
00114 }
00115 leftover_left = 0;
00116 leftover_right = 0;
00117 }
00118
00119
00120 difference_type thread_left, thread_left_border,
00121 thread_right, thread_right_border;
00122 thread_left = left + 1;
00123
00124
00125 thread_left_border = thread_left - 1;
00126 thread_right = n - 1;
00127 thread_right_border = thread_right + 1;
00128
00129 bool iam_finished = false;
00130 while (!iam_finished)
00131 {
00132 if (thread_left > thread_left_border)
00133 {
00134 omp_set_lock(&result_lock);
00135 if (left + (chunk_size - 1) > right)
00136 iam_finished = true;
00137 else
00138 {
00139 thread_left = left;
00140 thread_left_border = left + (chunk_size - 1);
00141 left += chunk_size;
00142 }
00143 omp_unset_lock(&result_lock);
00144 }
00145
00146 if (thread_right < thread_right_border)
00147 {
00148 omp_set_lock(&result_lock);
00149 if (left > right - (chunk_size - 1))
00150 iam_finished = true;
00151 else
00152 {
00153 thread_right = right;
00154 thread_right_border = right - (chunk_size - 1);
00155 right -= chunk_size;
00156 }
00157 omp_unset_lock(&result_lock);
00158 }
00159
00160 if (iam_finished)
00161 break;
00162
00163
00164 while (thread_left < thread_right)
00165 {
00166 while (pred(begin[thread_left])
00167 && thread_left <= thread_left_border)
00168 ++thread_left;
00169 while (!pred(begin[thread_right])
00170 && thread_right >= thread_right_border)
00171 --thread_right;
00172
00173 if (thread_left > thread_left_border
00174 || thread_right < thread_right_border)
00175
00176 break;
00177
00178 std::swap(begin[thread_left], begin[thread_right]);
00179 ++thread_left;
00180 --thread_right;
00181 }
00182 }
00183
00184
00185 if (thread_left <= thread_left_border)
00186 # pragma omp atomic
00187 ++leftover_left;
00188 if (thread_right >= thread_right_border)
00189 # pragma omp atomic
00190 ++leftover_right;
00191
00192 # pragma omp barrier
00193
00194 # pragma omp single
00195 {
00196 leftnew = left - leftover_left * chunk_size;
00197 rightnew = right + leftover_right * chunk_size;
00198 }
00199
00200 # pragma omp barrier
00201
00202
00203 if (thread_left <= thread_left_border
00204 && thread_left_border >= leftnew)
00205 {
00206
00207 reserved_left[(left - (thread_left_border + 1)) / chunk_size]
00208 = true;
00209 }
00210
00211
00212 if (thread_right >= thread_right_border
00213 && thread_right_border <= rightnew)
00214 {
00215
00216 reserved_right[((thread_right_border - 1) - right)
00217 / chunk_size] = true;
00218 }
00219
00220 # pragma omp barrier
00221
00222 if (thread_left <= thread_left_border
00223 && thread_left_border < leftnew)
00224 {
00225
00226 difference_type swapstart = -1;
00227 omp_set_lock(&result_lock);
00228 for (int r = 0; r < leftover_left; ++r)
00229 if (!reserved_left[r])
00230 {
00231 reserved_left[r] = true;
00232 swapstart = left - (r + 1) * chunk_size;
00233 break;
00234 }
00235 omp_unset_lock(&result_lock);
00236
00237 #if _GLIBCXX_ASSERTIONS
00238 _GLIBCXX_PARALLEL_ASSERT(swapstart != -1);
00239 #endif
00240
00241 std::swap_ranges(begin + thread_left_border
00242 - (chunk_size - 1),
00243 begin + thread_left_border + 1,
00244 begin + swapstart);
00245 }
00246
00247 if (thread_right >= thread_right_border
00248 && thread_right_border > rightnew)
00249 {
00250
00251 difference_type swapstart = -1;
00252 omp_set_lock(&result_lock);
00253 for (int r = 0; r < leftover_right; ++r)
00254 if (!reserved_right[r])
00255 {
00256 reserved_right[r] = true;
00257 swapstart = right + r * chunk_size + 1;
00258 break;
00259 }
00260 omp_unset_lock(&result_lock);
00261
00262 #if _GLIBCXX_ASSERTIONS
00263 _GLIBCXX_PARALLEL_ASSERT(swapstart != -1);
00264 #endif
00265
00266 std::swap_ranges(begin + thread_right_border,
00267 begin + thread_right_border + chunk_size,
00268 begin + swapstart);
00269 }
00270 #if _GLIBCXX_ASSERTIONS
00271 # pragma omp barrier
00272
00273 # pragma omp single
00274 {
00275 for (int r = 0; r < leftover_left; ++r)
00276 _GLIBCXX_PARALLEL_ASSERT(reserved_left[r]);
00277 for (int r = 0; r < leftover_right; ++r)
00278 _GLIBCXX_PARALLEL_ASSERT(reserved_right[r]);
00279 }
00280
00281 # pragma omp barrier
00282 #endif
00283
00284 # pragma omp barrier
00285
00286 left = leftnew;
00287 right = rightnew;
00288 }
00289 # pragma omp flush(left, right)
00290 }
00291
00292 difference_type final_left = left, final_right = right;
00293
00294 while (final_left < final_right)
00295 {
00296
00297 while (pred(begin[final_left]) && final_left < final_right)
00298 ++final_left;
00299
00300
00301 while (!pred(begin[final_right]) && final_left < final_right)
00302 --final_right;
00303
00304 if (final_left == final_right)
00305 break;
00306 std::swap(begin[final_left], begin[final_right]);
00307 ++final_left;
00308 --final_right;
00309 }
00310
00311
00312
00313 delete[] reserved_left;
00314 delete[] reserved_right;
00315
00316 omp_destroy_lock(&result_lock);
00317
00318
00319
00320 if (final_left < n && !pred(begin[final_left]))
00321
00322 return final_left;
00323 else
00324 return final_left + 1;
00325 }
00326
00327
00328
00329
00330
00331
00332
00333
00334 template<typename RandomAccessIterator, typename Comparator>
00335 void
00336 parallel_nth_element(RandomAccessIterator begin, RandomAccessIterator nth,
00337 RandomAccessIterator end, Comparator comp)
00338 {
00339 typedef std::iterator_traits<RandomAccessIterator> traits_type;
00340 typedef typename traits_type::value_type value_type;
00341 typedef typename traits_type::difference_type difference_type;
00342
00343 _GLIBCXX_CALL(end - begin)
00344
00345 RandomAccessIterator split;
00346 random_number rng;
00347
00348 difference_type minimum_length =
00349 std::max<difference_type>(2, _Settings::get().partition_minimal_n);
00350
00351
00352 while (static_cast<sequence_index_t>(end - begin) >= minimum_length)
00353 {
00354 difference_type n = end - begin;
00355
00356 RandomAccessIterator pivot_pos = begin + rng(n);
00357
00358
00359 if (pivot_pos != (end - 1))
00360 std::swap(*pivot_pos, *(end - 1));
00361 pivot_pos = end - 1;
00362
00363
00364
00365
00366
00367
00368
00369 __gnu_parallel::binder2nd<Comparator, value_type, value_type, bool>
00370 pred(comp, *pivot_pos);
00371
00372
00373 RandomAccessIterator split_pos1, split_pos2;
00374 split_pos1 = begin + parallel_partition(begin, end - 1, pred,
00375 get_max_threads());
00376
00377
00378
00379
00380 if (split_pos1 != pivot_pos)
00381 std::swap(*split_pos1, *pivot_pos);
00382 pivot_pos = split_pos1;
00383
00384
00385 if ((split_pos1 + 1 - begin) < (n >> 7)
00386 || (end - split_pos1) < (n >> 7))
00387 {
00388
00389
00390 __gnu_parallel::unary_negate<__gnu_parallel::
00391 binder1st<Comparator, value_type, value_type, bool>, value_type>
00392 pred(__gnu_parallel::binder1st<Comparator, value_type,
00393 value_type, bool>(comp, *pivot_pos));
00394
00395
00396 split_pos2 = __gnu_sequential::partition(split_pos1 + 1,
00397 end, pred);
00398 }
00399 else
00400
00401 split_pos2 = split_pos1 + 1;
00402
00403
00404 if (split_pos2 <= nth)
00405 begin = split_pos2;
00406 else if (nth < split_pos1)
00407 end = split_pos1;
00408 else
00409 break;
00410 }
00411
00412
00413 __gnu_sequential::sort(begin, end, comp);
00414 }
00415
00416
00417
00418
00419
00420
00421 template<typename RandomAccessIterator, typename Comparator>
00422 void
00423 parallel_partial_sort(RandomAccessIterator begin,
00424 RandomAccessIterator middle,
00425 RandomAccessIterator end, Comparator comp)
00426 {
00427 parallel_nth_element(begin, middle, end, comp);
00428 std::sort(begin, middle, comp);
00429 }
00430
00431 }
00432
00433 #undef _GLIBCXX_VOLATILE
00434
00435 #endif