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"
39#define TBB_PREVIEW_BLOCKED_RANGE_ND 1
47#define TBB_PREVIEW_WAITING_FOR_WORKERS 1
49#include <oneapi/tbb/concurrent_set.h>
50#include <oneapi/tbb/global_control.h>
71#if (TBB_VERSION_MAJOR > 2022) || (TBB_VERSION_MAJOR == 2022 && TBB_VERSION_MINOR > 0) || defined __TBB_blocked_nd_range_H
75template <
typename Value,
unsigned int N>
76using blocked_nd_range = tbb::blocked_nd_range<Value, N>;
80template <
typename Value,
unsigned int N>
81using blocked_nd_range = tbb::blocked_rangeNd<Value, N>;
90 constexpr Int32 cache_line_size = 64;
105 explicit ScopedExecInfo(
const ForLoopRunInfo& run_info)
106 : m_run_info(run_info)
112 ForLoopOneExecStat* ptr = run_info.execStat();
114 m_stat_info_ptr = ptr;
115 m_use_own_run_info =
false;
118 m_stat_info_ptr = isStatActive() ? &m_stat_info :
nullptr;
122#ifdef PRINT_STAT_INFO
123 if (m_stat_info_ptr) {
124 bool is_valid = m_run_info.traceInfo().isValid();
126 std::cout <<
"ADD_OWN_RUN_INFO nb_chunk=" << m_stat_info_ptr->nbChunk()
130 std::cout <<
"ADD_OWN_RUN_INFO nb_chunk=" << m_stat_info_ptr->nbChunk()
131 <<
" trace_name=" << m_run_info.traceInfo().traceInfo().name() <<
"\n";
134 if (m_stat_info_ptr && m_use_own_run_info) {
141 ForLoopOneExecStat* statInfo()
const {
return m_stat_info_ptr; }
142 bool isOwn()
const {
return m_use_own_run_info; }
146 ForLoopOneExecStat m_stat_info;
147 ForLoopOneExecStat* m_stat_info_ptr =
nullptr;
148 ForLoopRunInfo m_run_info;
150 bool m_use_own_run_info =
true;
156 inline int _currentTaskTreadIndex()
162 return tbb::this_task_arena::current_thread_index();
165 inline blocked_nd_range<Int32, 1>
168 return { { r.lowerBound<0>(), r.upperBound<0>() } };
171 inline blocked_nd_range<Int32, 2>
174 return { { r.lowerBound<0>(), r.upperBound<0>() },
175 { r.lowerBound<1>(), r.upperBound<1>() } };
178 inline blocked_nd_range<Int32, 3>
181 return { { r.lowerBound<0>(), r.upperBound<0>() },
182 { r.lowerBound<1>(), r.upperBound<1>() },
183 { r.lowerBound<2>(), r.upperBound<2>() } };
186 inline blocked_nd_range<Int32, 4>
189 return { { r.lowerBound<0>(), r.upperBound<0>() },
190 { r.lowerBound<1>(), r.upperBound<1>() },
191 { r.lowerBound<2>(), r.upperBound<2>() },
192 { r.lowerBound<3>(), r.upperBound<3>() } };
198 inline blocked_nd_range<Int32, 2>
201 return { { r.dim(0).begin(), r.dim(0).end(), grain_sizes[0] },
202 { r.dim(1).begin(), r.dim(1).end(), grain_sizes[1] } };
205 inline blocked_nd_range<Int32, 3>
208 return { { r.dim(0).begin(), r.dim(0).end(), grain_sizes[0] },
209 { r.dim(1).begin(), r.dim(1).end(), grain_sizes[1] },
210 { r.dim(2).begin(), r.dim(2).end(), grain_sizes[2] } };
213 inline blocked_nd_range<Int32, 4>
216 return { { r.dim(0).begin(), r.dim(0).end(), grain_sizes[0] },
217 { r.dim(1).begin(), r.dim(1).end(), grain_sizes[1] },
218 { r.dim(2).begin(), r.dim(2).end(), grain_sizes[2] },
219 { r.dim(3).begin(), r.dim(3).end(), grain_sizes[3] } };
226 _fromTBBRange(
const blocked_nd_range<Int32, 2>& r)
229 using ArrayExtentType = BoundsType::ArrayExtentType;
231 BoundsType lower_bounds(ArrayExtentType(r.dim(0).begin(), r.dim(1).begin()));
232 auto s0 =
static_cast<Int32>(r.dim(0).size());
233 auto s1 =
static_cast<Int32>(r.dim(1).size());
234 BoundsType sizes(ArrayExtentType(s0, s1));
235 return { lower_bounds, sizes };
239 _fromTBBRange(
const blocked_nd_range<Int32, 3>& r)
242 using ArrayExtentType = BoundsType::ArrayExtentType;
244 BoundsType lower_bounds(ArrayExtentType(r.dim(0).begin(), r.dim(1).begin(), r.dim(2).begin()));
245 auto s0 =
static_cast<Int32>(r.dim(0).size());
246 auto s1 =
static_cast<Int32>(r.dim(1).size());
247 auto s2 =
static_cast<Int32>(r.dim(2).size());
248 BoundsType sizes(ArrayExtentType(s0, s1, s2));
249 return { lower_bounds, sizes };
253 _fromTBBRange(
const blocked_nd_range<Int32, 4>& r)
256 using ArrayExtentType =
typename BoundsType::ArrayExtentType;
258 BoundsType lower_bounds(ArrayExtentType(r.dim(0).begin(), r.dim(1).begin(), r.dim(2).begin(), r.dim(3).begin()));
259 auto s0 =
static_cast<Int32>(r.dim(0).size());
260 auto s1 =
static_cast<Int32>(r.dim(1).size());
261 auto s2 =
static_cast<Int32>(r.dim(2).size());
262 auto s3 =
static_cast<Int32>(r.dim(3).size());
263 BoundsType sizes(ArrayExtentType(s0, s1, s2, s3));
264 return { lower_bounds, sizes };
272class OneTBBTaskFunctor
283 void operator()()
const
308 static const int FUNCTOR_CLASS_SIZE = 32;
315 m_functor = f->clone(m_functor_buf.data(), FUNCTOR_CLASS_SIZE);
342class TBBTaskImplementation
347 template <
int RankValue>
354 class ARCCORE_ALIGNAS_PACKED(64) TaskThreadInfo
364 void setTaskIndex(
Integer v) { m_task_index = v; }
365 Integer taskIndex()
const {
return m_task_index; }
378 class TaskInfoLockGuard
382 TaskInfoLockGuard(TaskThreadInfo* tti,
Integer task_index)
384 , m_old_task_index(-1)
387 m_old_task_index = tti->taskIndex();
388 tti->setTaskIndex(task_index);
394 m_tti->setTaskIndex(m_old_task_index);
399 TaskThreadInfo* m_tti;
405 TBBTaskImplementation() =
default;
406 ~TBBTaskImplementation()
override;
479 bool m_is_active = false;
484 template <
int RankValue>
void
494class TBBTaskImplementation::Impl
497 :
public tbb::task_scheduler_observer
502 : tbb::task_scheduler_observer(p->m_main_arena)
506 void on_scheduler_entry(
bool is_worker)
override
508 m_p->notifyThreadCreated(is_worker);
510 void on_scheduler_exit(
bool is_worker)
override
512 m_p->notifyThreadDestroyed(is_worker);
520 : m_task_observer(this)
521 , m_thread_task_infos(cache_line_size)
523 m_nb_allowed_thread = tbb::info::default_concurrency();
527 : m_main_arena(nb_thread)
528 , m_task_observer(this)
529 , m_thread_task_infos(cache_line_size)
531 m_nb_allowed_thread = nb_thread;
538 TaskThreadInfo* threadTaskInfo(
Integer index) {
return &m_thread_task_infos[index]; }
542 Int32 m_nb_allowed_thread = 0;
548 for (
auto x : m_sub_arena_list) {
553 m_sub_arena_list.clear();
554 m_main_arena.terminate();
555 m_task_observer.observe(
false);
556 oneapi::tbb::finalize(m_task_scheduler_handle);
561 void notifyThreadCreated(
bool is_worker)
563 std::thread::id my_thread_id = std::this_thread::get_id();
571 if (m_constructed_thread_map.contains(my_thread_id))
573 m_constructed_thread_map.insert(my_thread_id);
577 std::ostringstream ostr;
578 ostr <<
"TBB: CREATE THREAD"
579 <<
" nb_allowed=" << m_nb_allowed_thread
580 <<
" tbb_default_allowed=" << tbb::info::default_concurrency()
581 <<
" id=" << my_thread_id
582 <<
" arena_id=" << _currentTaskTreadIndex()
583 <<
" is_worker=" << is_worker
585 std::cout << ostr.str();
591 void notifyThreadDestroyed([[maybe_unused]]
bool is_worker)
602#if TBB_VERSION_MAJOR > 2021 || (TBB_VERSION_MAJOR == 2021 && TBB_VERSION_MINOR > 5)
603 oneapi::tbb::task_scheduler_handle m_task_scheduler_handle = oneapi::tbb::attach();
605 oneapi::tbb::task_scheduler_handle m_task_scheduler_handle = tbb::task_scheduler_handle::get();
610 tbb::task_arena m_main_arena;
617 std::mutex m_thread_created_mutex;
618 std::vector<TaskThreadInfo> m_thread_task_infos;
619 tbb::concurrent_set<std::thread::id> m_constructed_thread_map;
625 std::cout <<
"TBB: TBBTaskImplementationInit nb_allowed_thread=" << m_nb_allowed_thread
626 <<
" id=" << std::this_thread::get_id()
627 <<
" version=" << TBB_VERSION_MAJOR <<
"." << TBB_VERSION_MINOR
630 m_thread_task_infos.resize(m_nb_allowed_thread);
631 m_task_observer.observe(
true);
632 Integer max_arena_size = m_nb_allowed_thread;
635 if (max_arena_size > 512)
636 max_arena_size = 512;
637 if (max_arena_size < 2)
641 for (
Integer i = 2; i < max_arena_size; ++i)
657 , m_stat_info(stat_info)
658 , m_nb_allowed_thread(nb_allowed_thread)
663 void operator()(tbb::blocked_range<Integer>& range)
const
667 std::ostringstream o;
669 <<
" id=" << std::this_thread::get_id()
670 <<
" max_allowed=" << m_nb_allowed_thread
671 <<
" range_begin=" << range.begin() <<
" range_size=" << range.size()
673 std::cout << o.str();
677 int tbb_index = _currentTaskTreadIndex();
678 if (tbb_index < 0 || tbb_index >= m_nb_allowed_thread)
679 ARCCORE_FATAL(
"Invalid index for thread idx={0} valid_interval=[0..{1}[",
680 tbb_index, m_nb_allowed_thread);
684 m_stat_info->incrementNbChunk();
685 m_functor->executeFunctor(range.begin(), CheckedConvert::toInteger(range.size()));
692 Int32 m_nb_allowed_thread;
700template <
int RankValue>
701class TBBMDParallelFor
707 , m_stat_info(stat_info)
708 , m_nb_allowed_thread(nb_allowed_thread)
713 void operator()(blocked_nd_range<Int32, RankValue>& range)
const
717 std::ostringstream o;
719 <<
" id=" << std::this_thread::get_id()
720 <<
" max_allowed=" << m_nb_allowed_thread
722 for (
Int32 i = 0; i < RankValue; ++i) {
723 auto r0 =
static_cast<Int32>(range.dim(i).begin());
724 auto r1 =
static_cast<Int32>(range.dim(i).size());
725 o <<
" range" << i <<
" (begin=" << r0 <<
" size=" << r1 <<
")";
728 std::cout << o.str();
732 int tbb_index = _currentTaskTreadIndex();
733 if (tbb_index < 0 || tbb_index >= m_nb_allowed_thread)
734 ARCCORE_FATAL(
"Invalid index for thread idx={0} valid_interval=[0..{1}[",
735 tbb_index, m_nb_allowed_thread);
739 m_stat_info->incrementNbChunk();
740 m_functor->executeFunctor(_fromTBBRange(range));
747 Int32 m_nb_allowed_thread;
769class TBBDeterministicParallelFor
777 , m_nb_thread(nb_thread)
778 , m_begin_index(begin_index)
780 , m_grain_size(grain_size)
783 , m_nb_block_per_thread(0)
788 if (m_grain_size > 0) {
789 m_block_size = m_grain_size;
790 if (m_block_size > 0) {
791 m_nb_block = m_size / m_block_size;
792 if ((m_size % m_block_size) != 0)
797 m_nb_block_per_thread = m_nb_block / m_nb_thread;
798 if ((m_nb_block % m_nb_thread) != 0)
799 ++m_nb_block_per_thread;
803 m_nb_block = m_nb_thread;
804 m_block_size = m_size / m_nb_block;
805 m_nb_block_per_thread = 1;
808 std::cout <<
"TBBDeterministicParallelFor: BEGIN=" << m_begin_index <<
" size=" << m_size
809 <<
" grain_size=" << m_grain_size
810 <<
" nb_block=" << m_nb_block <<
" nb_thread=" << m_nb_thread
811 <<
" nb_block_per_thread=" << m_nb_block_per_thread
812 <<
" block_size=" << m_block_size
813 <<
" block_size*nb_block=" << m_block_size * m_nb_block <<
'\n';
827 auto nb_iter =
static_cast<Integer>(range.size());
828 for (
Integer i = 0; i < nb_iter; ++i) {
829 Integer task_id = range.begin() + i;
830 for (
Integer k = 0, kn = m_nb_block_per_thread; k < kn; ++k) {
831 Integer block_id = task_id + (k * m_nb_thread);
832 if (block_id < m_nb_block)
833 _doBlock(task_id, block_id);
842 Integer iter_begin = block_id * m_block_size;
843 Integer iter_size = m_block_size;
844 if ((block_id + 1) == m_nb_block) {
846 iter_size = m_size - iter_begin;
848 iter_begin += m_begin_index;
850 if (TaskFactory::verboseLevel() >= 3) {
851 std::ostringstream o;
852 o <<
"TBB: DoBlock: BLOCK task_id=" << task_id <<
" block_id=" << block_id
853 <<
" iter_begin=" << iter_begin <<
" iter_size=" << iter_size <<
'\n';
854 std::cout << o.str();
859 auto r = tbb::blocked_range<int>(iter_begin, iter_begin + iter_size);
866 TBBTaskImplementation* m_impl;
867 const TBBParallelFor& m_tbb_for;
891 , m_stat_info(stat_info)
896 void operator()()
const
898 Integer nb_thread = m_options.maxThread();
900 Integer gsize = m_options.grainSize();
901 tbb::blocked_range<Integer> range(m_begin, m_begin + m_size);
903 std::cout <<
"TBB: TBBTaskImplementationInit ParallelForExecute begin=" << m_begin
904 <<
" size=" << m_size <<
" gsize=" << gsize
905 <<
" partitioner=" << (int)m_options.partitioner()
906 <<
" nb_thread=" << nb_thread
907 <<
" has_stat_info=" << (m_stat_info !=
nullptr)
911 range = tbb::blocked_range<Integer>(m_begin, m_begin + m_size, gsize);
914 tbb::parallel_for(range, pf, tbb::static_partitioner());
917 tbb::blocked_range<Integer> range2(0, nb_thread, 1);
919 tbb::parallel_for(range2, dpf);
922 tbb::parallel_for(range, pf);
927 TBBTaskImplementation* m_impl =
nullptr;
938template <
int RankValue>
943 MDParallelForExecute(TBBTaskImplementation* impl,
948 , m_tbb_range(_toTBBRange(range))
951 , m_stat_info(stat_info)
956 Int32 gsize = m_options.grainSize();
963 constexpr bool is_verbose =
false;
964 std::array<Int32, RankValue> range_extents = range.extents().asStdArray();
965 double ratio =
static_cast<double>(gsize) /
static_cast<double>(range.nbElement());
966 if constexpr (is_verbose) {
967 std::cout <<
"GSIZE=" << gsize <<
" rank=" << RankValue <<
" ratio=" << ratio;
968 for (
Int32 i = 0; i < RankValue; ++i)
969 std::cout <<
" range" << i <<
"=" << range_extents[i];
972 Int32 index = RankValue - 1;
973 Int32 remaining_grain = gsize;
974 for (; index >= 0; --index) {
975 Int32 current = range_extents[index];
976 if constexpr (is_verbose)
977 std::cout <<
"Check index=" << index <<
" remaining=" << remaining_grain <<
" current=" << current <<
"\n";
978 if (remaining_grain > current) {
979 all_grain_sizes[index] = current;
980 remaining_grain /= current;
983 all_grain_sizes[index] = remaining_grain;
987 for (
Int32 i = 0; i < index; ++i)
988 all_grain_sizes[i] = 1;
989 if constexpr (is_verbose) {
990 for (
Int32 i = 0; i < RankValue; ++i)
991 std::cout <<
" grain" << i <<
"=" << all_grain_sizes[i];
994 m_tbb_range = _toTBBRangeWithGrain(m_tbb_range, all_grain_sizes);
1000 void operator()()
const
1002 Integer nb_thread = m_options.maxThread();
1006 tbb::parallel_for(m_tbb_range, pf, tbb::static_partitioner());
1016 tbb::parallel_for(m_tbb_range, pf);
1022 TBBTaskImplementation* m_impl =
nullptr;
1023 blocked_nd_range<Int32, RankValue> m_tbb_range;
1032TBBTaskImplementation::
1033~TBBTaskImplementation()
1046 m_is_active = (nb_thread != 1);
1048 m_p =
new Impl(nb_thread);
1071 o <<
"OneTBBTaskImplementation"
1072 <<
" version=" << TBB_VERSION_STRING
1073 <<
" interface=" << TBB_INTERFACE_VERSION
1074 <<
" runtime_interface=" << TBB_runtime_interface_version();
1080void TBBTaskImplementation::
1083 ScopedExecInfo sei(loop_info.runInfo());
1087 Int32 begin = loop_info.beginIndex();
1088 Int32 size = loop_info.size();
1094 Integer nb_allowed_thread = m_p->nbAllowedThread();
1096 max_thread = nb_allowed_thread;
1099 std::cout <<
"TBB: TBBTaskImplementation executeParallelFor begin=" << begin
1100 <<
" size=" << size <<
" max_thread=" << max_thread
1101 <<
" grain_size=" << options.
grainSize()
1102 <<
" nb_allowed=" << nb_allowed_thread <<
'\n';
1105 if (max_thread == 1 || max_thread == 0) {
1111 ParallelLoopOptions true_options(options);
1113 true_options.setMaxThread(max_thread);
1115 ParallelForExecute pfe(
this, true_options, begin, size, f, stat_info);
1117 tbb::task_arena* used_arena =
nullptr;
1118 if (max_thread < nb_allowed_thread && max_thread < m_p->m_sub_arena_list.size())
1121 used_arena = &(m_p->m_main_arena);
1122 used_arena->execute(pfe);
1131 _executeParallelFor(loop_info);
1148 if (run_info.options().has_value())
1149 options = run_info.options().value();
1151 ScopedExecInfo sei(run_info);
1156 std::cout <<
"TBB: TBBTaskImplementation executeMDParallelFor nb_dim=" << RankValue
1157 <<
" nb_element=" << loop_ranges.nbElement()
1158 <<
" grain_size=" << options.
grainSize()
1159 <<
" name=" << run_info.traceInfo().traceInfo()
1160 <<
" has_stat_info=" << (stat_info !=
nullptr)
1166 if (max_thread == 1 || max_thread == 0) {
1167 functor->executeFunctor(loop_ranges);
1175 Integer nb_allowed_thread = m_p->nbAllowedThread();
1177 max_thread = nb_allowed_thread;
1178 tbb::task_arena* used_arena =
nullptr;
1179 if (max_thread < nb_allowed_thread)
1180 used_arena = m_p->m_sub_arena_list[max_thread];
1182 used_arena = &(m_p->m_main_arena);
1185 if constexpr (RankValue == 1) {
1186 auto range_1d = _toTBBRange(loop_ranges);
1192 Integer begin1 = CheckedConvert::toInteger(range_1d.dim(0).begin());
1193 Integer size1 = CheckedConvert::toInteger(range_1d.dim(0).size());
1195 used_arena->execute(pfe);
1199 used_arena->execute(pfe);
1232 return m_p->threadTaskInfo(thread_id);
1245 if (thread_id < 0 || thread_id >= m_p->nbAllowedThread())
1249 Int32 task_index = tti->taskIndex();
1250 if (task_index >= 0)
1262 tbb::task_group task_group;
1263 task_group.run(taskFunctor());
1274 tbb::task_group task_group;
1280 for (
Integer i = 0; i < n; ++i) {
1281 auto* t =
static_cast<OneTBBTask*
>(tasks[i]);
1282 task_group.run(t->taskFunctor());
1285 for (
Integer i = 0; i < n; ++i) {
1286 auto* t =
static_cast<OneTBBTask*
>(tasks[i]);
1304ARCANE_DI_REGISTER_PROVIDER(TBBTaskImplementation,
1305 DependencyInjection::ProviderProperty(
"TBBTaskImplementation"),
1306 ARCANE_DI_INTERFACES(ITaskImplementation),
1307 ARCANE_DI_EMPTY_CONSTRUCTOR());
#define ARCCORE_FATAL(...)
Macro envoyant une exception FatalErrorException.
#define ARCCORE_THROW(exception_class,...)
Macro pour envoyer une exception avec formattage.
#define ARCCORE_CHECK_POINTER(ptr)
Macro retournant le pointeur ptr s'il est non nul ou lancant une exception s'il est nul.
Interval d'itération complexe.
static void _setMaxAllowedThread(Int32 v)
Positionne le nombre maximum de thread à utiliser.
Vue constante d'un tableau de type T.
constexpr Integer size() const noexcept
Nombre d'éléments du tableau.
Tableau 1D de taille fixe.
Classe pour gérer le profiling d'une seule exécution d'une boucle.
Intervalle d'itération pour une boucle.
Informations d'exécution d'une boucle.
Interface d'un fonctor sur un interval d'itération multi-dimensionnel de dimension RankValue.
Interface d'un fonctor sur un interval d'itération.
virtual void executeFunctor(Int32 begin, Int32 size)=0
Exécute la méthode associée.
Interface d'un fonctor pour une tâche.
virtual void executeFunctor(const TaskContext &tc)=0
Exécute la méthode associé
Implémentation d'une fabrique de tâches.
Int32 nbAllowedThread() const
Nombre de threads utilisés au maximum pour gérer les tâches.
Interface d'une tâche concourante.
Classe permettant de récupérer le temps passé entre l'appel au constructeur et au destructeur.
Fonctor sur un interval d'itération instancié via une lambda fonction.
Exception lorsqu'une fonction n'est pas implémentée.
void launchAndWait() override
Lance la tâche et bloque jusqu'à ce qu'elle se termine.
Caractéristiques d'un boucle 1D multi-thread.
Options d'exécution d'une boucle parallèle en multi-thread.
Integer grainSize() const
Taille d'un intervalle d'itération.
void mergeUnsetValues(const ParallelLoopOptions &po)
Fusionne les valeurs non modifiées de l'instance par celles de po.
Int32 maxThread() const
Nombre maximal de threads autorisés.
void setGrainSize(Integer v)
Positionne la taille (approximative) d'un intervalle d'itération.
void setMaxThread(Integer v)
Positionne le nombre maximal de threads autorisé.
@ Static
Utilise un partitionnement statique.
@ Deterministic
Utilise un partitionnement et un ordonnancement statique.
static Impl::ForLoopStatInfoList * _threadLocalForLoopInstance()
static bool hasProfiling()
Indique si le profilage est actif.
Implémentation déterministe de ParallelFor.
void operator()(tbb::blocked_range< Integer > &range) const
Opérateur pour un thread donné.
Exécuteur pour une boucle multi-dimension.
Exécuteur pour une boucle 1D.
std::vector< tbb::task_arena * > m_sub_arena_list
Tableau dont le i-ème élément contient la tbb::task_arena pour i thread.
Classe pour positionner TaskThreadInfo::taskIndex().
Int32 currentTaskThreadIndex() const final
Implémentation de TaskFactory::currentTaskThreadIndex()
void initialize(Int32 nb_thread) override
void executeParallelFor(const ComplexForLoopRanges< 1 > &loop_ranges, const ForLoopRunInfo &run_info, IMDRangeFunctor< 1 > *functor) final
Exécute une boucle 1D en concurrence.
void executeParallelFor(Int32 begin, Int32 size, IRangeFunctor *f) final
Exécute le fonctor f en concurrence.
ITask * createRootTask(ITaskFunctor *f) override
Créé une tâche racine. L'implémentation doit recopier la valeur de f qui est soit un TaskFunctor,...
void printInfos(std::ostream &o) const final
Affiche les informations sur le runtime utilisé
void executeParallelFor(Int32 begin, Int32 size, const ParallelLoopOptions &options, IRangeFunctor *f) final
Exécute le fonctor f en concurrence.
void executeParallelFor(const ComplexForLoopRanges< 3 > &loop_ranges, const ForLoopRunInfo &run_info, IMDRangeFunctor< 3 > *functor) final
Exécute une boucle 3D en concurrence.
void executeParallelFor(const ComplexForLoopRanges< 4 > &loop_ranges, const ForLoopRunInfo &run_info, IMDRangeFunctor< 4 > *functor) final
Exécute une boucle 4D en concurrence.
TaskThreadInfo * currentTaskThreadInfo() const
Instance de TaskThreadInfo associé au thread courant.
void terminate() override
bool isActive() const final
Indique si l'implémentation est active.
void _executeMDParallelFor(const ComplexForLoopRanges< RankValue > &loop_ranges, IMDRangeFunctor< RankValue > *functor, const ForLoopRunInfo &run_info)
Exécution d'une boucle N-dimensions.
Int32 currentTaskIndex() const final
Implémentation de TaskFactory::currentTaskIndex()
void executeParallelFor(const ComplexForLoopRanges< 2 > &loop_ranges, const ForLoopRunInfo &run_info, IMDRangeFunctor< 2 > *functor) final
Exécute une boucle 2D en concurrence.
Contexte d'éxecution d'une tâche.
static void notifyThreadCreated()
Notifie tous les observateurs de création de thread.
static const ParallelLoopOptions & defaultParallelLoopOptions()
Valeurs par défaut d'exécution d'une boucle parallèle.
static Integer verboseLevel()
Niveau de verbosité
static void setDefaultParallelLoopOptions(const ParallelLoopOptions &v)
Positionne les valeurs par défaut d'exécution d'une boucle parallèle.
static Int32 currentTaskThreadIndex()
Indice (entre 0 et nbAllowedThread()-1) du thread exécutant la tâche actuelle.
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
Int32 Integer
Type représentant un entier.
SimpleForLoopRanges< 1 > makeLoopRanges(Int32 n1)
Créé un intervalle d'itération [0,n1[.
std::int32_t Int32
Type entier signé sur 32 bits.