00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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 }
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
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
00206 while( !delay_list.empty() ) {
00207 task& t = delay_list.pop_front();
00208 t.destroy(t);
00209 }
00210 }
00211 };
00212
00213 }
00215
00216
00217 }
00218
00219 #endif