00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #ifndef __TBB_parallel_reduce_H
00022 #define __TBB_parallel_reduce_H
00023
00024 #include "task.h"
00025 #include "aligned_space.h"
00026 #include "partitioner.h"
00027 #include <new>
00028
00029 namespace tbb {
00030
00032 namespace internal {
00033
00035 void __TBB_EXPORTED_FUNC itt_store_pointer_with_release_v3( void* dst, void* src );
00036
00038 void* __TBB_EXPORTED_FUNC itt_load_pointer_with_acquire_v3( const void* src );
00039
00040 template<typename T> inline void parallel_reduce_store_body( T*& dst, T* src ) {
00041 #if TBB_USE_THREADING_TOOLS
00042 itt_store_pointer_with_release_v3(&dst,src);
00043 #else
00044 __TBB_store_with_release(dst,src);
00045 #endif
00046 }
00047
00048 template<typename T> inline T* parallel_reduce_load_body( T*& src ) {
00049 #if TBB_USE_THREADING_TOOLS
00050 return static_cast<T*>(itt_load_pointer_with_acquire_v3(&src));
00051 #else
00052 return __TBB_load_with_acquire(src);
00053 #endif
00054 }
00055
00057
00058 template<typename Body>
00059 class finish_reduce: public task {
00060 Body* const my_body;
00061 bool has_right_zombie;
00062 aligned_space<Body,1> zombie_space;
00063 finish_reduce( Body* body ) :
00064 my_body(body),
00065 has_right_zombie(false)
00066 {
00067 }
00068 task* execute() {
00069 if( has_right_zombie ) {
00070
00071 Body* s = zombie_space.begin();
00072 my_body->join( *s );
00073 s->~Body();
00074 }
00075 return NULL;
00076 }
00077 template<typename Range,typename Body_, typename Partitioner>
00078 friend class start_reduce;
00079 };
00080
00082
00083 template<typename Range, typename Body, typename Partitioner>
00084 class start_reduce: public task {
00085 typedef finish_reduce<Body> finish_type;
00086 Body* my_body;
00087 Range my_range;
00088 typename Partitioner::partition_type my_partition;
00089 task* execute();
00090 template<typename Body_>
00091 friend class finish_reduce;
00092
00094 start_reduce( const Range& range, Body* body, const Partitioner &partitioner ) :
00095 my_body(body),
00096 my_range(range),
00097 my_partition(partitioner)
00098 {
00099 }
00101
00102 start_reduce( start_reduce& parent, split ) :
00103 my_body(parent.my_body),
00104 my_range(parent.my_range,split()),
00105 my_partition(parent.my_partition,split())
00106 {
00107 }
00109
00110 void note_affinity( affinity_id ) {
00111 finish_type* p = static_cast<finish_type*>(parent() );
00112 Body* body = new( p->zombie_space.begin() ) Body(*my_body,split());
00113 p->has_right_zombie = true;
00114 my_body = body;
00115 }
00116 public:
00117 #if !__TBB_EXCEPTIONS
00118 static void run( const Range& range, Body& body, const Partitioner &partitioner ) {
00119 if( !range.empty() )
00120 task::spawn_root_and_wait( *new(task::allocate_root()) start_reduce(range,&body,partitioner) );
00121 }
00122 #else
00123 static void run( const Range& range, Body& body, const Partitioner &partitioner ) {
00124
00125
00126 if( !range.empty() ) {
00127 task_group_context context;
00128 task::spawn_root_and_wait( *new(task::allocate_root(context)) start_reduce(range,&body,partitioner) );
00129 }
00130 }
00131 static void run( const Range& range, Body& body, const Partitioner &partitioner, task_group_context& context ) {
00132 if( !range.empty() )
00133 task::spawn_root_and_wait( *new(task::allocate_root(context)) start_reduce(range,&body,partitioner) );
00134 }
00135 #endif
00136 };
00137
00138 template<typename Range, typename Body, typename Partitioner>
00139 task* start_reduce<Range,Body,Partitioner>::execute() {
00140 if( !my_range.is_divisible() || my_partition.should_execute_range(*this) ) {
00141 (*my_body)( my_range );
00142 return NULL;
00143 } else {
00144 finish_type& c = *new( allocate_continuation()) finish_type(my_body);
00145 recycle_as_child_of(c);
00146 c.set_ref_count(2);
00147 start_reduce& b = *new( c.allocate_child() ) start_reduce(*this,split());
00148 spawn(b);
00149 return this;
00150 }
00151 }
00152
00154
00155 typedef char reduction_context;
00156
00158
00159 template<typename Body>
00160 class finish_reduce_with_affinity: public task {
00162 Body* my_body;
00163 bool has_right_zombie;
00164 const reduction_context my_context;
00165 aligned_space<Body,1> zombie_space;
00166 finish_reduce_with_affinity( char context ) :
00167 my_body(NULL),
00168 has_right_zombie(false),
00169 my_context(context)
00170 {
00171 }
00172 task* execute() {
00173 if( has_right_zombie ) {
00174
00175 Body* s = zombie_space.begin();
00176 my_body->join( *s );
00177 s->~Body();
00178 }
00179 if( my_context==1 )
00180 parallel_reduce_store_body( static_cast<finish_reduce_with_affinity*>(parent())->my_body, my_body );
00181 return NULL;
00182 }
00183 template<typename Range,typename Body_>
00184 friend class start_reduce_with_affinity;
00185 };
00186
00188
00189 template<typename Range, typename Body>
00190 class start_reduce_with_affinity: public task {
00191 typedef finish_reduce_with_affinity<Body> finish_type;
00192 Body* my_body;
00193 Range my_range;
00194 typename affinity_partitioner::partition_type my_partition;
00195 reduction_context my_context;
00196 task* execute();
00197 template<typename Body_>
00198 friend class finish_reduce_with_affinity;
00199
00201 start_reduce_with_affinity( const Range& range, Body* body, affinity_partitioner& partitioner ) :
00202 my_body(body),
00203 my_range(range),
00204 my_partition(partitioner),
00205 my_context(0)
00206 {
00207 }
00209
00210 start_reduce_with_affinity( start_reduce_with_affinity& parent, split ) :
00211 my_body(parent.my_body),
00212 my_range(parent.my_range,split()),
00213 my_partition(parent.my_partition,split()),
00214 my_context(2)
00215 {
00216 my_partition.set_affinity(*this);
00217 parent.my_context = 1;
00218 }
00220 void note_affinity( affinity_id id ) {
00221 my_partition.note_affinity( id );
00222 }
00223
00224 public:
00225 static void run( const Range& range, Body& body, affinity_partitioner& partitioner ) {
00226 if( !range.empty() ) {
00227 #if !__TBB_EXCEPTIONS || TBB_JOIN_OUTER_TASK_GROUP
00228 task::spawn_root_and_wait( *new(task::allocate_root()) start_reduce_with_affinity(range,&body,partitioner) );
00229 #else
00230
00231
00232 task_group_context context;
00233 task::spawn_root_and_wait( *new(task::allocate_root(context)) start_reduce_with_affinity(range,&body,partitioner) );
00234 #endif
00235 }
00236 }
00237 #if __TBB_EXCEPTIONS
00238 static void run( const Range& range, Body& body, affinity_partitioner& partitioner, task_group_context& context ) {
00239 if( !range.empty() )
00240 task::spawn_root_and_wait( *new(task::allocate_root(context)) start_reduce_with_affinity(range,&body,partitioner) );
00241 }
00242 #endif
00243 };
00244
00245 template<typename Range, typename Body>
00246 task* start_reduce_with_affinity<Range,Body>::execute() {
00247 if( my_context==2 ) {
00248 finish_type* p = static_cast<finish_type*>(parent() );
00249 if( !parallel_reduce_load_body(p->my_body) ) {
00250 my_body = new( p->zombie_space.begin() ) Body(*my_body,split());
00251 p->has_right_zombie = true;
00252 }
00253 }
00254 if( !my_range.is_divisible() || my_partition.should_execute_range(*this) ) {
00255 (*my_body)( my_range );
00256 if( my_context==1 )
00257 parallel_reduce_store_body(static_cast<finish_type*>(parent())->my_body, my_body );
00258 return my_partition.continue_after_execute_range(*this);
00259 } else {
00260 finish_type& c = *new( allocate_continuation()) finish_type(my_context);
00261 recycle_as_child_of(c);
00262 c.set_ref_count(2);
00263 bool delay = my_partition.decide_whether_to_delay();
00264 start_reduce_with_affinity& b = *new( c.allocate_child() ) start_reduce_with_affinity(*this,split());
00265 my_partition.spawn_or_delay(delay,*this,b);
00266 return this;
00267 }
00268 }
00269
00271
00275 template<typename Range, typename Value, typename RealBody, typename Reduction>
00276 class lambda_reduce_body {
00277
00278
00279
00280
00281 const Value& identity_element;
00282 const RealBody& my_real_body;
00283 const Reduction& my_reduction;
00284 Value my_value;
00285 public:
00286 lambda_reduce_body( const Value& identity, const RealBody& body, const Reduction& reduction )
00287 : identity_element(identity)
00288 , my_real_body(body)
00289 , my_reduction(reduction)
00290 , my_value(identity)
00291 { }
00292 lambda_reduce_body( const lambda_reduce_body& other )
00293 : identity_element(other.identity_element)
00294 , my_real_body(other.my_real_body)
00295 , my_reduction(other.my_reduction)
00296 , my_value(other.my_value)
00297 { }
00298 lambda_reduce_body( lambda_reduce_body& other, tbb::split )
00299 : identity_element(other.identity_element)
00300 , my_real_body(other.my_real_body)
00301 , my_reduction(other.my_reduction)
00302 , my_value(other.identity_element)
00303 { }
00304 void operator()(Range& range) {
00305 my_value = my_real_body(range, const_cast<const Value&>(my_value));
00306 }
00307 void join( lambda_reduce_body& rhs ) {
00308 my_value = my_reduction(const_cast<const Value&>(my_value), const_cast<const Value&>(rhs.my_value));
00309 }
00310 Value result() const {
00311 return my_value;
00312 }
00313 };
00314
00315 }
00317
00318
00319
00338
00340
00341 template<typename Range, typename Body>
00342 void parallel_reduce( const Range& range, Body& body, const simple_partitioner& partitioner = simple_partitioner() ) {
00343 internal::start_reduce<Range,Body,simple_partitioner>::run( range, body, partitioner );
00344 }
00345
00347
00348 template<typename Range, typename Body>
00349 void parallel_reduce( const Range& range, Body& body, const auto_partitioner& partitioner ) {
00350 internal::start_reduce<Range,Body,auto_partitioner>::run( range, body, partitioner );
00351 }
00352
00354
00355 template<typename Range, typename Body>
00356 void parallel_reduce( const Range& range, Body& body, affinity_partitioner& partitioner ) {
00357 internal::start_reduce_with_affinity<Range,Body>::run( range, body, partitioner );
00358 }
00359
00360 #if __TBB_EXCEPTIONS
00362
00363 template<typename Range, typename Body>
00364 void parallel_reduce( const Range& range, Body& body, const simple_partitioner& partitioner, task_group_context& context ) {
00365 internal::start_reduce<Range,Body,simple_partitioner>::run( range, body, partitioner, context );
00366 }
00367
00369
00370 template<typename Range, typename Body>
00371 void parallel_reduce( const Range& range, Body& body, const auto_partitioner& partitioner, task_group_context& context ) {
00372 internal::start_reduce<Range,Body,auto_partitioner>::run( range, body, partitioner, context );
00373 }
00374
00376
00377 template<typename Range, typename Body>
00378 void parallel_reduce( const Range& range, Body& body, affinity_partitioner& partitioner, task_group_context& context ) {
00379 internal::start_reduce_with_affinity<Range,Body>::run( range, body, partitioner, context );
00380 }
00381 #endif
00382
00386
00387
00388 template<typename Range, typename Value, typename RealBody, typename Reduction>
00389 Value parallel_reduce( const Range& range, const Value& identity, const RealBody& real_body, const Reduction& reduction,
00390 const simple_partitioner& partitioner = simple_partitioner() ) {
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>,simple_partitioner>
00393 ::run(range, body, 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 auto_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>,auto_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 affinity_partitioner& partitioner ) {
00413 internal::lambda_reduce_body<Range,Value,RealBody,Reduction> body(identity, real_body, reduction);
00414 internal::start_reduce_with_affinity<Range,internal::lambda_reduce_body<Range,Value,RealBody,Reduction> >
00415 ::run( range, body, partitioner );
00416 return body.result();
00417 }
00418
00419 #if __TBB_EXCEPTIONS
00421
00422 template<typename Range, typename Value, typename RealBody, typename Reduction>
00423 Value parallel_reduce( const Range& range, const Value& identity, const RealBody& real_body, const Reduction& reduction,
00424 const simple_partitioner& partitioner, task_group_context& context ) {
00425 internal::lambda_reduce_body<Range,Value,RealBody,Reduction> body(identity, real_body, reduction);
00426 internal::start_reduce<Range,internal::lambda_reduce_body<Range,Value,RealBody,Reduction>,simple_partitioner>
00427 ::run( range, body, partitioner, context );
00428 return body.result();
00429 }
00430
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 auto_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>,auto_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 affinity_partitioner& partitioner, task_group_context& context ) {
00447 internal::lambda_reduce_body<Range,Value,RealBody,Reduction> body(identity, real_body, reduction);
00448 internal::start_reduce_with_affinity<Range,internal::lambda_reduce_body<Range,Value,RealBody,Reduction> >
00449 ::run( range, body, partitioner, context );
00450 return body.result();
00451 }
00452 #endif
00453
00454
00455 }
00456
00457 #endif
00458