partitioner.h

00001 /*
00002     Copyright 2005-2011 Intel Corporation.  All Rights Reserved.
00003 
00004     The source code contained or described herein and all documents related
00005     to the source code ("Material") are owned by Intel Corporation or its
00006     suppliers or licensors.  Title to the Material remains with Intel
00007     Corporation or its suppliers and licensors.  The Material is protected
00008     by worldwide copyright laws and treaty provisions.  No part of the
00009     Material may be used, copied, reproduced, modified, published, uploaded,
00010     posted, transmitted, distributed, or disclosed in any way without
00011     Intel's prior express written permission.
00012 
00013     No license under any patent, copyright, trade secret or other
00014     intellectual property right is granted to or conferred upon you by
00015     disclosure or delivery of the Materials, either expressly, by
00016     implication, inducement, estoppel or otherwise.  Any license under such
00017     intellectual property rights must be express and approved by Intel in
00018     writing.
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 } // namespace internal
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         // The possible underflow caused by "-1u" is deliberate
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         // The delay_list can be non-empty if an exception is thrown.
00205         while( !delay_list.empty() ) {
00206             task& t = delay_list.pop_front();
00207             t.destroy(t);
00208         } 
00209     }
00210 };
00211 
00212 } // namespace internal
00214 
00215 
00216 } // namespace tbb
00217 
00218 #endif /* __TBB_partitioner_H */

Copyright © 2005-2011 Intel Corporation. All Rights Reserved.

Intel, Pentium, Intel Xeon, Itanium, Intel XScale and VTune are registered trademarks or trademarks of Intel Corporation or its subsidiaries in the United States and other countries.

* Other names and brands may be claimed as the property of others.