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