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) {
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>
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;
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();
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;
551 for (
auto x : m_sub_arena_list) {
556 m_sub_arena_list.clear();
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();
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;
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;
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>
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();
1010 tbb::parallel_for(m_tbb_range, pf, tbb::static_partitioner());
1020 tbb::parallel_for(m_tbb_range, pf);
1026 TBBTaskImplementation* m_impl =
nullptr;
1027 blocked_nd_range<Int32, RankValue> m_tbb_range;
1036TBBTaskImplementation::
1037~TBBTaskImplementation()
1050 m_is_active = (nb_thread != 1);
1052 m_p =
new Impl(nb_thread);
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);
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) {
1172 functor->executeFunctor(loop_ranges);
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);
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);
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.
static void _setMaxAllowedThread(Int32 v)
Sets the maximum number of threads to use.
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.
Iteration range for a loop.
Loop execution information.
Interface of a functor on a multi-dimensional iteration interval of dimension RankValue.
Interface of a functor on an iteration interval.
virtual void executeFunctor(Int32 begin, Int32 size)=0
Executes the associated method.
Interface for a task functor.
virtual void executeFunctor(const TaskContext &tc)=0
Executes the associated method.
Implementation of a task factory.
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.
Functor over an iteration interval instantiated via a lambda function.
Exception when a function is not implemented.
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.
void mergeUnsetValues(const ParallelLoopOptions &po)
Merges the unmodified values of the instance with those of po.
Int32 maxThread() const
Maximum number of allowed threads.
void setGrainSize(Integer v)
Sets the size (approximate) of an iteration interval.
void setMaxThread(Integer v)
Sets the maximum number of allowed threads.
@ Static
Uses static partitioning.
@ Deterministic
Uses static partitioning and scheduling.
static Arcane::Impl::ForLoopStatInfoList * _threadLocalForLoopInstance()
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.
Executor for a multi-dimensional loop.
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 initialize(Int32 nb_thread) override
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.
void terminate() override
bool isActive() const final
Indicates if the implementation is active.
void _executeMDParallelFor(const ComplexForLoopRanges< RankValue > &loop_ranges, IMDRangeFunctor< RankValue > *functor, const ForLoopRunInfo &run_info)
Execution of an N-dimensional loop.
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 void notifyThreadCreated()
Notifies all observers of thread creation.
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.