CnC
 All Classes Namespaces Functions Variables Typedefs Enumerator Friends
default_partitioner.h
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_
 All Classes Namespaces Functions Variables Typedefs Enumerator Friends