parallel_for.h

00001 /*
00002     Copyright 2005-2012 Intel Corporation.  All Rights Reserved.
00003 
00004     The source code contained or described herein and all documents related
00005     to the source code ("Material") are owned by Intel Corporation or its
00006     suppliers or licensors.  Title to the Material remains with Intel
00007     Corporation or its suppliers and licensors.  The Material is protected
00008     by worldwide copyright laws and treaty provisions.  No part of the
00009     Material may be used, copied, reproduced, modified, published, uploaded,
00010     posted, transmitted, distributed, or disclosed in any way without
00011     Intel's prior express written permission.
00012 
00013     No license under any patent, copyright, trade secret or other
00014     intellectual property right is granted to or conferred upon you by
00015     disclosure or delivery of the Materials, either expressly, by
00016     implication, inducement, estoppel or otherwise.  Any license under such
00017     intellectual property rights must be express and approved by Intel in
00018     writing.
00019 */
00020 
00021 #ifndef __TBB_parallel_for_H
00022 #define __TBB_parallel_for_H
00023 
00024 #include <new>
00025 #include "task.h"
00026 #include "partitioner.h"
00027 #include "blocked_range.h"
00028 #include "tbb_exception.h"
00029 
00030 namespace tbb {
00031 
00032 namespace interface6 {
00034 namespace internal {
00035 
00037 
00038     template<typename Range, typename Body, typename Partitioner>
00039     class start_for: public task {
00040         Range my_range;
00041         const Body my_body;
00042         typename Partitioner::task_partition_type my_partition;
00043         /*override*/ task* execute();
00044 
00045     public:
00047         start_for( const Range& range, const Body& body, Partitioner& partitioner ) :
00048             my_range(range),    
00049             my_body(body),
00050             my_partition(partitioner)
00051         {
00052         }
00054 
00055         start_for( start_for& parent_, split ) :
00056             my_range(parent_.my_range,split()),
00057             my_body(parent_.my_body),
00058             my_partition(parent_.my_partition, split())
00059         {
00060             my_partition.set_affinity(*this);
00061         }
00063 
00064         start_for( start_for& parent_, const Range& r, depth_t d ) :
00065             my_range(r),
00066             my_body(parent_.my_body),
00067             my_partition(parent_.my_partition,split())
00068         {
00069             my_partition.set_affinity(*this);
00070             my_partition.align_depth( d );
00071         }
00073         /*override*/ void note_affinity( affinity_id id ) {
00074             my_partition.note_affinity( id );
00075         }
00076         static void run(  const Range& range, const Body& body, Partitioner& partitioner ) {
00077             if( !range.empty() ) {
00078 #if !__TBB_TASK_GROUP_CONTEXT || TBB_JOIN_OUTER_TASK_GROUP
00079                 start_for& a = *new(task::allocate_root()) start_for(range,body,partitioner);
00080 #else
00081                 // Bound context prevents exceptions from body to affect nesting or sibling algorithms,
00082                 // and allows users to handle exceptions safely by wrapping parallel_for in the try-block.
00083                 task_group_context context;
00084                 start_for& a = *new(task::allocate_root(context)) start_for(range,body,partitioner);
00085 #endif /* __TBB_TASK_GROUP_CONTEXT && !TBB_JOIN_OUTER_TASK_GROUP */
00086                 task::spawn_root_and_wait(a);
00087             }
00088         }
00089 #if __TBB_TASK_GROUP_CONTEXT
00090         static void run(  const Range& range, const Body& body, Partitioner& partitioner, task_group_context& context ) {
00091             if( !range.empty() ) {
00092                 start_for& a = *new(task::allocate_root(context)) start_for(range,body,partitioner);
00093                 task::spawn_root_and_wait(a);
00094             }
00095         }
00096 #endif /* __TBB_TASK_GROUP_CONTEXT */
00098         flag_task *create_continuation() {
00099             return new( allocate_continuation() ) flag_task();
00100         }
00102         void run_body( Range &r ) { my_body( r ); }
00103     };
00104 
00105     template<typename Range, typename Body, typename Partitioner>
00106     task* start_for<Range,Body,Partitioner>::execute() {
00107         my_partition.check_being_stolen( *this );
00108         my_partition.execute(*this, my_range);
00109         return NULL;
00110     } 
00111 } // namespace internal
00113 } // namespace interfaceX
00114 
00116 namespace internal {
00117     using interface6::internal::start_for;
00118     
00120     template<typename Function, typename Index>
00121     class parallel_for_body : internal::no_assign {
00122         const Function &my_func;
00123         const Index my_begin;
00124         const Index my_step; 
00125     public:
00126         parallel_for_body( const Function& _func, Index& _begin, Index& _step) 
00127             : my_func(_func), my_begin(_begin), my_step(_step) {}
00128         
00129         void operator()( tbb::blocked_range<Index>& r ) const {
00130 #if __INTEL_COMPILER
00131 #pragma ivdep
00132 #endif
00133             for( Index i = r.begin(),  k = my_begin + i * my_step; i < r.end(); i++, k = k + my_step)
00134                 my_func( k );
00135         }
00136     };
00137 } // namespace internal
00139 
00140 // Requirements on Range concept are documented in blocked_range.h
00141 
00152 
00154 
00155 template<typename Range, typename Body>
00156 void parallel_for( const Range& range, const Body& body ) {
00157     internal::start_for<Range,Body,const __TBB_DEFAULT_PARTITIONER>::run(range,body,__TBB_DEFAULT_PARTITIONER());
00158 }
00159 
00161 
00162 template<typename Range, typename Body>
00163 void parallel_for( const Range& range, const Body& body, const simple_partitioner& partitioner ) {
00164     internal::start_for<Range,Body,const simple_partitioner>::run(range,body,partitioner);
00165 }
00166 
00168 
00169 template<typename Range, typename Body>
00170 void parallel_for( const Range& range, const Body& body, const auto_partitioner& partitioner ) {
00171     internal::start_for<Range,Body,const auto_partitioner>::run(range,body,partitioner);
00172 }
00173 
00175 
00176 template<typename Range, typename Body>
00177 void parallel_for( const Range& range, const Body& body, affinity_partitioner& partitioner ) {
00178     internal::start_for<Range,Body,affinity_partitioner>::run(range,body,partitioner);
00179 }
00180 
00181 #if __TBB_TASK_GROUP_CONTEXT
00183 
00184 template<typename Range, typename Body>
00185 void parallel_for( const Range& range, const Body& body, task_group_context& context ) {
00186     internal::start_for<Range,Body,const __TBB_DEFAULT_PARTITIONER>::run(range, body, __TBB_DEFAULT_PARTITIONER(), context);
00187 }
00188 
00190 
00191 template<typename Range, typename Body>
00192 void parallel_for( const Range& range, const Body& body, const simple_partitioner& partitioner, task_group_context& context ) {
00193     internal::start_for<Range,Body,const simple_partitioner>::run(range, body, partitioner, context);
00194 }
00195 
00197 
00198 template<typename Range, typename Body>
00199 void parallel_for( const Range& range, const Body& body, const auto_partitioner& partitioner, task_group_context& context ) {
00200     internal::start_for<Range,Body,const auto_partitioner>::run(range, body, partitioner, context);
00201 }
00202 
00204 
00205 template<typename Range, typename Body>
00206 void parallel_for( const Range& range, const Body& body, affinity_partitioner& partitioner, task_group_context& context ) {
00207     internal::start_for<Range,Body,affinity_partitioner>::run(range,body,partitioner, context);
00208 }
00209 #endif /* __TBB_TASK_GROUP_CONTEXT */
00210 
00211 
00212 namespace strict_ppl {
00213 
00215 
00216 template <typename Index, typename Function, typename Partitioner>
00217 void parallel_for_impl(Index first, Index last, Index step, const Function& f, Partitioner& partitioner) {
00218     if (step <= 0 )
00219         internal::throw_exception(internal::eid_nonpositive_step); // throws std::invalid_argument
00220     else if (last > first) {
00221         // Above "else" avoids "potential divide by zero" warning on some platforms
00222         Index end = (last - first - Index(1)) / step + Index(1);
00223         tbb::blocked_range<Index> range(static_cast<Index>(0), end);
00224         internal::parallel_for_body<Function, Index> body(f, first, step);
00225         tbb::parallel_for(range, body, partitioner);
00226     }
00227 }    
00228 
00230 template <typename Index, typename Function>
00231 void parallel_for(Index first, Index last, Index step, const Function& f) {
00232     parallel_for_impl<Index,Function,const auto_partitioner>(first, last, step, f, auto_partitioner());
00233 }
00235 template <typename Index, typename Function>
00236 void parallel_for(Index first, Index last, Index step, const Function& f, const simple_partitioner& partitioner) {
00237     parallel_for_impl<Index,Function,const simple_partitioner>(first, last, step, f, partitioner);
00238 }
00240 template <typename Index, typename Function>
00241 void parallel_for(Index first, Index last, Index step, const Function& f, const auto_partitioner& partitioner) {
00242     parallel_for_impl<Index,Function,const auto_partitioner>(first, last, step, f, partitioner);
00243 }
00245 template <typename Index, typename Function>
00246 void parallel_for(Index first, Index last, Index step, const Function& f, affinity_partitioner& partitioner) {
00247     parallel_for_impl(first, last, step, f, partitioner);
00248 }
00249 
00251 template <typename Index, typename Function>
00252 void parallel_for(Index first, Index last, const Function& f) {
00253     parallel_for_impl<Index,Function,const auto_partitioner>(first, last, static_cast<Index>(1), f, auto_partitioner());
00254 }
00256 template <typename Index, typename Function>
00257 void parallel_for(Index first, Index last, const Function& f, const simple_partitioner& partitioner) {
00258     parallel_for_impl<Index,Function,const simple_partitioner>(first, last, static_cast<Index>(1), f, partitioner);
00259 }
00261 template <typename Index, typename Function>
00262 void parallel_for(Index first, Index last, const Function& f, const auto_partitioner& partitioner) {
00263     parallel_for_impl<Index,Function,const auto_partitioner>(first, last, static_cast<Index>(1), f, partitioner);
00264 }
00266 template <typename Index, typename Function>
00267 void parallel_for(Index first, Index last, const Function& f, affinity_partitioner& partitioner) {
00268     parallel_for_impl(first, last, static_cast<Index>(1), f, partitioner);
00269 }
00270 
00271 #if __TBB_TASK_GROUP_CONTEXT
00273 template <typename Index, typename Function, typename Partitioner>
00274 void parallel_for_impl(Index first, Index last, Index step, const Function& f, Partitioner& partitioner, tbb::task_group_context &context) {
00275     if (step <= 0 )
00276         internal::throw_exception(internal::eid_nonpositive_step); // throws std::invalid_argument
00277     else if (last > first) {
00278         // Above "else" avoids "potential divide by zero" warning on some platforms
00279         Index end = (last - first - Index(1)) / step + Index(1);
00280         tbb::blocked_range<Index> range(static_cast<Index>(0), end);
00281         internal::parallel_for_body<Function, Index> body(f, first, step);
00282         tbb::parallel_for(range, body, partitioner, context);
00283     }
00284 }
00285 
00287 template <typename Index, typename Function>
00288 void parallel_for(Index first, Index last, Index step, const Function& f, tbb::task_group_context &context) {
00289     parallel_for_impl<Index,Function,const auto_partitioner>(first, last, step, f, auto_partitioner(), context);
00290 }
00292  template <typename Index, typename Function>
00293 void parallel_for(Index first, Index last, Index step, const Function& f, const simple_partitioner& partitioner, tbb::task_group_context &context) {
00294     parallel_for_impl<Index,Function,const simple_partitioner>(first, last, step, f, partitioner, context);
00295 }
00297  template <typename Index, typename Function>
00298 void parallel_for(Index first, Index last, Index step, const Function& f, const auto_partitioner& partitioner, tbb::task_group_context &context) {
00299     parallel_for_impl<Index,Function,const auto_partitioner>(first, last, step, f, partitioner, context);
00300 }
00302  template <typename Index, typename Function>
00303 void parallel_for(Index first, Index last, Index step, const Function& f, affinity_partitioner& partitioner, tbb::task_group_context &context) {
00304     parallel_for_impl(first, last, step, f, partitioner, context);
00305 }
00306 
00307 
00309 template <typename Index, typename Function>
00310 void parallel_for(Index first, Index last, const Function& f, tbb::task_group_context &context) {
00311     parallel_for_impl<Index,Function,const auto_partitioner>(first, last, static_cast<Index>(1), f, auto_partitioner(), context);
00312 }
00314  template <typename Index, typename Function, typename Partitioner>
00315 void parallel_for(Index first, Index last, const Function& f, const simple_partitioner& partitioner, tbb::task_group_context &context) {
00316     parallel_for_impl<Index,Function,const simple_partitioner>(first, last, static_cast<Index>(1), f, partitioner, context);
00317 }
00319  template <typename Index, typename Function, typename Partitioner>
00320 void parallel_for(Index first, Index last, const Function& f, const auto_partitioner& partitioner, tbb::task_group_context &context) {
00321     parallel_for_impl<Index,Function,const auto_partitioner>(first, last, static_cast<Index>(1), f, partitioner, context);
00322 }
00324  template <typename Index, typename Function, typename Partitioner>
00325 void parallel_for(Index first, Index last, const Function& f, affinity_partitioner& partitioner, tbb::task_group_context &context) {
00326     parallel_for_impl(first, last, static_cast<Index>(1), f, partitioner, context);
00327 }
00328 
00329 #endif /* __TBB_TASK_GROUP_CONTEXT */
00330 
00331 
00332 } // namespace strict_ppl
00333 
00334 using strict_ppl::parallel_for;
00335 
00336 } // namespace tbb
00337 
00338 #if TBB_PREVIEW_SERIAL_SUBSET
00339 #define __TBB_NORMAL_EXECUTION
00340 #include "../serial/tbb/parallel_for.h"
00341 #undef __TBB_NORMAL_EXECUTION
00342 #endif
00343 
00344 #endif /* __TBB_parallel_for_H */
00345 

Copyright © 2005-2012 Intel Corporation. All Rights Reserved.

Intel, Pentium, Intel Xeon, Itanium, Intel XScale and VTune are registered trademarks or trademarks of Intel Corporation or its subsidiaries in the United States and other countries.

* Other names and brands may be claimed as the property of others.