partitioner.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_partitioner_H
00022 #define __TBB_partitioner_H
00023 
00024 #include "task.h"
00025 
00026 namespace tbb {
00027 class affinity_partitioner;
00028 
00030 namespace internal {
00031 size_t __TBB_EXPORTED_FUNC get_initial_auto_partitioner_divisor();
00032 
00034 
00035 class affinity_partitioner_base_v3: no_copy {
00036     friend class tbb::affinity_partitioner;
00038 
00039     affinity_id* my_array;
00041     size_t my_size;
00043     affinity_partitioner_base_v3() : my_array(NULL), my_size(0) {}
00045     ~affinity_partitioner_base_v3() {resize(0);}
00047 
00048     void __TBB_EXPORTED_METHOD resize( unsigned factor );
00049     friend class affinity_partition_type;
00050 };
00051 
00053 class partition_type_base {
00054 public:
00055     void set_affinity( task & ) {}
00056     void note_affinity( task::affinity_id ) {}
00057     task* continue_after_execute_range( task& ) {return NULL;}
00058     bool decide_whether_to_delay() {return false;}
00059     void spawn_or_delay( bool, task& a, task& b ) {
00060         a.spawn(b);
00061     }
00062 };
00063 
00064 class affinity_partition_type;
00065 
00066 template<typename Range, typename Body, typename Partitioner> class start_for;
00067 template<typename Range, typename Body, typename Partitioner> class start_reduce;
00068 template<typename Range, typename Body> class start_reduce_with_affinity;
00069 template<typename Range, typename Body, typename Partitioner> class start_scan;
00070 
00071 } // namespace internal
00073 
00075 
00077 class simple_partitioner {
00078 public:
00079     simple_partitioner() {}
00080 private:
00081     template<typename Range, typename Body, typename Partitioner> friend class internal::start_for;
00082     template<typename Range, typename Body, typename Partitioner> friend class internal::start_reduce;
00083     template<typename Range, typename Body, typename Partitioner> friend class internal::start_scan;
00084 
00085     class partition_type: public internal::partition_type_base {
00086     public:
00087         bool should_execute_range(const task& ) {return false;}
00088         partition_type( const simple_partitioner& ) {}
00089         partition_type( const partition_type&, split ) {}
00090     };
00091 };
00092 
00094 
00097 class auto_partitioner {
00098 public:
00099     auto_partitioner() {}
00100 
00101 private:
00102     template<typename Range, typename Body, typename Partitioner> friend class internal::start_for;
00103     template<typename Range, typename Body, typename Partitioner> friend class internal::start_reduce;
00104     template<typename Range, typename Body, typename Partitioner> friend class internal::start_scan;
00105 
00106     class partition_type: public internal::partition_type_base {
00107         size_t num_chunks;
00108         static const size_t VICTIM_CHUNKS = 4;
00109 public:
00110         bool should_execute_range(const task &t) {
00111             if( num_chunks<VICTIM_CHUNKS && t.is_stolen_task() )
00112                 num_chunks = VICTIM_CHUNKS;
00113             return num_chunks==1;
00114         }
00115         partition_type( const auto_partitioner& ) : num_chunks(internal::get_initial_auto_partitioner_divisor()) {}
00116         partition_type( partition_type& pt, split ) {
00117             num_chunks = pt.num_chunks /= 2u;
00118         }
00119     };
00120 };
00121 
00123 class affinity_partitioner: internal::affinity_partitioner_base_v3 {
00124 public:
00125     affinity_partitioner() {}
00126 
00127 private:
00128     template<typename Range, typename Body, typename Partitioner> friend class internal::start_for;
00129     template<typename Range, typename Body, typename Partitioner> friend class internal::start_reduce;
00130     template<typename Range, typename Body> friend class internal::start_reduce_with_affinity;
00131     template<typename Range, typename Body, typename Partitioner> friend class internal::start_scan;
00132 
00133     typedef internal::affinity_partition_type partition_type;
00134     friend class internal::affinity_partition_type;
00135 };
00136 
00138 namespace internal {
00139 
00140 class affinity_partition_type: public no_copy {
00142     static const unsigned factor = 16;
00143     static const size_t VICTIM_CHUNKS = 4;
00144 
00145     internal::affinity_id* my_array;
00146     task_list delay_list;
00147     unsigned map_begin, map_end;
00148     size_t num_chunks;
00149 public:
00150     affinity_partition_type( affinity_partitioner& ap ) {
00151         __TBB_ASSERT( (factor&(factor-1))==0, "factor must be power of two" ); 
00152         ap.resize(factor);
00153         my_array = ap.my_array;
00154         map_begin = 0;
00155         map_end = unsigned(ap.my_size);
00156         num_chunks = internal::get_initial_auto_partitioner_divisor();
00157     }
00158     affinity_partition_type(affinity_partition_type& p, split) : my_array(p.my_array) {
00159         __TBB_ASSERT( p.map_end-p.map_begin<factor || (p.map_end-p.map_begin)%factor==0, NULL );
00160         num_chunks = p.num_chunks /= 2;
00161         unsigned e = p.map_end;
00162         unsigned d = (e - p.map_begin)/2;
00163         if( d>factor ) 
00164             d &= 0u-factor;
00165         map_end = e;
00166         map_begin = p.map_end = e-d;
00167     }
00168 
00169     bool should_execute_range(const task &t) {
00170         if( num_chunks < VICTIM_CHUNKS && t.is_stolen_task() )
00171             num_chunks = VICTIM_CHUNKS;
00172         return num_chunks == 1;
00173     }
00174 
00175     void set_affinity( task &t ) {
00176         if( map_begin<map_end )
00177             t.set_affinity( my_array[map_begin] );
00178     }
00179     void note_affinity( task::affinity_id id ) {
00180         if( map_begin<map_end ) 
00181             my_array[map_begin] = id;
00182     }
00183     task* continue_after_execute_range( task& t ) {
00184         task* first = NULL;
00185         if( !delay_list.empty() ) {
00186             first = &delay_list.pop_front();
00187             while( !delay_list.empty() ) {
00188                 t.spawn(*first);
00189                 first = &delay_list.pop_front();
00190             }
00191         }
00192         return first;
00193     }
00194     bool decide_whether_to_delay() {
00195         // The possible underflow caused by "-1u" is deliberate
00196         return (map_begin&(factor-1))==0 && map_end-map_begin-1u<factor;
00197     }
00198     void spawn_or_delay( bool delay, task& a, task& b ) {
00199         if( delay )  
00200             delay_list.push_back(b);
00201         else 
00202             a.spawn(b);
00203     }
00204 
00205     ~affinity_partition_type() {
00206         // The delay_list can be non-empty if an exception is thrown.
00207         while( !delay_list.empty() ) {
00208             task& t = delay_list.pop_front();
00209             t.destroy(t);
00210         } 
00211     }
00212 };
00213 
00214 } // namespace internal
00216 
00217 
00218 } // namespace tbb
00219 
00220 #endif /* __TBB_partitioner_H */

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.