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() {return NULL;}
00058 bool decide_whether_to_delay() {return false;}
00059 void spawn_or_delay( bool, task& b ) {
00060 task::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, typename Partitioner> class start_scan;
00069
00070 }
00072
00074
00076 class simple_partitioner {
00077 public:
00078 simple_partitioner() {}
00079 private:
00080 template<typename Range, typename Body, typename Partitioner> friend class internal::start_for;
00081 template<typename Range, typename Body, typename Partitioner> friend class internal::start_reduce;
00082 template<typename Range, typename Body, typename Partitioner> friend class internal::start_scan;
00083
00084 class partition_type: public internal::partition_type_base {
00085 public:
00086 bool should_execute_range(const task& ) {return false;}
00087 partition_type( const simple_partitioner& ) {}
00088 partition_type( const partition_type&, split ) {}
00089 };
00090 };
00091
00093
00096 class auto_partitioner {
00097 public:
00098 auto_partitioner() {}
00099
00100 private:
00101 template<typename Range, typename Body, typename Partitioner> friend class internal::start_for;
00102 template<typename Range, typename Body, typename Partitioner> friend class internal::start_reduce;
00103 template<typename Range, typename Body, typename Partitioner> friend class internal::start_scan;
00104
00105 class partition_type: public internal::partition_type_base {
00106 size_t num_chunks;
00107 static const size_t VICTIM_CHUNKS = 4;
00108 public:
00109 bool should_execute_range(const task &t) {
00110 if( num_chunks<VICTIM_CHUNKS && t.is_stolen_task() )
00111 num_chunks = VICTIM_CHUNKS;
00112 return num_chunks==1;
00113 }
00114 partition_type( const auto_partitioner& ) : num_chunks(internal::get_initial_auto_partitioner_divisor()) {}
00115 partition_type( partition_type& pt, split ) {
00116 num_chunks = pt.num_chunks /= 2u;
00117 }
00118 };
00119 };
00120
00122 class affinity_partitioner: internal::affinity_partitioner_base_v3 {
00123 public:
00124 affinity_partitioner() {}
00125
00126 private:
00127 template<typename Range, typename Body, typename Partitioner> friend class internal::start_for;
00128 template<typename Range, typename Body, typename Partitioner> friend class internal::start_reduce;
00129 template<typename Range, typename Body, typename Partitioner> friend class internal::start_scan;
00130
00131 typedef internal::affinity_partition_type partition_type;
00132 friend class internal::affinity_partition_type;
00133 };
00134
00136 namespace internal {
00137
00138 class affinity_partition_type: public no_copy {
00140 static const unsigned factor = 16;
00141 static const size_t VICTIM_CHUNKS = 4;
00142
00143 internal::affinity_id* my_array;
00144 task_list delay_list;
00145 unsigned map_begin, map_end;
00146 size_t num_chunks;
00147 public:
00148 affinity_partition_type( affinity_partitioner& ap ) {
00149 __TBB_ASSERT( (factor&(factor-1))==0, "factor must be power of two" );
00150 ap.resize(factor);
00151 my_array = ap.my_array;
00152 map_begin = 0;
00153 map_end = unsigned(ap.my_size);
00154 num_chunks = internal::get_initial_auto_partitioner_divisor();
00155 }
00156 affinity_partition_type(affinity_partition_type& p, split) : my_array(p.my_array) {
00157 __TBB_ASSERT( p.map_end-p.map_begin<factor || (p.map_end-p.map_begin)%factor==0, NULL );
00158 num_chunks = p.num_chunks /= 2;
00159 unsigned e = p.map_end;
00160 unsigned d = (e - p.map_begin)/2;
00161 if( d>factor )
00162 d &= 0u-factor;
00163 map_end = e;
00164 map_begin = p.map_end = e-d;
00165 }
00166
00167 bool should_execute_range(const task &t) {
00168 if( num_chunks < VICTIM_CHUNKS && t.is_stolen_task() )
00169 num_chunks = VICTIM_CHUNKS;
00170 return num_chunks == 1;
00171 }
00172
00173 void set_affinity( task &t ) {
00174 if( map_begin<map_end )
00175 t.set_affinity( my_array[map_begin] );
00176 }
00177 void note_affinity( task::affinity_id id ) {
00178 if( map_begin<map_end )
00179 my_array[map_begin] = id;
00180 }
00181 task* continue_after_execute_range() {
00182 task* first = NULL;
00183 if( !delay_list.empty() ) {
00184 first = &delay_list.pop_front();
00185 while( !delay_list.empty() ) {
00186 task::spawn(*first);
00187 first = &delay_list.pop_front();
00188 }
00189 }
00190 return first;
00191 }
00192 bool decide_whether_to_delay() {
00193
00194 return (map_begin&(factor-1))==0 && map_end-map_begin-1u<factor;
00195 }
00196 void spawn_or_delay( bool delay, task& b ) {
00197 if( delay )
00198 delay_list.push_back(b);
00199 else
00200 task::spawn(b);
00201 }
00202
00203 ~affinity_partition_type() {
00204
00205 while( !delay_list.empty() ) {
00206 task& t = delay_list.pop_front();
00207 t.destroy(t);
00208 }
00209 }
00210 };
00211
00212 }
00214
00215
00216 }
00217
00218 #endif