Reference documentation for deal.II version GIT c14369f203 2023-10-01 07:40:02+00:00
\(\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 - 2023 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 
23 #include <deal.II/base/mutex.h>
26 
27 #include <cstddef>
28 #include <functional>
29 #include <memory>
30 #include <tuple>
31 
32 #ifdef DEAL_II_WITH_TBB
33 # include <tbb/blocked_range.h>
34 # include <tbb/parallel_for.h>
35 # include <tbb/parallel_reduce.h>
36 # include <tbb/partitioner.h>
37 #else
38 # include <boost/range/iterator_range.hpp>
39 #endif
40 
41 #ifdef DEAL_II_HAVE_CXX20
42 # include <concepts>
43 #endif
44 
45 
46 // TODO[WB]: allow calling functions to pass along a tbb::affinity_partitioner
47 // object to ensure that subsequent calls use the same cache lines
48 
50 
51 namespace parallel
52 {
53  namespace internal
54  {
59  template <typename Number>
61  {
62  static const bool value = true;
63  };
64 
65 #ifdef __INTEL_COMPILER
66  // Disable long double SIMD instructions on ICC. This is to work around a
67  // bug that generates wrong code at least up to intel 15 (see
68  // tests/lac/vector-vector, tests/lac/intel-15-bug, and the discussion at
69  // https://github.com/dealii/dealii/issues/598).
70  template <>
71  struct EnableOpenMPSimdFor<long double>
72  {
73  static const bool value = false;
74  };
75 #endif
76 
77 
78 #ifdef DEAL_II_WITH_TBB
82  template <typename Iterator, typename Functor>
83  void
84  parallel_for(Iterator x_begin,
85  Iterator x_end,
86  const Functor &functor,
87  const unsigned int grainsize)
88  {
89  tbb::parallel_for(tbb::blocked_range<Iterator>(x_begin, x_end, grainsize),
90  functor,
91  tbb::auto_partitioner());
92  }
93 
94 
95 
99  template <typename Iterator, typename Functor>
100  void
101  parallel_for(Iterator x_begin,
102  Iterator x_end,
103  const Functor &functor,
104  const unsigned int grainsize,
105  const std::shared_ptr<tbb::affinity_partitioner> &partitioner)
106  {
107  tbb::parallel_for(tbb::blocked_range<Iterator>(x_begin, x_end, grainsize),
108  functor,
109  *partitioner);
110  }
111 
112 #else
113 
117  template <typename Iterator, typename Functor>
118  void
119  parallel_for(Iterator x_begin,
120  Iterator x_end,
121  const Functor &functor,
122  const unsigned int)
123  {
124  functor(boost::iterator_range<Iterator>(x_begin, x_end));
125  }
126 
127 #endif
128  } // namespace internal
129 
159  template <typename InputIterator, typename OutputIterator, typename Function>
161  (std::invocable<Function, decltype(*std::declval<InputIterator>())> &&
162  std::assignable_from<
163  decltype(*std::declval<OutputIterator>()),
164  std::invoke_result_t<Function,
165  decltype(*std::declval<InputIterator>())>>))
166  void transform(const InputIterator &begin_in,
167  const InputIterator &end_in,
168  OutputIterator out,
169  const Function &function,
170  const unsigned int grainsize)
171  {
172 #ifndef DEAL_II_WITH_TBB
173  // make sure we don't get compiler
174  // warnings about unused arguments
175  (void)grainsize;
176 
177  for (OutputIterator in = begin_in; in != end_in;)
178  *out++ = function(*in++);
179 #else
180  using Iterators = std::tuple<InputIterator, OutputIterator>;
181  using SyncIterators = SynchronousIterators<Iterators>;
182  Iterators x_begin(begin_in, out);
183  Iterators x_end(end_in, OutputIterator());
185  SyncIterators(x_begin),
186  SyncIterators(x_end),
187  [function](const auto &range) {
188  for (const auto &p : range)
189  *std::get<1>(p) = function(*std::get<0>(p));
190  },
191  grainsize);
192 #endif
193  }
194 
195 
196 
228  template <typename InputIterator1,
229  typename InputIterator2,
230  typename OutputIterator,
231  typename Function>
233  (std::invocable<Function,
234  decltype(*std::declval<InputIterator1>()),
235  decltype(*std::declval<InputIterator2>())> &&
236  std::assignable_from<
237  decltype(*std::declval<OutputIterator>()),
238  std::invoke_result_t<Function,
239  decltype(*std::declval<InputIterator1>()),
240  decltype(*std::declval<InputIterator2>())>>))
241  void transform(const InputIterator1 &begin_in1,
242  const InputIterator1 &end_in1,
243  InputIterator2 in2,
244  OutputIterator out,
245  const Function &function,
246  const unsigned int grainsize)
247  {
248 #ifndef DEAL_II_WITH_TBB
249  // make sure we don't get compiler
250  // warnings about unused arguments
251  (void)grainsize;
252 
253  for (OutputIterator in1 = begin_in1; in1 != end_in1;)
254  *out++ = function(*in1++, *in2++);
255 #else
256  using Iterators =
257  std::tuple<InputIterator1, InputIterator2, OutputIterator>;
258  using SyncIterators = SynchronousIterators<Iterators>;
259  Iterators x_begin(begin_in1, in2, out);
260  Iterators x_end(end_in1, InputIterator2(), OutputIterator());
262  SyncIterators(x_begin),
263  SyncIterators(x_end),
264  [function](const auto &range) {
265  for (const auto &p : range)
266  *std::get<2>(p) = function(*std::get<0>(p), *std::get<1>(p));
267  },
268  grainsize);
269 #endif
270  }
271 
272 
273 
307  template <typename InputIterator1,
308  typename InputIterator2,
309  typename InputIterator3,
310  typename OutputIterator,
311  typename Function>
313  (std::invocable<Function,
314  decltype(*std::declval<InputIterator1>()),
315  decltype(*std::declval<InputIterator2>()),
316  decltype(*std::declval<InputIterator3>())> &&
317  std::assignable_from<
318  decltype(*std::declval<OutputIterator>()),
319  std::invoke_result_t<Function,
320  decltype(*std::declval<InputIterator1>()),
321  decltype(*std::declval<InputIterator2>()),
322  decltype(*std::declval<InputIterator3>())>>))
323  void transform(const InputIterator1 &begin_in1,
324  const InputIterator1 &end_in1,
325  InputIterator2 in2,
326  InputIterator3 in3,
327  OutputIterator out,
328  const Function &function,
329  const unsigned int grainsize)
330  {
331 #ifndef DEAL_II_WITH_TBB
332  // make sure we don't get compiler
333  // warnings about unused arguments
334  (void)grainsize;
335 
336  for (OutputIterator in1 = begin_in1; in1 != end_in1;)
337  *out++ = function(*in1++, *in2++, *in3++);
338 #else
339  using Iterators = std::
340  tuple<InputIterator1, InputIterator2, InputIterator3, OutputIterator>;
341  using SyncIterators = SynchronousIterators<Iterators>;
342  Iterators x_begin(begin_in1, in2, in3, out);
343  Iterators x_end(end_in1,
344  InputIterator2(),
345  InputIterator3(),
346  OutputIterator());
348  SyncIterators(x_begin),
349  SyncIterators(x_end),
350  [function](const auto &range) {
351  for (const auto &p : range)
352  *std::get<3>(p) =
353  function(*std::get<0>(p), *std::get<1>(p), *std::get<2>(p));
354  },
355  grainsize);
356 #endif
357  }
358 
359 
360  namespace internal
361  {
362 #ifdef DEAL_II_WITH_TBB
369  template <typename Iterator, typename Function>
370  DEAL_II_CXX20_REQUIRES((std::invocable<Function, Iterator, Iterator>))
371  void apply_to_subranges(const tbb::blocked_range<Iterator> &range,
372  const Function &f)
373  {
374  f(range.begin(), range.end());
375  }
376 #endif
377  } // namespace internal
378 
379 
451  template <typename Iterator, typename Function>
452  DEAL_II_CXX20_REQUIRES((std::invocable<Function, Iterator, Iterator>))
453  void apply_to_subranges(const Iterator &begin,
454  const std_cxx20::type_identity_t<Iterator> &end,
455  const Function &f,
456  const unsigned int grainsize)
457  {
458 #ifndef DEAL_II_WITH_TBB
459  // make sure we don't get compiler
460  // warnings about unused arguments
461  (void)grainsize;
462 
463  f(begin, end);
464 #else
466  begin,
467  end,
468  [&f](const tbb::blocked_range<Iterator> &range) {
469  internal::apply_to_subranges<Iterator, Function>(range, f);
470  },
471  grainsize);
472 #endif
473  }
474 
475 
476 
505  {
510  virtual ~ParallelForInteger() = default;
511 
520  void
521  apply_parallel(const std::size_t begin,
522  const std::size_t end,
523  const std::size_t minimum_parallel_grain_size) const;
524 
531  virtual void
532  apply_to_subrange(const std::size_t, const std::size_t) const = 0;
533  };
534 
535 
536 
603  template <typename ResultType, typename Iterator, typename Function>
605  (std::invocable<Function, Iterator, Iterator> &&
606  std::convertible_to<std::invoke_result_t<Function, Iterator, Iterator>,
607  ResultType>))
608  ResultType
610  const Iterator &begin,
611  const std_cxx20::type_identity_t<Iterator> &end,
612  const unsigned int grainsize)
613  {
614 #ifndef DEAL_II_WITH_TBB
615  // make sure we don't get compiler
616  // warnings about unused arguments
617  (void)grainsize;
618 
619  return f(begin, end);
620 #else
621  return tbb::parallel_reduce(
622  tbb::blocked_range<Iterator>(begin, end, grainsize),
623  ResultType(0),
624  [f](const auto &range, const ResultType &starting_value) {
625  ResultType value = starting_value;
626  value += f(range.begin(), range.end());
627  return value;
628  },
629  std::plus<ResultType>(),
630  tbb::auto_partitioner());
631 #endif
632  }
633 
634 
635  // --------------------- for loop affinity partitioner -----------------------
636 
646  namespace internal
647  {
649  {
650  public:
654  TBBPartitioner();
655 
656 #ifdef DEAL_II_WITH_TBB
661  ~TBBPartitioner();
662 
669  std::shared_ptr<tbb::affinity_partitioner>
671 
677  void
678  release_one_partitioner(std::shared_ptr<tbb::affinity_partitioner> &p);
679 
680  private:
685  std::shared_ptr<tbb::affinity_partitioner> my_partitioner;
686 
691  bool in_use;
692 
697 #endif
698  };
699  } // namespace internal
700 } // namespace parallel
701 
702 
703 namespace internal
704 {
705  namespace VectorImplementation
706  {
721  extern unsigned int minimum_parallel_grain_size;
722  } // namespace VectorImplementation
723 
724 
725  namespace SparseMatrixImplementation
726  {
732  extern unsigned int minimum_parallel_grain_size;
733  } // namespace SparseMatrixImplementation
734 
735 } // end of namespace internal
736 
737 
738 /* --------------------------- inline functions ------------------------- */
739 
740 namespace parallel
741 {
742  inline void
744  const std::size_t begin,
745  const std::size_t end,
746  const std::size_t minimum_parallel_grain_size) const
747  {
748 #ifndef DEAL_II_WITH_TBB
749  // make sure we don't get compiler
750  // warnings about unused arguments
752 
754 #else
756  begin,
757  end,
758  [this](const tbb::blocked_range<std::size_t> &range) {
759  apply_to_subrange(range.begin(), range.end());
760  },
762 #endif
763  }
764 
765 } // end of namespace parallel
766 
768 
769 #endif
std::shared_ptr< tbb::affinity_partitioner > acquire_one_partitioner()
Definition: parallel.cc:75
std::shared_ptr< tbb::affinity_partitioner > my_partitioner
Definition: parallel.h:685
void release_one_partitioner(std::shared_ptr< tbb::affinity_partitioner > &p)
Definition: parallel.cc:88
#define DEAL_II_NAMESPACE_OPEN
Definition: config.h:477
#define DEAL_II_CXX20_REQUIRES(condition)
Definition: config.h:166
#define DEAL_II_NAMESPACE_CLOSE
Definition: config.h:478
VectorType::value_type * begin(VectorType &V)
VectorType::value_type * end(VectorType &V)
unsigned int minimum_parallel_grain_size
Definition: parallel.cc:34
void parallel_reduce(const Operation &op, const size_type start, const size_type end, ResultType &result, const std::shared_ptr<::parallel::internal::TBBPartitioner > &partitioner)
void parallel_for(Iterator x_begin, Iterator x_end, const Functor &functor, const unsigned int grainsize)
Definition: parallel.h:84
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:101
void apply_to_subranges(const tbb::blocked_range< Iterator > &range, const Function &f)
Definition: parallel.h:371
void apply_to_subranges(const Iterator &begin, const std_cxx20::type_identity_t< Iterator > &end, const Function &f, const unsigned int grainsize)
Definition: parallel.h:453
void transform(const InputIterator &begin_in, const InputIterator &end_in, OutputIterator out, const Function &function, const unsigned int grainsize)
Definition: parallel.h:166
ResultType accumulate_from_subranges(const Function &f, const Iterator &begin, const std_cxx20::type_identity_t< Iterator > &end, const unsigned int grainsize)
Definition: parallel.h:609
Definition: c++.h:147
typename type_identity< T >::type type_identity_t
Definition: type_traits.h:96
virtual ~ParallelForInteger()=default
virtual void apply_to_subrange(const std::size_t, const std::size_t) const =0
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:743