00001 /* ******************************************************************************* 00002 * Copyright (c) 2007-2014, Intel Corporation 00003 * 00004 * Redistribution and use in source and binary forms, with or without 00005 * modification, are permitted provided that the following conditions are met: 00006 * 00007 * * Redistributions of source code must retain the above copyright notice, 00008 * this list of conditions and the following disclaimer. 00009 * * Redistributions in binary form must reproduce the above copyright 00010 * notice, this list of conditions and the following disclaimer in the 00011 * documentation and/or other materials provided with the distribution. 00012 * * Neither the name of Intel Corporation nor the names of its contributors 00013 * may be used to endorse or promote products derived from this software 00014 * without specific prior written permission. 00015 * 00016 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00017 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00018 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 00019 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 00020 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 00021 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 00022 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 00023 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 00024 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 00025 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00026 ********************************************************************************/ 00027 00028 /* 00029 CnC partitioner interfacem used by CnC tuners. 00030 */ 00031 00032 #ifndef _DEFAULT_PARTITIONER_H_ 00033 #define _DEFAULT_PARTITIONER_H_ 00034 00035 #include <tbb/task_scheduler_init.h> 00036 #include <cstdlib> 00037 00038 namespace CnC { 00039 00040 class range_is_tag_type {}; 00041 class range_is_range_type {}; 00042 00043 /// \brief Interface for partitioners: configuring how ranges are partitioned. 00044 /// 00045 /// The default_partitioner implements the template interface that each partitioner must satisfy. 00046 /// 00047 /// Given a range type "R", a partitioner "P" must provide a copy-constructor 00048 /// and the following (template) interface: 00049 /// - template< typename T > void divide_and_originate( R &, T & ) const; 00050 /// - split_type 00051 /// 00052 /// The default_partitioner can be parametrized as follows: 00053 /// Set template argument to > 0 to let it use a fixed grainsize. 00054 /// If it equals 0, the grainsize is set to "original_rangeSize / #threads / 4" 00055 /// If it is < 0, the grainsize of the given range is obeyed. 00056 template< int grainSize = 0 > 00057 class default_partitioner 00058 { 00059 public: 00060 default_partitioner() 00061 : m_grainSize( grainSize ), 00062 m_nt( getenv( "CNC_NUM_THREADS" ) ? atoi( getenv( "CNC_NUM_THREADS" ) ) : tbb::task_scheduler_init::default_num_threads() ) 00063 { 00064 // std::cerr << "d"; 00065 } 00066 default_partitioner( const default_partitioner< grainSize > & o ) 00067 : m_grainSize( o.m_grainSize ), 00068 m_nt( getenv( "CNC_NUM_THREADS" ) ? atoi( getenv( "CNC_NUM_THREADS" ) ) : tbb::task_scheduler_init::default_num_threads() ) 00069 { 00070 // std::cerr << "c"; 00071 } 00072 /// \brief divide given range into in arbitrary number of ranges of type Range 00073 /// 00074 /// Call si.originate_range( r ) for each new range. 00075 /// The original - but modified - range must *not* be passed to originate_range! 00076 /// If tag-types are self-dividing (e.g. if range-type == tag-type) you should call "originate" 00077 /// instead of "originate_range" for leaves of the recursive range-tree. 00078 /// \return true if the orignal - but modified - range needs further splitting, false if no further splitting is desired. 00079 /// 00080 /// The aggregated set of the members of the sub-ranges applied to "t.originate[_range]" must equal the set of member in given range. 00081 /// Overlapping ranges or gaps may lead to arbitrary effects. 00082 /// 00083 /// \param range the original range to split, may be altered 00084 /// \param si opaque object, call t.originate[_range]( r ) for all split-off sub-ranges 00085 template< typename Range, typename StepInstance > 00086 inline bool divide_and_originate( Range & range, StepInstance & si ) const; 00087 00088 /// 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 00089 /// set to range_is_range_type if tag is undivisible, e.g. if range-type != step_type 00090 typedef range_is_range_type split_type; 00091 00092 protected: 00093 /// \brief return true, if given range is divisible, false otherwise 00094 template< typename Range > 00095 bool is_divisible( const Range & range ) const; 00096 00097 /// \return grainsize for given size of unsplitted range 00098 int grain_size( size_t fullRangeSize ) const; 00099 00100 template< typename Range > 00101 bool is_divisible( const Range & range, int grain ) const; 00102 00103 private: 00104 // actual implemenation of divide_and_originate, avoiding repeated access to range.size() and grain_size() 00105 template< typename Range, typename StepInstance > 00106 bool divide_and_originate( Range & range, StepInstance & si, const int grain ) const; 00107 int m_grainSize; 00108 int m_nt; 00109 }; 00110 00111 00112 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00113 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00114 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00115 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00116 00117 template< int grainSize > 00118 inline int default_partitioner< grainSize >::grain_size( size_t rangeSize ) const 00119 { 00120 if( grainSize != 0 ) return grainSize; 00121 else { 00122 if( m_grainSize <= 0 ) { 00123 #define MX( _a, _b ) ((_a) > (_b) ? (_a) : (_b)) 00124 const_cast< int & >( m_grainSize ) = rangeSize > 0 ? MX( 1, (int)(rangeSize / (size_t)m_nt / 4) ) : 1; 00125 } 00126 return m_grainSize; 00127 } 00128 } 00129 00130 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00131 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00132 00133 template< int grainSize > 00134 template< typename Range, typename StepInstance > 00135 inline bool default_partitioner< grainSize >::divide_and_originate( Range & range, StepInstance & si, const int grain ) const 00136 { 00137 if( this->is_divisible( range, grain ) ) { 00138 Range _r( range, tbb::split() ); 00139 si.originate_range( _r ); 00140 } 00141 return this->is_divisible( range, grain ); 00142 } 00143 00144 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00145 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00146 00147 template< int grainSize > 00148 template< typename Range, typename StepInstance > 00149 inline bool default_partitioner< grainSize >::divide_and_originate( Range & range, StepInstance & si ) const 00150 { 00151 return this->divide_and_originate( range, si, this->grain_size( range.size() ) ); 00152 } 00153 00154 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00155 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00156 00157 template< int grainSize > 00158 template< typename Range > 00159 inline bool default_partitioner< grainSize >::is_divisible( const Range & range ) const 00160 { 00161 return this->is_divisible( range, this->grain_size( range.size() ) ); 00162 } 00163 00164 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00165 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00166 00167 template< int grainSize > 00168 template< typename Range > 00169 bool default_partitioner< grainSize >::is_divisible( const Range & range, int grain ) const 00170 { 00171 return ( grainSize < 0 || (int)range.size() > grain ) && range.is_divisible(); 00172 } 00173 00174 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00175 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00176 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00177 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00178 00179 /// Use this instead of default_partitioner if your tag is self-dividing (e.g. a range) 00180 /// and you want to use the partitioning mechanism through cnC::tag_collection::put_range 00181 template< int grainSize = 0 > 00182 class tag_partitioner : public default_partitioner< grainSize > 00183 { 00184 public: 00185 template< typename Range, typename StepInstance > 00186 inline bool divide_and_originate( Range & range, StepInstance & si ) const; 00187 typedef range_is_tag_type split_type; 00188 00189 private: 00190 template< typename Range, typename StepInstance > 00191 bool divide_and_originate( Range & range, StepInstance & si, const int grain ) const; 00192 }; 00193 00194 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00195 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00196 00197 template< int grainSize > 00198 template< typename Range, typename StepInstance > 00199 inline bool tag_partitioner< grainSize >::divide_and_originate( Range & range, StepInstance & si, const int grain ) const 00200 { 00201 if( this->is_divisible( range, grain ) ) { 00202 Range _r( range, tbb::split() ); 00203 si.originate_range( _r ); 00204 if( this->is_divisible( range, grain ) ) return true; 00205 } 00206 si.originate( range ); 00207 return false; 00208 } 00209 00210 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00211 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00212 00213 template< int grainSize > 00214 template< typename Range, typename StepInstance > 00215 inline bool tag_partitioner< grainSize >::divide_and_originate( Range & range, StepInstance & si ) const 00216 { 00217 return this->divide_and_originate( range, si, this->grain_size( range.size() ) ); 00218 } 00219 00220 } // namspace CnC 00221 00222 #endif // _DEFAULT_PARTITIONER_H_