parallel_sort.h Source File

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

- File List
- File Members

# parallel_sort.h

    00001 /*
    00002     Copyright 2005-2011 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
    00106 #if __TBB_TASK_GROUP_CONTEXT
    00108
    00109 template<typename RandomAccessIterator, typename Compare>
    00110 class quick_sort_pretest_body : internal::no_assign {
    00111     const Compare &comp;
    00112
    00113 public:
    00114     quick_sort_pretest_body(const Compare &_comp) : comp(_comp) {}
    00115
    00116     void operator()( const blocked_range<RandomAccessIterator>& range ) const {
    00117         task &my_task = task::self();
    00118         RandomAccessIterator my_end = range.end();
    00119
    00120         int i = 0;
    00121         for (RandomAccessIterator k = range.begin(); k != my_end; ++k, ++i) {
    00122             if ( i%64 == 0 && my_task.is_cancelled() ) break;
    00123
    00124             // The k-1 is never out-of-range because the first chunk starts at begin+serial_cutoff+1
    00125             if ( comp( *(k), *(k-1) ) ) {
    00126                 my_task.cancel_group_execution();
    00127                 break;
    00128             }
    00129         }
    00130     }
    00131
    00132 };
    00133 #endif /* __TBB_TASK_GROUP_CONTEXT */
    00134
    00136
    00137 template<typename RandomAccessIterator, typename Compare>
    00138 struct quick_sort_body {
    00139     void operator()( const quick_sort_range<RandomAccessIterator,Compare>& range ) const {
    00140         //SerialQuickSort( range.begin, range.size, range.comp );
    00141         std::sort( range.begin, range.begin + range.size, range.comp );
    00142     }
    00143 };
    00144
    00146
    00147 template<typename RandomAccessIterator, typename Compare>
    00148 void parallel_quick_sort( RandomAccessIterator begin, RandomAccessIterator end, const Compare& comp ) {
    00149 #if __TBB_TASK_GROUP_CONTEXT
    00150     task_group_context my_context;
    00151     const int serial_cutoff = 9;
    00152
    00153     __TBB_ASSERT( begin + serial_cutoff < end, "min_parallel_size is smaller than serial cutoff?" );
    00154     RandomAccessIterator k;
    00155     for ( k = begin ; k != begin + serial_cutoff; ++k ) {
    00156         if ( comp( *(k+1), *k ) ) {
    00157             goto do_parallel_quick_sort;
    00158         }
    00159     }
    00160
    00161     parallel_for( blocked_range<RandomAccessIterator>(k+1, end),
    00162                   quick_sort_pretest_body<RandomAccessIterator,Compare>(comp),
    00163                   auto_partitioner(),
    00164                   my_context);
    00165
    00166     if (my_context.is_group_execution_cancelled())
    00167 do_parallel_quick_sort:
    00168 #endif /* __TBB_TASK_GROUP_CONTEXT */
    00169         parallel_for( quick_sort_range<RandomAccessIterator,Compare>(begin, end-begin, comp ),
    00170                       quick_sort_body<RandomAccessIterator,Compare>(),
    00171                       auto_partitioner() );
    00172 }
    00173
    00174 } // namespace internal
    00176
    00187
    00189
    00192 template<typename RandomAccessIterator, typename Compare>
    00193 void parallel_sort( RandomAccessIterator begin, RandomAccessIterator end, const Compare& comp) {
    00194     const int min_parallel_size = 500;
    00195     if( end > begin ) {
    00196         if (end - begin < min_parallel_size) {
    00197             std::sort(begin, end, comp);
    00198         } else {
    00199             internal::parallel_quick_sort(begin, end, comp);
    00200         }
    00201     }
    00202 }
    00203
    00205
    00206 template<typename RandomAccessIterator>
    00207 inline void parallel_sort( RandomAccessIterator begin, RandomAccessIterator end ) {
    00208     parallel_sort( begin, end, std::less< typename std::iterator_traits<RandomAccessIterator>::value_type >() );
    00209 }
    00210
    00212
    00213 template<typename T>
    00214 inline void parallel_sort( T * begin, T * end ) {
    00215     parallel_sort( begin, end, std::less< T >() );
    00216 }
    00218
    00219
    00220 } // namespace tbb
    00221
    00222 #endif
    00223

Copyright © 2005-2011 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.