Shadowrun: Awakened 29 September 2011 - Build 871
partitioner.h
Go to the documentation of this file.
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.

GNU Lesser General Public License 3 Sourceforge.net