CnC
 All Classes Namespaces Functions Variables Typedefs Enumerator Friends
default_tuner.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 tuner interface(s).
00030 */
00031 
00032 #ifndef CNC_DEFAULT_TUNER_H_ALREADY_INCLUDED
00033 #define CNC_DEFAULT_TUNER_H_ALREADY_INCLUDED
00034 
00035 #include <cnc/internal/cnc_api.h>
00036 #include <cnc/default_partitioner.h>
00037 #include <cnc/internal/step_delayer.h>
00038 #include <cnc/internal/cnc_tag_hash_compare.h>
00039 #include <cnc/internal/no_range.h>
00040 #include <cnc/internal/no_tag_table.h>
00041 #include <cnc/internal/hash_tag_table.h>
00042 #include <cnc/internal/item_properties.h>
00043 #include <cnc/internal/item_properties.h>
00044 #include <cnc/internal/dist/distributor.h>
00045 #include <tbb/atomic.h>
00046 #include <tbb/concurrent_unordered_set.h>
00047 //#include <tbb/concurrent_hash_map.h>
00048 
00049 namespace CnC {
00050 
00051     template< class T > class context;
00052     namespace Internal {
00053         template< class Tag, class Range, class StepColl, class RangeStepI, class TIR, bool deps > struct range_step;
00054     }
00055 
00056     // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00057     // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00058 
00059     // Key-words tuning
00060     enum {
00061         COMPUTE_ON_LOCAL       = -2,  ///< let tuner::compute_on return COMPUTE_ON_LOCAL if the step should be executed locally
00062         COMPUTE_ON_ROUND_ROBIN = -3,  ///< let tuner::compute_on return COMPUTE_ON_ROUND_ROBIN to let the scheduler distribute it in a round-robin fashion
00063         COMPUTE_ON_ALL         = -4,  ///< let tuner::compute_on return COMPUTE_ON_ALL if the step should be executed on all processes, as well as locally
00064         COMPUTE_ON_ALL_OTHERS  = -5,  ///< let tuner::compute_on return COMPUTE_ON_ALL_OTHERS if the step should be executed on all processes, but not locally    
00065         PRODUCER_UNKNOWN    = -6,  ///< producer process of dependent item is unknown
00066         PRODUCER_LOCAL      = -7,  ///< producer process of dependent item is local process
00067         CONSUMER_UNKNOWN    = -8,  ///< consumer process of given item is unkown
00068         CONSUMER_LOCAL      = -9,  ///< consumer process of given item is the local process
00069         CONSUMER_ALL        = -10, ///< all processes consume given item
00070         CONSUMER_ALL_OTHERS = -11, ///< all processes but this consume given item
00071         NO_GETCOUNT         = Internal::item_properties::NO_GET_COUNT,   ///< no get-count specified
00072         AFFINITY_HERE       = Internal::scheduler_i::AFFINITY_HERE       ///< default affinity to current thread
00073     };
00074 
00075     // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00076     // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00077 
00078     /// Functionality that might be needed to implement all kinds of tuners.
00079     /// Always try to use higher level tuners which derive from this.
00080     /// Always use virtual inheritance (see higher level tuners).
00081     class tuner_base
00082     {
00083     public:
00084         /// returns id/rank of calling process
00085         /// defaults to 0 if running on one process only.
00086         inline static int myPid()
00087         {
00088             return Internal::distributor::myPid();
00089         }
00090         /// return total number of processes participating in this programm execution
00091         /// defaults to 1 if running on one process only.
00092         inline static int numProcs()
00093         {
00094             return Internal::distributor::numProcs();
00095         }
00096         /// returns number of threads used by scheduler in given context
00097         template< typename Ctxt >
00098         inline static int numThreads( const Ctxt & ctxt )
00099         {
00100             return ctxt.numThreads();
00101         }
00102     };
00103 
00104 
00105     // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00106     // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00107 
00108     /// \brief Default (NOP) implementations of the step_tuner interface.
00109     ///
00110     /// Also defines the interface a user-provided tuner must satisfy.
00111     /// Derive your tuner from this (to avoid implementing the entire interface).
00112     ///
00113     /// It is recommended that your tuner does not implement the methods as templates.
00114     /// Instead, you should use the actual types that it expects.
00115     ///
00116     /// \#include <cnc/default_tuner.h>
00117     template< bool check_deps = true >
00118     struct /*CNC_API*/ step_tuner : public virtual tuner_base
00119     {
00120         /// \brief Allows definition of priorities to individual steps (which are identified by the tag).
00121         /// \return the default implementation always return 1.
00122         /// \param tag the tag which identifies the step to be executed
00123         /// \param arg the argument as passed to context< Derived >::prescribed (usually the context)
00124         /// \see also CNCROOT/samples/floyd_warshall
00125         template< typename Tag, typename Arg >
00126         int priority( const Tag & tag, Arg & arg ) const
00127         {
00128             return 1;
00129         }
00130 
00131         /// \brief Allows declaration of data dependencies (to items) of
00132         /// given step (identified by the tag).
00133         ///
00134         /// When a step-instance is prescribed through a corresponding
00135         /// tag_collection::put, this method will be called.  You can
00136         /// declare dependencies to items by calling
00137         /// dC.depends( item_collection, dependent_item_tag )
00138         /// for every item the step is going to 'get' in its execute
00139         /// method. The actual step execution will be delayed until
00140         /// all dependencies can be satisfied.  The default
00141         /// implementation does nothing (NOP). Your implementation
00142         /// must accept dC by reference (T&).
00143         /// \param tag the tag which identifies the step to be executed.
00144         /// \param arg the argument as passed to context< Derived >::prescribed
00145         ///            (usually the context)
00146         /// \param dC  opaque object (must be by reference!) providing method depends
00147         ///            to declare item dependencies
00148         template< typename Tag, typename Arg, typename T >
00149         void depends( const Tag & tag, Arg & arg, T & dC ) const
00150         {
00151         }
00152 
00153         /// \brief Returns whether the step should be pre-scheduled 
00154         ///
00155         /// Pre-scheduling provides an alternative method for detecting
00156         /// data dependencies, in particular if it is combined with
00157         /// item_collection::unsafe_get and context::flush_gets() in the
00158         /// step-code.
00159         ///
00160         /// The step instance will be run immediately when prescribed
00161         /// by a tag_collection::put. All items that are not yet
00162         /// available when accessed by the blocking
00163         /// item_collection::get() and/or non-blocking
00164         /// item_collection::unsafe_get() methods will automatically
00165         /// be treated as dependent items. The pre-run will end at the
00166         /// first unsuccessful blocking get or at
00167         /// context::flush_gets() (if any items got through
00168         /// item_collection::unsafe_get() were unavailable). Execution
00169         /// stops by throwing an exception, similar to un unsuccessful
00170         /// item_collection::get(). The step execution will be delayed
00171         /// until all detected dependencies can be satisfied.
00172         /// \note If all dependent items are available in the pre-scheduling
00173         ///       execution the step gets fully executed. This can lead to
00174         ///       very deep call-stacks if items are always available and
00175         ///       new control is produced in steps.
00176         bool preschedule() const
00177         {
00178             return false;
00179         }
00180                   
00181         /// \brief Tell the scheduler the preferred thread for executing given step
00182         ///
00183         /// Not all schedulers might actually evaluate this call (see \ref scheduler);
00184         /// it involves a virtual function call whenever a step is (re-)scheduled.
00185         /// This feature is most useful in combination with 
00186         /// the CNC_PIN_THREADS environment variable (\ref priorpin).
00187         /// \return thread id or AFFINITY_HERE (default)
00188         template< typename Tag, typename Arg >
00189         int affinity( const Tag & /*tag*/, Arg & /*arg*/ ) const
00190         {
00191             return AFFINITY_HERE;
00192         }
00193 
00194         /// \brief tell the scheduler on which process to run the step
00195         /// (or range of steps) (distCnC)
00196         ///
00197         /// return process id where the step will be executed, or
00198         /// COMPUTE_ON_ROUND_ROBIN, or COMPUTE_ON_LOCAL, or
00199         /// COMPUTE_ON_ALL, or COMPUTE_ON_ALL_OTHERS
00200         template< typename Tag, typename Arg >
00201         int compute_on( const Tag & /*tag*/, Arg & /*arg*/ ) const
00202         {
00203             return COMPUTE_ON_ROUND_ROBIN;
00204         }
00205 
00206         /// \brief true if steps launched through ranges consume items
00207         /// or need global locking, false otherwise.
00208         ///
00209         /// Avoiding checks for dependencies and global locks saves
00210         /// overhead and will perform better (e.g. for parallel_for).
00211         /// Safe execution (with checks) is the default (check_deps
00212         /// template argument).
00213         static const bool check_deps_in_ranges = check_deps;
00214 
00215         /// \brief check for cancelation of given step
00216         ///
00217         /// \return true if step was canceled, false otherwise (default)
00218         /// \note Must be thread-safe.
00219         /// Runtime will try to not execute the step, but it might still get executed.
00220         /// Best effort - but no guarantees.
00221         /// Canceling steps makes all determinism guarantees void.
00222         ///
00223         /// For distributed memory your implementation might require to sync its state
00224         /// across processes. Currently there is no API exposed to do that conveniently.
00225         /// However, an example implementatino CnC::cancel_tuner is provided which
00226         /// works on distributed memory.
00227         /// \see also CNCROOT/samples/floyd_warshall
00228         template< typename Tag, typename Arg >
00229         int was_canceled( const Tag & /*tag*/, Arg & /*arg*/ ) const
00230         {
00231             return false;
00232         }
00233 
00234         /// \brief check if given step-instance needs to be executed sequentially
00235         /// \return false by default, if true, step-instance gets queued for execution
00236         ///         in a sequential phase (after all workers are quienscent)
00237         template< typename Tag, typename Arg >
00238         bool sequentialize( const Tag & /*tag*/, Arg & /*arg*/ ) const
00239         {
00240             return false;
00241         }
00242     };
00243 
00244     // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00245 
00246     /// \brief Default (NOP) implementations of the pfor_tuner interface.
00247     ///
00248     /// Also defines the interface a user-provided step-tuner must satisfy.
00249     /// Derive your tuner from this (to avoid implementing the entire interface).
00250     ///
00251     /// It is recommended that your tuner does not implement the methods as templates.
00252     /// Instead, you should use the actual types that it expects.
00253     ///
00254     /// \#include <cnc/default_tuner.h>
00255     template< bool check_deps = true, typename Partitioner = default_partitioner<>  >
00256     struct /*CNC_API*/ pfor_tuner : public virtual tuner_base
00257     {
00258         template< typename Tag, typename Arg >
00259         int priority( const Tag & tag, Arg & arg ) const
00260         {
00261             return 1;
00262         }
00263 
00264         template< typename Tag, typename Arg, typename T >
00265         void depends( const Tag & tag, Arg & arg, T & dC ) const
00266         {
00267         }
00268 
00269         bool preschedule() const
00270         {
00271             return false;
00272         }
00273 
00274         template< typename Tag, typename Arg >
00275         int affinity( const Tag & /*tag*/, Arg & /*arg*/ ) const
00276         {
00277             return AFFINITY_HERE;
00278         }
00279 
00280         static const bool check_deps_in_ranges = check_deps;
00281 
00282         typedef Partitioner partitioner_type;
00283 
00284         partitioner_type partitioner() const
00285         {
00286             return typename pfor_tuner< check_deps, Partitioner >::partitioner_type();
00287         }
00288     };
00289 
00290     // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00291     // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00292 
00293     namespace CT {
00294 #ifdef _DIST_CNC_
00295         static const char SINGLE  = 0; // single tag
00296         static const char ALL     = 1; // cancel all
00297         static const char RESET   = 2; // reset
00298 #endif
00299     }
00300 
00301     /// \brief Step tuner with convenient cancelation capabilities
00302     ///
00303     /// Allows cancelation of individual step-instances by their tags as well as
00304     /// canceling all instances at once. All cancelation requests are "active" until
00305     /// unsafe_reset() is called (or the tuner is destructed).
00306     ///
00307     /// To use it, you need a cancel_tuner object in your context which you pass
00308     /// to the constructor of the respective step_collection.
00309     ///
00310     /// It works on distributed memory but might perform poorly if used frequently.
00311     ///
00312     /// \param Tag tag-type
00313     /// \param check_deps if false, avoid some mechanics to handle unavailable items
00314     /// \param Hasher hash-functor for Tag, defaults to tbb::tbb_hash< Tag >
00315     /// \param Equality equality operator for Tag, defaults to std::equal_to< Tag >
00316     /// \note It is assumed that cancelation per instance happens relatively rarely. Hence
00317     ///       no automatic garbage collection of the tags is provided. If you cancel individual
00318     ///       step-instances frequently, it is recommended to prune the internal data structure
00319     ///       from time to time in a safe state through unsafe_reset().
00320     /// \see also CNCROOT/samples/floyd_warshall
00321     template< typename Tag, bool check_deps = true,
00322               typename Hasher = cnc_hash< Tag >, typename Equality = cnc_equal< Tag > >
00323     class cancel_tuner : public step_tuner< check_deps >, public Internal::distributable
00324     {
00325     public:
00326         template< typename C >
00327         cancel_tuner( C & ctxt )
00328             : Internal::distributable( "cancel_tuner" ), m_context( ctxt ), m_canceledTags(), m_cancelAll()
00329         {
00330             m_context.subscribe( this );
00331             m_cancelAll = false;
00332         }
00333 
00334         ~cancel_tuner()
00335         {
00336             m_context.unsubscribe( this );
00337         }
00338 
00339         /// \brief cancel given step (identified by tag)
00340         void cancel( const Tag & t, bool from_msg = false  )
00341         {
00342             if( ! m_cancelAll ) {
00343 #ifdef _DIST_CNC_
00344                 if( !from_msg && Internal::distributor::numProcs() > 1 ) {
00345                     serializer * _ser = m_context.new_serializer( this );
00346                     (*_ser) & CT::SINGLE & t;
00347                     m_context.bcast_msg( _ser ); 
00348                 }
00349 #endif
00350                 m_canceledTags.insert( t );
00351             }
00352         }
00353 
00354         /// \brief cancel all steps
00355         void cancel_all( bool from_msg = false )
00356         {
00357 #ifdef _DIST_CNC_
00358             if( !from_msg && Internal::distributor::numProcs() > 1 ) {
00359                 serializer * _ser = m_context.new_serializer( this );
00360                 (*_ser) & CT::ALL;
00361                 m_context.bcast_msg( _ser ); 
00362             }
00363 #endif
00364             m_cancelAll = true;
00365         }
00366 
00367         void unsafe_reset( )
00368         {
00369             unsafe_reset( true );
00370         }
00371 
00372         /// \brief implements/overwrites step_tuner::was_canceled(...)
00373         template< typename Arg >
00374         int was_canceled( const Tag & tag, Arg & /*arg*/ ) const
00375         {
00376             return m_cancelAll == true || m_canceledTags.count( tag ) > 0;
00377         }
00378 
00379         // from distributable
00380         virtual void recv_msg( serializer * ser )
00381         {
00382 #ifdef _DIST_CNC_
00383             CNC_ASSERT( Internal::distributor::active() );
00384             char _msg;
00385             (*ser) & _msg;
00386             switch( _msg ) {
00387             case CT::SINGLE :
00388                 Tag _tag;
00389                 (*ser) & _tag;
00390                 this->cancel( _tag, true );
00391                 break;
00392             case CT::ALL :
00393                 this->cancel_all( true );
00394                 break;
00395             case CT::RESET :
00396                 this->unsafe_reset( false );
00397                 break;
00398             default:
00399                 CNC_ABORT( "Unexpected message received (cancel_tuner)." );
00400             }
00401 #endif
00402         }
00403 
00404     private:
00405         /// \brief reset all current cancel states
00406         /// \note not thread-safe, to be called in safe state only
00407         ///       (between program start or calling context::wait() and putting the first tag or item).
00408         virtual void unsafe_reset( bool dist )
00409         {
00410 #ifdef _DIST_CNC_
00411             if( dist && Internal::distributor::numProcs() > 1 ) {
00412                 serializer * _ser = m_context.new_serializer( this );
00413                 (*_ser) & CT::RESET;
00414                 m_context.bcast_msg( _ser ); 
00415             }
00416 #endif
00417             m_canceledTags.clear();
00418             m_cancelAll = false;
00419         }
00420 
00421         Internal::distributable_context & m_context;
00422         tbb::concurrent_unordered_set< Tag, Hasher, Equality > m_canceledTags;
00423         tbb::atomic< bool > m_cancelAll;
00424     };
00425 
00426 
00427     // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00428     // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00429 
00430     /// \brief Default implementations of the item-tuner interface for item-collections
00431     ///
00432     /// Usually you will not need to use this directly for anything else than documentation and interface.
00433     template< template< typename T, typename I, typename A > class TT >
00434     struct item_tuner : public virtual tuner_base
00435     {
00436         /// \brief Defines the type of the internal data store.
00437         ///
00438         /// It forwards the functionality of the template parameter template.
00439         /// The expected interface of the template is not yet exposed.
00440         /// Use hashmap_tuner or vector_tuner to derive your own tuner.
00441         template< typename Tag, typename Item, typename Coll >
00442         struct table_type : public TT< Tag, Item, Coll >
00443         {
00444             table_type( const Coll * c, size_t sz = 0 ) : TT< Tag, Item, Coll >( c, sz ) {}
00445         };
00446         
00447         /// \brief Initialize the internal storage.
00448         ///
00449         /// Can be used to configure the storage table.
00450         /// Called in the collection constructor.
00451         template< typename Tag, typename Item, typename Coll >
00452         void init_table( TT< Tag, Item, Coll > & stbl ) const
00453         {}
00454 
00455         /// \brief Allows specifying the number of gets to the given item.
00456         ///
00457         /// After get_count() many 'get()'s the item can be removed from the collection.
00458         /// By default, the item is not removed until the collection is deleted.
00459         /// Gets by the environment are ignored, use CnC::NO_GETCOUNT for items 
00460         /// which are consumed by the environment.
00461         /// \param tag the tag which identifies the item
00462         /// \return number of expected gets to this item, or CNC::NO_GETCOUNT
00463         template< typename Tag >
00464         int get_count( const Tag & tag ) const
00465         {
00466             return NO_GETCOUNT;
00467         }
00468 
00469         /// \brief Tells the scheduler on which process(es) this item is going to be consumed
00470         ///
00471         /// return process id where the item will be consumed (get), or CONSUMER_UNKNOWN (default)
00472         ///     or std::vector<int>, containing all ids of consuming processes.
00473         ///        To indicate that the consumer processes are unknown, return an empty vector.
00474         ///        The vector must contain special values like CONSUMER_LOCAL.
00475         /// If not CnC::CONSUMER_UKNOWN (or empty vector), this declaration will overwrite what
00476         /// the step-tuner might declare in depends.
00477         /// Providing this method leads to the most efficient communication pattern for
00478         /// to getting the data to where it is needed.
00479         /// \param tag the tag which identifies the item
00480         template< typename Tag >
00481         int consumed_on( const Tag & tag ) const
00482         {
00483             return CONSUMER_UNKNOWN;
00484         }
00485 
00486         /// \brief Tells the scheduler on which process(es) this item is going to be produced
00487         ///
00488         /// return process id where the item will be produced. If unknown return CnC::PRODUCER_UNKNOWN.
00489         /// return PRODUCER_LOCAL if local process is the owner.
00490         /// Implementing this method reduces the communication cost for locating and sending data.
00491         /// Implementing item_tuner::consumed_on is more efficient, but might be more complicated.
00492         /// Will be evaluated only if item_tuner::consumed_on returns CnC::CONSUMER_UNKNOWN
00493         /// \param tag the tag which identifies the item
00494         template< typename Tag >
00495         int produced_on( const Tag & tag ) const
00496         {
00497             return PRODUCER_UNKNOWN;
00498         }
00499     };
00500 
00501     // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00502 
00503     namespace Internal {
00504         template< typename Tag, typename ItemT, typename Coll > class hash_item_table;
00505         template< typename Tag, typename ItemT, typename Coll > class vec_item_table;
00506     }
00507 
00508     /// \brief The tuner base for hashmap-based item-tuners.
00509     ///
00510     /// The internal hash-map uses cnc_tag_hash_compare. If your
00511     /// tag-type is not supported by default, you need to provide a
00512     /// template specialization for it.
00513     struct hashmap_tuner : public item_tuner< Internal::hash_item_table >
00514     {
00515     };
00516 
00517     // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00518 
00519     /// \brief The tuner base for vector-based item-tuners.
00520     ///
00521     /// Your tags must be convertable to and from size_t.  You must
00522     /// provide the maximum value before accessing the collection
00523     /// (constructor or set_max).  The runtime will allocate as many
00524     /// slots. Hence, use this only if your tags-space is dense,
00525     /// without a large offset and if it is not too large.
00526     struct vector_tuner : public item_tuner< Internal::vec_item_table >
00527     {
00528     };
00529 
00530     // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00531     // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00532 
00533     /// \brief Default implementations of the tag-tuner interface for tag-collections
00534     ///
00535     /// Use this if you are going put ranges. Optional argument is a custom partitioner. 
00536     /// Ranges don't work with memoization (yet)
00537     template< typename Range = Internal::no_range, typename Partitioner = default_partitioner<> >
00538     struct tag_tuner : public virtual tuner_base
00539     {
00540         /// A tag tuner must provide the type of the range, default is no range
00541         typedef Range range_type;
00542         /// A tag tuner must provide a tag-table type; default is no tag-table
00543         typedef Internal::no_tag_table tag_table_type;
00544         /// \brief The type of the partitioner
00545         typedef Partitioner partitioner_type;
00546 
00547         /// \brief return a partitioner for range-based features, such as parallel_for
00548         /// \see default_partitioner for the expected signature of partitioners
00549         /// overwrite partitioner() if it doesn't come with default-constructor or
00550         /// if the default constructor is insufficient.
00551         partitioner_type partitioner() const
00552         {
00553             return typename tag_tuner< Range, Partitioner >::partitioner_type();
00554         }
00555 
00556         /// return true if tag memoization is wanted; returns false by default (with no_tag_table)
00557         bool preserve_tags() const
00558         {
00559             return false;
00560         };
00561     };
00562 
00563     // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00564     
00565     /// Use this if your tag-collection should preserve tags (memoization)
00566     /// \note Memoization doesn't work with ranges (yet)
00567     template< typename Tag, typename H = cnc_hash< Tag >, typename E = cnc_equal< Tag > >
00568     struct preserve_tuner : public tag_tuner< Internal::no_range, default_partitioner<> >
00569     {
00570         /// A tag tuner must provide a tag-table type; default is no tag-table
00571         typedef Internal::hash_tag_table< Tag, H, E > tag_table_type;
00572 
00573         bool preserve_tags() const
00574         {
00575             return true;
00576         };
00577     };
00578 
00579     // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00580     // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00581 
00582     namespace Internal {
00583         template< typename Tuner >
00584         const Tuner & get_default_tuner()
00585         {
00586             static tbb::atomic< Tuner * > s_tuner;
00587             if( s_tuner == NULL ) {
00588                 Tuner * _tmp = new Tuner;
00589                 if( s_tuner.compare_and_swap( _tmp, NULL ) != NULL ) delete _tmp;
00590             }
00591             return *s_tuner;
00592         }
00593     }
00594 
00595 } // end namespace CnC
00596 
00597 #endif //CNC_DEFAULT_TUNER_H_ALREADY_INCLUDED
 All Classes Namespaces Functions Variables Typedefs Enumerator Friends