Reference documentation for deal.II version 8.5.1
parallel.h
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2008 - 2016 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE at
12 // the top level of the deal.II distribution.
13 //
14 // ---------------------------------------------------------------------
15 
16 #ifndef dealii__parallel_h
17 #define dealii__parallel_h
18 
19 
20 #include <deal.II/base/config.h>
21 #include <deal.II/base/exceptions.h>
22 #include <deal.II/base/template_constraints.h>
23 #include <deal.II/base/synchronous_iterator.h>
24 #include <deal.II/base/thread_management.h>
25 
26 #include <deal.II/base/std_cxx11/tuple.h>
27 #include <deal.II/base/std_cxx11/bind.h>
28 #include <deal.II/base/std_cxx11/function.h>
29 #include <deal.II/base/std_cxx11/shared_ptr.h>
30 
31 #include <cstddef>
32 
33 #ifdef DEAL_II_WITH_THREADS
34 # include <tbb/parallel_for.h>
35 # include <tbb/parallel_reduce.h>
36 # include <tbb/partitioner.h>
37 # include <tbb/blocked_range.h>
38 #endif
39 
40 
41 //TODO[WB]: allow calling functions to pass along a tbb::affinity_partitioner object to ensure that subsequent calls use the same cache lines
42 
43 DEAL_II_NAMESPACE_OPEN
44 
45 namespace parallel
46 {
47  namespace internal
48  {
53  template <typename Number>
55  {
56  static const bool value = true;
57  };
58 
59 #ifdef __INTEL_COMPILER
60  // Disable long double SIMD instructions on ICC. This is to work around a bug
61  // that generates wrong code at least up to intel 15 (see
62  // tests/lac/vector-vector, tests/lac/intel-15-bug, and the discussion at
63  // https://github.com/dealii/dealii/issues/598).
64  template <>
65  struct EnableOpenMPSimdFor<long double>
66  {
67  static const bool value = false;
68  };
69 #endif
70 
71 
72 
77  template <typename F>
78  struct Body
79  {
83  Body (const F &f)
84  :
85  f (f)
86  {}
87 
88  template <typename Range>
89  void
90  operator () (const Range &range) const
91  {
92  for (typename Range::const_iterator p=range.begin();
93  p != range.end(); ++p)
94  apply (f, p.iterators);
95  }
96 
97  private:
101  const F f;
102 
106  template <typename I1, typename I2>
107  static
108  void
109  apply (const F &f,
110  const std_cxx11::tuple<I1,I2> &p)
111  {
112  *std_cxx11::get<1>(p) = f (*std_cxx11::get<0>(p));
113  }
114 
118  template <typename I1, typename I2, typename I3>
119  static
120  void
121  apply (const F &f,
122  const std_cxx11::tuple<I1,I2,I3> &p)
123  {
124  *std_cxx11::get<2>(p) = f (*std_cxx11::get<0>(p),
125  *std_cxx11::get<1>(p));
126  }
127 
131  template <typename I1, typename I2,
132  typename I3, typename I4>
133  static
134  void
135  apply (const F &f,
136  const std_cxx11::tuple<I1,I2,I3,I4> &p)
137  {
138  *std_cxx11::get<3>(p) = f (*std_cxx11::get<0>(p),
139  *std_cxx11::get<1>(p),
140  *std_cxx11::get<2>(p));
141  }
142  };
143 
144 
151  template <typename F>
152  Body<F> make_body(const F &f)
153  {
154  return Body<F>(f);
155  }
156  }
157 
181  template <typename InputIterator,
182  typename OutputIterator,
183  typename Predicate>
184  void transform (const InputIterator &begin_in,
185  const InputIterator &end_in,
186  OutputIterator out,
187  Predicate &predicate,
188  const unsigned int grainsize)
189  {
190 #ifndef DEAL_II_WITH_THREADS
191  // make sure we don't get compiler
192  // warnings about unused arguments
193  (void) grainsize;
194 
195  for (OutputIterator in = begin_in; in != end_in;)
196  *out++ = predicate (*in++);
197 #else
198  typedef std_cxx11::tuple<InputIterator,OutputIterator> Iterators;
199  typedef SynchronousIterators<Iterators> SyncIterators;
200  Iterators x_begin (begin_in, out);
201  Iterators x_end (end_in, OutputIterator());
202  tbb::parallel_for (tbb::blocked_range<SyncIterators>(x_begin,
203  x_end,
204  grainsize),
205  internal::make_body (predicate),
206  tbb::auto_partitioner());
207 #endif
208  }
209 
210 
211 
235  template <typename InputIterator1,
236  typename InputIterator2,
237  typename OutputIterator,
238  typename Predicate>
239  void transform (const InputIterator1 &begin_in1,
240  const InputIterator1 &end_in1,
241  InputIterator2 in2,
242  OutputIterator out,
243  Predicate &predicate,
244  const unsigned int grainsize)
245  {
246 #ifndef DEAL_II_WITH_THREADS
247  // make sure we don't get compiler
248  // warnings about unused arguments
249  (void) grainsize;
250 
251  for (OutputIterator in1 = begin_in1; in1 != end_in1;)
252  *out++ = predicate (*in1++, *in2++);
253 #else
254  typedef
255  std_cxx11::tuple<InputIterator1,InputIterator2,OutputIterator>
256  Iterators;
257  typedef SynchronousIterators<Iterators> SyncIterators;
258  Iterators x_begin (begin_in1, in2, out);
259  Iterators x_end (end_in1, InputIterator2(), OutputIterator());
260  tbb::parallel_for (tbb::blocked_range<SyncIterators>(x_begin,
261  x_end,
262  grainsize),
263  internal::make_body (predicate),
264  tbb::auto_partitioner());
265 #endif
266  }
267 
268 
269 
293  template <typename InputIterator1,
294  typename InputIterator2,
295  typename InputIterator3,
296  typename OutputIterator,
297  typename Predicate>
298  void transform (const InputIterator1 &begin_in1,
299  const InputIterator1 &end_in1,
300  InputIterator2 in2,
301  InputIterator3 in3,
302  OutputIterator out,
303  Predicate &predicate,
304  const unsigned int grainsize)
305  {
306 #ifndef DEAL_II_WITH_THREADS
307  // make sure we don't get compiler
308  // warnings about unused arguments
309  (void) grainsize;
310 
311  for (OutputIterator in1 = begin_in1; in1 != end_in1;)
312  *out++ = predicate (*in1++, *in2++, *in3++);
313 #else
314  typedef
315  std_cxx11::tuple<InputIterator1,InputIterator2,InputIterator3,OutputIterator>
316  Iterators;
317  typedef SynchronousIterators<Iterators> SyncIterators;
318  Iterators x_begin (begin_in1, in2, in3, out);
319  Iterators x_end (end_in1, InputIterator2(),
320  InputIterator3(), OutputIterator());
321  tbb::parallel_for (tbb::blocked_range<SyncIterators>(x_begin,
322  x_end,
323  grainsize),
324  internal::make_body (predicate),
325  tbb::auto_partitioner());
326 #endif
327  }
328 
329 
330  namespace internal
331  {
332 #ifdef DEAL_II_WITH_THREADS
333 
337  template <typename RangeType, typename Function>
338  void apply_to_subranges (const tbb::blocked_range<RangeType> &range,
339  const Function &f)
340  {
341  f (range.begin(), range.end());
342  }
343 #endif
344  }
345 
346 
418  template <typename RangeType, typename Function>
419  void apply_to_subranges (const RangeType &begin,
420  const typename identity<RangeType>::type &end,
421  const Function &f,
422  const unsigned int grainsize)
423  {
424 #ifndef DEAL_II_WITH_THREADS
425  // make sure we don't get compiler
426  // warnings about unused arguments
427  (void) grainsize;
428 
429 # ifndef DEAL_II_BIND_NO_CONST_OP_PARENTHESES
430  f (begin, end);
431 # else
432  // work around a problem with MS VC++ where there is no const
433  // operator() in 'Function' if 'Function' is the result of std::bind
434  Function ff = f;
435  ff (begin, end);
436 # endif
437 #else
438  tbb::parallel_for (tbb::blocked_range<RangeType>
439  (begin, end, grainsize),
440  std_cxx11::bind (&internal::apply_to_subranges<RangeType,Function>,
441  std_cxx11::_1,
442  std_cxx11::cref(f)),
443  tbb::auto_partitioner());
444 #endif
445  }
446 
447 
448 
477  {
482  virtual ~ParallelForInteger ();
483 
492  void apply_parallel (const std::size_t begin,
493  const std::size_t end,
494  const std::size_t minimum_parallel_grain_size) const;
495 
502  virtual void apply_to_subrange (const std::size_t,
503  const std::size_t) const = 0;
504  };
505 
506 
507 
508  namespace internal
509  {
510 #ifdef DEAL_II_WITH_THREADS
511 
517  template <typename ResultType,
518  typename Function>
520  {
524  ResultType result;
525 
535  template <typename Reductor>
537  const Reductor &reductor,
538  const ResultType neutral_element = ResultType())
539  :
541  f (f),
544  {}
545 
550  tbb::split)
551  :
553  f (r.f),
555  reductor (r.reductor)
556  {}
557 
562  void join (const ReductionOnSubranges &r)
563  {
565  }
566 
570  template <typename RangeType>
571  void operator () (const tbb::blocked_range<RangeType> &range)
572  {
574  f (range.begin(), range.end()));
575  }
576 
577  private:
581  const Function f;
582 
588  const ResultType neutral_element;
589 
594  const std_cxx11::function<ResultType (ResultType, ResultType)> reductor;
595  };
596 #endif
597  }
598 
599 
659  template <typename ResultType, typename RangeType, typename Function>
660  ResultType accumulate_from_subranges (const Function &f,
661  const RangeType &begin,
662  const typename identity<RangeType>::type &end,
663  const unsigned int grainsize)
664  {
665 #ifndef DEAL_II_WITH_THREADS
666  // make sure we don't get compiler
667  // warnings about unused arguments
668  (void) grainsize;
669 
670 # ifndef DEAL_II_BIND_NO_CONST_OP_PARENTHESES
671  return f (begin, end);
672 # else
673  // work around a problem with MS VC++ where there is no const
674  // operator() in 'Function' if 'Function' is the result of std::bind
675  Function ff = f;
676  return ff (begin, end);
677 # endif
678 #else
680  reductor (f, std::plus<ResultType>(), 0);
681  tbb::parallel_reduce (tbb::blocked_range<RangeType>(begin, end, grainsize),
682  reductor,
683  tbb::auto_partitioner());
684  return reductor.result;
685 #endif
686  }
687 
688 
689 // --------------------- for loop affinity partitioner -----------------------
690 
700  namespace internal
701  {
702  class TBBPartitioner
703  {
704  public:
708  TBBPartitioner()
709 #ifdef DEAL_II_WITH_THREADS
710  :
711  my_partitioner(new tbb::affinity_partitioner()),
712  in_use(false)
713 #endif
714  {}
715 
716 #ifdef DEAL_II_WITH_THREADS
717 
721  ~TBBPartitioner()
722  {
723  Assert(in_use == false,
724  ExcInternalError("A vector partitioner goes out of scope, but "
725  "it appears to be still in use."));
726  }
727 
734  std_cxx11::shared_ptr<tbb::affinity_partitioner>
735  acquire_one_partitioner()
736  {
737  ::Threads::Mutex::ScopedLock lock(mutex);
738  if (in_use)
739  return std_cxx11::shared_ptr<tbb::affinity_partitioner>(new tbb::affinity_partitioner());
740 
741  in_use = true;
742  return my_partitioner;
743  }
744 
750  void release_one_partitioner(std_cxx11::shared_ptr<tbb::affinity_partitioner> &p)
751  {
752  if (p.get() == my_partitioner.get())
753  {
754  ::Threads::Mutex::ScopedLock lock(mutex);
755  in_use = false;
756  }
757  }
758 
759  private:
764  std_cxx11::shared_ptr<tbb::affinity_partitioner> my_partitioner;
765 
770  bool in_use;
771 
775  ::Threads::Mutex mutex;
776 #endif
777  };
778  }
779 }
780 
781 
782 namespace internal
783 {
784  namespace Vector
785  {
800  extern unsigned int minimum_parallel_grain_size;
801  }
802 
803 
804  namespace SparseMatrix
805  {
810  extern unsigned int minimum_parallel_grain_size;
811  }
812 
813 } // end of namespace internal
814 
815 
816 /* --------------------------- inline functions ------------------------- */
817 
818 namespace parallel
819 {
820 
821 #ifdef DEAL_II_WITH_THREADS
822 
823  namespace internal
824  {
830  {
832  :
833  worker_ (worker)
834  {}
835 
836  void operator() (const tbb::blocked_range<std::size_t> &range) const
837  {
838  worker_.apply_to_subrange (range.begin(), range.end());
839  }
840 
841  const parallel::ParallelForInteger &worker_;
842  };
843  }
844 
845 #endif
846 
847 
848  inline
850  {}
851 
852 
853  inline
854  void
855  ParallelForInteger::apply_parallel (const std::size_t begin,
856  const std::size_t end,
857  const std::size_t minimum_parallel_grain_size) const
858  {
859 #ifndef DEAL_II_WITH_THREADS
860  // make sure we don't get compiler
861  // warnings about unused arguments
862  (void) minimum_parallel_grain_size;
863 
864  apply_to_subrange (begin, end);
865 #else
866  internal::ParallelForWrapper worker(*this);
867  tbb::parallel_for (tbb::blocked_range<std::size_t>
868  (begin, end, minimum_parallel_grain_size),
869  worker,
870  tbb::auto_partitioner());
871 #endif
872  }
873 
874 } // end of namespace parallel
875 
876 DEAL_II_NAMESPACE_CLOSE
877 
878 #endif
Body< F > make_body(const F &f)
Definition: parallel.h:152
void join(const ReductionOnSubranges &r)
Definition: parallel.h:562
void operator()(const tbb::blocked_range< RangeType > &range)
Definition: parallel.h:571
void apply_to_subranges(const RangeType &begin, const typename identity< RangeType >::type &end, const Function &f, const unsigned int grainsize)
Definition: parallel.h:419
ReductionOnSubranges(const Function &f, const Reductor &reductor, const ResultType neutral_element=ResultType())
Definition: parallel.h:536
static void apply(const F &f, const std_cxx11::tuple< I1, I2 > &p)
Definition: parallel.h:109
#define Assert(cond, exc)
Definition: exceptions.h:313
void apply_to_subranges(const tbb::blocked_range< RangeType > &range, const Function &f)
Definition: parallel.h:338
ReductionOnSubranges(const ReductionOnSubranges &r, tbb::split)
Definition: parallel.h:549
ResultType accumulate_from_subranges(const Function &f, const RangeType &begin, const typename identity< RangeType >::type &end, const unsigned int grainsize)
Definition: parallel.h:660
void transform(const InputIterator &begin_in, const InputIterator &end_in, OutputIterator out, Predicate &predicate, const unsigned int grainsize)
Definition: parallel.h:184
void apply_parallel(const std::size_t begin, const std::size_t end, const std::size_t minimum_parallel_grain_size) const
Definition: parallel.h:855
virtual void apply_to_subrange(const std::size_t, const std::size_t) const =0
const std_cxx11::function< ResultType(ResultType, ResultType)> reductor
Definition: parallel.h:594
static void apply(const F &f, const std_cxx11::tuple< I1, I2, I3 > &p)
Definition: parallel.h:121
static void apply(const F &f, const std_cxx11::tuple< I1, I2, I3, I4 > &p)
Definition: parallel.h:135
static ::ExceptionBase & ExcInternalError()