deal.II version GIT relicensing-2206-gaa53ff9447 2024-12-02 09:10:00+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\}}\)
Loading...
Searching...
No Matches
parallel.h
Go to the documentation of this file.
1// ------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: LGPL-2.1-or-later
4// Copyright (C) 2009 - 2024 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Part of the source code is dual licensed under Apache-2.0 WITH
9// LLVM-exception OR LGPL-2.1-or-later. Detailed license information
10// governing the source code and code contributions can be found in
11// LICENSE.md and CONTRIBUTING.md at the top level directory of deal.II.
12//
13// ------------------------------------------------------------------------
14
15#ifndef dealii_parallel_h
16#define dealii_parallel_h
17
18
19#include <deal.II/base/config.h>
20
22#include <deal.II/base/mutex.h>
25
26#include <cstddef>
27#include <functional>
28#include <memory>
29#include <tuple>
30
31#ifdef DEAL_II_WITH_TBB
32# include <tbb/blocked_range.h>
33# include <tbb/parallel_for.h>
34# include <tbb/parallel_reduce.h>
35# include <tbb/partitioner.h>
36#else
37# include <boost/range/iterator_range.hpp>
38#endif
39
40#ifdef DEAL_II_HAVE_CXX20
41# include <concepts>
42#endif
43
44
45// TODO[WB]: allow calling functions to pass along a tbb::affinity_partitioner
46// object to ensure that subsequent calls use the same cache lines
47
49
50namespace parallel
51{
52 namespace internal
53 {
58 template <typename Number>
60 {
61 static const bool value = true;
62 };
63
64#ifdef __INTEL_COMPILER
65 // Disable long double SIMD instructions on ICC. This is to work around a
66 // bug that generates wrong code at least up to intel 15 (see
67 // tests/lac/vector-vector, tests/lac/intel-15-bug, and the discussion at
68 // https://github.com/dealii/dealii/issues/598).
69 template <>
70 struct EnableOpenMPSimdFor<long double>
71 {
72 static const bool value = false;
73 };
74#endif
75
76
77#ifdef DEAL_II_WITH_TBB
81 template <typename Iterator, typename Functor>
82 void
83 parallel_for(Iterator x_begin,
84 Iterator x_end,
85 const Functor &functor,
86 const unsigned int grainsize)
87 {
88 tbb::parallel_for(tbb::blocked_range<Iterator>(x_begin, x_end, grainsize),
89 functor,
90 tbb::auto_partitioner());
91 }
92
93
94
98 template <typename Iterator, typename Functor>
99 void
100 parallel_for(Iterator x_begin,
101 Iterator x_end,
102 const Functor &functor,
103 const unsigned int grainsize,
104 const std::shared_ptr<tbb::affinity_partitioner> &partitioner)
105 {
106 tbb::parallel_for(tbb::blocked_range<Iterator>(x_begin, x_end, grainsize),
107 functor,
108 *partitioner);
109 }
110
111#else
112
116 template <typename Iterator, typename Functor>
117 void
118 parallel_for(Iterator x_begin,
119 Iterator x_end,
120 const Functor &functor,
121 const unsigned int)
122 {
123 functor(boost::iterator_range<Iterator>(x_begin, x_end));
124 }
125
126#endif
127 } // namespace internal
128
158 template <typename InputIterator, typename OutputIterator, typename Function>
160 (std::invocable<Function, decltype(*std::declval<InputIterator>())> &&
161 std::assignable_from<
162 decltype(*std::declval<OutputIterator>()),
163 std::invoke_result_t<Function,
164 decltype(*std::declval<InputIterator>())>>))
165 void transform(const InputIterator &begin_in,
166 const InputIterator &end_in,
167 OutputIterator out,
168 const Function &function,
169 const unsigned int grainsize)
170 {
171#ifndef DEAL_II_WITH_TBB
172 // make sure we don't get compiler
173 // warnings about unused arguments
174 (void)grainsize;
175
176 for (InputIterator in = begin_in; in != end_in;)
177 *out++ = function(*in++);
178#else
179 using Iterators = std::tuple<InputIterator, OutputIterator>;
180 using SyncIterators = SynchronousIterators<Iterators>;
181 Iterators x_begin(begin_in, out);
182 Iterators x_end(end_in, OutputIterator());
184 SyncIterators(x_begin),
185 SyncIterators(x_end),
186 [function](const auto &range) {
187 for (const auto &p : range)
188 *std::get<1>(p) = function(*std::get<0>(p));
189 },
190 grainsize);
191#endif
192 }
193
194
195
227 template <typename InputIterator1,
228 typename InputIterator2,
229 typename OutputIterator,
230 typename Function>
232 (std::invocable<Function,
233 decltype(*std::declval<InputIterator1>()),
234 decltype(*std::declval<InputIterator2>())> &&
235 std::assignable_from<
236 decltype(*std::declval<OutputIterator>()),
237 std::invoke_result_t<Function,
238 decltype(*std::declval<InputIterator1>()),
239 decltype(*std::declval<InputIterator2>())>>))
240 void transform(const InputIterator1 &begin_in1,
241 const InputIterator1 &end_in1,
242 InputIterator2 in2,
243 OutputIterator out,
244 const Function &function,
245 const unsigned int grainsize)
246 {
247#ifndef DEAL_II_WITH_TBB
248 // make sure we don't get compiler
249 // warnings about unused arguments
250 (void)grainsize;
251
252 for (InputIterator1 in1 = begin_in1; in1 != end_in1;)
253 *out++ = function(*in1++, *in2++);
254#else
255 using Iterators =
256 std::tuple<InputIterator1, InputIterator2, OutputIterator>;
257 using SyncIterators = SynchronousIterators<Iterators>;
258 Iterators x_begin(begin_in1, in2, out);
259 Iterators x_end(end_in1, InputIterator2(), OutputIterator());
261 SyncIterators(x_begin),
262 SyncIterators(x_end),
263 [function](const auto &range) {
264 for (const auto &p : range)
265 *std::get<2>(p) = function(*std::get<0>(p), *std::get<1>(p));
266 },
267 grainsize);
268#endif
269 }
270
271
272
306 template <typename InputIterator1,
307 typename InputIterator2,
308 typename InputIterator3,
309 typename OutputIterator,
310 typename Function>
312 (std::invocable<Function,
313 decltype(*std::declval<InputIterator1>()),
314 decltype(*std::declval<InputIterator2>()),
315 decltype(*std::declval<InputIterator3>())> &&
316 std::assignable_from<
317 decltype(*std::declval<OutputIterator>()),
318 std::invoke_result_t<Function,
319 decltype(*std::declval<InputIterator1>()),
320 decltype(*std::declval<InputIterator2>()),
321 decltype(*std::declval<InputIterator3>())>>))
322 void transform(const InputIterator1 &begin_in1,
323 const InputIterator1 &end_in1,
324 InputIterator2 in2,
325 InputIterator3 in3,
326 OutputIterator out,
327 const Function &function,
328 const unsigned int grainsize)
329 {
330#ifndef DEAL_II_WITH_TBB
331 // make sure we don't get compiler
332 // warnings about unused arguments
333 (void)grainsize;
334
335 for (InputIterator1 in1 = begin_in1; in1 != end_in1;)
336 *out++ = function(*in1++, *in2++, *in3++);
337#else
338 using Iterators = std::
339 tuple<InputIterator1, InputIterator2, InputIterator3, OutputIterator>;
340 using SyncIterators = SynchronousIterators<Iterators>;
341 Iterators x_begin(begin_in1, in2, in3, out);
342 Iterators x_end(end_in1,
343 InputIterator2(),
344 InputIterator3(),
345 OutputIterator());
347 SyncIterators(x_begin),
348 SyncIterators(x_end),
349 [function](const auto &range) {
350 for (const auto &p : range)
351 *std::get<3>(p) =
352 function(*std::get<0>(p), *std::get<1>(p), *std::get<2>(p));
353 },
354 grainsize);
355#endif
356 }
357
358
359 namespace internal
360 {
361#ifdef DEAL_II_WITH_TBB
368 template <typename Iterator, typename Function>
369 DEAL_II_CXX20_REQUIRES((std::invocable<Function, Iterator, Iterator>))
370 void apply_to_subranges(const tbb::blocked_range<Iterator> &range,
371 const Function &f)
372 {
373 f(range.begin(), range.end());
374 }
375#endif
376 } // namespace internal
377
378
450 template <typename Iterator, typename Function>
451 DEAL_II_CXX20_REQUIRES((std::invocable<Function, Iterator, Iterator>))
452 void apply_to_subranges(const Iterator &begin,
453 const std_cxx20::type_identity_t<Iterator> &end,
454 const Function &f,
455 const unsigned int grainsize)
456 {
457#ifndef DEAL_II_WITH_TBB
458 // make sure we don't get compiler
459 // warnings about unused arguments
460 (void)grainsize;
461
462 f(begin, end);
463#else
465 begin,
466 end,
467 [&f](const tbb::blocked_range<Iterator> &range) {
468 internal::apply_to_subranges<Iterator, Function>(range, f);
469 },
470 grainsize);
471#endif
472 }
473
474
475
504 {
509 virtual ~ParallelForInteger() = default;
510
519 void
520 apply_parallel(const std::size_t begin,
521 const std::size_t end,
522 const std::size_t minimum_parallel_grain_size) const;
523
530 virtual void
531 apply_to_subrange(const std::size_t, const std::size_t) const = 0;
532 };
533
534
535
602 template <typename ResultType, typename Iterator, typename Function>
604 (std::invocable<Function, Iterator, Iterator> &&
605 std::convertible_to<std::invoke_result_t<Function, Iterator, Iterator>,
606 ResultType>))
607 ResultType
609 const Iterator &begin,
610 const std_cxx20::type_identity_t<Iterator> &end,
611 const unsigned int grainsize)
612 {
613#ifndef DEAL_II_WITH_TBB
614 // make sure we don't get compiler
615 // warnings about unused arguments
616 (void)grainsize;
617
618 return f(begin, end);
619#else
620 return tbb::parallel_reduce(
621 tbb::blocked_range<Iterator>(begin, end, grainsize),
622 ResultType(0),
623 [f](const auto &range, const ResultType &starting_value) {
624 ResultType value = starting_value;
625 value += f(range.begin(), range.end());
626 return value;
627 },
628 std::plus<ResultType>(),
629 tbb::auto_partitioner());
630#endif
631 }
632
633
634 // --------------------- for loop affinity partitioner -----------------------
635
645 namespace internal
646 {
648 {
649 public:
654
655#ifdef DEAL_II_WITH_TBB
661
668 std::shared_ptr<tbb::affinity_partitioner>
670
676 void
678 const 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
703namespace 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
740namespace 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
751 (void)minimum_parallel_grain_size;
752
753 apply_to_subrange(begin, end);
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 },
761 minimum_parallel_grain_size);
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:74
void release_one_partitioner(const std::shared_ptr< tbb::affinity_partitioner > &p)
Definition parallel.cc:87
std::shared_ptr< tbb::affinity_partitioner > my_partitioner
Definition parallel.h:685
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:498
#define DEAL_II_CXX20_REQUIRES(condition)
Definition config.h:175
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:499
unsigned int minimum_parallel_grain_size
Definition parallel.cc:33
void parallel_for(Iterator x_begin, Iterator x_end, const Functor &functor, const unsigned int grainsize)
Definition parallel.h:83
void apply_to_subranges(const tbb::blocked_range< Iterator > &range, const Function &f)
Definition parallel.h:370
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:452
void transform(const InputIterator &begin_in, const InputIterator &end_in, OutputIterator out, const Function &function, const unsigned int grainsize)
Definition parallel.h:165
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:608
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