Reference documentation for deal.II version GIT 8e09676776 2023-03-27 21:15:01+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 - 2022 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 #endif
38 
39 #ifdef DEAL_II_HAVE_CXX20
40 # include <concepts>
41 #endif
42 
43 
44 // TODO[WB]: allow calling functions to pass along a tbb::affinity_partitioner
45 // object to ensure that subsequent calls use the same cache lines
46 
48 
49 namespace parallel
50 {
51  namespace internal
52  {
57  template <typename Number>
59  {
60  static const bool value = true;
61  };
62 
63 #ifdef __INTEL_COMPILER
64  // Disable long double SIMD instructions on ICC. This is to work around a
65  // bug that generates wrong code at least up to intel 15 (see
66  // tests/lac/vector-vector, tests/lac/intel-15-bug, and the discussion at
67  // https://github.com/dealii/dealii/issues/598).
68  template <>
69  struct EnableOpenMPSimdFor<long double>
70  {
71  static const bool value = false;
72  };
73 #endif
74 
75 
76 #ifdef DEAL_II_WITH_TBB
80  template <typename Iterator, typename Functor>
81  void
82  parallel_for(Iterator x_begin,
83  Iterator x_end,
84  const Functor & functor,
85  const unsigned int grainsize)
86  {
87  tbb::parallel_for(tbb::blocked_range<Iterator>(x_begin, x_end, grainsize),
88  functor,
89  tbb::auto_partitioner());
90  }
91 
92 
93 
97  template <typename Iterator, typename Functor>
98  void
99  parallel_for(Iterator x_begin,
100  Iterator x_end,
101  const Functor & functor,
102  const unsigned int grainsize,
103  const std::shared_ptr<tbb::affinity_partitioner> &partitioner)
104  {
105  tbb::parallel_for(tbb::blocked_range<Iterator>(x_begin, x_end, grainsize),
106  functor,
107  *partitioner);
108  }
109 #endif
110  } // namespace internal
111 
135  template <typename InputIterator, typename OutputIterator, typename Function>
137  (std::invocable<Function, decltype(*std::declval<InputIterator>())> &&
138  std::assignable_from<
139  decltype(*std::declval<OutputIterator>()),
140  std::invoke_result_t<Function,
141  decltype(*std::declval<InputIterator>())>>))
142  void transform(const InputIterator &begin_in,
143  const InputIterator &end_in,
144  OutputIterator out,
145  const Function & function,
146  const unsigned int grainsize)
147  {
148 #ifndef DEAL_II_WITH_TBB
149  // make sure we don't get compiler
150  // warnings about unused arguments
151  (void)grainsize;
152 
153  for (OutputIterator in = begin_in; in != end_in;)
154  *out++ = function(*in++);
155 #else
156  using Iterators = std::tuple<InputIterator, OutputIterator>;
157  using SyncIterators = SynchronousIterators<Iterators>;
158  Iterators x_begin(begin_in, out);
159  Iterators x_end(end_in, OutputIterator());
161  SyncIterators(x_begin),
162  SyncIterators(x_end),
163  [function](const auto &range) {
164  for (const auto &p : range)
165  *std::get<1>(p) = function(*std::get<0>(p));
166  },
167  grainsize);
168 #endif
169  }
170 
171 
172 
196  template <typename InputIterator1,
197  typename InputIterator2,
198  typename OutputIterator,
199  typename Function>
201  (std::invocable<Function,
202  decltype(*std::declval<InputIterator1>()),
203  decltype(*std::declval<InputIterator2>())> &&
204  std::assignable_from<
205  decltype(*std::declval<OutputIterator>()),
206  std::invoke_result_t<Function,
207  decltype(*std::declval<InputIterator1>()),
208  decltype(*std::declval<InputIterator2>())>>))
209  void transform(const InputIterator1 &begin_in1,
210  const InputIterator1 &end_in1,
211  InputIterator2 in2,
212  OutputIterator out,
213  const Function & function,
214  const unsigned int grainsize)
215  {
216 #ifndef DEAL_II_WITH_TBB
217  // make sure we don't get compiler
218  // warnings about unused arguments
219  (void)grainsize;
220 
221  for (OutputIterator in1 = begin_in1; in1 != end_in1;)
222  *out++ = function(*in1++, *in2++);
223 #else
224  using Iterators =
225  std::tuple<InputIterator1, InputIterator2, OutputIterator>;
226  using SyncIterators = SynchronousIterators<Iterators>;
227  Iterators x_begin(begin_in1, in2, out);
228  Iterators x_end(end_in1, InputIterator2(), OutputIterator());
230  SyncIterators(x_begin),
231  SyncIterators(x_end),
232  [function](const auto &range) {
233  for (const auto &p : range)
234  *std::get<2>(p) = function(*std::get<0>(p), *std::get<1>(p));
235  },
236  grainsize);
237 #endif
238  }
239 
240 
241 
265  template <typename InputIterator1,
266  typename InputIterator2,
267  typename InputIterator3,
268  typename OutputIterator,
269  typename Function>
271  (std::invocable<Function,
272  decltype(*std::declval<InputIterator1>()),
273  decltype(*std::declval<InputIterator2>()),
274  decltype(*std::declval<InputIterator3>())> &&
275  std::assignable_from<
276  decltype(*std::declval<OutputIterator>()),
277  std::invoke_result_t<Function,
278  decltype(*std::declval<InputIterator1>()),
279  decltype(*std::declval<InputIterator2>()),
280  decltype(*std::declval<InputIterator3>())>>))
281  void transform(const InputIterator1 &begin_in1,
282  const InputIterator1 &end_in1,
283  InputIterator2 in2,
284  InputIterator3 in3,
285  OutputIterator out,
286  const Function & function,
287  const unsigned int grainsize)
288  {
289 #ifndef DEAL_II_WITH_TBB
290  // make sure we don't get compiler
291  // warnings about unused arguments
292  (void)grainsize;
293 
294  for (OutputIterator in1 = begin_in1; in1 != end_in1;)
295  *out++ = function(*in1++, *in2++, *in3++);
296 #else
297  using Iterators = std::
298  tuple<InputIterator1, InputIterator2, InputIterator3, OutputIterator>;
299  using SyncIterators = SynchronousIterators<Iterators>;
300  Iterators x_begin(begin_in1, in2, in3, out);
301  Iterators x_end(end_in1,
302  InputIterator2(),
303  InputIterator3(),
304  OutputIterator());
306  SyncIterators(x_begin),
307  SyncIterators(x_end),
308  [function](const auto &range) {
309  for (const auto &p : range)
310  *std::get<3>(p) =
311  function(*std::get<0>(p), *std::get<1>(p), *std::get<2>(p));
312  },
313  grainsize);
314 #endif
315  }
316 
317 
318  namespace internal
319  {
320 #ifdef DEAL_II_WITH_TBB
325  template <typename Iterator, typename Function>
326  DEAL_II_CXX20_REQUIRES((std::invocable<Function, Iterator, Iterator>))
327  void apply_to_subranges(const tbb::blocked_range<Iterator> &range,
328  const Function & f)
329  {
330  f(range.begin(), range.end());
331  }
332 #endif
333  } // namespace internal
334 
335 
405  template <typename Iterator, typename Function>
406  DEAL_II_CXX20_REQUIRES((std::invocable<Function, Iterator, Iterator>))
407  void apply_to_subranges(const Iterator & begin,
408  const std_cxx20::type_identity_t<Iterator> &end,
409  const Function & f,
410  const unsigned int grainsize)
411  {
412 #ifndef DEAL_II_WITH_TBB
413  // make sure we don't get compiler
414  // warnings about unused arguments
415  (void)grainsize;
416 
417  f(begin, end);
418 #else
420  begin,
421  end,
422  [&f](const tbb::blocked_range<Iterator> &range) {
423  internal::apply_to_subranges<Iterator, Function>(range, f);
424  },
425  grainsize);
426 #endif
427  }
428 
429 
430 
459  {
464  virtual ~ParallelForInteger() = default;
465 
474  void
475  apply_parallel(const std::size_t begin,
476  const std::size_t end,
477  const std::size_t minimum_parallel_grain_size) const;
478 
485  virtual void
486  apply_to_subrange(const std::size_t, const std::size_t) const = 0;
487  };
488 
489 
490 
551  template <typename ResultType, typename Iterator, typename Function>
553  (std::invocable<Function, Iterator, Iterator> &&
554  std::convertible_to<std::invoke_result_t<Function, Iterator, Iterator>,
555  ResultType>))
556  ResultType
558  const Iterator & begin,
559  const std_cxx20::type_identity_t<Iterator> &end,
560  const unsigned int grainsize)
561  {
562 #ifndef DEAL_II_WITH_TBB
563  // make sure we don't get compiler
564  // warnings about unused arguments
565  (void)grainsize;
566 
567  return f(begin, end);
568 #else
569  return tbb::parallel_reduce(
570  tbb::blocked_range<Iterator>(begin, end, grainsize),
571  ResultType(0),
572  [f](const auto &range, const ResultType &starting_value) {
573  ResultType value = starting_value;
574  value += f(range.begin(), range.end());
575  return value;
576  },
577  std::plus<ResultType>(),
578  tbb::auto_partitioner());
579 #endif
580  }
581 
582 
583  // --------------------- for loop affinity partitioner -----------------------
584 
594  namespace internal
595  {
597  {
598  public:
602  TBBPartitioner();
603 
604 #ifdef DEAL_II_WITH_TBB
609  ~TBBPartitioner();
610 
617  std::shared_ptr<tbb::affinity_partitioner>
619 
625  void
626  release_one_partitioner(std::shared_ptr<tbb::affinity_partitioner> &p);
627 
628  private:
633  std::shared_ptr<tbb::affinity_partitioner> my_partitioner;
634 
639  bool in_use;
640 
645 #endif
646  };
647  } // namespace internal
648 } // namespace parallel
649 
650 
651 namespace internal
652 {
653  namespace VectorImplementation
654  {
669  extern unsigned int minimum_parallel_grain_size;
670  } // namespace VectorImplementation
671 
672 
673  namespace SparseMatrixImplementation
674  {
680  extern unsigned int minimum_parallel_grain_size;
681  } // namespace SparseMatrixImplementation
682 
683 } // end of namespace internal
684 
685 
686 /* --------------------------- inline functions ------------------------- */
687 
688 namespace parallel
689 {
690  inline void
692  const std::size_t begin,
693  const std::size_t end,
694  const std::size_t minimum_parallel_grain_size) const
695  {
696 #ifndef DEAL_II_WITH_TBB
697  // make sure we don't get compiler
698  // warnings about unused arguments
700 
702 #else
704  begin,
705  end,
706  [this](const tbb::blocked_range<std::size_t> &range) {
707  apply_to_subrange(range.begin(), range.end());
708  },
710 #endif
711  }
712 
713 } // end of namespace parallel
714 
716 
717 #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:633
void release_one_partitioner(std::shared_ptr< tbb::affinity_partitioner > &p)
Definition: parallel.cc:88
#define DEAL_II_NAMESPACE_OPEN
Definition: config.h:474
#define DEAL_II_CXX20_REQUIRES(condition)
Definition: config.h:162
#define DEAL_II_NAMESPACE_CLOSE
Definition: config.h:475
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:82
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:99
void apply_to_subranges(const tbb::blocked_range< Iterator > &range, const Function &f)
Definition: parallel.h:327
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:407
void transform(const InputIterator &begin_in, const InputIterator &end_in, OutputIterator out, const Function &function, const unsigned int grainsize)
Definition: parallel.h:142
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:557
Definition: c++.h:171
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:691