Reference documentation for deal.II version Git ce7b8fd3ef 2020-09-19 21:33:14 +0200
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
parallel.h
Go to the documentation of this file.
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2008 - 2020 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 
26 
27 #include <cstddef>
28 #include <functional>
29 #include <memory>
30 #include <tuple>
31 
32 #ifdef DEAL_II_WITH_TBB
34 # include <tbb/blocked_range.h>
35 # include <tbb/parallel_for.h>
36 # include <tbb/parallel_reduce.h>
37 # include <tbb/partitioner.h>
39 #endif
40 
41 
42 // TODO[WB]: allow calling functions to pass along a tbb::affinity_partitioner
43 // object to ensure that subsequent calls use the same cache lines
44 
46 
47 namespace parallel
48 {
49  namespace internal
50  {
55  template <typename Number>
57  {
58  static const bool value = true;
59  };
60 
61 #ifdef __INTEL_COMPILER
62  // Disable long double SIMD instructions on ICC. This is to work around a
63  // bug that generates wrong code at least up to intel 15 (see
64  // tests/lac/vector-vector, tests/lac/intel-15-bug, and the discussion at
65  // https://github.com/dealii/dealii/issues/598).
66  template <>
67  struct EnableOpenMPSimdFor<long double>
68  {
69  static const bool value = false;
70  };
71 #endif
72 
73 
74 
79  template <typename F>
80  struct Body
81  {
85  Body(const F &f)
86  : f(f)
87  {}
88 
89  template <typename Range>
90  void
91  operator()(const Range &range) const
92  {
93  for (typename Range::const_iterator p = range.begin(); p != range.end();
94  ++p)
95  apply(f, *p);
96  }
97 
98  private:
102  const F f;
103 
107  template <typename I1, typename I2>
108  static void
109  apply(const F &f, const std::tuple<I1, I2> &p)
110  {
111  *std::get<1>(p) = f(*std::get<0>(p));
112  }
113 
117  template <typename I1, typename I2, typename I3>
118  static void
119  apply(const F &f, const std::tuple<I1, I2, I3> &p)
120  {
121  *std::get<2>(p) = f(*std::get<0>(p), *std::get<1>(p));
122  }
123 
127  template <typename I1, typename I2, typename I3, typename I4>
128  static void
129  apply(const F &f, const std::tuple<I1, I2, I3, I4> &p)
130  {
131  *std::get<3>(p) = f(*std::get<0>(p), *std::get<1>(p), *std::get<2>(p));
132  }
133  };
134 
135 
136 
143  template <typename F>
144  Body<F>
145  make_body(const F &f)
146  {
147  return Body<F>(f);
148  }
149 
150 
151 
152 #ifdef DEAL_II_WITH_TBB
153 
156  template <typename Iterator, typename Functor>
157  void
158  parallel_for(Iterator x_begin,
159  Iterator x_end,
160  const Functor & functor,
161  const unsigned int grainsize)
162  {
163  tbb::parallel_for(tbb::blocked_range<Iterator>(x_begin, x_end, grainsize),
164  functor,
165  tbb::auto_partitioner());
166  }
167 
168 
169 
173  template <typename Iterator, typename Functor>
174  void
175  parallel_for(Iterator x_begin,
176  Iterator x_end,
177  const Functor & functor,
178  const unsigned int grainsize,
179  const std::shared_ptr<tbb::affinity_partitioner> &partitioner)
180  {
181  tbb::parallel_for(tbb::blocked_range<Iterator>(x_begin, x_end, grainsize),
182  functor,
183  *partitioner);
184  }
185 #endif
186  } // namespace internal
187 
211  template <typename InputIterator, typename OutputIterator, typename Predicate>
212  void
213  transform(const InputIterator &begin_in,
214  const InputIterator &end_in,
215  OutputIterator out,
216  const Predicate & predicate,
217  const unsigned int grainsize)
218  {
219 #ifndef DEAL_II_WITH_TBB
220  // make sure we don't get compiler
221  // warnings about unused arguments
222  (void)grainsize;
223 
224  for (OutputIterator in = begin_in; in != end_in;)
225  *out++ = predicate(*in++);
226 #else
227  using Iterators = std::tuple<InputIterator, OutputIterator>;
228  using SyncIterators = SynchronousIterators<Iterators>;
229  Iterators x_begin(begin_in, out);
230  Iterators x_end(end_in, OutputIterator());
231  internal::parallel_for(SyncIterators(x_begin),
232  SyncIterators(x_end),
233  internal::make_body(predicate),
234  grainsize);
235 #endif
236  }
237 
238 
239 
263  template <typename InputIterator1,
264  typename InputIterator2,
265  typename OutputIterator,
266  typename Predicate>
267  void
268  transform(const InputIterator1 &begin_in1,
269  const InputIterator1 &end_in1,
270  InputIterator2 in2,
271  OutputIterator out,
272  const Predicate & predicate,
273  const unsigned int grainsize)
274  {
275 #ifndef DEAL_II_WITH_TBB
276  // make sure we don't get compiler
277  // warnings about unused arguments
278  (void)grainsize;
279 
280  for (OutputIterator in1 = begin_in1; in1 != end_in1;)
281  *out++ = predicate(*in1++, *in2++);
282 #else
283  using Iterators =
284  std::tuple<InputIterator1, InputIterator2, OutputIterator>;
285  using SyncIterators = SynchronousIterators<Iterators>;
286  Iterators x_begin(begin_in1, in2, out);
287  Iterators x_end(end_in1, InputIterator2(), OutputIterator());
288  internal::parallel_for(SyncIterators(x_begin),
289  SyncIterators(x_end),
290  internal::make_body(predicate),
291  grainsize);
292 #endif
293  }
294 
295 
296 
320  template <typename InputIterator1,
321  typename InputIterator2,
322  typename InputIterator3,
323  typename OutputIterator,
324  typename Predicate>
325  void
326  transform(const InputIterator1 &begin_in1,
327  const InputIterator1 &end_in1,
328  InputIterator2 in2,
329  InputIterator3 in3,
330  OutputIterator out,
331  const Predicate & predicate,
332  const unsigned int grainsize)
333  {
334 #ifndef DEAL_II_WITH_TBB
335  // make sure we don't get compiler
336  // warnings about unused arguments
337  (void)grainsize;
338 
339  for (OutputIterator in1 = begin_in1; in1 != end_in1;)
340  *out++ = predicate(*in1++, *in2++, *in3++);
341 #else
342  using Iterators = std::
343  tuple<InputIterator1, InputIterator2, InputIterator3, OutputIterator>;
344  using SyncIterators = SynchronousIterators<Iterators>;
345  Iterators x_begin(begin_in1, in2, in3, out);
346  Iterators x_end(end_in1,
347  InputIterator2(),
348  InputIterator3(),
349  OutputIterator());
350  internal::parallel_for(SyncIterators(x_begin),
351  SyncIterators(x_end),
352  internal::make_body(predicate),
353  grainsize);
354 #endif
355  }
356 
357 
358  namespace internal
359  {
360 #ifdef DEAL_II_WITH_TBB
361 
365  template <typename RangeType, typename Function>
366  void
367  apply_to_subranges(const tbb::blocked_range<RangeType> &range,
368  const Function & f)
369  {
370  f(range.begin(), range.end());
371  }
372 #endif
373  } // namespace internal
374 
375 
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_TBB
453  // make sure we don't get compiler
454  // warnings about unused arguments
455  (void)grainsize;
456 
457  f(begin, end);
458 #else
460  end,
461  [&f](const tbb::blocked_range<RangeType> &range) {
462  internal::apply_to_subranges<RangeType, Function>(
463  range, f);
464  },
465  grainsize);
466 #endif
467  }
468 
469 
470 
499  {
504  virtual ~ParallelForInteger() = default;
505 
514  void
515  apply_parallel(const std::size_t begin,
516  const std::size_t end,
517  const std::size_t minimum_parallel_grain_size) const;
518 
525  virtual void
526  apply_to_subrange(const std::size_t, const std::size_t) const = 0;
527  };
528 
529 
530 
531  namespace internal
532  {
533 #ifdef DEAL_II_WITH_TBB
534 
540  template <typename ResultType, typename Function>
542  {
546  ResultType result;
547 
557  template <typename Reductor>
559  const Reductor & reductor,
560  const ResultType neutral_element = ResultType())
561  : result(neutral_element)
562  , f(f)
563  , neutral_element(neutral_element)
564  , reductor(reductor)
565  {}
566 
571  : result(r.neutral_element)
572  , f(r.f)
573  , neutral_element(r.neutral_element)
574  , reductor(r.reductor)
575  {}
576 
581  void
583  {
584  result = reductor(result, r.result);
585  }
586 
590  template <typename RangeType>
591  void
592  operator()(const tbb::blocked_range<RangeType> &range)
593  {
594  result = reductor(result, f(range.begin(), range.end()));
595  }
596 
597  private:
601  const Function f;
602 
608  const ResultType neutral_element;
609 
614  const std::function<ResultType(ResultType, ResultType)> reductor;
615  };
616 #endif
617  } // namespace internal
618 
619 
680  template <typename ResultType, typename RangeType, typename Function>
681  ResultType
683  const RangeType & begin,
684  const typename identity<RangeType>::type &end,
685  const unsigned int grainsize)
686  {
687 #ifndef DEAL_II_WITH_TBB
688  // make sure we don't get compiler
689  // warnings about unused arguments
690  (void)grainsize;
691 
692  return f(begin, end);
693 #else
695  f, std::plus<ResultType>(), 0);
696  tbb::parallel_reduce(tbb::blocked_range<RangeType>(begin, end, grainsize),
697  reductor,
698  tbb::auto_partitioner());
699  return reductor.result;
700 #endif
701  }
702 
703 
704  // --------------------- for loop affinity partitioner -----------------------
705 
715  namespace internal
716  {
718  {
719  public:
723  TBBPartitioner();
724 
725 #ifdef DEAL_II_WITH_TBB
726 
730  ~TBBPartitioner();
731 
738  std::shared_ptr<tbb::affinity_partitioner>
739  acquire_one_partitioner();
740 
746  void
747  release_one_partitioner(std::shared_ptr<tbb::affinity_partitioner> &p);
748 
749  private:
754  std::shared_ptr<tbb::affinity_partitioner> my_partitioner;
755 
760  bool in_use;
761 
765  std::mutex mutex;
766 #endif
767  };
768  } // namespace internal
769 } // namespace parallel
770 
771 
772 namespace internal
773 {
774  namespace VectorImplementation
775  {
790  extern unsigned int minimum_parallel_grain_size;
791  } // namespace VectorImplementation
792 
793 
794  namespace SparseMatrixImplementation
795  {
801  extern unsigned int minimum_parallel_grain_size;
802  } // namespace SparseMatrixImplementation
803 
804 } // end of namespace internal
805 
806 
807 /* --------------------------- inline functions ------------------------- */
808 
809 namespace parallel
810 {
811 #ifdef DEAL_II_WITH_TBB
812 
813  namespace internal
814  {
820  {
822  : worker_(worker)
823  {}
824 
825  void
826  operator()(const tbb::blocked_range<std::size_t> &range) const
827  {
828  worker_.apply_to_subrange(range.begin(), range.end());
829  }
830 
832  };
833  } // namespace internal
834 
835 #endif
836 
837 
838  inline void
840  const std::size_t begin,
841  const std::size_t end,
842  const std::size_t minimum_parallel_grain_size) const
843  {
844 #ifndef DEAL_II_WITH_TBB
845  // make sure we don't get compiler
846  // warnings about unused arguments
847  (void)minimum_parallel_grain_size;
848 
849  apply_to_subrange(begin, end);
850 #else
851  internal::ParallelForWrapper worker(*this);
852  internal::parallel_for(begin, end, worker, minimum_parallel_grain_size);
853 #endif
854  }
855 
856 } // end of namespace parallel
857 
859 
860 #endif
Body< F > make_body(const F &f)
Definition: parallel.h:145
void transform(const InputIterator &begin_in, const InputIterator &end_in, OutputIterator out, const Predicate &predicate, const unsigned int grainsize)
Definition: parallel.h:213
void parallel_for(Iterator x_begin, Iterator x_end, const Functor &functor, const unsigned int grainsize)
Definition: parallel.h:158
void join(const ReductionOnSubranges &r)
Definition: parallel.h:582
static void apply(const F &f, const std::tuple< I1, I2, I3 > &p)
Definition: parallel.h:119
std::shared_ptr< tbb::affinity_partitioner > my_partitioner
Definition: parallel.h:754
void operator()(const tbb::blocked_range< RangeType > &range)
Definition: parallel.h:592
Tensor< 2, dim, Number > F(const Tensor< 2, dim, Number > &Grad_u)
#define DEAL_II_DISABLE_EXTRA_DIAGNOSTICS
Definition: config.h:376
ReductionOnSubranges(const Function &f, const Reductor &reductor, const ResultType neutral_element=ResultType())
Definition: parallel.h:558
static void apply(const F &f, const std::tuple< I1, I2, I3, I4 > &p)
Definition: parallel.h:129
void apply_to_subranges(const tbb::blocked_range< RangeType > &range, const Function &f)
Definition: parallel.h:367
auto apply(F &&fn, Tuple &&t) -> decltype(apply_impl(std::forward< F >(fn), std::forward< Tuple >(t), std::make_index_sequence< std::tuple_size< typename std::remove_reference< Tuple >::type >::value >()))
Definition: tuple.h:36
#define DEAL_II_NAMESPACE_CLOSE
Definition: config.h:363
VectorType::value_type * end(VectorType &V)
ReductionOnSubranges(const ReductionOnSubranges &r, tbb::split)
Definition: parallel.h:570
void parallel_reduce(const Operation &op, const size_type start, const size_type end, ResultType &result, const std::shared_ptr<::parallel::internal::TBBPartitioner > &partitioner)
const std::function< ResultType(ResultType, ResultType)> reductor
Definition: parallel.h:614
static void apply(const F &f, const std::tuple< I1, I2 > &p)
Definition: parallel.h:109
void parallel_for(Iterator x_begin, Iterator x_end, const Functor &functor, const unsigned int grainsize, const std::shared_ptr< tbb::affinity_partitioner > &partitioner)
Definition: parallel.h:175
ResultType accumulate_from_subranges(const Function &f, const RangeType &begin, const typename identity< RangeType >::type &end, const unsigned int grainsize)
Definition: parallel.h:682
std::vector< value_type > split(const typename ::Triangulation< dim, spacedim >::cell_iterator &parent, const value_type parent_value)
void operator()(const Range &range) const
Definition: parallel.h:91
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:839
#define DEAL_II_ENABLE_EXTRA_DIAGNOSTICS
Definition: config.h:413
#define DEAL_II_NAMESPACE_OPEN
Definition: config.h:362
VectorType::value_type * begin(VectorType &V)
void operator()(const tbb::blocked_range< std::size_t > &range) const
Definition: parallel.h:826
const parallel::ParallelForInteger & worker_
Definition: parallel.h:831
ParallelForWrapper(const parallel::ParallelForInteger &worker)
Definition: parallel.h:821