13#ifndef dealii_parallel_h
14#define dealii_parallel_h
31#ifdef DEAL_II_WITH_TASKFLOW
33# include <taskflow/algorithm/for_each.hpp>
34# include <taskflow/taskflow.hpp>
37#ifdef DEAL_II_WITH_TBB
38# include <tbb/blocked_range.h>
39# include <tbb/parallel_for.h>
40# include <tbb/parallel_reduce.h>
41# include <tbb/partitioner.h>
43# include <boost/range/iterator_range.hpp>
46#ifdef DEAL_II_HAVE_CXX20
64 template <
typename Number>
70#ifdef __INTEL_COMPILER
78 static const bool value =
false;
82#ifdef DEAL_II_WITH_TASKFLOW
86 template <
typename Iterator,
typename Functor>
90 const Functor &functor,
91 const unsigned int grainsize)
94 tf::Taskflow taskflow;
108 [&](
const auto &item) { functor(item); },
109 tf::StaticPartitioner(grainsize));
114 if (executor.this_worker_id() != -1)
115 executor.corun(taskflow);
117 executor.run(taskflow).wait();
121#ifdef DEAL_II_WITH_TBB
125 template <
typename Iterator,
typename Functor>
129 const Functor &functor,
130 const unsigned int grainsize)
132 tbb::parallel_for(tbb::blocked_range<Iterator>(x_begin, x_end, grainsize),
134 tbb::auto_partitioner());
142 template <
typename Iterator,
typename Functor>
146 const Functor &functor,
147 const unsigned int grainsize,
148 const std::shared_ptr<tbb::affinity_partitioner> &partitioner)
150 tbb::parallel_for(tbb::blocked_range<Iterator>(x_begin, x_end, grainsize),
160 template <
typename Iterator,
typename Functor>
164 const Functor &functor,
167 functor(boost::iterator_range<Iterator>(x_begin, x_end));
202 template <
typename InputIterator,
typename OutputIterator,
typename Function>
204 (std::invocable<Function,
decltype(*std::declval<InputIterator>())> &&
205 std::assignable_from<
206 decltype(*std::declval<OutputIterator>()),
207 std::invoke_result_t<Function,
208 decltype(*std::declval<InputIterator>())>>))
210 const InputIterator &end_in,
213 const
unsigned int grainsize)
215#ifdef DEAL_II_WITH_TASKFLOW
216 using Iterators = std::tuple<InputIterator, OutputIterator>;
218 Iterators x_begin(begin_in, out);
219 Iterators x_end(end_in, OutputIterator());
222 SyncIterators(x_begin),
223 SyncIterators(x_end),
224 [function](
const auto &it) {
225 *std::get<1>(it) = function(*std::get<0>(it));
229#elif defined(DEAL_II_WITH_TBB)
230 using Iterators = std::tuple<InputIterator, OutputIterator>;
232 Iterators x_begin(begin_in, out);
233 Iterators x_end(end_in, OutputIterator());
235 SyncIterators(x_begin),
236 SyncIterators(x_end),
237 [function](
const auto &range) {
238 for (
const auto &p : range)
239 *std::get<1>(p) = function(*std::get<0>(p));
247 for (InputIterator in = begin_in; in != end_in;)
248 *out++ = function(*in++);
285 template <
typename InputIterator1,
286 typename InputIterator2,
287 typename OutputIterator,
291 decltype(*std::declval<InputIterator1>()),
292 decltype(*std::declval<InputIterator2>())> &&
293 std::assignable_from<
294 decltype(*std::declval<OutputIterator>()),
296 decltype(*std::declval<InputIterator1>()),
297 decltype(*std::declval<InputIterator2>())>>))
299 const InputIterator1 &end_in1,
303 const
unsigned int grainsize)
305#ifdef DEAL_II_WITH_TASKFLOW
307 std::tuple<InputIterator1, InputIterator2, OutputIterator>;
309 Iterators x_begin(begin_in1, in2, out);
310 Iterators x_end(end_in1, InputIterator2(), OutputIterator());
313 SyncIterators(x_begin),
314 SyncIterators(x_end),
315 [function](
const auto &it) {
316 *std::get<2>(it) = function(*std::get<0>(it), *std::get<1>(it));
320#elif defined(DEAL_II_WITH_TBB)
322 std::tuple<InputIterator1, InputIterator2, OutputIterator>;
324 Iterators x_begin(begin_in1, in2, out);
325 Iterators x_end(end_in1, InputIterator2(), OutputIterator());
327 SyncIterators(x_begin),
328 SyncIterators(x_end),
329 [function](
const auto &range) {
330 for (
const auto &p : range)
331 *std::get<2>(p) = function(*std::get<0>(p), *std::get<1>(p));
340 for (InputIterator1 in1 = begin_in1; in1 != end_in1;)
341 *out++ = function(*in1++, *in2++);
380 template <
typename InputIterator1,
381 typename InputIterator2,
382 typename InputIterator3,
383 typename OutputIterator,
387 decltype(*std::declval<InputIterator1>()),
388 decltype(*std::declval<InputIterator2>()),
389 decltype(*std::declval<InputIterator3>())> &&
390 std::assignable_from<
391 decltype(*std::declval<OutputIterator>()),
393 decltype(*std::declval<InputIterator1>()),
394 decltype(*std::declval<InputIterator2>()),
395 decltype(*std::declval<InputIterator3>())>>))
397 const InputIterator1 &end_in1,
402 const
unsigned int grainsize)
404#ifdef DEAL_II_WITH_TASKFLOW
405 using Iterators = std::
406 tuple<InputIterator1, InputIterator2, InputIterator3, OutputIterator>;
408 Iterators x_begin(begin_in1, in2, in3, out);
409 Iterators x_end(end_in1,
415 SyncIterators(x_begin),
416 SyncIterators(x_end),
417 [function](
const auto &it) {
419 function(*std::get<0>(it), *std::get<1>(it), *std::get<2>(it));
423#elif defined(DEAL_II_WITH_TBB)
424 using Iterators = std::
425 tuple<InputIterator1, InputIterator2, InputIterator3, OutputIterator>;
427 Iterators x_begin(begin_in1, in2, in3, out);
428 Iterators x_end(end_in1,
433 SyncIterators(x_begin),
434 SyncIterators(x_end),
435 [function](
const auto &range) {
436 for (
const auto &p : range)
438 function(*std::get<0>(p), *std::get<1>(p), *std::get<2>(p));
446 for (OutputIterator in1 = begin_in1; in1 != end_in1;)
447 *out++ = function(*in1++, *in2++, *in3++);
454#ifdef DEAL_II_WITH_TBB
461 template <
typename Iterator,
typename Function>
466 f(range.begin(), range.end());
543 template <
typename Iterator,
typename Function>
548 const
unsigned int grainsize)
553 const std::size_t n = [&]() ->
auto {
554 if constexpr (std::is_integral_v<Iterator>)
555 return static_cast<std::size_t
>(
end -
begin);
557 return static_cast<std::size_t
>(std::distance(
begin,
end));
560 const bool worth_doing_in_parallel =
563#ifdef DEAL_II_WITH_TASKFLOW
564 if (worth_doing_in_parallel)
567 tf::Taskflow taskflow;
569 if constexpr (std::is_integral_v<Iterator>)
572 using integral_type = Iterator;
574 tf::IndexRange<integral_type> range(0, n, 1);
576 taskflow.for_each_by_index(
578 [&,
begin](
const tf::IndexRange<integral_type> &subrange) {
579 integral_type subrange_begin =
580 begin +
static_cast<integral_type
>(subrange.begin());
582 integral_type subrange_end =
583 subrange_begin +
static_cast<integral_type
>(subrange.size());
585 f(subrange_begin, subrange_end);
587 tf::GuidedPartitioner(grainsize));
594 typename std::iterator_traits<Iterator>::difference_type;
596 tf::IndexRange<std::size_t> range(0, n, 1);
598 taskflow.for_each_by_index(
600 [&,
begin](
const tf::IndexRange<std::size_t> &subrange) {
601 Iterator subrange_begin =
begin;
602 std::advance(subrange_begin,
603 static_cast<diff_t
>(subrange.begin()));
605 Iterator subrange_end = subrange_begin;
606 std::advance(subrange_end,
607 static_cast<diff_t
>(subrange.size()));
609 f(subrange_begin, subrange_end);
611 tf::GuidedPartitioner(grainsize));
617 if (executor.this_worker_id() != -1)
618 executor.corun(taskflow);
620 executor.run(taskflow).wait();
624#elif defined(DEAL_II_WITH_TBB)
625 if (worth_doing_in_parallel)
630 [&f](
const tbb::blocked_range<Iterator> &range) {
638 (void)worth_doing_in_parallel;
693 const std::size_t
end,
694 const std::size_t minimum_parallel_grain_size)
const;
774 template <
typename ResultType,
typename Iterator,
typename Function>
776 (std::invocable<Function, Iterator, Iterator> &&
777 std::convertible_to<std::invoke_result_t<Function, Iterator, Iterator>,
781 const Iterator &
begin,
783 const
unsigned int grainsize)
785#ifndef DEAL_II_WITH_TBB
792 return tbb::parallel_reduce(
793 tbb::blocked_range<Iterator>(
begin,
end, grainsize),
795 [f](
const auto &range,
const ResultType &starting_value) {
796 ResultType
value = starting_value;
797 value += f(range.begin(), range.end());
800 std::plus<ResultType>(),
801 tbb::auto_partitioner());
827#ifdef DEAL_II_WITH_TBB
840 std::shared_ptr<tbb::affinity_partitioner>
850 const std::shared_ptr<tbb::affinity_partitioner> &p);
916 const std::size_t
begin,
917 const std::size_t
end,
918 const std::size_t minimum_parallel_grain_size)
const
920#ifndef DEAL_II_WITH_TBB
923 (void)minimum_parallel_grain_size;
930 [
this](
const tbb::blocked_range<std::size_t> &range) {
933 minimum_parallel_grain_size);
static unsigned int n_threads()
static tf::Executor & get_taskflow_executor()
std::shared_ptr< tbb::affinity_partitioner > acquire_one_partitioner()
void release_one_partitioner(const std::shared_ptr< tbb::affinity_partitioner > &p)
std::shared_ptr< tbb::affinity_partitioner > my_partitioner
#define DEAL_II_DEPRECATED
#define DEAL_II_NAMESPACE_OPEN
#define DEAL_II_CXX20_REQUIRES(condition)
#define DEAL_II_NAMESPACE_CLOSE
#define Assert(cond, exc)
static ::ExceptionBase & ExcMessage(std::string arg1)
const bool IsBlockVector< VectorType >::value
unsigned int minimum_parallel_grain_size
unsigned int minimum_parallel_grain_size
void parallel_for(Iterator x_begin, Iterator x_end, const Functor &functor, const unsigned int grainsize)
void taskflow_parallel_for(Iterator x_begin, Iterator x_end, const Functor &functor, const unsigned int grainsize)
void apply_to_subranges(const tbb::blocked_range< Iterator > &range, const Function &f)
void apply_to_subranges(const Iterator &begin, const std_cxx20::type_identity_t< Iterator > &end, const Function &f, const unsigned int grainsize)
void transform(const InputIterator &begin_in, const InputIterator &end_in, OutputIterator out, const Function &function, const unsigned int grainsize)
ResultType accumulate_from_subranges(const Function &f, const Iterator &begin, const std_cxx20::type_identity_t< Iterator > &end, const unsigned int grainsize)
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