00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #ifndef __TBB_parallel_reduce_H
00030 #define __TBB_parallel_reduce_H
00031
00032 #include <new>
00033 #include "task.h"
00034 #include "aligned_space.h"
00035 #include "partitioner.h"
00036 #include "tbb_profiling.h"
00037
00038 namespace tbb {
00039
00040 namespace interface6 {
00042 namespace internal {
00043
00044 using namespace tbb::internal;
00045
00047 enum {
00048 root_task, left_child, right_child
00049 };
00050
00052 typedef char reduction_context;
00053
00055
00056 template<typename Body>
00057 class finish_reduce: public flag_task {
00059 bool has_right_zombie;
00060 const reduction_context my_context;
00061 Body* my_body;
00062 aligned_space<Body,1> zombie_space;
00063 finish_reduce( reduction_context context_ ) :
00064 has_right_zombie(false),
00065 my_context(context_),
00066 my_body(NULL)
00067 {
00068 }
00069 task* execute() {
00070 if( has_right_zombie ) {
00071
00072 Body* s = zombie_space.begin();
00073 my_body->join( *s );
00074 s->~Body();
00075 }
00076 if( my_context==left_child )
00077 itt_store_word_with_release( static_cast<finish_reduce*>(parent())->my_body, my_body );
00078 return NULL;
00079 }
00080 template<typename Range,typename Body_, typename Partitioner>
00081 friend class start_reduce;
00082 };
00083
00085
00086 template<typename Range, typename Body, typename Partitioner>
00087 class start_reduce: public task {
00088 typedef finish_reduce<Body> finish_type;
00089 Body* my_body;
00090 Range my_range;
00091 typename Partitioner::task_partition_type my_partition;
00092 reduction_context my_context;
00093 task* execute();
00094 template<typename Body_>
00095 friend class finish_reduce;
00096
00097 public:
00099 start_reduce( const Range& range, Body* body, Partitioner& partitioner ) :
00100 my_body(body),
00101 my_range(range),
00102 my_partition(partitioner),
00103 my_context(root_task)
00104 {
00105 }
00107
00108 start_reduce( start_reduce& parent_, split ) :
00109 my_body(parent_.my_body),
00110 my_range(parent_.my_range,split()),
00111 my_partition(parent_.my_partition,split()),
00112 my_context(right_child)
00113 {
00114 my_partition.set_affinity(*this);
00115 parent_.my_context = left_child;
00116 }
00118
00119 start_reduce( start_reduce& parent_, const Range& r, depth_t d ) :
00120 my_body(parent_.my_body),
00121 my_range(r),
00122 my_partition(parent_.my_partition,split()),
00123 my_context(right_child)
00124 {
00125 my_partition.set_affinity(*this);
00126 my_partition.align_depth( d );
00127 parent_.my_context = left_child;
00128 }
00130 void note_affinity( affinity_id id ) {
00131 my_partition.note_affinity( id );
00132 }
00133 static void run( const Range& range, Body& body, Partitioner& partitioner ) {
00134 if( !range.empty() ) {
00135 #if !__TBB_TASK_GROUP_CONTEXT || TBB_JOIN_OUTER_TASK_GROUP
00136 task::spawn_root_and_wait( *new(task::allocate_root()) start_reduce(range,&body,partitioner) );
00137 #else
00138
00139
00140 task_group_context context;
00141 task::spawn_root_and_wait( *new(task::allocate_root(context)) start_reduce(range,&body,partitioner) );
00142 #endif
00143 }
00144 }
00145 #if __TBB_TASK_GROUP_CONTEXT
00146 static void run( const Range& range, Body& body, Partitioner& partitioner, task_group_context& context ) {
00147 if( !range.empty() )
00148 task::spawn_root_and_wait( *new(task::allocate_root(context)) start_reduce(range,&body,partitioner) );
00149 }
00150 #endif
00152 finish_type *create_continuation() {
00153 return new( allocate_continuation() ) finish_type(my_context);
00154 }
00156 void run_body( Range &r ) { (*my_body)( r ); }
00157 };
00158 template<typename Range, typename Body, typename Partitioner>
00159 task* start_reduce<Range,Body,Partitioner>::execute() {
00160 my_partition.check_being_stolen( *this );
00161 if( my_context==right_child ) {
00162 finish_type* parent_ptr = static_cast<finish_type*>(parent());
00163 if( !itt_load_word_with_acquire(parent_ptr->my_body) ) {
00164 my_body = new( parent_ptr->zombie_space.begin() ) Body(*my_body,split());
00165 parent_ptr->has_right_zombie = true;
00166 }
00167 } else __TBB_ASSERT(my_context==root_task,NULL);
00168 my_partition.execute(*this, my_range);
00169 if( my_context==left_child ) {
00170 finish_type* parent_ptr = static_cast<finish_type*>(parent());
00171 __TBB_ASSERT(my_body!=parent_ptr->zombie_space.begin(),NULL);
00172 itt_store_word_with_release(parent_ptr->my_body, my_body );
00173 }
00174 return NULL;
00175 }
00176
00178
00179 template<typename Body>
00180 class finish_deterministic_reduce: public task {
00181 Body &my_left_body;
00182 Body my_right_body;
00183
00184 finish_deterministic_reduce( Body &body ) :
00185 my_left_body( body ),
00186 my_right_body( body, split() )
00187 {
00188 }
00189 task* execute() {
00190 my_left_body.join( my_right_body );
00191 return NULL;
00192 }
00193 template<typename Range,typename Body_>
00194 friend class start_deterministic_reduce;
00195 };
00196
00198
00199 template<typename Range, typename Body>
00200 class start_deterministic_reduce: public task {
00201 typedef finish_deterministic_reduce<Body> finish_type;
00202 Body &my_body;
00203 Range my_range;
00204 task* execute();
00205
00207 start_deterministic_reduce( const Range& range, Body& body ) :
00208 my_body( body ),
00209 my_range( range )
00210 {
00211 }
00213
00214 start_deterministic_reduce( start_deterministic_reduce& parent_, finish_type& c ) :
00215 my_body( c.my_right_body ),
00216 my_range( parent_.my_range, split() )
00217 {
00218 }
00219
00220 public:
00221 static void run( const Range& range, Body& body ) {
00222 if( !range.empty() ) {
00223 #if !__TBB_TASK_GROUP_CONTEXT || TBB_JOIN_OUTER_TASK_GROUP
00224 task::spawn_root_and_wait( *new(task::allocate_root()) start_deterministic_reduce(range,&body) );
00225 #else
00226
00227
00228 task_group_context context;
00229 task::spawn_root_and_wait( *new(task::allocate_root(context)) start_deterministic_reduce(range,body) );
00230 #endif
00231 }
00232 }
00233 #if __TBB_TASK_GROUP_CONTEXT
00234 static void run( const Range& range, Body& body, task_group_context& context ) {
00235 if( !range.empty() )
00236 task::spawn_root_and_wait( *new(task::allocate_root(context)) start_deterministic_reduce(range,body) );
00237 }
00238 #endif
00239 };
00240
00241 template<typename Range, typename Body>
00242 task* start_deterministic_reduce<Range,Body>::execute() {
00243 if( !my_range.is_divisible() ) {
00244 my_body( my_range );
00245 return NULL;
00246 } else {
00247 finish_type& c = *new( allocate_continuation() ) finish_type( my_body );
00248 recycle_as_child_of(c);
00249 c.set_ref_count(2);
00250 start_deterministic_reduce& b = *new( c.allocate_child() ) start_deterministic_reduce( *this, c );
00251 task::spawn(b);
00252 return this;
00253 }
00254 }
00255 }
00257 }
00258
00260 namespace internal {
00261 using interface6::internal::start_reduce;
00262 using interface6::internal::start_deterministic_reduce;
00264
00268 template<typename Range, typename Value, typename RealBody, typename Reduction>
00269 class lambda_reduce_body {
00270
00271
00272
00273
00274 const Value& identity_element;
00275 const RealBody& my_real_body;
00276 const Reduction& my_reduction;
00277 Value my_value;
00278 lambda_reduce_body& operator= ( const lambda_reduce_body& other );
00279 public:
00280 lambda_reduce_body( const Value& identity, const RealBody& body, const Reduction& reduction )
00281 : identity_element(identity)
00282 , my_real_body(body)
00283 , my_reduction(reduction)
00284 , my_value(identity)
00285 { }
00286 lambda_reduce_body( const lambda_reduce_body& other )
00287 : identity_element(other.identity_element)
00288 , my_real_body(other.my_real_body)
00289 , my_reduction(other.my_reduction)
00290 , my_value(other.my_value)
00291 { }
00292 lambda_reduce_body( lambda_reduce_body& other, tbb::split )
00293 : identity_element(other.identity_element)
00294 , my_real_body(other.my_real_body)
00295 , my_reduction(other.my_reduction)
00296 , my_value(other.identity_element)
00297 { }
00298 void operator()(Range& range) {
00299 my_value = my_real_body(range, const_cast<const Value&>(my_value));
00300 }
00301 void join( lambda_reduce_body& rhs ) {
00302 my_value = my_reduction(const_cast<const Value&>(my_value), const_cast<const Value&>(rhs.my_value));
00303 }
00304 Value result() const {
00305 return my_value;
00306 }
00307 };
00308
00309 }
00311
00312
00313
00332
00334
00335 template<typename Range, typename Body>
00336 void parallel_reduce( const Range& range, Body& body ) {
00337 internal::start_reduce<Range,Body, const __TBB_DEFAULT_PARTITIONER>::run( range, body, __TBB_DEFAULT_PARTITIONER() );
00338 }
00339
00341
00342 template<typename Range, typename Body>
00343 void parallel_reduce( const Range& range, Body& body, const simple_partitioner& partitioner ) {
00344 internal::start_reduce<Range,Body,const simple_partitioner>::run( range, body, partitioner );
00345 }
00346
00348
00349 template<typename Range, typename Body>
00350 void parallel_reduce( const Range& range, Body& body, const auto_partitioner& partitioner ) {
00351 internal::start_reduce<Range,Body,const auto_partitioner>::run( range, body, partitioner );
00352 }
00353
00355
00356 template<typename Range, typename Body>
00357 void parallel_reduce( const Range& range, Body& body, affinity_partitioner& partitioner ) {
00358 internal::start_reduce<Range,Body,affinity_partitioner>::run( range, body, partitioner );
00359 }
00360
00361 #if __TBB_TASK_GROUP_CONTEXT
00363
00364 template<typename Range, typename Body>
00365 void parallel_reduce( const Range& range, Body& body, const simple_partitioner& partitioner, task_group_context& context ) {
00366 internal::start_reduce<Range,Body,const simple_partitioner>::run( range, body, partitioner, context );
00367 }
00368
00370
00371 template<typename Range, typename Body>
00372 void parallel_reduce( const Range& range, Body& body, const auto_partitioner& partitioner, task_group_context& context ) {
00373 internal::start_reduce<Range,Body,const auto_partitioner>::run( range, body, partitioner, context );
00374 }
00375
00377
00378 template<typename Range, typename Body>
00379 void parallel_reduce( const Range& range, Body& body, affinity_partitioner& partitioner, task_group_context& context ) {
00380 internal::start_reduce<Range,Body,affinity_partitioner>::run( range, body, partitioner, context );
00381 }
00382 #endif
00383
00387
00388
00389 template<typename Range, typename Value, typename RealBody, typename Reduction>
00390 Value parallel_reduce( const Range& range, const Value& identity, const RealBody& real_body, const Reduction& reduction ) {
00391 internal::lambda_reduce_body<Range,Value,RealBody,Reduction> body(identity, real_body, reduction);
00392 internal::start_reduce<Range,internal::lambda_reduce_body<Range,Value,RealBody,Reduction>,const __TBB_DEFAULT_PARTITIONER>
00393 ::run(range, body, __TBB_DEFAULT_PARTITIONER() );
00394 return body.result();
00395 }
00396
00398
00399 template<typename Range, typename Value, typename RealBody, typename Reduction>
00400 Value parallel_reduce( const Range& range, const Value& identity, const RealBody& real_body, const Reduction& reduction,
00401 const simple_partitioner& partitioner ) {
00402 internal::lambda_reduce_body<Range,Value,RealBody,Reduction> body(identity, real_body, reduction);
00403 internal::start_reduce<Range,internal::lambda_reduce_body<Range,Value,RealBody,Reduction>,const simple_partitioner>
00404 ::run(range, body, partitioner );
00405 return body.result();
00406 }
00407
00409
00410 template<typename Range, typename Value, typename RealBody, typename Reduction>
00411 Value parallel_reduce( const Range& range, const Value& identity, const RealBody& real_body, const Reduction& reduction,
00412 const auto_partitioner& partitioner ) {
00413 internal::lambda_reduce_body<Range,Value,RealBody,Reduction> body(identity, real_body, reduction);
00414 internal::start_reduce<Range,internal::lambda_reduce_body<Range,Value,RealBody,Reduction>,const auto_partitioner>
00415 ::run( range, body, partitioner );
00416 return body.result();
00417 }
00418
00420
00421 template<typename Range, typename Value, typename RealBody, typename Reduction>
00422 Value parallel_reduce( const Range& range, const Value& identity, const RealBody& real_body, const Reduction& reduction,
00423 affinity_partitioner& partitioner ) {
00424 internal::lambda_reduce_body<Range,Value,RealBody,Reduction> body(identity, real_body, reduction);
00425 internal::start_reduce<Range,internal::lambda_reduce_body<Range,Value,RealBody,Reduction>,affinity_partitioner>
00426 ::run( range, body, partitioner );
00427 return body.result();
00428 }
00429
00430 #if __TBB_TASK_GROUP_CONTEXT
00432
00433 template<typename Range, typename Value, typename RealBody, typename Reduction>
00434 Value parallel_reduce( const Range& range, const Value& identity, const RealBody& real_body, const Reduction& reduction,
00435 const simple_partitioner& partitioner, task_group_context& context ) {
00436 internal::lambda_reduce_body<Range,Value,RealBody,Reduction> body(identity, real_body, reduction);
00437 internal::start_reduce<Range,internal::lambda_reduce_body<Range,Value,RealBody,Reduction>,const simple_partitioner>
00438 ::run( range, body, partitioner, context );
00439 return body.result();
00440 }
00441
00443
00444 template<typename Range, typename Value, typename RealBody, typename Reduction>
00445 Value parallel_reduce( const Range& range, const Value& identity, const RealBody& real_body, const Reduction& reduction,
00446 const auto_partitioner& partitioner, task_group_context& context ) {
00447 internal::lambda_reduce_body<Range,Value,RealBody,Reduction> body(identity, real_body, reduction);
00448 internal::start_reduce<Range,internal::lambda_reduce_body<Range,Value,RealBody,Reduction>,const auto_partitioner>
00449 ::run( range, body, partitioner, context );
00450 return body.result();
00451 }
00452
00454
00455 template<typename Range, typename Value, typename RealBody, typename Reduction>
00456 Value parallel_reduce( const Range& range, const Value& identity, const RealBody& real_body, const Reduction& reduction,
00457 affinity_partitioner& partitioner, task_group_context& context ) {
00458 internal::lambda_reduce_body<Range,Value,RealBody,Reduction> body(identity, real_body, reduction);
00459 internal::start_reduce<Range,internal::lambda_reduce_body<Range,Value,RealBody,Reduction>,affinity_partitioner>
00460 ::run( range, body, partitioner, context );
00461 return body.result();
00462 }
00463 #endif
00464
00466
00467 template<typename Range, typename Body>
00468 void parallel_deterministic_reduce( const Range& range, Body& body ) {
00469 internal::start_deterministic_reduce<Range,Body>::run( range, body );
00470 }
00471
00472 #if __TBB_TASK_GROUP_CONTEXT
00474
00475 template<typename Range, typename Body>
00476 void parallel_deterministic_reduce( const Range& range, Body& body, task_group_context& context ) {
00477 internal::start_deterministic_reduce<Range,Body>::run( range, body, context );
00478 }
00479 #endif
00480
00484
00485
00486 template<typename Range, typename Value, typename RealBody, typename Reduction>
00487 Value parallel_deterministic_reduce( const Range& range, const Value& identity, const RealBody& real_body, const Reduction& reduction ) {
00488 internal::lambda_reduce_body<Range,Value,RealBody,Reduction> body(identity, real_body, reduction);
00489 internal::start_deterministic_reduce<Range,internal::lambda_reduce_body<Range,Value,RealBody,Reduction> >
00490 ::run(range, body);
00491 return body.result();
00492 }
00493
00494 #if __TBB_TASK_GROUP_CONTEXT
00496
00497 template<typename Range, typename Value, typename RealBody, typename Reduction>
00498 Value parallel_deterministic_reduce( const Range& range, const Value& identity, const RealBody& real_body, const Reduction& reduction,
00499 task_group_context& context ) {
00500 internal::lambda_reduce_body<Range,Value,RealBody,Reduction> body(identity, real_body, reduction);
00501 internal::start_deterministic_reduce<Range,internal::lambda_reduce_body<Range,Value,RealBody,Reduction> >
00502 ::run( range, body, context );
00503 return body.result();
00504 }
00505 #endif
00506
00507
00508 }
00509
00510 #endif
00511