default_partitioner.h

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_

Generated on Tue Aug 31 15:30:27 2010 for CnC by  doxygen 1.5.6