![]() |
Shadowrun: Awakened 29 September 2011 - Build 871
|
00001 /* 00002 Copyright 2005-2010 Intel Corporation. All Rights Reserved. 00003 00004 This file is part of Threading Building Blocks. 00005 00006 Threading Building Blocks is free software; you can redistribute it 00007 and/or modify it under the terms of the GNU General Public License 00008 version 2 as published by the Free Software Foundation. 00009 00010 Threading Building Blocks is distributed in the hope that it will be 00011 useful, but WITHOUT ANY WARRANTY; without even the implied warranty 00012 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 GNU General Public License for more details. 00014 00015 You should have received a copy of the GNU General Public License 00016 along with Threading Building Blocks; if not, write to the Free Software 00017 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00018 00019 As a special exception, you may use this file as part of a free software 00020 library without restriction. Specifically, if other files instantiate 00021 templates or use macros or inline functions from this file, or you compile 00022 this file and link it with other files to produce an executable, this 00023 file does not by itself cause the resulting executable to be covered by 00024 the GNU General Public License. This exception does not however 00025 invalidate any other reasons why the executable file might be covered by 00026 the GNU General Public License. 00027 */ 00028 00029 #ifndef __TBB_partitioner_H 00030 #define __TBB_partitioner_H 00031 00032 #include "task.h" 00033 00034 namespace tbb { 00035 class affinity_partitioner; 00036 00038 namespace internal { 00039 size_t __TBB_EXPORTED_FUNC get_initial_auto_partitioner_divisor(); 00040 00042 00043 class affinity_partitioner_base_v3: no_copy { 00044 friend class tbb::affinity_partitioner; 00046 00047 affinity_id* my_array; 00049 size_t my_size; 00051 affinity_partitioner_base_v3() : my_array(NULL), my_size(0) {} 00053 ~affinity_partitioner_base_v3() {resize(0);} 00055 00056 void __TBB_EXPORTED_METHOD resize( unsigned factor ); 00057 friend class affinity_partition_type; 00058 }; 00059 00061 class partition_type_base { 00062 public: 00063 void set_affinity( task & ) {} 00064 void note_affinity( task::affinity_id ) {} 00065 task* continue_after_execute_range() {return NULL;} 00066 bool decide_whether_to_delay() {return false;} 00067 void spawn_or_delay( bool, task& b ) { 00068 task::spawn(b); 00069 } 00070 }; 00071 00072 class affinity_partition_type; 00073 00074 template<typename Range, typename Body, typename Partitioner> class start_for; 00075 template<typename Range, typename Body, typename Partitioner> class start_reduce; 00076 template<typename Range, typename Body> class start_reduce_with_affinity; 00077 template<typename Range, typename Body, typename Partitioner> class start_scan; 00078 00079 } // namespace internal 00081 00083 00085 class simple_partitioner { 00086 public: 00087 simple_partitioner() {} 00088 private: 00089 template<typename Range, typename Body, typename Partitioner> friend class internal::start_for; 00090 template<typename Range, typename Body, typename Partitioner> friend class internal::start_reduce; 00091 template<typename Range, typename Body, typename Partitioner> friend class internal::start_scan; 00092 00093 class partition_type: public internal::partition_type_base { 00094 public: 00095 bool should_execute_range(const task& ) {return false;} 00096 partition_type( const simple_partitioner& ) {} 00097 partition_type( const partition_type&, split ) {} 00098 }; 00099 }; 00100 00102 00105 class auto_partitioner { 00106 public: 00107 auto_partitioner() {} 00108 00109 private: 00110 template<typename Range, typename Body, typename Partitioner> friend class internal::start_for; 00111 template<typename Range, typename Body, typename Partitioner> friend class internal::start_reduce; 00112 template<typename Range, typename Body, typename Partitioner> friend class internal::start_scan; 00113 00114 class partition_type: public internal::partition_type_base { 00115 size_t num_chunks; 00116 static const size_t VICTIM_CHUNKS = 4; 00117 public: 00118 bool should_execute_range(const task &t) { 00119 if( num_chunks<VICTIM_CHUNKS && t.is_stolen_task() ) 00120 num_chunks = VICTIM_CHUNKS; 00121 return num_chunks==1; 00122 } 00123 partition_type( const auto_partitioner& ) : num_chunks(internal::get_initial_auto_partitioner_divisor()) {} 00124 partition_type( partition_type& pt, split ) { 00125 num_chunks = pt.num_chunks /= 2u; 00126 } 00127 }; 00128 }; 00129 00131 class affinity_partitioner: internal::affinity_partitioner_base_v3 { 00132 public: 00133 affinity_partitioner() {} 00134 00135 private: 00136 template<typename Range, typename Body, typename Partitioner> friend class internal::start_for; 00137 template<typename Range, typename Body, typename Partitioner> friend class internal::start_reduce; 00138 template<typename Range, typename Body> friend class internal::start_reduce_with_affinity; 00139 template<typename Range, typename Body, typename Partitioner> friend class internal::start_scan; 00140 00141 typedef internal::affinity_partition_type partition_type; 00142 friend class internal::affinity_partition_type; 00143 }; 00144 00146 namespace internal { 00147 00148 class affinity_partition_type: public no_copy { 00150 static const unsigned factor = 16; 00151 static const size_t VICTIM_CHUNKS = 4; 00152 00153 internal::affinity_id* my_array; 00154 task_list delay_list; 00155 unsigned map_begin, map_end; 00156 size_t num_chunks; 00157 public: 00158 affinity_partition_type( affinity_partitioner& ap ) { 00159 __TBB_ASSERT( (factor&(factor-1))==0, "factor must be power of two" ); 00160 ap.resize(factor); 00161 my_array = ap.my_array; 00162 map_begin = 0; 00163 map_end = unsigned(ap.my_size); 00164 num_chunks = internal::get_initial_auto_partitioner_divisor(); 00165 } 00166 affinity_partition_type(affinity_partition_type& p, split) : my_array(p.my_array) { 00167 __TBB_ASSERT( p.map_end-p.map_begin<factor || (p.map_end-p.map_begin)%factor==0, NULL ); 00168 num_chunks = p.num_chunks /= 2; 00169 unsigned e = p.map_end; 00170 unsigned d = (e - p.map_begin)/2; 00171 if( d>factor ) 00172 d &= 0u-factor; 00173 map_end = e; 00174 map_begin = p.map_end = e-d; 00175 } 00176 00177 bool should_execute_range(const task &t) { 00178 if( num_chunks < VICTIM_CHUNKS && t.is_stolen_task() ) 00179 num_chunks = VICTIM_CHUNKS; 00180 return num_chunks == 1; 00181 } 00182 00183 void set_affinity( task &t ) { 00184 if( map_begin<map_end ) 00185 t.set_affinity( my_array[map_begin] ); 00186 } 00187 void note_affinity( task::affinity_id id ) { 00188 if( map_begin<map_end ) 00189 my_array[map_begin] = id; 00190 } 00191 task* continue_after_execute_range() { 00192 task* first = NULL; 00193 if( !delay_list.empty() ) { 00194 first = &delay_list.pop_front(); 00195 while( !delay_list.empty() ) { 00196 task::spawn(*first); 00197 first = &delay_list.pop_front(); 00198 } 00199 } 00200 return first; 00201 } 00202 bool decide_whether_to_delay() { 00203 // The possible underflow caused by "-1u" is deliberate 00204 return (map_begin&(factor-1))==0 && map_end-map_begin-1u<factor; 00205 } 00206 void spawn_or_delay( bool delay, task& b ) { 00207 if( delay ) 00208 delay_list.push_back(b); 00209 else 00210 task::spawn(b); 00211 } 00212 00213 ~affinity_partition_type() { 00214 // The delay_list can be non-empty if an exception is thrown. 00215 while( !delay_list.empty() ) { 00216 task& t = delay_list.pop_front(); 00217 t.destroy(t); 00218 } 00219 } 00220 }; 00221 00222 } // namespace internal 00224 00225 00226 } // namespace tbb 00227 00228 #endif /* __TBB_partitioner_H */
Copyright © 2007-2010 by The Shadowrun: Awakened Team. This work is licensed under the GNU Lesser General Public License 3.