parallel_sort.h

00001 /*
00002     Copyright 2005-2009 Intel Corporation.  All Rights Reserved.
00003 
00004     The source code contained or described herein and all documents related
00005     to the source code ("Material") are owned by Intel Corporation or its
00006     suppliers or licensors.  Title to the Material remains with Intel
00007     Corporation or its suppliers and licensors.  The Material is protected
00008     by worldwide copyright laws and treaty provisions.  No part of the
00009     Material may be used, copied, reproduced, modified, published, uploaded,
00010     posted, transmitted, distributed, or disclosed in any way without
00011     Intel's prior express written permission.
00012 
00013     No license under any patent, copyright, trade secret or other
00014     intellectual property right is granted to or conferred upon you by
00015     disclosure or delivery of the Materials, either expressly, by
00016     implication, inducement, estoppel or otherwise.  Any license under such
00017     intellectual property rights must be express and approved by Intel in
00018     writing.
00019 */
00020 
00021 #ifndef __TBB_parallel_sort_H
00022 #define __TBB_parallel_sort_H
00023 
00024 #include "parallel_for.h"
00025 #include "blocked_range.h"
00026 #include <algorithm>
00027 #include <iterator>
00028 #include <functional>
00029 
00030 namespace tbb {
00031 
00033 namespace internal {
00034 
00036 
00039 template<typename RandomAccessIterator, typename Compare>
00040 class quick_sort_range: private no_assign {
00041 
00042     inline size_t median_of_three(const RandomAccessIterator &array, size_t l, size_t m, size_t r) const {
00043         return comp(array[l], array[m]) ? ( comp(array[m], array[r]) ? m : ( comp( array[l], array[r]) ? r : l ) ) 
00044                                         : ( comp(array[r], array[m]) ? m : ( comp( array[r], array[l] ) ? r : l ) );
00045     }
00046 
00047     inline size_t pseudo_median_of_nine( const RandomAccessIterator &array, const quick_sort_range &range ) const {
00048         size_t offset = range.size/8u;
00049         return median_of_three(array, 
00050                                median_of_three(array, 0, offset, offset*2),
00051                                median_of_three(array, offset*3, offset*4, offset*5),
00052                                median_of_three(array, offset*6, offset*7, range.size - 1) );
00053 
00054     }
00055 
00056 public:
00057 
00058     static const size_t grainsize = 500;
00059     const Compare &comp;
00060     RandomAccessIterator begin;
00061     size_t size;
00062 
00063     quick_sort_range( RandomAccessIterator begin_, size_t size_, const Compare &comp_ ) :
00064         comp(comp_), begin(begin_), size(size_) {}
00065 
00066     bool empty() const {return size==0;}
00067     bool is_divisible() const {return size>=grainsize;}
00068 
00069     quick_sort_range( quick_sort_range& range, split ) : comp(range.comp) {
00070         RandomAccessIterator array = range.begin;
00071         RandomAccessIterator key0 = range.begin; 
00072         size_t m = pseudo_median_of_nine(array, range);
00073         if (m) std::swap ( array[0], array[m] );
00074 
00075         size_t i=0;
00076         size_t j=range.size;
00077         // Partition interval [i+1,j-1] with key *key0.
00078         for(;;) {
00079             __TBB_ASSERT( i<j, NULL );
00080             // Loop must terminate since array[l]==*key0.
00081             do {
00082                 --j;
00083                 __TBB_ASSERT( i<=j, "bad ordering relation?" );
00084             } while( comp( *key0, array[j] ));
00085             do {
00086                 __TBB_ASSERT( i<=j, NULL );
00087                 if( i==j ) goto partition;
00088                 ++i;
00089             } while( comp( array[i],*key0 ));
00090             if( i==j ) goto partition;
00091             std::swap( array[i], array[j] );
00092         }
00093 partition:
00094         // Put the partition key were it belongs
00095         std::swap( array[j], *key0 );
00096         // array[l..j) is less or equal to key.
00097         // array(j..r) is greater or equal to key.
00098         // array[j] is equal to key
00099         i=j+1;
00100         begin = array+i;
00101         size = range.size-i;
00102         range.size = j;
00103     }
00104 };
00105 
00107 
00108 template<typename RandomAccessIterator, typename Compare>
00109 class quick_sort_pretest_body : internal::no_assign {
00110     const Compare &comp;
00111 
00112 public:
00113     quick_sort_pretest_body(const Compare &_comp) : comp(_comp) {}
00114 
00115     void operator()( const blocked_range<RandomAccessIterator>& range ) const {
00116         task &my_task = task::self();
00117         RandomAccessIterator my_end = range.end();
00118 
00119         int i = 0;
00120         for (RandomAccessIterator k = range.begin(); k != my_end; ++k, ++i) {
00121             if ( i%64 == 0 && my_task.is_cancelled() ) break;
00122           
00123             // The k-1 is never out-of-range because the first chunk starts at begin+serial_cutoff+1
00124             if ( comp( *(k), *(k-1) ) ) {
00125                 my_task.cancel_group_execution();
00126                 break;
00127             }
00128         }
00129     }
00130 
00131 };
00132 
00134 
00135 template<typename RandomAccessIterator, typename Compare>
00136 struct quick_sort_body {
00137     void operator()( const quick_sort_range<RandomAccessIterator,Compare>& range ) const {
00138         //SerialQuickSort( range.begin, range.size, range.comp );
00139         std::sort( range.begin, range.begin + range.size, range.comp );
00140     }
00141 };
00142 
00144 
00145 template<typename RandomAccessIterator, typename Compare>
00146 void parallel_quick_sort( RandomAccessIterator begin, RandomAccessIterator end, const Compare& comp ) {
00147     task_group_context my_context;
00148     const int serial_cutoff = 9;
00149 
00150     __TBB_ASSERT( begin + serial_cutoff < end, "min_parallel_size is smaller than serial cutoff?" );
00151     RandomAccessIterator k;
00152     for ( k = begin ; k != begin + serial_cutoff; ++k ) {
00153         if ( comp( *(k+1), *k ) ) {
00154             goto do_parallel_quick_sort;
00155         }
00156     }
00157 
00158     parallel_for( blocked_range<RandomAccessIterator>(k+1, end),
00159                   quick_sort_pretest_body<RandomAccessIterator,Compare>(comp),
00160                   auto_partitioner(),
00161                   my_context);
00162 
00163     if (my_context.is_group_execution_cancelled())
00164 do_parallel_quick_sort:
00165         parallel_for( quick_sort_range<RandomAccessIterator,Compare>(begin, end-begin, comp ), 
00166                       quick_sort_body<RandomAccessIterator,Compare>(),
00167                       auto_partitioner() );
00168 }
00169 
00170 } // namespace internal
00172 
00183 
00185 
00188 template<typename RandomAccessIterator, typename Compare>
00189 void parallel_sort( RandomAccessIterator begin, RandomAccessIterator end, const Compare& comp) { 
00190     const int min_parallel_size = 500; 
00191     if( end > begin ) {
00192         if (end - begin < min_parallel_size) { 
00193             std::sort(begin, end, comp);
00194         } else {
00195             internal::parallel_quick_sort(begin, end, comp);
00196         }
00197     }
00198 }
00199 
00201 
00202 template<typename RandomAccessIterator>
00203 inline void parallel_sort( RandomAccessIterator begin, RandomAccessIterator end ) { 
00204     parallel_sort( begin, end, std::less< typename std::iterator_traits<RandomAccessIterator>::value_type >() );
00205 }
00206 
00208 
00209 template<typename T>
00210 inline void parallel_sort( T * begin, T * end ) {
00211     parallel_sort( begin, end, std::less< T >() );
00212 }   
00214 
00215 
00216 } // namespace tbb
00217 
00218 #endif
00219 

Copyright © 2005-2009 Intel Corporation. All Rights Reserved.

Intel, Pentium, Intel Xeon, Itanium, Intel XScale and VTune are registered trademarks or trademarks of Intel Corporation or its subsidiaries in the United States and other countries.

* Other names and brands may be claimed as the property of others.