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, 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
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
00207 while( !delay_list.empty() ) {
00208 task& t = delay_list.pop_front();
00209 t.destroy(t);
00210 }
00211 }
00212 };
00213
00214 }
00216
00217
00218 }
00219
00220 #endif