1*38fd1498Szrj // -*- C++ -*- 2*38fd1498Szrj 3*38fd1498Szrj // Copyright (C) 2007-2018 Free Software Foundation, Inc. 4*38fd1498Szrj // 5*38fd1498Szrj // This file is part of the GNU ISO C++ Library. This library is free 6*38fd1498Szrj // software; you can redistribute it and/or modify it under the terms 7*38fd1498Szrj // of the GNU General Public License as published by the Free Software 8*38fd1498Szrj // Foundation; either version 3, or (at your option) any later 9*38fd1498Szrj // version. 10*38fd1498Szrj 11*38fd1498Szrj // This library is distributed in the hope that it will be useful, but 12*38fd1498Szrj // WITHOUT ANY WARRANTY; without even the implied warranty of 13*38fd1498Szrj // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14*38fd1498Szrj // General Public License for more details. 15*38fd1498Szrj 16*38fd1498Szrj // Under Section 7 of GPL version 3, you are granted additional 17*38fd1498Szrj // permissions described in the GCC Runtime Library Exception, version 18*38fd1498Szrj // 3.1, as published by the Free Software Foundation. 19*38fd1498Szrj 20*38fd1498Szrj // You should have received a copy of the GNU General Public License and 21*38fd1498Szrj // a copy of the GCC Runtime Library Exception along with this program; 22*38fd1498Szrj // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23*38fd1498Szrj // <http://www.gnu.org/licenses/>. 24*38fd1498Szrj 25*38fd1498Szrj /** @file parallel/random_shuffle.h 26*38fd1498Szrj * @brief Parallel implementation of std::random_shuffle(). 27*38fd1498Szrj * This file is a GNU parallel extension to the Standard C++ Library. 28*38fd1498Szrj */ 29*38fd1498Szrj 30*38fd1498Szrj // Written by Johannes Singler. 31*38fd1498Szrj 32*38fd1498Szrj #ifndef _GLIBCXX_PARALLEL_RANDOM_SHUFFLE_H 33*38fd1498Szrj #define _GLIBCXX_PARALLEL_RANDOM_SHUFFLE_H 1 34*38fd1498Szrj 35*38fd1498Szrj #include <limits> 36*38fd1498Szrj #include <bits/stl_numeric.h> 37*38fd1498Szrj #include <parallel/parallel.h> 38*38fd1498Szrj #include <parallel/random_number.h> 39*38fd1498Szrj 40*38fd1498Szrj namespace __gnu_parallel 41*38fd1498Szrj { 42*38fd1498Szrj /** @brief Type to hold the index of a bin. 43*38fd1498Szrj * 44*38fd1498Szrj * Since many variables of this type are allocated, it should be 45*38fd1498Szrj * chosen as small as possible. 46*38fd1498Szrj */ 47*38fd1498Szrj typedef unsigned short _BinIndex; 48*38fd1498Szrj 49*38fd1498Szrj /** @brief Data known to every thread participating in 50*38fd1498Szrj __gnu_parallel::__parallel_random_shuffle(). */ 51*38fd1498Szrj template<typename _RAIter> 52*38fd1498Szrj struct _DRandomShufflingGlobalData 53*38fd1498Szrj { 54*38fd1498Szrj typedef std::iterator_traits<_RAIter> _TraitsType; 55*38fd1498Szrj typedef typename _TraitsType::value_type _ValueType; 56*38fd1498Szrj typedef typename _TraitsType::difference_type _DifferenceType; 57*38fd1498Szrj 58*38fd1498Szrj /** @brief Begin iterator of the __source. */ 59*38fd1498Szrj _RAIter& _M_source; 60*38fd1498Szrj 61*38fd1498Szrj /** @brief Temporary arrays for each thread. */ 62*38fd1498Szrj _ValueType** _M_temporaries; 63*38fd1498Szrj 64*38fd1498Szrj /** @brief Two-dimensional array to hold the thread-bin distribution. 65*38fd1498Szrj * 66*38fd1498Szrj * Dimensions (_M_num_threads + 1) __x (_M_num_bins + 1). */ 67*38fd1498Szrj _DifferenceType** _M_dist; 68*38fd1498Szrj 69*38fd1498Szrj /** @brief Start indexes of the threads' __chunks. */ 70*38fd1498Szrj _DifferenceType* _M_starts; 71*38fd1498Szrj 72*38fd1498Szrj /** @brief Number of the thread that will further process the 73*38fd1498Szrj corresponding bin. */ 74*38fd1498Szrj _ThreadIndex* _M_bin_proc; 75*38fd1498Szrj 76*38fd1498Szrj /** @brief Number of bins to distribute to. */ 77*38fd1498Szrj int _M_num_bins; 78*38fd1498Szrj 79*38fd1498Szrj /** @brief Number of bits needed to address the bins. */ 80*38fd1498Szrj int _M_num_bits; 81*38fd1498Szrj 82*38fd1498Szrj /** @brief Constructor. */ _DRandomShufflingGlobalData_DRandomShufflingGlobalData83*38fd1498Szrj _DRandomShufflingGlobalData(_RAIter& __source) 84*38fd1498Szrj : _M_source(__source) { } 85*38fd1498Szrj }; 86*38fd1498Szrj 87*38fd1498Szrj /** @brief Local data for a thread participating in 88*38fd1498Szrj __gnu_parallel::__parallel_random_shuffle(). 89*38fd1498Szrj */ 90*38fd1498Szrj template<typename _RAIter, typename _RandomNumberGenerator> 91*38fd1498Szrj struct _DRSSorterPU 92*38fd1498Szrj { 93*38fd1498Szrj /** @brief Number of threads participating in total. */ 94*38fd1498Szrj int _M_num_threads; 95*38fd1498Szrj 96*38fd1498Szrj /** @brief Begin index for bins taken care of by this thread. */ 97*38fd1498Szrj _BinIndex _M_bins_begin; 98*38fd1498Szrj 99*38fd1498Szrj /** @brief End index for bins taken care of by this thread. */ 100*38fd1498Szrj _BinIndex __bins_end; 101*38fd1498Szrj 102*38fd1498Szrj /** @brief Random _M_seed for this thread. */ 103*38fd1498Szrj uint32_t _M_seed; 104*38fd1498Szrj 105*38fd1498Szrj /** @brief Pointer to global data. */ 106*38fd1498Szrj _DRandomShufflingGlobalData<_RAIter>* _M_sd; 107*38fd1498Szrj }; 108*38fd1498Szrj 109*38fd1498Szrj /** @brief Generate a random number in @c [0,2^__logp). 110*38fd1498Szrj * @param __logp Logarithm (basis 2) of the upper range __bound. 111*38fd1498Szrj * @param __rng Random number generator to use. 112*38fd1498Szrj */ 113*38fd1498Szrj template<typename _RandomNumberGenerator> 114*38fd1498Szrj inline int __random_number_pow2(int __logp,_RandomNumberGenerator & __rng)115*38fd1498Szrj __random_number_pow2(int __logp, _RandomNumberGenerator& __rng) 116*38fd1498Szrj { return __rng.__genrand_bits(__logp); } 117*38fd1498Szrj 118*38fd1498Szrj /** @brief Random shuffle code executed by each thread. 119*38fd1498Szrj * @param __pus Array of thread-local data records. */ 120*38fd1498Szrj template<typename _RAIter, typename _RandomNumberGenerator> 121*38fd1498Szrj void __parallel_random_shuffle_drs_pu(_DRSSorterPU<_RAIter,_RandomNumberGenerator> * __pus)122*38fd1498Szrj __parallel_random_shuffle_drs_pu(_DRSSorterPU<_RAIter, 123*38fd1498Szrj _RandomNumberGenerator>* __pus) 124*38fd1498Szrj { 125*38fd1498Szrj typedef std::iterator_traits<_RAIter> _TraitsType; 126*38fd1498Szrj typedef typename _TraitsType::value_type _ValueType; 127*38fd1498Szrj typedef typename _TraitsType::difference_type _DifferenceType; 128*38fd1498Szrj 129*38fd1498Szrj _ThreadIndex __iam = omp_get_thread_num(); 130*38fd1498Szrj _DRSSorterPU<_RAIter, _RandomNumberGenerator>* __d = &__pus[__iam]; 131*38fd1498Szrj _DRandomShufflingGlobalData<_RAIter>* __sd = __d->_M_sd; 132*38fd1498Szrj 133*38fd1498Szrj // Indexing: _M_dist[bin][processor] 134*38fd1498Szrj _DifferenceType __length = (__sd->_M_starts[__iam + 1] 135*38fd1498Szrj - __sd->_M_starts[__iam]); 136*38fd1498Szrj _BinIndex* __oracles = new _BinIndex[__length]; 137*38fd1498Szrj _DifferenceType* __dist = new _DifferenceType[__sd->_M_num_bins + 1]; 138*38fd1498Szrj _BinIndex* __bin_proc = new _BinIndex[__sd->_M_num_bins]; 139*38fd1498Szrj _ValueType** __temporaries = new _ValueType*[__d->_M_num_threads]; 140*38fd1498Szrj 141*38fd1498Szrj // Compute oracles and count appearances. 142*38fd1498Szrj for (_BinIndex __b = 0; __b < __sd->_M_num_bins + 1; ++__b) 143*38fd1498Szrj __dist[__b] = 0; 144*38fd1498Szrj int __num_bits = __sd->_M_num_bits; 145*38fd1498Szrj 146*38fd1498Szrj _RandomNumber __rng(__d->_M_seed); 147*38fd1498Szrj 148*38fd1498Szrj // First main loop. 149*38fd1498Szrj for (_DifferenceType __i = 0; __i < __length; ++__i) 150*38fd1498Szrj { 151*38fd1498Szrj _BinIndex __oracle = __random_number_pow2(__num_bits, __rng); 152*38fd1498Szrj __oracles[__i] = __oracle; 153*38fd1498Szrj 154*38fd1498Szrj // To allow prefix (partial) sum. 155*38fd1498Szrj ++(__dist[__oracle + 1]); 156*38fd1498Szrj } 157*38fd1498Szrj 158*38fd1498Szrj for (_BinIndex __b = 0; __b < __sd->_M_num_bins + 1; ++__b) 159*38fd1498Szrj __sd->_M_dist[__b][__iam + 1] = __dist[__b]; 160*38fd1498Szrj 161*38fd1498Szrj # pragma omp barrier 162*38fd1498Szrj 163*38fd1498Szrj # pragma omp single 164*38fd1498Szrj { 165*38fd1498Szrj // Sum up bins, __sd->_M_dist[__s + 1][__d->_M_num_threads] now 166*38fd1498Szrj // contains the total number of items in bin __s 167*38fd1498Szrj for (_BinIndex __s = 0; __s < __sd->_M_num_bins; ++__s) 168*38fd1498Szrj __gnu_sequential::partial_sum(__sd->_M_dist[__s + 1], 169*38fd1498Szrj __sd->_M_dist[__s + 1] 170*38fd1498Szrj + __d->_M_num_threads + 1, 171*38fd1498Szrj __sd->_M_dist[__s + 1]); 172*38fd1498Szrj } 173*38fd1498Szrj 174*38fd1498Szrj # pragma omp barrier 175*38fd1498Szrj 176*38fd1498Szrj _SequenceIndex __offset = 0, __global_offset = 0; 177*38fd1498Szrj for (_BinIndex __s = 0; __s < __d->_M_bins_begin; ++__s) 178*38fd1498Szrj __global_offset += __sd->_M_dist[__s + 1][__d->_M_num_threads]; 179*38fd1498Szrj 180*38fd1498Szrj # pragma omp barrier 181*38fd1498Szrj 182*38fd1498Szrj for (_BinIndex __s = __d->_M_bins_begin; __s < __d->__bins_end; ++__s) 183*38fd1498Szrj { 184*38fd1498Szrj for (int __t = 0; __t < __d->_M_num_threads + 1; ++__t) 185*38fd1498Szrj __sd->_M_dist[__s + 1][__t] += __offset; 186*38fd1498Szrj __offset = __sd->_M_dist[__s + 1][__d->_M_num_threads]; 187*38fd1498Szrj } 188*38fd1498Szrj 189*38fd1498Szrj __sd->_M_temporaries[__iam] = static_cast<_ValueType*> 190*38fd1498Szrj (::operator new(sizeof(_ValueType) * __offset)); 191*38fd1498Szrj 192*38fd1498Szrj # pragma omp barrier 193*38fd1498Szrj 194*38fd1498Szrj // Draw local copies to avoid false sharing. 195*38fd1498Szrj for (_BinIndex __b = 0; __b < __sd->_M_num_bins + 1; ++__b) 196*38fd1498Szrj __dist[__b] = __sd->_M_dist[__b][__iam]; 197*38fd1498Szrj for (_BinIndex __b = 0; __b < __sd->_M_num_bins; ++__b) 198*38fd1498Szrj __bin_proc[__b] = __sd->_M_bin_proc[__b]; 199*38fd1498Szrj for (_ThreadIndex __t = 0; __t < __d->_M_num_threads; ++__t) 200*38fd1498Szrj __temporaries[__t] = __sd->_M_temporaries[__t]; 201*38fd1498Szrj 202*38fd1498Szrj _RAIter __source = __sd->_M_source; 203*38fd1498Szrj _DifferenceType __start = __sd->_M_starts[__iam]; 204*38fd1498Szrj 205*38fd1498Szrj // Distribute according to oracles, second main loop. 206*38fd1498Szrj for (_DifferenceType __i = 0; __i < __length; ++__i) 207*38fd1498Szrj { 208*38fd1498Szrj _BinIndex __target_bin = __oracles[__i]; 209*38fd1498Szrj _ThreadIndex __target_p = __bin_proc[__target_bin]; 210*38fd1498Szrj 211*38fd1498Szrj // Last column [__d->_M_num_threads] stays unchanged. 212*38fd1498Szrj ::new(&(__temporaries[__target_p][__dist[__target_bin + 1]++])) 213*38fd1498Szrj _ValueType(*(__source + __i + __start)); 214*38fd1498Szrj } 215*38fd1498Szrj 216*38fd1498Szrj delete[] __oracles; 217*38fd1498Szrj delete[] __dist; 218*38fd1498Szrj delete[] __bin_proc; 219*38fd1498Szrj delete[] __temporaries; 220*38fd1498Szrj 221*38fd1498Szrj # pragma omp barrier 222*38fd1498Szrj 223*38fd1498Szrj // Shuffle bins internally. 224*38fd1498Szrj for (_BinIndex __b = __d->_M_bins_begin; __b < __d->__bins_end; ++__b) 225*38fd1498Szrj { 226*38fd1498Szrj _ValueType* __begin = 227*38fd1498Szrj (__sd->_M_temporaries[__iam] 228*38fd1498Szrj + (__b == __d->_M_bins_begin 229*38fd1498Szrj ? 0 : __sd->_M_dist[__b][__d->_M_num_threads])), 230*38fd1498Szrj *__end = (__sd->_M_temporaries[__iam] 231*38fd1498Szrj + __sd->_M_dist[__b + 1][__d->_M_num_threads]); 232*38fd1498Szrj 233*38fd1498Szrj __sequential_random_shuffle(__begin, __end, __rng); 234*38fd1498Szrj std::copy(__begin, __end, __sd->_M_source + __global_offset 235*38fd1498Szrj + (__b == __d->_M_bins_begin 236*38fd1498Szrj ? 0 : __sd->_M_dist[__b][__d->_M_num_threads])); 237*38fd1498Szrj } 238*38fd1498Szrj 239*38fd1498Szrj for (_SequenceIndex __i = 0; __i < __offset; ++__i) 240*38fd1498Szrj __sd->_M_temporaries[__iam][__i].~_ValueType(); 241*38fd1498Szrj ::operator delete(__sd->_M_temporaries[__iam]); 242*38fd1498Szrj } 243*38fd1498Szrj 244*38fd1498Szrj /** @brief Round up to the next greater power of 2. 245*38fd1498Szrj * @param __x _Integer to round up */ 246*38fd1498Szrj template<typename _Tp> 247*38fd1498Szrj _Tp __round_up_to_pow2(_Tp __x)248*38fd1498Szrj __round_up_to_pow2(_Tp __x) 249*38fd1498Szrj { 250*38fd1498Szrj if (__x <= 1) 251*38fd1498Szrj return 1; 252*38fd1498Szrj else 253*38fd1498Szrj return (_Tp)1 << (__rd_log2(__x - 1) + 1); 254*38fd1498Szrj } 255*38fd1498Szrj 256*38fd1498Szrj /** @brief Main parallel random shuffle step. 257*38fd1498Szrj * @param __begin Begin iterator of sequence. 258*38fd1498Szrj * @param __end End iterator of sequence. 259*38fd1498Szrj * @param __n Length of sequence. 260*38fd1498Szrj * @param __num_threads Number of threads to use. 261*38fd1498Szrj * @param __rng Random number generator to use. 262*38fd1498Szrj */ 263*38fd1498Szrj template<typename _RAIter, typename _RandomNumberGenerator> 264*38fd1498Szrj void __parallel_random_shuffle_drs(_RAIter __begin,_RAIter __end,typename std::iterator_traits<_RAIter>::difference_type __n,_ThreadIndex __num_threads,_RandomNumberGenerator & __rng)265*38fd1498Szrj __parallel_random_shuffle_drs(_RAIter __begin, _RAIter __end, 266*38fd1498Szrj typename std::iterator_traits 267*38fd1498Szrj <_RAIter>::difference_type __n, 268*38fd1498Szrj _ThreadIndex __num_threads, 269*38fd1498Szrj _RandomNumberGenerator& __rng) 270*38fd1498Szrj { 271*38fd1498Szrj typedef std::iterator_traits<_RAIter> _TraitsType; 272*38fd1498Szrj typedef typename _TraitsType::value_type _ValueType; 273*38fd1498Szrj typedef typename _TraitsType::difference_type _DifferenceType; 274*38fd1498Szrj 275*38fd1498Szrj _GLIBCXX_CALL(__n) 276*38fd1498Szrj 277*38fd1498Szrj const _Settings& __s = _Settings::get(); 278*38fd1498Szrj 279*38fd1498Szrj if (__num_threads > __n) 280*38fd1498Szrj __num_threads = static_cast<_ThreadIndex>(__n); 281*38fd1498Szrj 282*38fd1498Szrj _BinIndex __num_bins, __num_bins_cache; 283*38fd1498Szrj 284*38fd1498Szrj #if _GLIBCXX_RANDOM_SHUFFLE_CONSIDER_L1 285*38fd1498Szrj // Try the L1 cache first. 286*38fd1498Szrj 287*38fd1498Szrj // Must fit into L1. 288*38fd1498Szrj __num_bins_cache = 289*38fd1498Szrj std::max<_DifferenceType>(1, __n / (__s.L1_cache_size_lb 290*38fd1498Szrj / sizeof(_ValueType))); 291*38fd1498Szrj __num_bins_cache = __round_up_to_pow2(__num_bins_cache); 292*38fd1498Szrj 293*38fd1498Szrj // No more buckets than TLB entries, power of 2 294*38fd1498Szrj // Power of 2 and at least one element per bin, at most the TLB size. 295*38fd1498Szrj __num_bins = std::min<_DifferenceType>(__n, __num_bins_cache); 296*38fd1498Szrj 297*38fd1498Szrj #if _GLIBCXX_RANDOM_SHUFFLE_CONSIDER_TLB 298*38fd1498Szrj // 2 TLB entries needed per bin. 299*38fd1498Szrj __num_bins = std::min<_DifferenceType>(__s.TLB_size / 2, __num_bins); 300*38fd1498Szrj #endif 301*38fd1498Szrj __num_bins = __round_up_to_pow2(__num_bins); 302*38fd1498Szrj 303*38fd1498Szrj if (__num_bins < __num_bins_cache) 304*38fd1498Szrj { 305*38fd1498Szrj #endif 306*38fd1498Szrj // Now try the L2 cache 307*38fd1498Szrj // Must fit into L2 308*38fd1498Szrj __num_bins_cache = static_cast<_BinIndex> 309*38fd1498Szrj (std::max<_DifferenceType>(1, __n / (__s.L2_cache_size 310*38fd1498Szrj / sizeof(_ValueType)))); 311*38fd1498Szrj __num_bins_cache = __round_up_to_pow2(__num_bins_cache); 312*38fd1498Szrj 313*38fd1498Szrj // No more buckets than TLB entries, power of 2. 314*38fd1498Szrj __num_bins = static_cast<_BinIndex> 315*38fd1498Szrj (std::min(__n, static_cast<_DifferenceType>(__num_bins_cache))); 316*38fd1498Szrj // Power of 2 and at least one element per bin, at most the TLB size. 317*38fd1498Szrj #if _GLIBCXX_RANDOM_SHUFFLE_CONSIDER_TLB 318*38fd1498Szrj // 2 TLB entries needed per bin. 319*38fd1498Szrj __num_bins = std::min(static_cast<_DifferenceType>(__s.TLB_size / 2), 320*38fd1498Szrj __num_bins); 321*38fd1498Szrj #endif 322*38fd1498Szrj __num_bins = __round_up_to_pow2(__num_bins); 323*38fd1498Szrj #if _GLIBCXX_RANDOM_SHUFFLE_CONSIDER_L1 324*38fd1498Szrj } 325*38fd1498Szrj #endif 326*38fd1498Szrj 327*38fd1498Szrj __num_bins = __round_up_to_pow2( 328*38fd1498Szrj std::max<_BinIndex>(__num_threads, __num_bins)); 329*38fd1498Szrj 330*38fd1498Szrj if (__num_threads <= 1) 331*38fd1498Szrj { 332*38fd1498Szrj _RandomNumber __derived_rng( 333*38fd1498Szrj __rng(std::numeric_limits<uint32_t>::max())); 334*38fd1498Szrj __sequential_random_shuffle(__begin, __end, __derived_rng); 335*38fd1498Szrj return; 336*38fd1498Szrj } 337*38fd1498Szrj 338*38fd1498Szrj _DRandomShufflingGlobalData<_RAIter> __sd(__begin); 339*38fd1498Szrj _DRSSorterPU<_RAIter, _RandomNumber >* __pus; 340*38fd1498Szrj _DifferenceType* __starts; 341*38fd1498Szrj 342*38fd1498Szrj # pragma omp parallel num_threads(__num_threads) 343*38fd1498Szrj { 344*38fd1498Szrj _ThreadIndex __num_threads = omp_get_num_threads(); 345*38fd1498Szrj # pragma omp single 346*38fd1498Szrj { 347*38fd1498Szrj __pus = new _DRSSorterPU<_RAIter, _RandomNumber>[__num_threads]; 348*38fd1498Szrj 349*38fd1498Szrj __sd._M_temporaries = new _ValueType*[__num_threads]; 350*38fd1498Szrj __sd._M_dist = new _DifferenceType*[__num_bins + 1]; 351*38fd1498Szrj __sd._M_bin_proc = new _ThreadIndex[__num_bins]; 352*38fd1498Szrj for (_BinIndex __b = 0; __b < __num_bins + 1; ++__b) 353*38fd1498Szrj __sd._M_dist[__b] = new _DifferenceType[__num_threads + 1]; 354*38fd1498Szrj for (_BinIndex __b = 0; __b < (__num_bins + 1); ++__b) 355*38fd1498Szrj { 356*38fd1498Szrj __sd._M_dist[0][0] = 0; 357*38fd1498Szrj __sd._M_dist[__b][0] = 0; 358*38fd1498Szrj } 359*38fd1498Szrj __starts = __sd._M_starts = new _DifferenceType[__num_threads + 1]; 360*38fd1498Szrj int __bin_cursor = 0; 361*38fd1498Szrj __sd._M_num_bins = __num_bins; 362*38fd1498Szrj __sd._M_num_bits = __rd_log2(__num_bins); 363*38fd1498Szrj 364*38fd1498Szrj _DifferenceType __chunk_length = __n / __num_threads, 365*38fd1498Szrj __split = __n % __num_threads, 366*38fd1498Szrj __start = 0; 367*38fd1498Szrj _DifferenceType __bin_chunk_length = __num_bins / __num_threads, 368*38fd1498Szrj __bin_split = __num_bins % __num_threads; 369*38fd1498Szrj for (_ThreadIndex __i = 0; __i < __num_threads; ++__i) 370*38fd1498Szrj { 371*38fd1498Szrj __starts[__i] = __start; 372*38fd1498Szrj __start += (__i < __split 373*38fd1498Szrj ? (__chunk_length + 1) : __chunk_length); 374*38fd1498Szrj int __j = __pus[__i]._M_bins_begin = __bin_cursor; 375*38fd1498Szrj 376*38fd1498Szrj // Range of bins for this processor. 377*38fd1498Szrj __bin_cursor += (__i < __bin_split 378*38fd1498Szrj ? (__bin_chunk_length + 1) 379*38fd1498Szrj : __bin_chunk_length); 380*38fd1498Szrj __pus[__i].__bins_end = __bin_cursor; 381*38fd1498Szrj for (; __j < __bin_cursor; ++__j) 382*38fd1498Szrj __sd._M_bin_proc[__j] = __i; 383*38fd1498Szrj __pus[__i]._M_num_threads = __num_threads; 384*38fd1498Szrj __pus[__i]._M_seed = __rng(std::numeric_limits<uint32_t>::max()); 385*38fd1498Szrj __pus[__i]._M_sd = &__sd; 386*38fd1498Szrj } 387*38fd1498Szrj __starts[__num_threads] = __start; 388*38fd1498Szrj } //single 389*38fd1498Szrj // Now shuffle in parallel. 390*38fd1498Szrj __parallel_random_shuffle_drs_pu(__pus); 391*38fd1498Szrj } // parallel 392*38fd1498Szrj 393*38fd1498Szrj delete[] __starts; 394*38fd1498Szrj delete[] __sd._M_bin_proc; 395*38fd1498Szrj for (int __s = 0; __s < (__num_bins + 1); ++__s) 396*38fd1498Szrj delete[] __sd._M_dist[__s]; 397*38fd1498Szrj delete[] __sd._M_dist; 398*38fd1498Szrj delete[] __sd._M_temporaries; 399*38fd1498Szrj 400*38fd1498Szrj delete[] __pus; 401*38fd1498Szrj } 402*38fd1498Szrj 403*38fd1498Szrj /** @brief Sequential cache-efficient random shuffle. 404*38fd1498Szrj * @param __begin Begin iterator of sequence. 405*38fd1498Szrj * @param __end End iterator of sequence. 406*38fd1498Szrj * @param __rng Random number generator to use. 407*38fd1498Szrj */ 408*38fd1498Szrj template<typename _RAIter, typename _RandomNumberGenerator> 409*38fd1498Szrj void __sequential_random_shuffle(_RAIter __begin,_RAIter __end,_RandomNumberGenerator & __rng)410*38fd1498Szrj __sequential_random_shuffle(_RAIter __begin, _RAIter __end, 411*38fd1498Szrj _RandomNumberGenerator& __rng) 412*38fd1498Szrj { 413*38fd1498Szrj typedef std::iterator_traits<_RAIter> _TraitsType; 414*38fd1498Szrj typedef typename _TraitsType::value_type _ValueType; 415*38fd1498Szrj typedef typename _TraitsType::difference_type _DifferenceType; 416*38fd1498Szrj 417*38fd1498Szrj _DifferenceType __n = __end - __begin; 418*38fd1498Szrj const _Settings& __s = _Settings::get(); 419*38fd1498Szrj 420*38fd1498Szrj _BinIndex __num_bins, __num_bins_cache; 421*38fd1498Szrj 422*38fd1498Szrj #if _GLIBCXX_RANDOM_SHUFFLE_CONSIDER_L1 423*38fd1498Szrj // Try the L1 cache first, must fit into L1. 424*38fd1498Szrj __num_bins_cache = std::max<_DifferenceType> 425*38fd1498Szrj (1, __n / (__s.L1_cache_size_lb / sizeof(_ValueType))); 426*38fd1498Szrj __num_bins_cache = __round_up_to_pow2(__num_bins_cache); 427*38fd1498Szrj 428*38fd1498Szrj // No more buckets than TLB entries, power of 2 429*38fd1498Szrj // Power of 2 and at least one element per bin, at most the TLB size 430*38fd1498Szrj __num_bins = std::min(__n, (_DifferenceType)__num_bins_cache); 431*38fd1498Szrj #if _GLIBCXX_RANDOM_SHUFFLE_CONSIDER_TLB 432*38fd1498Szrj // 2 TLB entries needed per bin 433*38fd1498Szrj __num_bins = std::min((_DifferenceType)__s.TLB_size / 2, __num_bins); 434*38fd1498Szrj #endif 435*38fd1498Szrj __num_bins = __round_up_to_pow2(__num_bins); 436*38fd1498Szrj 437*38fd1498Szrj if (__num_bins < __num_bins_cache) 438*38fd1498Szrj { 439*38fd1498Szrj #endif 440*38fd1498Szrj // Now try the L2 cache, must fit into L2. 441*38fd1498Szrj __num_bins_cache = static_cast<_BinIndex> 442*38fd1498Szrj (std::max<_DifferenceType>(1, __n / (__s.L2_cache_size 443*38fd1498Szrj / sizeof(_ValueType)))); 444*38fd1498Szrj __num_bins_cache = __round_up_to_pow2(__num_bins_cache); 445*38fd1498Szrj 446*38fd1498Szrj // No more buckets than TLB entries, power of 2 447*38fd1498Szrj // Power of 2 and at least one element per bin, at most the TLB size. 448*38fd1498Szrj __num_bins = static_cast<_BinIndex> 449*38fd1498Szrj (std::min(__n, static_cast<_DifferenceType>(__num_bins_cache))); 450*38fd1498Szrj 451*38fd1498Szrj #if _GLIBCXX_RANDOM_SHUFFLE_CONSIDER_TLB 452*38fd1498Szrj // 2 TLB entries needed per bin 453*38fd1498Szrj __num_bins = std::min<_DifferenceType>(__s.TLB_size / 2, __num_bins); 454*38fd1498Szrj #endif 455*38fd1498Szrj __num_bins = __round_up_to_pow2(__num_bins); 456*38fd1498Szrj #if _GLIBCXX_RANDOM_SHUFFLE_CONSIDER_L1 457*38fd1498Szrj } 458*38fd1498Szrj #endif 459*38fd1498Szrj 460*38fd1498Szrj int __num_bits = __rd_log2(__num_bins); 461*38fd1498Szrj 462*38fd1498Szrj if (__num_bins > 1) 463*38fd1498Szrj { 464*38fd1498Szrj _ValueType* __target = 465*38fd1498Szrj static_cast<_ValueType*>(::operator new(sizeof(_ValueType) * __n)); 466*38fd1498Szrj _BinIndex* __oracles = new _BinIndex[__n]; 467*38fd1498Szrj _DifferenceType* __dist0 = new _DifferenceType[__num_bins + 1], 468*38fd1498Szrj * __dist1 = new _DifferenceType[__num_bins + 1]; 469*38fd1498Szrj 470*38fd1498Szrj for (int __b = 0; __b < __num_bins + 1; ++__b) 471*38fd1498Szrj __dist0[__b] = 0; 472*38fd1498Szrj 473*38fd1498Szrj _RandomNumber __bitrng(__rng(0xFFFFFFFF)); 474*38fd1498Szrj 475*38fd1498Szrj for (_DifferenceType __i = 0; __i < __n; ++__i) 476*38fd1498Szrj { 477*38fd1498Szrj _BinIndex __oracle = __random_number_pow2(__num_bits, __bitrng); 478*38fd1498Szrj __oracles[__i] = __oracle; 479*38fd1498Szrj 480*38fd1498Szrj // To allow prefix (partial) sum. 481*38fd1498Szrj ++(__dist0[__oracle + 1]); 482*38fd1498Szrj } 483*38fd1498Szrj 484*38fd1498Szrj // Sum up bins. 485*38fd1498Szrj __gnu_sequential::partial_sum(__dist0, __dist0 + __num_bins + 1, 486*38fd1498Szrj __dist0); 487*38fd1498Szrj 488*38fd1498Szrj for (int __b = 0; __b < __num_bins + 1; ++__b) 489*38fd1498Szrj __dist1[__b] = __dist0[__b]; 490*38fd1498Szrj 491*38fd1498Szrj // Distribute according to oracles. 492*38fd1498Szrj for (_DifferenceType __i = 0; __i < __n; ++__i) 493*38fd1498Szrj ::new(&(__target[(__dist0[__oracles[__i]])++])) 494*38fd1498Szrj _ValueType(*(__begin + __i)); 495*38fd1498Szrj 496*38fd1498Szrj for (int __b = 0; __b < __num_bins; ++__b) 497*38fd1498Szrj __sequential_random_shuffle(__target + __dist1[__b], 498*38fd1498Szrj __target + __dist1[__b + 1], __rng); 499*38fd1498Szrj 500*38fd1498Szrj // Copy elements back. 501*38fd1498Szrj std::copy(__target, __target + __n, __begin); 502*38fd1498Szrj 503*38fd1498Szrj delete[] __dist0; 504*38fd1498Szrj delete[] __dist1; 505*38fd1498Szrj delete[] __oracles; 506*38fd1498Szrj 507*38fd1498Szrj for (_DifferenceType __i = 0; __i < __n; ++__i) 508*38fd1498Szrj __target[__i].~_ValueType(); 509*38fd1498Szrj ::operator delete(__target); 510*38fd1498Szrj } 511*38fd1498Szrj else 512*38fd1498Szrj __gnu_sequential::random_shuffle(__begin, __end, __rng); 513*38fd1498Szrj } 514*38fd1498Szrj 515*38fd1498Szrj /** @brief Parallel random public call. 516*38fd1498Szrj * @param __begin Begin iterator of sequence. 517*38fd1498Szrj * @param __end End iterator of sequence. 518*38fd1498Szrj * @param __rng Random number generator to use. 519*38fd1498Szrj */ 520*38fd1498Szrj template<typename _RAIter, typename _RandomNumberGenerator> 521*38fd1498Szrj inline void 522*38fd1498Szrj __parallel_random_shuffle(_RAIter __begin, _RAIter __end, 523*38fd1498Szrj _RandomNumberGenerator __rng = _RandomNumber()) 524*38fd1498Szrj { 525*38fd1498Szrj typedef std::iterator_traits<_RAIter> _TraitsType; 526*38fd1498Szrj typedef typename _TraitsType::difference_type _DifferenceType; 527*38fd1498Szrj _DifferenceType __n = __end - __begin; 528*38fd1498Szrj __parallel_random_shuffle_drs(__begin, __end, __n, 529*38fd1498Szrj __get_max_threads(), __rng); 530*38fd1498Szrj } 531*38fd1498Szrj } 532*38fd1498Szrj 533*38fd1498Szrj #endif /* _GLIBCXX_PARALLEL_RANDOM_SHUFFLE_H */ 534