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"
33#include "arcane/utils/Array.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>;
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);
343class TBBTaskImplementation
348 template <
int RankValue>
365 void setTaskIndex(
Integer v) { m_task_index = v; }
366 Integer taskIndex()
const {
return m_task_index; }
379 class TaskInfoLockGuard
385 , m_old_task_index(-1)
388 m_old_task_index = tti->taskIndex();
389 tti->setTaskIndex(task_index);
395 m_tti->setTaskIndex(m_old_task_index);
406 TBBTaskImplementation() =
default;
407 ~TBBTaskImplementation()
override;
480 bool m_is_active = false;
485 template <
int RankValue>
void
495class TBBTaskImplementation::Impl
498 :
public tbb::task_scheduler_observer
503 : tbb::task_scheduler_observer(p->m_main_arena)
507 void on_scheduler_entry(
bool is_worker)
override
509 m_p->notifyThreadCreated(is_worker);
511 void on_scheduler_exit(
bool is_worker)
override
513 m_p->notifyThreadDestroyed(is_worker);
521 : m_task_observer(this)
524 m_nb_allowed_thread = tbb::info::default_concurrency();
528 : m_main_arena(nb_thread)
529 , m_task_observer(this)
532 m_nb_allowed_thread = nb_thread;
539 TaskThreadInfo* threadTaskInfo(
Integer index) {
return &m_thread_task_infos[index]; }
543 Int32 m_nb_allowed_thread = 0;
549 for (
auto x : m_sub_arena_list) {
554 m_sub_arena_list.clear();
555 m_main_arena.terminate();
556 m_task_observer.observe(
false);
557 oneapi::tbb::finalize(m_task_scheduler_handle);
562 void notifyThreadCreated(
bool is_worker)
564 std::thread::id my_thread_id = std::this_thread::get_id();
572 if (m_constructed_thread_map.contains(my_thread_id))
574 m_constructed_thread_map.insert(my_thread_id);
578 std::ostringstream ostr;
579 ostr <<
"TBB: CREATE THREAD"
580 <<
" nb_allowed=" << m_nb_allowed_thread
581 <<
" tbb_default_allowed=" << tbb::info::default_concurrency()
582 <<
" id=" << my_thread_id
583 <<
" arena_id=" << _currentTaskTreadIndex()
584 <<
" is_worker=" << is_worker
586 std::cout << ostr.str();
592 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;
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)
658 , m_stat_info(stat_info)
659 , m_nb_allowed_thread(nb_allowed_thread)
664 void operator()(tbb::blocked_range<Integer>& range)
const
668 std::ostringstream o;
670 <<
" id=" << std::this_thread::get_id()
671 <<
" max_allowed=" << m_nb_allowed_thread
672 <<
" range_begin=" << range.begin() <<
" range_size=" << range.size()
674 std::cout << o.str();
678 int tbb_index = _currentTaskTreadIndex();
679 if (tbb_index < 0 || tbb_index >= m_nb_allowed_thread)
680 ARCANE_FATAL(
"Invalid index for thread idx={0} valid_interval=[0..{1}[",
681 tbb_index, m_nb_allowed_thread);
685 m_stat_info->incrementNbChunk();
686 m_functor->executeFunctor(range.begin(), CheckedConvert::toInteger(range.size()));
693 Int32 m_nb_allowed_thread;
701template <
int RankValue>
702class TBBMDParallelFor
708 , m_stat_info(stat_info)
709 , m_nb_allowed_thread(nb_allowed_thread)
714 void operator()(blocked_nd_range<Int32, RankValue>& range)
const
718 std::ostringstream o;
720 <<
" id=" << std::this_thread::get_id()
721 <<
" max_allowed=" << m_nb_allowed_thread
723 for (
Int32 i = 0; i < RankValue; ++i) {
724 auto r0 =
static_cast<Int32>(range.dim(i).begin());
725 auto r1 =
static_cast<Int32>(range.dim(i).size());
726 o <<
" range" << i <<
" (begin=" << r0 <<
" size=" << r1 <<
")";
729 std::cout << o.str();
733 int tbb_index = _currentTaskTreadIndex();
734 if (tbb_index < 0 || tbb_index >= m_nb_allowed_thread)
735 ARCANE_FATAL(
"Invalid index for thread idx={0} valid_interval=[0..{1}[",
736 tbb_index, m_nb_allowed_thread);
740 m_stat_info->incrementNbChunk();
741 m_functor->executeFunctor(_fromTBBRange(range));
748 Int32 m_nb_allowed_thread;
770class TBBDeterministicParallelFor
778 , m_nb_thread(nb_thread)
779 , m_begin_index(begin_index)
781 , m_grain_size(grain_size)
784 , m_nb_block_per_thread(0)
789 if (m_grain_size > 0) {
790 m_block_size = m_grain_size;
791 if (m_block_size > 0) {
792 m_nb_block = m_size / m_block_size;
793 if ((m_size % m_block_size) != 0)
798 m_nb_block_per_thread = m_nb_block / m_nb_thread;
799 if ((m_nb_block % m_nb_thread) != 0)
800 ++m_nb_block_per_thread;
804 m_nb_block = m_nb_thread;
805 m_block_size = m_size / m_nb_block;
806 m_nb_block_per_thread = 1;
809 std::cout <<
"TBBDeterministicParallelFor: BEGIN=" << m_begin_index <<
" size=" << m_size
810 <<
" grain_size=" << m_grain_size
811 <<
" nb_block=" << m_nb_block <<
" nb_thread=" << m_nb_thread
812 <<
" nb_block_per_thread=" << m_nb_block_per_thread
813 <<
" block_size=" << m_block_size
814 <<
" block_size*nb_block=" << m_block_size * m_nb_block <<
'\n';
828 auto nb_iter =
static_cast<Integer>(range.size());
829 for (
Integer i = 0; i < nb_iter; ++i) {
830 Integer task_id = range.begin() + i;
831 for (
Integer k = 0, kn = m_nb_block_per_thread; k < kn; ++k) {
832 Integer block_id = task_id + (k * m_nb_thread);
833 if (block_id < m_nb_block)
834 _doBlock(task_id, block_id);
843 Integer iter_begin = block_id * m_block_size;
844 Integer iter_size = m_block_size;
845 if ((block_id + 1) == m_nb_block) {
847 iter_size = m_size - iter_begin;
849 iter_begin += m_begin_index;
851 if (TaskFactory::verboseLevel() >= 3) {
852 std::ostringstream o;
853 o <<
"TBB: DoBlock: BLOCK task_id=" << task_id <<
" block_id=" << block_id
854 <<
" iter_begin=" << iter_begin <<
" iter_size=" << iter_size <<
'\n';
855 std::cout << o.str();
860 auto r = tbb::blocked_range<int>(iter_begin, iter_begin + iter_size);
867 TBBTaskImplementation* m_impl;
868 const TBBParallelFor& m_tbb_for;
892 , m_stat_info(stat_info)
897 void operator()()
const
899 Integer nb_thread = m_options.maxThread();
901 Integer gsize = m_options.grainSize();
902 tbb::blocked_range<Integer> range(m_begin, m_begin + m_size);
904 std::cout <<
"TBB: TBBTaskImplementationInit ParallelForExecute begin=" << m_begin
905 <<
" size=" << m_size <<
" gsize=" << gsize
906 <<
" partitioner=" << (int)m_options.partitioner()
907 <<
" nb_thread=" << nb_thread
908 <<
" has_stat_info=" << (m_stat_info !=
nullptr)
912 range = tbb::blocked_range<Integer>(m_begin, m_begin + m_size, gsize);
915 tbb::parallel_for(range, pf, tbb::static_partitioner());
918 tbb::blocked_range<Integer> range2(0, nb_thread, 1);
920 tbb::parallel_for(range2, dpf);
923 tbb::parallel_for(range, pf);
928 TBBTaskImplementation* m_impl =
nullptr;
939template <
int RankValue>
944 MDParallelForExecute(TBBTaskImplementation* impl,
949 , m_tbb_range(_toTBBRange(range))
952 , m_stat_info(stat_info)
957 Int32 gsize = m_options.grainSize();
964 constexpr bool is_verbose =
false;
965 std::array<Int32, RankValue> range_extents = range.extents().asStdArray();
966 double ratio =
static_cast<double>(gsize) /
static_cast<double>(range.nbElement());
967 if constexpr (is_verbose) {
968 std::cout <<
"GSIZE=" << gsize <<
" rank=" << RankValue <<
" ratio=" << ratio;
969 for (
Int32 i = 0; i < RankValue; ++i)
970 std::cout <<
" range" << i <<
"=" << range_extents[i];
973 Int32 index = RankValue - 1;
974 Int32 remaining_grain = gsize;
975 for (; index >= 0; --index) {
976 Int32 current = range_extents[index];
977 if constexpr (is_verbose)
978 std::cout <<
"Check index=" << index <<
" remaining=" << remaining_grain <<
" current=" << current <<
"\n";
979 if (remaining_grain > current) {
980 all_grain_sizes[index] = current;
981 remaining_grain /= current;
984 all_grain_sizes[index] = remaining_grain;
988 for (
Int32 i = 0; i < index; ++i)
989 all_grain_sizes[i] = 1;
990 if constexpr (is_verbose) {
991 for (
Int32 i = 0; i < RankValue; ++i)
992 std::cout <<
" grain" << i <<
"=" << all_grain_sizes[i];
995 m_tbb_range = _toTBBRangeWithGrain(m_tbb_range, all_grain_sizes);
1001 void operator()()
const
1003 Integer nb_thread = m_options.maxThread();
1007 tbb::parallel_for(m_tbb_range, pf, tbb::static_partitioner());
1017 tbb::parallel_for(m_tbb_range, pf);
1023 TBBTaskImplementation* m_impl =
nullptr;
1024 blocked_nd_range<Int32, RankValue> m_tbb_range;
1033TBBTaskImplementation::
1034~TBBTaskImplementation()
1047 m_is_active = (nb_thread != 1);
1049 m_p =
new Impl(nb_thread);
1072 o <<
"OneTBBTaskImplementation"
1073 <<
" version=" << TBB_VERSION_STRING
1074 <<
" interface=" << TBB_INTERFACE_VERSION
1075 <<
" runtime_interface=" << TBB_runtime_interface_version();
1081void TBBTaskImplementation::
1084 ScopedExecInfo sei(loop_info.runInfo());
1088 Int32 begin = loop_info.beginIndex();
1089 Int32 size = loop_info.size();
1095 Integer nb_allowed_thread = m_p->nbAllowedThread();
1097 max_thread = nb_allowed_thread;
1100 std::cout <<
"TBB: TBBTaskImplementation executeParallelFor begin=" << begin
1101 <<
" size=" << size <<
" max_thread=" << max_thread
1102 <<
" grain_size=" << options.
grainSize()
1103 <<
" nb_allowed=" << nb_allowed_thread <<
'\n';
1106 if (max_thread == 1 || max_thread == 0) {
1112 ParallelLoopOptions true_options(options);
1114 true_options.setMaxThread(max_thread);
1116 ParallelForExecute pfe(
this, true_options, begin, size, f, stat_info);
1118 tbb::task_arena* used_arena =
nullptr;
1119 if (max_thread < nb_allowed_thread && max_thread < m_p->m_sub_arena_list.size())
1122 used_arena = &(m_p->m_main_arena);
1123 used_arena->execute(pfe);
1132 _executeParallelFor(loop_info);
1149 if (run_info.options().has_value())
1150 options = run_info.options().value();
1152 ScopedExecInfo sei(run_info);
1157 std::cout <<
"TBB: TBBTaskImplementation executeMDParallelFor nb_dim=" << RankValue
1158 <<
" nb_element=" << loop_ranges.nbElement()
1159 <<
" grain_size=" << options.
grainSize()
1160 <<
" name=" << run_info.traceInfo().traceInfo()
1161 <<
" has_stat_info=" << (stat_info !=
nullptr)
1167 if (max_thread == 1 || max_thread == 0) {
1168 functor->executeFunctor(loop_ranges);
1176 Integer nb_allowed_thread = m_p->nbAllowedThread();
1178 max_thread = nb_allowed_thread;
1179 tbb::task_arena* used_arena =
nullptr;
1180 if (max_thread < nb_allowed_thread)
1181 used_arena = m_p->m_sub_arena_list[max_thread];
1183 used_arena = &(m_p->m_main_arena);
1186 if constexpr (RankValue == 1) {
1187 auto range_1d = _toTBBRange(loop_ranges);
1193 Integer begin1 = CheckedConvert::toInteger(range_1d.dim(0).begin());
1194 Integer size1 = CheckedConvert::toInteger(range_1d.dim(0).size());
1196 used_arena->execute(pfe);
1200 used_arena->execute(pfe);
1233 return m_p->threadTaskInfo(thread_id);
1246 if (thread_id < 0 || thread_id >= m_p->nbAllowedThread())
1250 Int32 task_index = tti->taskIndex();
1251 if (task_index >= 0)
1263 tbb::task_group task_group;
1264 task_group.run(taskFunctor());
1275 tbb::task_group task_group;
1281 for (
Integer i = 0; i < n; ++i) {
1282 auto* t =
static_cast<OneTBBTask*
>(tasks[i]);
1283 task_group.run(t->taskFunctor());
1286 for (
Integer i = 0; i < n; ++i) {
1287 auto* t =
static_cast<OneTBBTask*
>(tasks[i]);
1305ARCANE_DI_REGISTER_PROVIDER(TBBTaskImplementation,
1306 DependencyInjection::ProviderProperty(
"TBBTaskImplementation"),
1307 ARCANE_DI_INTERFACES(ITaskImplementation),
1308 ARCANE_DI_EMPTY_CONSTRUCTOR());
#define ARCANE_CHECK_POINTER(ptr)
Macro retournant le pointeur ptr s'il est non nul ou lancant une exception s'il est nul.
#define ARCANE_THROW(exception_class,...)
Macro pour envoyer une exception avec formattage.
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
#define ARCANE_ALIGNAS_PACKED(value)
Macro pour garantir le compactage et l'alignement d'une classe sur value octets.
Allocateur mémoire avec alignement mémoire spécifique.
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.
UniqueArray< 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.
Vecteur 1D de données avec sémantique par valeur (style STL).
-*- 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.