parallel_sort.h Source File

- Main Page
- Modules
- Namespaces
- Classes
- Files
- Related Pages

- File List
- File Members

# parallel_sort.h

    00001 /*
    00002     Copyright 2005-2010 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-2010 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.