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> friend class internal::start_reduce_with_affinity;
00130     template<typename Range, typename Body, typename Partitioner> friend class internal::start_scan;
00131 
00132     typedef internal::affinity_partition_type partition_type;
00133     friend class internal::affinity_partition_type;
00134 };
00135 
00137 namespace internal {
00138 
00139 class affinity_partition_type: public no_copy {
00141     static const unsigned factor = 16;
00142     static const size_t VICTIM_CHUNKS = 4;
00143 
00144     internal::affinity_id* my_array;
00145     task_list delay_list;
00146     unsigned map_begin, map_end;
00147     size_t num_chunks;
00148 public:
00149     affinity_partition_type( affinity_partitioner& ap ) {
00150         __TBB_ASSERT( (factor&(factor-1))==0, "factor must be power of two" ); 
00151         ap.resize(factor);
00152         my_array = ap.my_array;
00153         map_begin = 0;
00154         map_end = unsigned(ap.my_size);
00155         num_chunks = internal::get_initial_auto_partitioner_divisor();
00156     }
00157     affinity_partition_type(affinity_partition_type& p, split) : my_array(p.my_array) {
00158         __TBB_ASSERT( p.map_end-p.map_begin<factor || (p.map_end-p.map_begin)%factor==0, NULL );
00159         num_chunks = p.num_chunks /= 2;
00160         unsigned e = p.map_end;
00161         unsigned d = (e - p.map_begin)/2;
00162         if( d>factor ) 
00163             d &= 0u-factor;
00164         map_end = e;
00165         map_begin = p.map_end = e-d;
00166     }
00167 
00168     bool should_execute_range(const task &t) {
00169         if( num_chunks < VICTIM_CHUNKS && t.is_stolen_task() )
00170             num_chunks = VICTIM_CHUNKS;
00171         return num_chunks == 1;
00172     }
00173 
00174     void set_affinity( task &t ) {
00175         if( map_begin<map_end )
00176             t.set_affinity( my_array[map_begin] );
00177     }
00178     void note_affinity( task::affinity_id id ) {
00179         if( map_begin<map_end ) 
00180             my_array[map_begin] = id;
00181     }
00182     task* continue_after_execute_range( task& t ) {
00183         task* first = NULL;
00184         if( !delay_list.empty() ) {
00185             first = &delay_list.pop_front();
00186             while( !delay_list.empty() ) {
00187                 t.spawn(*first);
00188                 first = &delay_list.pop_front();
00189             }
00190         }
00191         return first;
00192     }
00193     bool decide_whether_to_delay() {
00194         // The possible underflow caused by "-1u" is deliberate
00195         return (map_begin&(factor-1))==0 && map_end-map_begin-1u<factor;
00196     }
00197     void spawn_or_delay( bool delay, task& a, task& b ) {
00198         if( delay )  
00199             delay_list.push_back(b);
00200         else 
00201             a.spawn(b);
00202     }
00203 
00204     ~affinity_partition_type() {
00205         // The delay_list can be non-empty if an exception is thrown.
00206         while( !delay_list.empty() ) {
00207             task& t = delay_list.pop_front();
00208             t.destroy(t);
00209         } 
00210     }
00211 };
00212 
00213 } // namespace internal
00215 
00216 
00217 } // namespace tbb
00218 
00219 #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.