14#include "arccore/base/NotImplementedException.h"
15#include "arccore/base/IFunctor.h"
16#include "arccore/base/ForLoopRanges.h"
17#include "arccore/base/IObservable.h"
18#include "arccore/base/PlatformUtils.h"
19#include "arccore/base/FixedArray.h"
20#include "arccore/base/Profiling.h"
21#include "arccore/base/CheckedConvert.h"
22#include "arccore/base/FixedArray.h"
23#include "arccore/base/ForLoopRunInfo.h"
24#include "arccore/base/internal/DependencyInjection.h"
26#include "arccore/concurrency/IThreadImplementation.h"
27#include "arccore/concurrency/Task.h"
28#include "arccore/concurrency/ITaskImplementation.h"
29#include "arccore/concurrency/TaskFactory.h"
30#include "arccore/concurrency/ParallelFor.h"
31#include "arccore/concurrency/internal/TaskFactoryInternal.h"
40#define TBB_PREVIEW_BLOCKED_RANGE_ND 1
48#define TBB_PREVIEW_WAITING_FOR_WORKERS 1
50#include <oneapi/tbb/concurrent_set.h>
51#include <oneapi/tbb/global_control.h>
72#if (TBB_VERSION_MAJOR > 2022) || (TBB_VERSION_MAJOR == 2022 && TBB_VERSION_MINOR > 0) || defined __TBB_blocked_nd_range_H
76template <
typename Value,
unsigned int N>
77using blocked_nd_range = tbb::blocked_nd_range<Value, N>;
81template <
typename Value,
unsigned int N>
82using blocked_nd_range = tbb::blocked_rangeNd<Value, N>;
91 constexpr Int32 cache_line_size = 64;
106 explicit ScopedExecInfo(
const ForLoopRunInfo& run_info)
107 : m_run_info(run_info)
113 ForLoopOneExecStat* ptr = run_info.execStat();
115 m_stat_info_ptr = ptr;
116 m_use_own_run_info =
false;
119 m_stat_info_ptr = isStatActive() ? &m_stat_info :
nullptr;
123#ifdef PRINT_STAT_INFO
124 if (m_stat_info_ptr) {
125 bool is_valid = m_run_info.traceInfo().isValid();
127 std::cout <<
"ADD_OWN_RUN_INFO nb_chunk=" << m_stat_info_ptr->nbChunk()
131 std::cout <<
"ADD_OWN_RUN_INFO nb_chunk=" << m_stat_info_ptr->nbChunk()
132 <<
" trace_name=" << m_run_info.traceInfo().traceInfo().name() <<
"\n";
135 if (m_stat_info_ptr && m_use_own_run_info) {
136 ProfilingRegistry::_threadLocalForLoopInstance()->merge(*m_stat_info_ptr, m_run_info.traceInfo());
142 ForLoopOneExecStat* statInfo()
const {
return m_stat_info_ptr; }
143 bool isOwn()
const {
return m_use_own_run_info; }
147 ForLoopOneExecStat m_stat_info;
148 ForLoopOneExecStat* m_stat_info_ptr =
nullptr;
149 ForLoopRunInfo m_run_info;
151 bool m_use_own_run_info =
true;
157 inline int _currentTaskTreadIndex()
163 return tbb::this_task_arena::current_thread_index();
166 inline blocked_nd_range<Int32, 1>
169 return { { r.lowerBound<0>(), r.upperBound<0>() } };
172 inline blocked_nd_range<Int32, 2>
175 return { { r.lowerBound<0>(), r.upperBound<0>() },
176 { r.lowerBound<1>(), r.upperBound<1>() } };
179 inline blocked_nd_range<Int32, 3>
182 return { { r.lowerBound<0>(), r.upperBound<0>() },
183 { r.lowerBound<1>(), r.upperBound<1>() },
184 { r.lowerBound<2>(), r.upperBound<2>() } };
187 inline blocked_nd_range<Int32, 4>
190 return { { r.lowerBound<0>(), r.upperBound<0>() },
191 { r.lowerBound<1>(), r.upperBound<1>() },
192 { r.lowerBound<2>(), r.upperBound<2>() },
193 { r.lowerBound<3>(), r.upperBound<3>() } };
199 inline blocked_nd_range<Int32, 2>
202 return { { r.dim(0).begin(), r.dim(0).end(), grain_sizes[0] },
203 { r.dim(1).begin(), r.dim(1).end(), grain_sizes[1] } };
206 inline blocked_nd_range<Int32, 3>
209 return { { r.dim(0).begin(), r.dim(0).end(), grain_sizes[0] },
210 { r.dim(1).begin(), r.dim(1).end(), grain_sizes[1] },
211 { r.dim(2).begin(), r.dim(2).end(), grain_sizes[2] } };
214 inline blocked_nd_range<Int32, 4>
217 return { { r.dim(0).begin(), r.dim(0).end(), grain_sizes[0] },
218 { r.dim(1).begin(), r.dim(1).end(), grain_sizes[1] },
219 { r.dim(2).begin(), r.dim(2).end(), grain_sizes[2] },
220 { r.dim(3).begin(), r.dim(3).end(), grain_sizes[3] } };
227 _fromTBBRange(
const blocked_nd_range<Int32, 2>& r)
230 using ArrayExtentType = BoundsType::ArrayExtentType;
232 BoundsType lower_bounds(ArrayExtentType(r.dim(0).begin(), r.dim(1).begin()));
233 auto s0 =
static_cast<Int32>(r.dim(0).size());
234 auto s1 =
static_cast<Int32>(r.dim(1).size());
235 BoundsType sizes(ArrayExtentType(s0, s1));
236 return { lower_bounds, sizes };
240 _fromTBBRange(
const blocked_nd_range<Int32, 3>& r)
243 using ArrayExtentType = BoundsType::ArrayExtentType;
245 BoundsType lower_bounds(ArrayExtentType(r.dim(0).begin(), r.dim(1).begin(), r.dim(2).begin()));
246 auto s0 =
static_cast<Int32>(r.dim(0).size());
247 auto s1 =
static_cast<Int32>(r.dim(1).size());
248 auto s2 =
static_cast<Int32>(r.dim(2).size());
249 BoundsType sizes(ArrayExtentType(s0, s1, s2));
250 return { lower_bounds, sizes };
254 _fromTBBRange(
const blocked_nd_range<Int32, 4>& r)
257 using ArrayExtentType =
typename BoundsType::ArrayExtentType;
259 BoundsType lower_bounds(ArrayExtentType(r.dim(0).begin(), r.dim(1).begin(), r.dim(2).begin(), r.dim(3).begin()));
260 auto s0 =
static_cast<Int32>(r.dim(0).size());
261 auto s1 =
static_cast<Int32>(r.dim(1).size());
262 auto s2 =
static_cast<Int32>(r.dim(2).size());
263 auto s3 =
static_cast<Int32>(r.dim(3).size());
264 BoundsType sizes(ArrayExtentType(s0, s1, s2, s3));
265 return { lower_bounds, sizes };
273class OneTBBTaskFunctor
284 void operator()()
const
309 static const int FUNCTOR_CLASS_SIZE = 32;
316 m_functor = f->clone(m_functor_buf.data(), FUNCTOR_CLASS_SIZE);
344class TBBTaskImplementation
349 template <
int RankValue>
350 class MDParallelForExecute;
356 class ARCCORE_ALIGNAS_PACKED(64) TaskThreadInfo
366 void setTaskIndex(
Integer v) { m_task_index = v; }
367 Integer taskIndex()
const {
return m_task_index; }
381 class TaskInfoLockGuard
385 TaskInfoLockGuard(TaskThreadInfo* tti,
Integer task_index)
387 , m_old_task_index(-1)
390 m_old_task_index = tti->taskIndex();
391 tti->setTaskIndex(task_index);
397 m_tti->setTaskIndex(m_old_task_index);
402 TaskThreadInfo* m_tti;
408 TBBTaskImplementation() =
default;
409 ~TBBTaskImplementation()
override;
414 void initialize(
Int32 nb_thread)
override;
415 void terminate()
override;
435 _executeMDParallelFor<1>(loop_ranges, functor, run_info);
441 _executeMDParallelFor<2>(loop_ranges, functor, run_info);
447 _executeMDParallelFor<3>(loop_ranges, functor, run_info);
453 _executeMDParallelFor<4>(loop_ranges, functor, run_info);
482 bool m_is_active = false;
487 template <
int RankValue>
void
497class TBBTaskImplementation::Impl
500 :
public tbb::task_scheduler_observer
505 : tbb::task_scheduler_observer(p->m_main_arena)
509 void on_scheduler_entry(
bool is_worker)
override
511 m_p->notifyThreadCreated(is_worker);
513 void on_scheduler_exit(
bool is_worker)
override
515 m_p->notifyThreadDestroyed(is_worker);
523 : m_task_observer(
this)
524 , m_thread_task_infos(cache_line_size)
526 m_nb_allowed_thread = tbb::info::default_concurrency();
529 Impl(
Int32 nb_thread)
530 : m_main_arena(nb_thread)
531 , m_task_observer(
this)
532 , m_thread_task_infos(cache_line_size)
534 m_nb_allowed_thread = nb_thread;
541 TaskThreadInfo* threadTaskInfo(
Integer index) {
return &m_thread_task_infos[index]; }
545 Int32 m_nb_allowed_thread = 0;
557 m_main_arena.terminate();
558 m_task_observer.observe(
false);
559 oneapi::tbb::finalize(m_task_scheduler_handle);
564 void notifyThreadCreated(
bool is_worker)
566 std::thread::id my_thread_id = std::this_thread::get_id();
573 if (m_constructed_thread_map.contains(my_thread_id))
575 m_constructed_thread_map.insert(my_thread_id);
579 std::ostringstream ostr;
580 ostr <<
"TBB: CREATE THREAD"
581 <<
" nb_allowed=" << m_nb_allowed_thread
582 <<
" tbb_default_allowed=" << tbb::info::default_concurrency()
583 <<
" id=" << my_thread_id
584 <<
" arena_id=" << _currentTaskTreadIndex()
585 <<
" is_worker=" << is_worker
587 std::cout << ostr.str();
589 TaskFactoryInternal::notifyThreadCreated();
593 void notifyThreadDestroyed([[maybe_unused]]
bool is_worker)
603#if TBB_VERSION_MAJOR > 2021 || (TBB_VERSION_MAJOR == 2021 && TBB_VERSION_MINOR > 5)
604 oneapi::tbb::task_scheduler_handle m_task_scheduler_handle = oneapi::tbb::attach();
606 oneapi::tbb::task_scheduler_handle m_task_scheduler_handle = tbb::task_scheduler_handle::get();
611 tbb::task_arena m_main_arena;
617 TaskObserver m_task_observer;
618 std::mutex m_thread_created_mutex;
619 std::vector<TaskThreadInfo> m_thread_task_infos;
620 tbb::concurrent_set<std::thread::id> m_constructed_thread_map;
623 ConcurrencyBase::_setMaxAllowedThread(m_nb_allowed_thread);
626 std::cout <<
"TBB: TBBTaskImplementationInit nb_allowed_thread=" << m_nb_allowed_thread
627 <<
" id=" << std::this_thread::get_id()
628 <<
" version=" << TBB_VERSION_MAJOR <<
"." << TBB_VERSION_MINOR
631 m_thread_task_infos.resize(m_nb_allowed_thread);
632 m_task_observer.observe(
true);
633 Integer max_arena_size = m_nb_allowed_thread;
636 if (max_arena_size > 512)
637 max_arena_size = 512;
638 if (max_arena_size < 2)
642 for (
Integer i = 2; i < max_arena_size; ++i)
659 , m_stat_info(stat_info)
660 , m_nb_allowed_thread(nb_allowed_thread)
665 void operator()(tbb::blocked_range<Integer>& range)
const
669 std::ostringstream o;
671 <<
" id=" << std::this_thread::get_id()
672 <<
" max_allowed=" << m_nb_allowed_thread
673 <<
" range_begin=" << range.begin() <<
" range_size=" << range.size()
675 std::cout << o.str();
679 int tbb_index = _currentTaskTreadIndex();
680 if (tbb_index < 0 || tbb_index >= m_nb_allowed_thread)
681 ARCCORE_FATAL(
"Invalid index for thread idx={0} valid_interval=[0..{1}[",
682 tbb_index, m_nb_allowed_thread);
686 m_stat_info->incrementNbChunk();
687 m_functor->executeFunctor(range.begin(), CheckedConvert::toInteger(range.size()));
694 Int32 m_nb_allowed_thread;
703template <
int RankValue>
704class TBBMDParallelFor
710 , m_stat_info(stat_info)
711 , m_nb_allowed_thread(nb_allowed_thread)
716 void operator()(blocked_nd_range<Int32, RankValue>& range)
const
720 std::ostringstream o;
722 <<
" id=" << std::this_thread::get_id()
723 <<
" max_allowed=" << m_nb_allowed_thread
725 for (
Int32 i = 0; i < RankValue; ++i) {
726 auto r0 =
static_cast<Int32>(range.dim(i).begin());
727 auto r1 =
static_cast<Int32>(range.dim(i).size());
728 o <<
" range" << i <<
" (begin=" << r0 <<
" size=" << r1 <<
")";
731 std::cout << o.str();
735 int tbb_index = _currentTaskTreadIndex();
736 if (tbb_index < 0 || tbb_index >= m_nb_allowed_thread)
737 ARCCORE_FATAL(
"Invalid index for thread idx={0} valid_interval=[0..{1}[",
738 tbb_index, m_nb_allowed_thread);
742 m_stat_info->incrementNbChunk();
743 m_functor->executeFunctor(_fromTBBRange(range));
750 Int32 m_nb_allowed_thread;
774class TBBDeterministicParallelFor
782 , m_nb_thread(nb_thread)
783 , m_begin_index(begin_index)
785 , m_grain_size(grain_size)
788 , m_nb_block_per_thread(0)
793 if (m_grain_size > 0) {
794 m_block_size = m_grain_size;
795 if (m_block_size > 0) {
796 m_nb_block = m_size / m_block_size;
797 if ((m_size % m_block_size) != 0)
802 m_nb_block_per_thread = m_nb_block / m_nb_thread;
803 if ((m_nb_block % m_nb_thread) != 0)
804 ++m_nb_block_per_thread;
808 m_nb_block = m_nb_thread;
809 m_block_size = m_size / m_nb_block;
810 m_nb_block_per_thread = 1;
813 std::cout <<
"TBBDeterministicParallelFor: BEGIN=" << m_begin_index <<
" size=" << m_size
814 <<
" grain_size=" << m_grain_size
815 <<
" nb_block=" << m_nb_block <<
" nb_thread=" << m_nb_thread
816 <<
" nb_block_per_thread=" << m_nb_block_per_thread
817 <<
" block_size=" << m_block_size
818 <<
" block_size*nb_block=" << m_block_size * m_nb_block <<
'\n';
832 auto nb_iter =
static_cast<Integer>(range.size());
833 for (
Integer i = 0; i < nb_iter; ++i) {
834 Integer task_id = range.begin() + i;
835 for (
Integer k = 0, kn = m_nb_block_per_thread; k < kn; ++k) {
836 Integer block_id = task_id + (k * m_nb_thread);
837 if (block_id < m_nb_block)
838 _doBlock(task_id, block_id);
847 Integer iter_begin = block_id * m_block_size;
848 Integer iter_size = m_block_size;
849 if ((block_id + 1) == m_nb_block) {
851 iter_size = m_size - iter_begin;
853 iter_begin += m_begin_index;
855 if (TaskFactory::verboseLevel() >= 3) {
856 std::ostringstream o;
857 o <<
"TBB: DoBlock: BLOCK task_id=" << task_id <<
" block_id=" << block_id
858 <<
" iter_begin=" << iter_begin <<
" iter_size=" << iter_size <<
'\n';
859 std::cout << o.str();
864 auto r = tbb::blocked_range<int>(iter_begin, iter_begin + iter_size);
871 TBBTaskImplementation* m_impl;
872 const TBBParallelFor& m_tbb_for;
896 , m_stat_info(stat_info)
901 void operator()()
const
903 Integer nb_thread = m_options.maxThread();
905 Integer gsize = m_options.grainSize();
906 tbb::blocked_range<Integer> range(m_begin, m_begin + m_size);
908 std::cout <<
"TBB: TBBTaskImplementationInit ParallelForExecute begin=" << m_begin
909 <<
" size=" << m_size <<
" gsize=" << gsize
910 <<
" partitioner=" << (int)m_options.partitioner()
911 <<
" nb_thread=" << nb_thread
912 <<
" has_stat_info=" << (m_stat_info !=
nullptr)
916 range = tbb::blocked_range<Integer>(m_begin, m_begin + m_size, gsize);
919 tbb::parallel_for(range, pf, tbb::static_partitioner());
922 tbb::blocked_range<Integer> range2(0, nb_thread, 1);
924 tbb::parallel_for(range2, dpf);
927 tbb::parallel_for(range, pf);
932 TBBTaskImplementation* m_impl =
nullptr;
943template <
int RankValue>
944class TBBTaskImplementation::MDParallelForExecute
948 MDParallelForExecute(TBBTaskImplementation* impl,
953 , m_tbb_range(_toTBBRange(range))
956 , m_stat_info(stat_info)
961 Int32 gsize = m_options.grainSize();
967 constexpr bool is_verbose =
false;
968 std::array<Int32, RankValue> range_extents = range.extents().asStdArray();
969 double ratio =
static_cast<double>(gsize) /
static_cast<double>(range.nbElement());
970 if constexpr (is_verbose) {
971 std::cout <<
"GSIZE=" << gsize <<
" rank=" << RankValue <<
" ratio=" << ratio;
972 for (
Int32 i = 0; i < RankValue; ++i)
973 std::cout <<
" range" << i <<
"=" << range_extents[i];
976 Int32 index = RankValue - 1;
977 Int32 remaining_grain = gsize;
978 for (; index >= 0; --index) {
979 Int32 current = range_extents[index];
980 if constexpr (is_verbose)
981 std::cout <<
"Check index=" << index <<
" remaining=" << remaining_grain <<
" current=" << current <<
"\n";
982 if (remaining_grain > current) {
983 all_grain_sizes[index] = current;
984 remaining_grain /= current;
987 all_grain_sizes[index] = remaining_grain;
991 for (Int32 i = 0; i < index; ++i)
992 all_grain_sizes[i] = 1;
993 if constexpr (is_verbose) {
994 for (Int32 i = 0; i < RankValue; ++i)
995 std::cout <<
" grain" << i <<
"=" << all_grain_sizes[i];
998 m_tbb_range = _toTBBRangeWithGrain(m_tbb_range, all_grain_sizes);
1004 void operator()()
const
1006 Integer nb_thread = m_options.maxThread();
1007 TBBMDParallelFor<RankValue> pf(m_functor, nb_thread, m_stat_info);
1009 if (m_options.partitioner() == ParallelLoopOptions::Partitioner::Static) {
1010 tbb::parallel_for(m_tbb_range, pf, tbb::static_partitioner());
1012 else if (m_options.partitioner() == ParallelLoopOptions::Partitioner::Deterministic) {
1014 ARCCORE_THROW(NotImplementedException,
"ParallelLoopOptions::Partitioner::Deterministic for multi-dimensionnal loops");
1020 tbb::parallel_for(m_tbb_range, pf);
1026 TBBTaskImplementation* m_impl =
nullptr;
1027 blocked_nd_range<Int32, RankValue> m_tbb_range;
1028 IMDRangeFunctor<RankValue>* m_functor =
nullptr;
1029 ParallelLoopOptions m_options;
1030 ForLoopOneExecStat* m_stat_info =
nullptr;
1036TBBTaskImplementation::
1037~TBBTaskImplementation()
1045void TBBTaskImplementation::
1046initialize(
Int32 nb_thread)
1050 m_is_active = (nb_thread != 1);
1052 m_p =
new Impl(nb_thread);
1063void TBBTaskImplementation::
1075 o <<
"OneTBBTaskImplementation"
1076 <<
" version=" << TBB_VERSION_STRING
1077 <<
" interface=" << TBB_INTERFACE_VERSION
1078 <<
" runtime_interface=" << TBB_runtime_interface_version();
1084void TBBTaskImplementation::
1087 ScopedExecInfo sei(loop_info.runInfo());
1091 Int32 begin = loop_info.beginIndex();
1092 Int32 size = loop_info.size();
1098 Integer nb_allowed_thread = m_p->nbAllowedThread();
1100 max_thread = nb_allowed_thread;
1103 std::cout <<
"TBB: TBBTaskImplementation executeParallelFor begin=" << begin
1104 <<
" size=" << size <<
" max_thread=" << max_thread
1105 <<
" grain_size=" << options.
grainSize()
1106 <<
" nb_allowed=" << nb_allowed_thread <<
'\n';
1109 if (max_thread == 1 || max_thread == 0) {
1115 ParallelLoopOptions true_options(options);
1117 true_options.setMaxThread(max_thread);
1119 ParallelForExecute pfe(
this, true_options, begin, size, f, stat_info);
1121 tbb::task_arena* used_arena =
nullptr;
1122 if (max_thread < nb_allowed_thread && max_thread < m_p->m_sub_arena_list.size())
1125 used_arena = &(m_p->m_main_arena);
1126 used_arena->execute(pfe);
1135 _executeParallelFor(loop_info);
1147template <
int RankValue>
void TBBTaskImplementation::
1153 if (run_info.options().has_value())
1154 options = run_info.options().value();
1156 ScopedExecInfo sei(run_info);
1161 std::cout <<
"TBB: TBBTaskImplementation executeMDParallelFor nb_dim=" << RankValue
1162 <<
" nb_element=" << loop_ranges.nbElement()
1163 <<
" grain_size=" << options.
grainSize()
1164 <<
" name=" << run_info.traceInfo().traceInfo()
1165 <<
" has_stat_info=" << (stat_info !=
nullptr)
1171 if (max_thread == 1 || max_thread == 0) {
1177 ParallelLoopOptions true_options(options);
1180 Integer nb_allowed_thread = m_p->nbAllowedThread();
1182 max_thread = nb_allowed_thread;
1183 tbb::task_arena* used_arena =
nullptr;
1184 if (max_thread < nb_allowed_thread)
1185 used_arena = m_p->m_sub_arena_list[max_thread];
1187 used_arena = &(m_p->m_main_arena);
1190 if constexpr (RankValue == 1) {
1191 auto range_1d = _toTBBRange(loop_ranges);
1196 LambdaRangeFunctorT<
decltype(x1)> functor_1d(x1);
1197 Integer begin1 = CheckedConvert::toInteger(range_1d.dim(0).begin());
1198 Integer size1 = CheckedConvert::toInteger(range_1d.dim(0).size());
1200 used_arena->execute(pfe);
1203 MDParallelForExecute<RankValue> pfe(
this, true_options, loop_ranges, functor, stat_info);
1204 used_arena->execute(pfe);
1237 return m_p->threadTaskInfo(thread_id);
1250 if (thread_id < 0 || thread_id >= m_p->nbAllowedThread())
1254 Int32 task_index = tti->taskIndex();
1255 if (task_index >= 0)
1267 tbb::task_group task_group;
1268 task_group.run(taskFunctor());
1279 tbb::task_group task_group;
1285 for (
Integer i = 0; i < n; ++i) {
1286 auto* t =
static_cast<OneTBBTask*
>(tasks[i]);
1287 task_group.run(t->taskFunctor());
1290 for (
Integer i = 0; i < n; ++i) {
1291 auto* t =
static_cast<OneTBBTask*
>(tasks[i]);
1309ARCANE_DI_REGISTER_PROVIDER(TBBTaskImplementation,
1310 DependencyInjection::ProviderProperty(
"TBBTaskImplementation"),
1311 ARCANE_DI_INTERFACES(ITaskImplementation),
1312 ARCANE_DI_EMPTY_CONSTRUCTOR());
#define ARCCORE_FATAL(...)
Macro throwing a FatalErrorException.
#define ARCCORE_THROW(exception_class,...)
Macro to throw an exception with formatting.
#define ARCCORE_CHECK_POINTER(ptr)
Macro that returns the pointer ptr if it is not null or throws an exception if it is null.
Represents the bounds of a multidimensional array.
Constant view of an array of type T.
constexpr Integer size() const noexcept
Number of elements in the array.
Class to manage the profiling of a single loop execution.
Loop execution information.
Interface of a functor on a multi-dimensional iteration interval of dimension RankValue.
virtual void executeFunctor(const ComplexForLoopRanges< RankValue > &loop_range)=0
Executes the associated method.
Interface of a functor on an iteration interval.
virtual void executeFunctor(Int32 begin, Int32 size)=0
Executes the associated method.
virtual void executeFunctor(const TaskContext &tc)=0
Executes the associated method.
Int32 nbAllowedThread() const
Maximum number of threads used to manage tasks.
Interface for a concurrent task.
Class allowing retrieval of the time spent between the constructor call and the destructor call.
void launchAndWait() override
Launches the task and blocks until it finishes.
Characteristics of a multi-thread 1D loop.
Execution options for a parallel loop in multi-threading.
Integer grainSize() const
Size of an iteration interval.
Int32 maxThread() const
Maximum number of allowed threads.
void setGrainSize(Integer v)
Sets the size (approximate) of an iteration interval.
@ Static
Uses static partitioning.
@ Deterministic
Uses static partitioning and scheduling.
static bool hasProfiling()
Indicates if profiling is active.
Deterministic implementation of ParallelFor.
void operator()(tbb::blocked_range< Integer > &range) const
Operator for a given thread.
std::vector< tbb::task_arena * > m_sub_arena_list
Array whose i-th element contains the tbb::task_arena for i thread.
Class for positioning TaskThreadInfo::taskIndex().
Int32 currentTaskThreadIndex() const final
Implementation of TaskFactory::currentTaskThreadIndex().
void executeParallelFor(const ComplexForLoopRanges< 1 > &loop_ranges, const ForLoopRunInfo &run_info, IMDRangeFunctor< 1 > *functor) final
Executes a 1D loop in parallel.
void executeParallelFor(Int32 begin, Int32 size, IRangeFunctor *f) final
Executes the functor f in parallel.
ITask * createRootTask(ITaskFunctor *f) override
Creates a root task. The implementation must copy the value of f, which is either a TaskFunctor or a ...
void printInfos(std::ostream &o) const final
Prints information about the runtime used.
void executeParallelFor(Int32 begin, Int32 size, const ParallelLoopOptions &options, IRangeFunctor *f) final
Executes the functor f in parallel.
void executeParallelFor(const ComplexForLoopRanges< 3 > &loop_ranges, const ForLoopRunInfo &run_info, IMDRangeFunctor< 3 > *functor) final
Executes a 3D loop in parallel.
void executeParallelFor(const ComplexForLoopRanges< 4 > &loop_ranges, const ForLoopRunInfo &run_info, IMDRangeFunctor< 4 > *functor) final
Executes a 4D loop in parallel.
TaskThreadInfo * currentTaskThreadInfo() const
Instance of TaskThreadInfo associated with the current thread.
bool isActive() const final
Indicates if the implementation is active.
Int32 currentTaskIndex() const final
Implementation of TaskFactory::currentTaskIndex().
void executeParallelFor(const ComplexForLoopRanges< 2 > &loop_ranges, const ForLoopRunInfo &run_info, IMDRangeFunctor< 2 > *functor) final
Executes a 2D loop in parallel.
Execution context of a task.
static const ParallelLoopOptions & defaultParallelLoopOptions()
Default parallel loop execution options.
static Integer verboseLevel()
Verbosity level.
static void setDefaultParallelLoopOptions(const ParallelLoopOptions &v)
Sets the default parallel loop execution options.
static Int32 currentTaskThreadIndex()
Index (between 0 and nbAllowedThread()-1) of the thread executing the current task.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
Int32 Integer
Type representing an integer.
SimpleForLoopRanges< 1 > makeLoopRanges(Int32 n1)
Creates an iteration range [0,n1[, [0,n2[.
std::int32_t Int32
Signed integer type of 32 bits.