Reference documentation for deal.II version Git 7026f387cc 2019-10-15 14:19:01 -0400
\(\newcommand{\dealcoloneq}{\mathrel{\vcenter{:}}=}\)
parallel.h
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2008 - 2019 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.md at
12 // the top level directory of deal.II.
13 //
14 // ---------------------------------------------------------------------
15 
16 #ifndef dealii_parallel_h
17 #define dealii_parallel_h
18 
19 
20 #include <deal.II/base/config.h>
21 
22 #include <deal.II/base/exceptions.h>
23 #include <deal.II/base/synchronous_iterator.h>
24 #include <deal.II/base/template_constraints.h>
25 #include <deal.II/base/thread_management.h>
26 
27 #include <cstddef>
28 #include <functional>
29 #include <memory>
30 #include <tuple>
31 
32 #ifdef DEAL_II_WITH_THREADS
33 # include <tbb/blocked_range.h>
34 # include <tbb/parallel_for.h>
35 # include <tbb/parallel_reduce.h>
36 # include <tbb/partitioner.h>
37 #endif
38 
39 
40 // TODO[WB]: allow calling functions to pass along a tbb::affinity_partitioner
41 // 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
61  // bug 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  : f(f)
85  {}
86 
87  template <typename Range>
88  void
89  operator()(const Range &range) const
90  {
91  for (typename Range::const_iterator p = range.begin(); p != range.end();
92  ++p)
93  apply(f, *p);
94  }
95 
96  private:
100  const F f;
101 
105  template <typename I1, typename I2>
106  static void
107  apply(const F &f, const std::tuple<I1, I2> &p)
108  {
109  *std::get<1>(p) = f(*std::get<0>(p));
110  }
111 
115  template <typename I1, typename I2, typename I3>
116  static void
117  apply(const F &f, const std::tuple<I1, I2, I3> &p)
118  {
119  *std::get<2>(p) = f(*std::get<0>(p), *std::get<1>(p));
120  }
121 
125  template <typename I1, typename I2, typename I3, typename I4>
126  static void
127  apply(const F &f, const std::tuple<I1, I2, I3, I4> &p)
128  {
129  *std::get<3>(p) = f(*std::get<0>(p), *std::get<1>(p), *std::get<2>(p));
130  }
131  };
132 
133 
134 
141  template <typename F>
142  Body<F>
143  make_body(const F &f)
144  {
145  return Body<F>(f);
146  }
147 
148 
149 
150 #ifdef DEAL_II_WITH_THREADS
151 
154  template <typename Iterator, typename Functor>
155  void
156  parallel_for(Iterator x_begin,
157  Iterator x_end,
158  const Functor & functor,
159  const unsigned int grainsize)
160  {
161  tbb::parallel_for(tbb::blocked_range<Iterator>(x_begin, x_end, grainsize),
162  functor,
163  tbb::auto_partitioner());
164  }
165 
166 
167 
171  template <typename Iterator, typename Functor>
172  void
173  parallel_for(Iterator x_begin,
174  Iterator x_end,
175  const Functor & functor,
176  const unsigned int grainsize,
177  const std::shared_ptr<tbb::affinity_partitioner> &partitioner)
178  {
179  tbb::parallel_for(tbb::blocked_range<Iterator>(x_begin, x_end, grainsize),
180  functor,
181  *partitioner);
182  }
183 #endif
184  } // namespace internal
185 
209  template <typename InputIterator, typename OutputIterator, typename Predicate>
210  void
211  transform(const InputIterator &begin_in,
212  const InputIterator &end_in,
213  OutputIterator out,
214  const Predicate & predicate,
215  const unsigned int grainsize)
216  {
217 #ifndef DEAL_II_WITH_THREADS
218  // make sure we don't get compiler
219  // warnings about unused arguments
220  (void)grainsize;
221 
222  for (OutputIterator in = begin_in; in != end_in;)
223  *out++ = predicate(*in++);
224 #else
225  using Iterators = std::tuple<InputIterator, OutputIterator>;
226  using SyncIterators = SynchronousIterators<Iterators>;
227  Iterators x_begin(begin_in, out);
228  Iterators x_end(end_in, OutputIterator());
229  internal::parallel_for(SyncIterators(x_begin),
230  SyncIterators(x_end),
231  internal::make_body(predicate),
232  grainsize);
233 #endif
234  }
235 
236 
237 
261  template <typename InputIterator1,
262  typename InputIterator2,
263  typename OutputIterator,
264  typename Predicate>
265  void
266  transform(const InputIterator1 &begin_in1,
267  const InputIterator1 &end_in1,
268  InputIterator2 in2,
269  OutputIterator out,
270  const Predicate & predicate,
271  const unsigned int grainsize)
272  {
273 #ifndef DEAL_II_WITH_THREADS
274  // make sure we don't get compiler
275  // warnings about unused arguments
276  (void)grainsize;
277 
278  for (OutputIterator in1 = begin_in1; in1 != end_in1;)
279  *out++ = predicate(*in1++, *in2++);
280 #else
281  using Iterators =
282  std::tuple<InputIterator1, InputIterator2, OutputIterator>;
283  using SyncIterators = SynchronousIterators<Iterators>;
284  Iterators x_begin(begin_in1, in2, out);
285  Iterators x_end(end_in1, InputIterator2(), OutputIterator());
286  internal::parallel_for(SyncIterators(x_begin),
287  SyncIterators(x_end),
288  internal::make_body(predicate),
289  grainsize);
290 #endif
291  }
292 
293 
294 
318  template <typename InputIterator1,
319  typename InputIterator2,
320  typename InputIterator3,
321  typename OutputIterator,
322  typename Predicate>
323  void
324  transform(const InputIterator1 &begin_in1,
325  const InputIterator1 &end_in1,
326  InputIterator2 in2,
327  InputIterator3 in3,
328  OutputIterator out,
329  const Predicate & predicate,
330  const unsigned int grainsize)
331  {
332 #ifndef DEAL_II_WITH_THREADS
333  // make sure we don't get compiler
334  // warnings about unused arguments
335  (void)grainsize;
336 
337  for (OutputIterator in1 = begin_in1; in1 != end_in1;)
338  *out++ = predicate(*in1++, *in2++, *in3++);
339 #else
340  using Iterators = std::
341  tuple<InputIterator1, InputIterator2, InputIterator3, OutputIterator>;
342  using SyncIterators = SynchronousIterators<Iterators>;
343  Iterators x_begin(begin_in1, in2, in3, out);
344  Iterators x_end(end_in1,
345  InputIterator2(),
346  InputIterator3(),
347  OutputIterator());
348  internal::parallel_for(SyncIterators(x_begin),
349  SyncIterators(x_end),
350  internal::make_body(predicate),
351  grainsize);
352 #endif
353  }
354 
355 
356  namespace internal
357  {
358 #ifdef DEAL_II_WITH_THREADS
359 
363  template <typename RangeType, typename Function>
364  void
365  apply_to_subranges(const tbb::blocked_range<RangeType> &range,
366  const Function & f)
367  {
368  f(range.begin(), range.end());
369  }
370 #endif
371  } // namespace internal
372 
373 
445  template <typename RangeType, typename Function>
446  void
447  apply_to_subranges(const RangeType & begin,
448  const typename identity<RangeType>::type &end,
449  const Function & f,
450  const unsigned int grainsize)
451  {
452 #ifndef DEAL_II_WITH_THREADS
453  // make sure we don't get compiler
454  // warnings about unused arguments
455  (void)grainsize;
456 
457 # ifndef DEAL_II_BIND_NO_CONST_OP_PARENTHESES
458  f(begin, end);
459 # else
460  // work around a problem with MS VC++ where there is no const
461  // operator() in 'Function' if 'Function' is the result of std::bind
462  Function ff = f;
463  ff(begin, end);
464 # endif
465 #else
467  end,
468  [&f](const tbb::blocked_range<RangeType> &range) {
469  internal::apply_to_subranges<RangeType, Function>(
470  range, f);
471  },
472  grainsize);
473 #endif
474  }
475 
476 
477 
506  {
511  virtual ~ParallelForInteger() = default;
512 
521  void
522  apply_parallel(const std::size_t begin,
523  const std::size_t end,
524  const std::size_t minimum_parallel_grain_size) const;
525 
532  virtual void
533  apply_to_subrange(const std::size_t, const std::size_t) const = 0;
534  };
535 
536 
537 
538  namespace internal
539  {
540 #ifdef DEAL_II_WITH_THREADS
541 
547  template <typename ResultType, typename Function>
549  {
553  ResultType result;
554 
564  template <typename Reductor>
566  const Reductor & reductor,
567  const ResultType neutral_element = ResultType())
568  : result(neutral_element)
569  , f(f)
570  , neutral_element(neutral_element)
571  , reductor(reductor)
572  {}
573 
578  : result(r.neutral_element)
579  , f(r.f)
580  , neutral_element(r.neutral_element)
581  , reductor(r.reductor)
582  {}
583 
588  void
590  {
591  result = reductor(result, r.result);
592  }
593 
597  template <typename RangeType>
598  void
599  operator()(const tbb::blocked_range<RangeType> &range)
600  {
601  result = reductor(result, f(range.begin(), range.end()));
602  }
603 
604  private:
608  const Function f;
609 
615  const ResultType neutral_element;
616 
621  const std::function<ResultType(ResultType, ResultType)> reductor;
622  };
623 #endif
624  } // namespace internal
625 
626 
686  template <typename ResultType, typename RangeType, typename Function>
687  ResultType
689  const RangeType & begin,
690  const typename identity<RangeType>::type &end,
691  const unsigned int grainsize)
692  {
693 #ifndef DEAL_II_WITH_THREADS
694  // make sure we don't get compiler
695  // warnings about unused arguments
696  (void)grainsize;
697 
698 # ifndef DEAL_II_BIND_NO_CONST_OP_PARENTHESES
699  return f(begin, end);
700 # else
701  // work around a problem with MS VC++ where there is no const
702  // operator() in 'Function' if 'Function' is the result of std::bind
703  Function ff = f;
704  return ff(begin, end);
705 # endif
706 #else
708  f, std::plus<ResultType>(), 0);
709  tbb::parallel_reduce(tbb::blocked_range<RangeType>(begin, end, grainsize),
710  reductor,
711  tbb::auto_partitioner());
712  return reductor.result;
713 #endif
714  }
715 
716 
717  // --------------------- for loop affinity partitioner -----------------------
718 
728  namespace internal
729  {
730  class TBBPartitioner
731  {
732  public:
736  TBBPartitioner();
737 
738 #ifdef DEAL_II_WITH_THREADS
739 
743  ~TBBPartitioner();
744 
751  std::shared_ptr<tbb::affinity_partitioner>
752  acquire_one_partitioner();
753 
759  void
760  release_one_partitioner(std::shared_ptr<tbb::affinity_partitioner> &p);
761 
762  private:
767  std::shared_ptr<tbb::affinity_partitioner> my_partitioner;
768 
773  bool in_use;
774 
778  ::Threads::Mutex mutex;
779 #endif
780  };
781  } // namespace internal
782 } // namespace parallel
783 
784 
785 namespace internal
786 {
787  namespace VectorImplementation
788  {
803  extern unsigned int minimum_parallel_grain_size;
804  } // namespace VectorImplementation
805 
806 
807  namespace SparseMatrixImplementation
808  {
814  extern unsigned int minimum_parallel_grain_size;
815  } // namespace SparseMatrixImplementation
816 
817 } // end of namespace internal
818 
819 
820 /* --------------------------- inline functions ------------------------- */
821 
822 namespace parallel
823 {
824 #ifdef DEAL_II_WITH_THREADS
825 
826  namespace internal
827  {
833  {
835  : worker_(worker)
836  {}
837 
838  void
839  operator()(const tbb::blocked_range<std::size_t> &range) const
840  {
841  worker_.apply_to_subrange(range.begin(), range.end());
842  }
843 
844  const parallel::ParallelForInteger &worker_;
845  };
846  } // namespace internal
847 
848 #endif
849 
850 
851  inline void
853  const std::size_t begin,
854  const std::size_t end,
855  const std::size_t minimum_parallel_grain_size) const
856  {
857 #ifndef DEAL_II_WITH_THREADS
858  // make sure we don't get compiler
859  // warnings about unused arguments
860  (void)minimum_parallel_grain_size;
861 
862  apply_to_subrange(begin, end);
863 #else
864  internal::ParallelForWrapper worker(*this);
865  internal::parallel_for(begin, end, worker, minimum_parallel_grain_size);
866 #endif
867  }
868 
869 } // end of namespace parallel
870 
871 DEAL_II_NAMESPACE_CLOSE
872 
873 #endif
Body< F > make_body(const F &f)
Definition: parallel.h:143
void transform(const InputIterator &begin_in, const InputIterator &end_in, OutputIterator out, const Predicate &predicate, const unsigned int grainsize)
Definition: parallel.h:211
void parallel_for(Iterator x_begin, Iterator x_end, const Functor &functor, const unsigned int grainsize)
Definition: parallel.h:156
void join(const ReductionOnSubranges &r)
Definition: parallel.h:589
static void apply(const F &f, const std::tuple< I1, I2, I3 > &p)
Definition: parallel.h:117
void operator()(const tbb::blocked_range< RangeType > &range)
Definition: parallel.h:599
ReductionOnSubranges(const Function &f, const Reductor &reductor, const ResultType neutral_element=ResultType())
Definition: parallel.h:565
static void apply(const F &f, const std::tuple< I1, I2, I3, I4 > &p)
Definition: parallel.h:127
void apply_to_subranges(const tbb::blocked_range< RangeType > &range, const Function &f)
Definition: parallel.h:365
ReductionOnSubranges(const ReductionOnSubranges &r, tbb::split)
Definition: parallel.h:577
const std::function< ResultType(ResultType, ResultType)> reductor
Definition: parallel.h:621
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:688
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:852