00001 //******************************************************************************** 00002 // Copyright 2007-2010 Intel Corporation All Rights Reserved. ** 00003 // ** 00004 // The source code contained or described herein and all documents related to ** 00005 // the source code ("Material") are owned by Intel Corporation or its suppliers ** 00006 // or licensors. Title to the Material remains with Intel Corporation or its ** 00007 // suppliers and licensors. The Material contains trade secrets and proprietary ** 00008 // and confidential information of Intel or its suppliers and licensors. The ** 00009 // Material is protected by worldwide copyright and trade secret laws and ** 00010 // treaty provisions. No part of the Material may be used, copied, reproduced, ** 00011 // modified, published, uploaded, posted, transmitted, distributed, or ** 00012 // disclosed in any way without Intel's prior express written permission. ** 00013 // ** 00014 // No license under any patent, copyright, trade secret or other intellectual ** 00015 // property right is granted to or conferred upon you by disclosure or delivery ** 00016 // of the Materials, either expressly, by implication, inducement, estoppel or ** 00017 // otherwise. Any license under such intellectual property rights must be ** 00018 // express and approved by Intel in writing. ** 00019 //******************************************************************************** 00020 00021 00022 #ifndef _DEFAULT_PARTITIONER_H_ 00023 #define _DEFAULT_PARTITIONER_H_ 00024 00025 #include <tbb/task_scheduler_init.h> 00026 #include <cstdlib> 00027 00028 namespace CnC { 00029 00030 class range_is_tag_type {}; 00031 class range_is_range_type {}; 00032 00033 /// \brief Interface for partitioners: configuring how ranges are partitioned. 00034 /// 00035 /// The default_partitioner implements the template interface that each partitioner must satisfy. 00036 /// 00037 /// Given a range type "R", a partitioner "P" must provide a copy-constructor 00038 /// and the following (template) interface: 00039 /// - int size() const; 00040 /// - template< typename T > void divide_and_originate( R &, T & ) const; 00041 /// - bool is_divisible( const R & ) const; 00042 /// - int grain_size( size_t fullRangeSize ) const; 00043 /// - split_type 00044 /// 00045 /// The default_partitioner can be parametrized as follows: 00046 /// Set template argument to > 0 to let it use a fixed grainsize. 00047 /// If it equals 0, the grainsize is set to "original_rangeSize / #threads / 4" 00048 template< int grainSize = 0 > 00049 class default_partitioner 00050 { 00051 public: 00052 default_partitioner() : m_grainSize( grainSize ) 00053 { 00054 // std::cerr << "d"; 00055 } 00056 default_partitioner( const default_partitioner< grainSize > & o ) : m_grainSize( o.m_grainSize ) 00057 { 00058 // std::cerr << "c"; 00059 } 00060 /// \brief divide given range into in arbitrary number of ranges of type Range 00061 /// 00062 /// Call si.originate_range( r ) for each new range. 00063 /// The original - but modified - range is treated as unsplittable afterwards. It must *not* be passed to originate_range! 00064 /// If tag-types are self-dividing (e.g. if range-type == tag-type) you can call "originate" 00065 /// instead of "originate_range" for leaves of the recursive range-tree. 00066 /// 00067 /// The aggregated set of the members of the sub-ranges applied to "t.originate[_range]" must equal the set of member in given range. 00068 /// Overlapping ranges or gaps may lead to arbitrary effects. 00069 /// 00070 /// \param range the original range to split, may be altered 00071 /// \param si opaque object, call t.Put( r, splittable ) for all sub-ranges 00072 template< typename Range, typename StepInstance > 00073 inline void divide_and_originate( Range & range, StepInstance & si ) const; 00074 00075 /// \brief return true, if given range is divisible, false otherwise 00076 template< typename Range > 00077 bool is_divisible( const Range & range ) const; 00078 00079 /// \return grainsize for given size of unsplitted range 00080 int grain_size( size_t fullRangeSize ) const; 00081 00082 /// set to range_is_tag_type if tag is self-dividing, e.g. if the range-type is also the tag-type as passed to the step 00083 /// set to range_is_range_type if tag is undivisible, e.g. if range-type != step_type 00084 typedef range_is_range_type split_type; 00085 00086 private: 00087 template< typename Range > 00088 bool is_divisible( const Range & range, int grain ) const; 00089 // actual implemenation of divide_and_originate, avoiding repeated access to range.size() and grain_size() 00090 template< typename Range, typename StepInstance > 00091 void divide_and_originate( Range & range, StepInstance & si, const int grain ) const; 00092 int m_grainSize; 00093 }; 00094 00095 00096 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00097 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00098 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00099 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00100 00101 template< int grainSize > 00102 inline int default_partitioner< grainSize >::grain_size( size_t rangeSize ) const 00103 { 00104 if( grainSize > 0 ) return grainSize; 00105 else { 00106 if( m_grainSize <= 0 ) { 00107 static int _nt = 0; 00108 if( _nt == 0 ) { 00109 if( getenv( "CNC_NUM_THREADS" ) ) { 00110 _nt = atoi( getenv( "CNC_NUM_THREADS" ) ); 00111 } else { 00112 _nt = tbb::task_scheduler_init::default_num_threads(); 00113 } 00114 } 00115 #define MX( _a, _b ) ((_a) > (_b) ? (_a) : (_b)) 00116 const_cast< int & >( m_grainSize ) = rangeSize > 0 ? MX( 1, (int)(rangeSize / (size_t)_nt / 4) ) : 1; 00117 } 00118 return m_grainSize; 00119 } 00120 } 00121 00122 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00123 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00124 00125 template< int grainSize > 00126 template< typename Range, typename StepInstance > 00127 inline void default_partitioner< grainSize >::divide_and_originate( Range & range, StepInstance & si, const int grain ) const 00128 { 00129 while( (int)range.size() > grain && range.is_divisible() ) { 00130 Range _r( range, tbb::split() ); 00131 si.originate_range( _r ); 00132 } 00133 } 00134 00135 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00136 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00137 00138 template< int grainSize > 00139 template< typename Range, typename StepInstance > 00140 inline void default_partitioner< grainSize >::divide_and_originate( Range & range, StepInstance & si ) const 00141 { 00142 divide_and_originate( range, si, grain_size( range.size() ) ); 00143 } 00144 00145 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00146 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00147 00148 template< int grainSize > 00149 template< typename Range > 00150 inline bool default_partitioner< grainSize >::is_divisible( const Range & range ) const 00151 { 00152 return is_divisible( range, grain_size( range.size() ) ); 00153 } 00154 00155 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00156 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00157 00158 template< int grainSize > 00159 template< typename Range > 00160 bool default_partitioner< grainSize >::is_divisible( const Range & range, int grain ) const 00161 { 00162 return ( (int)range.size() > grain ) && range.is_divisible(); 00163 } 00164 00165 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00166 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00167 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00168 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00169 00170 /// Use this instead of default_partitioner if your tag is self-dividing (e.g. a range) 00171 /// and you want to use the partitioning mechanism through cnC::tag_collection::put_range 00172 template< int grainSize = 0 > 00173 class tag_partitioner : public default_partitioner< grainSize > 00174 { 00175 public: 00176 template< typename Range, typename StepInstance > 00177 inline void divide_and_originate( Range & range, StepInstance & si ) const; 00178 typedef range_is_tag_type split_type; 00179 00180 private: 00181 template< typename Range, typename StepInstance > 00182 void divide_and_originate( Range & range, StepInstance & si, const int grain ) const; 00183 }; 00184 00185 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00186 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00187 00188 template< int grainSize > 00189 template< typename Range, typename StepInstance > 00190 inline void tag_partitioner< grainSize >::divide_and_originate( Range & range, StepInstance & si, const int grain ) const 00191 { 00192 while( (int)range.size() > grain && range.is_divisible() ) { 00193 Range _r( range, tbb::split() ); 00194 si.originate_range( _r ); 00195 } 00196 si.originate( range ); 00197 } 00198 00199 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00200 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00201 00202 template< int grainSize > 00203 template< typename Range, typename StepInstance > 00204 inline void tag_partitioner< grainSize >::divide_and_originate( Range & range, StepInstance & si ) const 00205 { 00206 divide_and_originate( range, si, grain_size( range.size() ) ); 00207 } 00208 00209 } // namspace CnC 00210 00211 #endif // _DEFAULT_PARTITIONER_H_
1.5.6