00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #ifndef __deal2__parallel_h
00013 #define __deal2__parallel_h
00014
00015
00016 #include <deal.II/base/config.h>
00017 #include <deal.II/base/exceptions.h>
00018 #include <deal.II/base/template_constraints.h>
00019 #include <deal.II/base/synchronous_iterator.h>
00020
00021 #include <deal.II/base/std_cxx1x/tuple.h>
00022 #include <deal.II/base/std_cxx1x/bind.h>
00023 #include <deal.II/base/std_cxx1x/function.h>
00024
00025 #include <cstddef>
00026
00027 #if DEAL_II_USE_MT == 1
00028 # include <tbb/parallel_for.h>
00029 # include <tbb/parallel_reduce.h>
00030 # include <tbb/partitioner.h>
00031 # include <tbb/blocked_range.h>
00032 #endif
00033
00034
00035
00036
00037 DEAL_II_NAMESPACE_OPEN
00038
00039 namespace parallel
00040 {
00041 namespace internal
00042 {
00049 template <typename F>
00050 struct Body
00051 {
00056 Body (const F &f)
00057 :
00058 f (f)
00059 {}
00060
00061 template <typename Range>
00062 void
00063 operator () (const Range &range) const
00064 {
00065 for (typename Range::const_iterator p=range.begin();
00066 p != range.end(); ++p)
00067 apply (f, p.iterators);
00068 }
00069
00070 private:
00074 const F f;
00075
00080 template <typename I1, typename I2>
00081 static
00082 void
00083 apply (const F &f,
00084 const std_cxx1x::tuple<I1,I2> &p)
00085 {
00086 *std_cxx1x::get<1>(p) = f (*std_cxx1x::get<0>(p));
00087 }
00088
00093 template <typename I1, typename I2, typename I3>
00094 static
00095 void
00096 apply (const F &f,
00097 const std_cxx1x::tuple<I1,I2,I3> &p)
00098 {
00099 *std_cxx1x::get<2>(p) = f (*std_cxx1x::get<0>(p),
00100 *std_cxx1x::get<1>(p));
00101 }
00102
00107 template <typename I1, typename I2,
00108 typename I3, typename I4>
00109 static
00110 void
00111 apply (const F &f,
00112 const std_cxx1x::tuple<I1,I2,I3,I4> &p)
00113 {
00114 *std_cxx1x::get<3>(p) = f (*std_cxx1x::get<0>(p),
00115 *std_cxx1x::get<1>(p),
00116 *std_cxx1x::get<2>(p));
00117 }
00118 };
00119
00120
00130 template <typename F>
00131 Body<F> make_body(const F &f)
00132 {
00133 return Body<F>(f);
00134 }
00135 }
00136
00170 template <typename InputIterator,
00171 typename OutputIterator,
00172 typename Predicate>
00173 void transform (const InputIterator &begin_in,
00174 const InputIterator &end_in,
00175 OutputIterator out,
00176 Predicate &predicate,
00177 const unsigned int grainsize)
00178 {
00179 #if DEAL_II_USE_MT == 0
00180
00181
00182 (void) grainsize;
00183
00184 for (OutputIterator in = begin_in; in != end_in;)
00185 *out++ = predicate (*in++);
00186 #else
00187 typedef std_cxx1x::tuple<InputIterator,OutputIterator> Iterators;
00188 typedef SynchronousIterators<Iterators> SyncIterators;
00189 Iterators x_begin (begin_in, out);
00190 Iterators x_end (end_in, OutputIterator());
00191 tbb::parallel_for (tbb::blocked_range<SyncIterators>(x_begin,
00192 x_end,
00193 grainsize),
00194 internal::make_body (predicate),
00195 tbb::auto_partitioner());
00196 #endif
00197 }
00198
00199
00200
00236 template <typename InputIterator1,
00237 typename InputIterator2,
00238 typename OutputIterator,
00239 typename Predicate>
00240 void transform (const InputIterator1 &begin_in1,
00241 const InputIterator1 &end_in1,
00242 InputIterator2 in2,
00243 OutputIterator out,
00244 Predicate &predicate,
00245 const unsigned int grainsize)
00246 {
00247 #if DEAL_II_USE_MT == 0
00248
00249
00250 (void) grainsize;
00251
00252 for (OutputIterator in1 = begin_in1; in1 != end_in1;)
00253 *out++ = predicate (*in1++, *in2++);
00254 #else
00255 typedef
00256 std_cxx1x::tuple<InputIterator1,InputIterator2,OutputIterator>
00257 Iterators;
00258 typedef SynchronousIterators<Iterators> SyncIterators;
00259 Iterators x_begin (begin_in1, in2, out);
00260 Iterators x_end (end_in1, InputIterator2(), OutputIterator());
00261 tbb::parallel_for (tbb::blocked_range<SyncIterators>(x_begin,
00262 x_end,
00263 grainsize),
00264 internal::make_body (predicate),
00265 tbb::auto_partitioner());
00266 #endif
00267 }
00268
00269
00270
00304 template <typename InputIterator1,
00305 typename InputIterator2,
00306 typename InputIterator3,
00307 typename OutputIterator,
00308 typename Predicate>
00309 void transform (const InputIterator1 &begin_in1,
00310 const InputIterator1 &end_in1,
00311 InputIterator2 in2,
00312 InputIterator3 in3,
00313 OutputIterator out,
00314 Predicate &predicate,
00315 const unsigned int grainsize)
00316 {
00317 #if DEAL_II_USE_MT == 0
00318
00319
00320 (void) grainsize;
00321
00322 for (OutputIterator in1 = begin_in1; in1 != end_in1;)
00323 *out++ = predicate (*in1++, *in2++, *in3++);
00324 #else
00325 typedef
00326 std_cxx1x::tuple<InputIterator1,InputIterator2,InputIterator3,OutputIterator>
00327 Iterators;
00328 typedef SynchronousIterators<Iterators> SyncIterators;
00329 Iterators x_begin (begin_in1, in2, in3, out);
00330 Iterators x_end (end_in1, InputIterator2(),
00331 InputIterator3(), OutputIterator());
00332 tbb::parallel_for (tbb::blocked_range<SyncIterators>(x_begin,
00333 x_end,
00334 grainsize),
00335 internal::make_body (predicate),
00336 tbb::auto_partitioner());
00337 #endif
00338 }
00339
00340
00341 namespace internal
00342 {
00343 #if DEAL_II_USE_MT == 1
00344
00348 template <typename RangeType, typename Function>
00349 void apply_to_subranges (const tbb::blocked_range<RangeType> &range,
00350 const Function &f)
00351 {
00352 f (range.begin(), range.end());
00353 }
00354 #endif
00355 }
00356
00357
00458 template <typename RangeType, typename Function>
00459 void apply_to_subranges (const RangeType &begin,
00460 const typename identity<RangeType>::type &end,
00461 const Function &f,
00462 const unsigned int grainsize)
00463 {
00464 #if DEAL_II_USE_MT == 0
00465
00466
00467 (void) grainsize;
00468
00469 f (begin, end);
00470 #else
00471 tbb::parallel_for (tbb::blocked_range<RangeType>
00472 (begin, end, grainsize),
00473 std_cxx1x::bind (&internal::apply_to_subranges<RangeType,Function>,
00474 std_cxx1x::_1,
00475 std_cxx1x::cref(f)),
00476 tbb::auto_partitioner());
00477 #endif
00478 }
00479
00480
00481
00509 struct ParallelForInteger
00510 {
00515 virtual ~ParallelForInteger ();
00516
00528 void apply_parallel (const std::size_t begin,
00529 const std::size_t end,
00530 const std::size_t minimum_parallel_grain_size) const;
00531
00541 virtual void apply_to_subrange (const std::size_t,
00542 const std::size_t) const = 0;
00543 };
00544
00545
00546
00547 namespace internal
00548 {
00549 #if DEAL_II_USE_MT == 1
00550
00560 template <typename ResultType,
00561 typename Function>
00562 struct ReductionOnSubranges
00563 {
00568 ResultType result;
00569
00585 template <typename Reductor>
00586 ReductionOnSubranges (const Function &f,
00587 const Reductor &reductor,
00588 const ResultType neutral_element = ResultType())
00589 :
00590 result (neutral_element),
00591 f (f),
00592 neutral_element (neutral_element),
00593 reductor (reductor)
00594 {}
00595
00600 ReductionOnSubranges (const ReductionOnSubranges &r,
00601 tbb::split)
00602 :
00603 result (r.neutral_element),
00604 f (r.f),
00605 neutral_element (r.neutral_element),
00606 reductor (r.reductor)
00607 {}
00608
00614 void join (const ReductionOnSubranges &r)
00615 {
00616 result = reductor(result, r.result);
00617 }
00618
00623 template <typename RangeType>
00624 void operator () (const tbb::blocked_range<RangeType> &range)
00625 {
00626 result = reductor(result,
00627 f (range.begin(), range.end()));
00628 }
00629
00630 private:
00635 const Function f;
00636
00645 const ResultType neutral_element;
00646
00652 const std_cxx1x::function<ResultType (ResultType, ResultType)> reductor;
00653 };
00654 #endif
00655 }
00656
00657
00738 template <typename ResultType, typename RangeType, typename Function>
00739 ResultType accumulate_from_subranges (const Function &f,
00740 const RangeType &begin,
00741 const typename identity<RangeType>::type &end,
00742 const unsigned int grainsize)
00743 {
00744 #if DEAL_II_USE_MT == 0
00745
00746
00747 (void) grainsize;
00748
00749 return f(begin,end);
00750 #else
00751 internal::ReductionOnSubranges<ResultType,Function>
00752 reductor (f, std::plus<ResultType>(), 0);
00753 tbb::parallel_reduce (tbb::blocked_range<RangeType>(begin, end, grainsize),
00754 reductor,
00755 tbb::auto_partitioner());
00756 return reductor.result;
00757 #endif
00758 }
00759
00760 }
00761
00762
00763 namespace internal
00764 {
00765 namespace Vector
00766 {
00792 extern unsigned int minimum_parallel_grain_size;
00793 }
00794
00795
00796 namespace SparseMatrix
00797 {
00805 extern unsigned int minimum_parallel_grain_size;
00806 }
00807
00808 }
00809
00810
00811
00812
00813 namespace parallel
00814 {
00815
00816 #if DEAL_II_USE_MT == 1
00817
00818 namespace internal
00819 {
00824 struct ParallelForWrapper
00825 {
00826 ParallelForWrapper (const parallel::ParallelForInteger &worker)
00827 :
00828 worker_ (worker)
00829 {}
00830
00831 void operator() (const tbb::blocked_range<std::size_t> &range) const
00832 {
00833 worker_.apply_to_subrange (range.begin(), range.end());
00834 }
00835
00836 const parallel::ParallelForInteger &worker_;
00837 };
00838 }
00839
00840 #endif
00841
00842
00843 inline
00844 ParallelForInteger::~ParallelForInteger ()
00845 {}
00846
00847
00848 inline
00849 void
00850 ParallelForInteger::apply_parallel (const std::size_t begin,
00851 const std::size_t end,
00852 const std::size_t minimum_parallel_grain_size) const
00853 {
00854 #if DEAL_II_USE_MT == 0
00855
00856
00857 (void) minimum_parallel_grain_size;
00858
00859 apply_to_subrange (begin, end);
00860 #else
00861 internal::ParallelForWrapper worker(*this);
00862 tbb::parallel_for (tbb::blocked_range<std::size_t>
00863 (begin, end, minimum_parallel_grain_size),
00864 worker,
00865 tbb::auto_partitioner());
00866 #endif
00867 }
00868
00869 }
00870
00871 DEAL_II_NAMESPACE_CLOSE
00872
00873 #endif
00874