Reference documentation for deal.II version 9.0.0
parallel.h
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2008 - 2018 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 <cstddef>
27 #include <tuple>
28 #include <memory>
29 #include <functional>
30 
31 #ifdef DEAL_II_WITH_THREADS
32 # include <tbb/parallel_for.h>
33 # include <tbb/parallel_reduce.h>
34 # include <tbb/partitioner.h>
35 # include <tbb/blocked_range.h>
36 #endif
37 
38 
39 //TODO[WB]: allow calling functions to pass along a tbb::affinity_partitioner object to ensure that subsequent calls use the same cache lines
40 
41 DEAL_II_NAMESPACE_OPEN
42 
43 namespace parallel
44 {
45  namespace internal
46  {
51  template <typename Number>
53  {
54  static const bool value = true;
55  };
56 
57 #ifdef __INTEL_COMPILER
58  // Disable long double SIMD instructions on ICC. This is to work around a bug
59  // that generates wrong code at least up to intel 15 (see
60  // tests/lac/vector-vector, tests/lac/intel-15-bug, and the discussion at
61  // https://github.com/dealii/dealii/issues/598).
62  template <>
63  struct EnableOpenMPSimdFor<long double>
64  {
65  static const bool value = false;
66  };
67 #endif
68 
69 
70 
75  template <typename F>
76  struct Body
77  {
81  Body (const F &f)
82  :
83  f (f)
84  {}
85 
86  template <typename Range>
87  void
88  operator () (const Range &range) const
89  {
90  for (typename Range::const_iterator p=range.begin();
91  p != range.end(); ++p)
92  apply (f, *p);
93  }
94 
95  private:
99  const F f;
100 
104  template <typename I1, typename I2>
105  static
106  void
107  apply (const F &f,
108  const std::tuple<I1,I2> &p)
109  {
110  *std::get<1>(p) = f (*std::get<0>(p));
111  }
112 
116  template <typename I1, typename I2, typename I3>
117  static
118  void
119  apply (const F &f,
120  const std::tuple<I1,I2,I3> &p)
121  {
122  *std::get<2>(p) = f (*std::get<0>(p),
123  *std::get<1>(p));
124  }
125 
129  template <typename I1, typename I2,
130  typename I3, typename I4>
131  static
132  void
133  apply (const F &f,
134  const std::tuple<I1,I2,I3,I4> &p)
135  {
136  *std::get<3>(p) = f (*std::get<0>(p),
137  *std::get<1>(p),
138  *std::get<2>(p));
139  }
140  };
141 
142 
149  template <typename F>
150  Body<F> make_body(const F &f)
151  {
152  return Body<F>(f);
153  }
154  }
155 
179  template <typename InputIterator,
180  typename OutputIterator,
181  typename Predicate>
182  void transform (const InputIterator &begin_in,
183  const InputIterator &end_in,
184  OutputIterator out,
185  Predicate &predicate,
186  const unsigned int grainsize)
187  {
188 #ifndef DEAL_II_WITH_THREADS
189  // make sure we don't get compiler
190  // warnings about unused arguments
191  (void) grainsize;
192 
193  for (OutputIterator in = begin_in; in != end_in;)
194  *out++ = predicate (*in++);
195 #else
196  typedef std::tuple<InputIterator,OutputIterator> Iterators;
197  typedef SynchronousIterators<Iterators> SyncIterators;
198  Iterators x_begin (begin_in, out);
199  Iterators x_end (end_in, OutputIterator());
200  tbb::parallel_for (tbb::blocked_range<SyncIterators>(x_begin,
201  x_end,
202  grainsize),
203  internal::make_body (predicate),
204  tbb::auto_partitioner());
205 #endif
206  }
207 
208 
209 
233  template <typename InputIterator1,
234  typename InputIterator2,
235  typename OutputIterator,
236  typename Predicate>
237  void transform (const InputIterator1 &begin_in1,
238  const InputIterator1 &end_in1,
239  InputIterator2 in2,
240  OutputIterator out,
241  Predicate &predicate,
242  const unsigned int grainsize)
243  {
244 #ifndef DEAL_II_WITH_THREADS
245  // make sure we don't get compiler
246  // warnings about unused arguments
247  (void) grainsize;
248 
249  for (OutputIterator in1 = begin_in1; in1 != end_in1;)
250  *out++ = predicate (*in1++, *in2++);
251 #else
252  typedef
253  std::tuple<InputIterator1,InputIterator2,OutputIterator>
254  Iterators;
255  typedef SynchronousIterators<Iterators> SyncIterators;
256  Iterators x_begin (begin_in1, in2, out);
257  Iterators x_end (end_in1, InputIterator2(), OutputIterator());
258  tbb::parallel_for (tbb::blocked_range<SyncIterators>(x_begin,
259  x_end,
260  grainsize),
261  internal::make_body (predicate),
262  tbb::auto_partitioner());
263 #endif
264  }
265 
266 
267 
291  template <typename InputIterator1,
292  typename InputIterator2,
293  typename InputIterator3,
294  typename OutputIterator,
295  typename Predicate>
296  void transform (const InputIterator1 &begin_in1,
297  const InputIterator1 &end_in1,
298  InputIterator2 in2,
299  InputIterator3 in3,
300  OutputIterator out,
301  Predicate &predicate,
302  const unsigned int grainsize)
303  {
304 #ifndef DEAL_II_WITH_THREADS
305  // make sure we don't get compiler
306  // warnings about unused arguments
307  (void) grainsize;
308 
309  for (OutputIterator in1 = begin_in1; in1 != end_in1;)
310  *out++ = predicate (*in1++, *in2++, *in3++);
311 #else
312  typedef
313  std::tuple<InputIterator1,InputIterator2,InputIterator3,OutputIterator>
314  Iterators;
315  typedef SynchronousIterators<Iterators> SyncIterators;
316  Iterators x_begin (begin_in1, in2, in3, out);
317  Iterators x_end (end_in1, InputIterator2(),
318  InputIterator3(), OutputIterator());
319  tbb::parallel_for (tbb::blocked_range<SyncIterators>(x_begin,
320  x_end,
321  grainsize),
322  internal::make_body (predicate),
323  tbb::auto_partitioner());
324 #endif
325  }
326 
327 
328  namespace internal
329  {
330 #ifdef DEAL_II_WITH_THREADS
331 
335  template <typename RangeType, typename Function>
336  void apply_to_subranges (const tbb::blocked_range<RangeType> &range,
337  const Function &f)
338  {
339  f (range.begin(), range.end());
340  }
341 #endif
342  }
343 
344 
416  template <typename RangeType, typename Function>
417  void apply_to_subranges (const RangeType &begin,
418  const typename identity<RangeType>::type &end,
419  const Function &f,
420  const unsigned int grainsize)
421  {
422 #ifndef DEAL_II_WITH_THREADS
423  // make sure we don't get compiler
424  // warnings about unused arguments
425  (void) grainsize;
426 
427 # ifndef DEAL_II_BIND_NO_CONST_OP_PARENTHESES
428  f (begin, end);
429 # else
430  // work around a problem with MS VC++ where there is no const
431  // operator() in 'Function' if 'Function' is the result of std::bind
432  Function ff = f;
433  ff (begin, end);
434 # endif
435 #else
436  tbb::parallel_for (tbb::blocked_range<RangeType>
437  (begin, end, grainsize),
438  std::bind (&internal::apply_to_subranges<RangeType,Function>,
439  std::placeholders::_1,
440  std::cref(f)),
441  tbb::auto_partitioner());
442 #endif
443  }
444 
445 
446 
475  {
480  virtual ~ParallelForInteger () = default;
481 
490  void apply_parallel (const std::size_t begin,
491  const std::size_t end,
492  const std::size_t minimum_parallel_grain_size) const;
493 
500  virtual void apply_to_subrange (const std::size_t,
501  const std::size_t) const = 0;
502  };
503 
504 
505 
506  namespace internal
507  {
508 #ifdef DEAL_II_WITH_THREADS
509 
515  template <typename ResultType,
516  typename Function>
518  {
522  ResultType result;
523 
533  template <typename Reductor>
535  const Reductor &reductor,
536  const ResultType neutral_element = ResultType())
537  :
539  f (f),
542  {}
543 
548  tbb::split)
549  :
551  f (r.f),
553  reductor (r.reductor)
554  {}
555 
560  void join (const ReductionOnSubranges &r)
561  {
563  }
564 
568  template <typename RangeType>
569  void operator () (const tbb::blocked_range<RangeType> &range)
570  {
572  f (range.begin(), range.end()));
573  }
574 
575  private:
579  const Function f;
580 
586  const ResultType neutral_element;
587 
592  const std::function<ResultType (ResultType, ResultType)> reductor;
593  };
594 #endif
595  }
596 
597 
657  template <typename ResultType, typename RangeType, typename Function>
658  ResultType accumulate_from_subranges (const Function &f,
659  const RangeType &begin,
660  const typename identity<RangeType>::type &end,
661  const unsigned int grainsize)
662  {
663 #ifndef DEAL_II_WITH_THREADS
664  // make sure we don't get compiler
665  // warnings about unused arguments
666  (void) grainsize;
667 
668 # ifndef DEAL_II_BIND_NO_CONST_OP_PARENTHESES
669  return f (begin, end);
670 # else
671  // work around a problem with MS VC++ where there is no const
672  // operator() in 'Function' if 'Function' is the result of std::bind
673  Function ff = f;
674  return ff (begin, end);
675 # endif
676 #else
678  reductor (f, std::plus<ResultType>(), 0);
679  tbb::parallel_reduce (tbb::blocked_range<RangeType>(begin, end, grainsize),
680  reductor,
681  tbb::auto_partitioner());
682  return reductor.result;
683 #endif
684  }
685 
686 
687 // --------------------- for loop affinity partitioner -----------------------
688 
698  namespace internal
699  {
700  class TBBPartitioner
701  {
702  public:
706  TBBPartitioner();
707 
708 #ifdef DEAL_II_WITH_THREADS
709 
713  ~TBBPartitioner();
714 
721  std::shared_ptr<tbb::affinity_partitioner>
722  acquire_one_partitioner();
723 
729  void release_one_partitioner(std::shared_ptr<tbb::affinity_partitioner> &p);
730 
731  private:
736  std::shared_ptr<tbb::affinity_partitioner> my_partitioner;
737 
742  bool in_use;
743 
747  ::Threads::Mutex mutex;
748 #endif
749  };
750  }
751 }
752 
753 
754 namespace internal
755 {
756  namespace VectorImplementation
757  {
772  extern unsigned int minimum_parallel_grain_size;
773  }
774 
775 
776  namespace SparseMatrixImplementation
777  {
782  extern unsigned int minimum_parallel_grain_size;
783  }
784 
785 } // end of namespace internal
786 
787 
788 /* --------------------------- inline functions ------------------------- */
789 
790 namespace parallel
791 {
792 
793 #ifdef DEAL_II_WITH_THREADS
794 
795  namespace internal
796  {
802  {
804  :
805  worker_ (worker)
806  {}
807 
808  void operator() (const tbb::blocked_range<std::size_t> &range) const
809  {
810  worker_.apply_to_subrange (range.begin(), range.end());
811  }
812 
813  const parallel::ParallelForInteger &worker_;
814  };
815  }
816 
817 #endif
818 
819 
820  inline
821  void
822  ParallelForInteger::apply_parallel (const std::size_t begin,
823  const std::size_t end,
824  const std::size_t minimum_parallel_grain_size) const
825  {
826 #ifndef DEAL_II_WITH_THREADS
827  // make sure we don't get compiler
828  // warnings about unused arguments
829  (void) minimum_parallel_grain_size;
830 
831  apply_to_subrange (begin, end);
832 #else
833  internal::ParallelForWrapper worker(*this);
834  tbb::parallel_for (tbb::blocked_range<std::size_t>
835  (begin, end, minimum_parallel_grain_size),
836  worker,
837  tbb::auto_partitioner());
838 #endif
839  }
840 
841 } // end of namespace parallel
842 
843 DEAL_II_NAMESPACE_CLOSE
844 
845 #endif
Body< F > make_body(const F &f)
Definition: parallel.h:150
const std::function< ResultType(ResultType, ResultType)> reductor
Definition: parallel.h:592
void join(const ReductionOnSubranges &r)
Definition: parallel.h:560
static void apply(const F &f, const std::tuple< I1, I2, I3 > &p)
Definition: parallel.h:119
void operator()(const tbb::blocked_range< RangeType > &range)
Definition: parallel.h:569
void apply_to_subranges(const RangeType &begin, const typename identity< RangeType >::type &end, const Function &f, const unsigned int grainsize)
Definition: parallel.h:417
ReductionOnSubranges(const Function &f, const Reductor &reductor, const ResultType neutral_element=ResultType())
Definition: parallel.h:534
static void apply(const F &f, const std::tuple< I1, I2, I3, I4 > &p)
Definition: parallel.h:133
void apply_to_subranges(const tbb::blocked_range< RangeType > &range, const Function &f)
Definition: parallel.h:336
ReductionOnSubranges(const ReductionOnSubranges &r, tbb::split)
Definition: parallel.h:547
static void apply(const F &f, const std::tuple< I1, I2 > &p)
Definition: parallel.h:107
ResultType accumulate_from_subranges(const Function &f, const RangeType &begin, const typename identity< RangeType >::type &end, const unsigned int grainsize)
Definition: parallel.h:658
void transform(const InputIterator &begin_in, const InputIterator &end_in, OutputIterator out, Predicate &predicate, const unsigned int grainsize)
Definition: parallel.h:182
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:822
virtual void apply_to_subrange(const std::size_t, const std::size_t) const =0
virtual ~ParallelForInteger()=default