14#include "arcane/utils/IThreadImplementation.h"
15#include "arcane/utils/NotImplementedException.h"
16#include "arcane/utils/IFunctor.h"
17#include "arcane/utils/CheckedConvert.h"
18#include "arcane/utils/ForLoopRanges.h"
20#include "arcane/utils/IObservable.h"
21#include "arcane/utils/PlatformUtils.h"
22#include "arcane/utils/Profiling.h"
23#include "arcane/utils/MemoryAllocator.h"
24#include "arcane/utils/FixedArray.h"
25#include "arcane/utils/internal/TaskFactoryInternal.h"
26#include "arcane/utils/internal/DependencyInjection.h"
28#include "arcane/core/FactoryService.h"
35#define TBB_PREVIEW_BLOCKED_RANGE_ND 1
42#ifdef ARCANE_USE_ONETBB
45#define TBB_PREVIEW_WAITING_FOR_WORKERS 1
47#include <oneapi/tbb/concurrent_set.h>
48#include <oneapi/tbb/global_control.h>
54#include <tbb/blocked_rangeNd.h>
58#if (TBB_VERSION_MAJOR < 4) || (TBB_VERSION_MAJOR==4 && TBB_VERSION_MINOR<2)
62#if (TBB_VERSION_MAJOR<2018)
67#error "Your version of TBB is tool old. TBB 2018+ is required. Please disable TBB in configuration"
81class TBBTaskImplementation;
108 explicit ScopedExecInfo(
const ForLoopRunInfo& run_info)
109 : m_run_info(run_info)
115 ForLoopOneExecStat* ptr = run_info.execStat();
117 m_stat_info_ptr = ptr;
118 m_use_own_run_info =
false;
121 m_stat_info_ptr = isStatActive() ? &m_stat_info :
nullptr;
125#ifdef PRINT_STAT_INFO
126 if (m_stat_info_ptr){
127 bool is_valid = m_run_info.traceInfo().isValid();
129 std::cout <<
"ADD_OWN_RUN_INFO nb_chunk=" << m_stat_info_ptr->nbChunk()
130 <<
" stack=" << platform::getStackTrace()
133 std::cout <<
"ADD_OWN_RUN_INFO nb_chunk=" << m_stat_info_ptr->nbChunk()
134 <<
" trace_name=" << m_run_info.traceInfo().traceInfo().name() <<
"\n";
137 if (m_stat_info_ptr && m_use_own_run_info){
144 ForLoopOneExecStat* statInfo()
const {
return m_stat_info_ptr; }
145 bool isOwn()
const {
return m_use_own_run_info; }
148 ForLoopOneExecStat m_stat_info;
149 ForLoopOneExecStat* m_stat_info_ptr =
nullptr;
150 ForLoopRunInfo m_run_info;
152 bool m_use_own_run_info =
true;
158inline int _currentTaskTreadIndex()
164 return tbb::this_task_arena::current_thread_index();
167inline tbb::blocked_rangeNd<Int32,1>
168_toTBBRange(
const ComplexForLoopRanges<1>& r)
170 return {{r.lowerBound<0>(), r.upperBound<0>()}};
173inline tbb::blocked_rangeNd<Int32,2>
174_toTBBRange(
const ComplexForLoopRanges<2>& r)
176 return {{r.lowerBound<0>(), r.upperBound<0>()},
177 {r.lowerBound<1>(), r.upperBound<1>()}};
181inline tbb::blocked_rangeNd<Int32,3>
182_toTBBRange(
const ComplexForLoopRanges<3>& r)
184 return {{r.lowerBound<0>(), r.upperBound<0>()},
185 {r.lowerBound<1>(), r.upperBound<1>()},
186 {r.lowerBound<2>(), r.upperBound<2>()}};
189inline tbb::blocked_rangeNd<Int32,4>
190_toTBBRange(
const ComplexForLoopRanges<4>& r)
192 return {{r.lowerBound<0>(), r.upperBound<0>()},
193 {r.lowerBound<1>(), r.upperBound<1>()},
194 {r.lowerBound<2>(), r.upperBound<2>()},
195 {r.lowerBound<3>(), r.upperBound<3>()}};
201inline tbb::blocked_rangeNd<Int32,2>
202_toTBBRangeWithGrain(
const tbb::blocked_rangeNd<Int32,2>& r,FixedArray<size_t,2> grain_sizes)
204 return {{r.dim(0).begin(), r.dim(0).end(), grain_sizes[0]},
205 {r.dim(1).begin(), r.dim(1).end(), grain_sizes[1]}};
208inline tbb::blocked_rangeNd<Int32,3>
209_toTBBRangeWithGrain(
const tbb::blocked_rangeNd<Int32,3>& r,FixedArray<size_t,3> grain_sizes)
211 return {{r.dim(0).begin(), r.dim(0).end(), grain_sizes[0]},
212 {r.dim(1).begin(), r.dim(1).end(), grain_sizes[1]},
213 {r.dim(2).begin(), r.dim(2).end(), grain_sizes[2]}};
216inline tbb::blocked_rangeNd<Int32,4>
217_toTBBRangeWithGrain(
const tbb::blocked_rangeNd<Int32,4>& r,FixedArray<size_t,4> grain_sizes)
219 return {{r.dim(0).begin(), r.dim(0).end(), grain_sizes[0]},
220 {r.dim(1).begin(), r.dim(1).end(), grain_sizes[1]},
221 {r.dim(2).begin(), r.dim(2).end(), grain_sizes[2]},
222 {r.dim(3).begin(), r.dim(3).end(), grain_sizes[3]}};
228inline ComplexForLoopRanges<2>
229_fromTBBRange(
const tbb::blocked_rangeNd<Int32,2>& r)
231 using BoundsType = ArrayBounds<MDDim2>;
232 using ArrayExtentType =
typename BoundsType::ArrayExtentType;
234 BoundsType lower_bounds(ArrayExtentType(r.dim(0).begin(),r.dim(1).begin()));
235 auto s0 =
static_cast<Int32>(r.dim(0).size());
236 auto s1 =
static_cast<Int32>(r.dim(1).size());
237 BoundsType sizes(ArrayExtentType(s0,s1));
238 return { lower_bounds, sizes };
241inline ComplexForLoopRanges<3>
242_fromTBBRange(
const tbb::blocked_rangeNd<Int32,3> & r)
244 using BoundsType = ArrayBounds<MDDim3>;
245 using ArrayExtentType =
typename BoundsType::ArrayExtentType;
247 BoundsType lower_bounds(ArrayExtentType(r.dim(0).begin(),r.dim(1).begin(),r.dim(2).begin()));
248 auto s0 =
static_cast<Int32>(r.dim(0).size());
249 auto s1 =
static_cast<Int32>(r.dim(1).size());
250 auto s2 =
static_cast<Int32>(r.dim(2).size());
251 BoundsType sizes(ArrayExtentType(s0,s1,s2));
252 return { lower_bounds, sizes };
255inline ComplexForLoopRanges<4>
256_fromTBBRange(
const tbb::blocked_rangeNd<Int32,4>& r)
258 using BoundsType = ArrayBounds<MDDim4>;
259 using ArrayExtentType =
typename BoundsType::ArrayExtentType;
261 BoundsType lower_bounds(ArrayExtentType(r.dim(0).begin(),r.dim(1).begin(),r.dim(2).begin(),r.dim(3).begin()));
262 auto s0 =
static_cast<Int32>(r.dim(0).size());
263 auto s1 =
static_cast<Int32>(r.dim(1).size());
264 auto s2 =
static_cast<Int32>(r.dim(2).size());
265 auto s3 =
static_cast<Int32>(r.dim(3).size());
266 BoundsType sizes(ArrayExtentType(s0,s1,s2,s3));
267 return { lower_bounds, sizes };
275#ifdef ARCANE_USE_ONETBB
280class OneTBBTaskFunctor
283 OneTBBTaskFunctor(ITaskFunctor* functor,ITask* task)
284 : m_functor(functor), m_task(task) {}
286 void operator()()
const
289 ITaskFunctor* tf = m_functor;
291 TaskContext task_context(m_task);
293 tf->executeFunctor(task_context);
297 mutable ITaskFunctor* m_functor;
308 static const int FUNCTOR_CLASS_SIZE = 32;
310 OneTBBTask(ITaskFunctor* f)
313 m_functor = f->clone(functor_buf,FUNCTOR_CLASS_SIZE);
316 OneTBBTaskFunctor taskFunctor() {
return OneTBBTaskFunctor(m_functor,
this); }
317 void launchAndWait()
override;
318 void launchAndWait(ConstArrayView<ITask*> tasks)
override;
320 virtual ITask* _createChildTask(ITaskFunctor* functor)
override;
322 ITaskFunctor* m_functor;
323 char functor_buf[FUNCTOR_CLASS_SIZE];
325using TBBTask = OneTBBTask;
340 static const int FUNCTOR_CLASS_SIZE = 32;
345 m_functor = f->clone(functor_buf,FUNCTOR_CLASS_SIZE);
348 tbb::task* execute()
override
365 char functor_buf[FUNCTOR_CLASS_SIZE];
386 template<
int RankValue>
397 void setTaskIndex(Integer v) { m_task_index = v; }
398 Integer taskIndex()
const {
return m_task_index; }
400 Integer m_task_index;
413 : m_tti(
tti), m_old_task_index(-1)
416 m_old_task_index =
tti->taskIndex();
423 m_tti->setTaskIndex(m_old_task_index);
427 Integer m_old_task_index;
443#ifdef ARCANE_USE_ONETBB
453 void executeParallelFor(Int32 begin,Int32 size,
IRangeFunctor* f)
final
457 void executeParallelFor(
const ParallelFor1DLoopInfo& loop_info)
override;
512 bool m_is_active =
false;
530 :
public tbb::task_scheduler_observer
535#ifdef ARCANE_USE_ONETBB
536 tbb::task_scheduler_observer(
p->m_main_arena),
541 void on_scheduler_entry(
bool is_worker)
override
545 void on_scheduler_exit(
bool is_worker)
override
554 m_task_observer(this),
557#ifdef ARCANE_USE_ONETBB
558 m_nb_allowed_thread = tbb::info::default_concurrency();
560 m_nb_allowed_thread = tbb::task_scheduler_init::default_num_threads();
570 m_task_observer(this),
578 TaskThreadInfo* threadTaskInfo(Integer index) {
return &m_thread_task_infos[index]; }
580 Int32 m_nb_allowed_thread;
585 for(
auto x : m_sub_arena_list ){
590 m_sub_arena_list.clear();
591 m_main_arena.terminate();
592#ifdef ARCANE_USE_ONETBB
593 m_task_observer.observe(
false);
594 oneapi::tbb::finalize(m_task_scheduler_handle);
596 m_scheduler_init.terminate();
597 m_task_observer.observe(
false);
601 void notifyThreadCreated(
bool is_worker)
603 std::thread::id my_thread_id = std::this_thread::get_id();
605#ifdef ARCANE_USE_ONETBB
612 if (m_constructed_thread_map.contains(my_thread_id))
614 m_constructed_thread_map.insert(my_thread_id);
619 std::ostringstream ostr;
620 ostr <<
"TBB: CREATE THREAD"
621 <<
" nb_allowed=" << m_nb_allowed_thread
622#ifdef ARCANE_USE_ONETBB
623 <<
" tbb_default_allowed=" << tbb::info::default_concurrency()
625 <<
" tbb_default_allowed=" << tbb::task_scheduler_init::default_num_threads()
627 <<
" id=" << my_thread_id
628 <<
" arena_id=" << _currentTaskTreadIndex()
629 <<
" is_worker=" << is_worker
631 std::cout << ostr.str();
637 void notifyThreadDestroyed([[maybe_unused]]
bool is_worker)
639#ifdef ARCANE_USE_ONETBB
649 std::scoped_lock sl(m_thread_created_mutex);
651 std::cout <<
"TBB: DESTROY THREAD"
652 <<
" id=" << std::this_thread::get_id()
653 <<
" arena_id=" << _currentTaskTreadIndex()
654 <<
" is_worker=" << is_worker
662#ifdef ARCANE_USE_ONETBB
663#if TBB_VERSION_MAJOR>2021 || (TBB_VERSION_MAJOR==2021 && TBB_VERSION_MINOR>5)
664 oneapi::tbb::task_scheduler_handle m_task_scheduler_handle = oneapi::tbb::attach();
666 oneapi::tbb::task_scheduler_handle m_task_scheduler_handle = tbb::task_scheduler_handle::get();
669 tbb::task_scheduler_init m_scheduler_init;
672 tbb::task_arena m_main_arena;
677 std::mutex m_thread_created_mutex;
679#ifdef ARCANE_USE_ONETBB
685 std::cout <<
"TBB: TBBTaskImplementationInit nb_allowed_thread=" << m_nb_allowed_thread
686 <<
" id=" << std::this_thread::get_id()
690 m_thread_task_infos.resize(m_nb_allowed_thread);
691 m_task_observer.observe(
true);
698 m_sub_arena_list[0] = m_sub_arena_list[1] =
nullptr;
700 m_sub_arena_list[i] =
new tbb::task_arena(i);
716 void operator()(tbb::blocked_range<Integer>&
range)
const
719 if (TaskFactory::verboseLevel()>=3){
720 std::ostringstream o;
721 o <<
"TBB: INDEX=" << TaskFactory::currentTaskThreadIndex()
722 <<
" id=" << std::this_thread::get_id()
723 <<
" max_allowed=" << m_nb_allowed_thread
724 <<
" range_begin=" <<
range.begin() <<
" range_size=" <<
range.size()
726 std::cout << o.str();
732 ARCANE_FATAL(
"Invalid index for thread idx={0} valid_interval=[0..{1}[",
737 m_stat_info->incrementNbChunk();
738 m_functor->executeFunctor(
range.begin(),CheckedConvert::toInteger(
range.size()));
744 Int32 m_nb_allowed_thread;
752template<
int RankValue>
762 void operator()(tbb::blocked_rangeNd<Int32,RankValue>&
range)
const
765 if (TaskFactory::verboseLevel()>=3){
766 std::ostringstream o;
767 o <<
"TBB: INDEX=" << TaskFactory::currentTaskThreadIndex()
768 <<
" id=" << std::this_thread::get_id()
769 <<
" max_allowed=" << m_nb_allowed_thread
772 Int32
r0 =
static_cast<Int32
>(
range.dim(i).begin());
773 Int32
r1 =
static_cast<Int32
>(
range.dim(i).size());
774 o <<
" range" << i <<
" (begin=" <<
r0 <<
" size=" <<
r1 <<
")";
777 std::cout << o.str();
783 ARCANE_FATAL(
"Invalid index for thread idx={0} valid_interval=[0..{1}[",
788 m_stat_info->incrementNbChunk();
796 Int32 m_nb_allowed_thread;
824 m_grain_size(
grain_size), m_nb_block(0), m_block_size(0), m_nb_block_per_thread(0)
830 m_block_size = m_grain_size;
832 m_nb_block = m_size / m_block_size;
833 if ((m_size % m_block_size)!=0)
838 m_nb_block_per_thread = m_nb_block / m_nb_thread;
839 if ((m_nb_block % m_nb_thread) != 0)
840 ++m_nb_block_per_thread;
844 m_nb_block = m_nb_thread;
845 m_block_size = m_size / m_nb_block;
846 m_nb_block_per_thread = 1;
848 if (TaskFactory::verboseLevel()>=2){
849 std::cout <<
"TBBDeterministicParallelFor: BEGIN=" << m_begin_index <<
" size=" << m_size
850 <<
" grain_size=" << m_grain_size
851 <<
" nb_block=" << m_nb_block <<
" nb_thread=" << m_nb_thread
852 <<
" nb_block_per_thread=" << m_nb_block_per_thread
853 <<
" block_size=" << m_block_size
854 <<
" block_size*nb_block=" << m_block_size*m_nb_block <<
'\n';
868 for( Integer i=0; i<
nb_iter; ++i ){
870 for ( Integer
k=0,
kn=m_nb_block_per_thread;
k<
kn; ++
k ){
888 iter_begin += m_begin_index;
890 if (TaskFactory::verboseLevel()>=3){
891 std::ostringstream o;
892 o <<
"TBB: DoBlock: BLOCK task_id=" << task_id <<
" block_id=" << block_id
893 <<
" iter_begin=" << iter_begin <<
" iter_size=" << iter_size <<
'\n';
894 std::cout << o.str();
899 auto r = tbb::blocked_range<int>(iter_begin,iter_begin + iter_size);
906 TBBTaskImplementation* m_impl;
907 const TBBParallelFor& m_tbb_for;
926 : m_impl(impl), m_begin(begin), m_size(size), m_functor(f), m_options(options), m_stat_info(
stat_info){}
930 void operator()()
const
932 Integer
nb_thread = m_options.maxThread();
934 Integer
gsize = m_options.grainSize();
935 tbb::blocked_range<Integer>
range(m_begin,m_begin+m_size);
936 if (TaskFactory::verboseLevel()>=1)
937 std::cout <<
"TBB: TBBTaskImplementationInit ParallelForExecute begin=" << m_begin
938 <<
" size=" << m_size <<
" gsize=" <<
gsize
939 <<
" partitioner=" << (
int)m_options.partitioner()
941 <<
" has_stat_info=" << (m_stat_info!=
nullptr)
945 range = tbb::blocked_range<Integer>(m_begin,m_begin+m_size,
gsize);
947 if (m_options.partitioner()==ParallelLoopOptions::Partitioner::Static){
948 tbb::parallel_for(
range,
pf,tbb::static_partitioner());
950 else if (m_options.partitioner()==ParallelLoopOptions::Partitioner::Deterministic){
970template<
int RankValue>
988 Int32
gsize = m_options.grainSize();
995 constexpr bool is_verbose =
false;
997 double ratio =
static_cast<double>(
gsize) /
static_cast<double>(
range.nbElement());
998 if constexpr (is_verbose){
1006 for( ; index>=0; --index ){
1008 if constexpr (is_verbose)
1009 std::cout <<
"Check index=" << index <<
" remaining=" <<
remaining_grain <<
" current=" << current <<
"\n";
1019 for( Int32 i=0; i<index; ++i )
1021 if constexpr (is_verbose){
1032 void operator()()
const
1034 Integer
nb_thread = m_options.maxThread();
1037 if (m_options.partitioner()==ParallelLoopOptions::Partitioner::Static){
1038 tbb::parallel_for(m_tbb_range,
pf,tbb::static_partitioner());
1040 else if (m_options.partitioner()==ParallelLoopOptions::Partitioner::Deterministic){
1048 tbb::parallel_for(m_tbb_range,
pf);
1053 tbb::blocked_rangeNd<Int32,RankValue> m_tbb_range;
1062TBBTaskImplementation::
1063~TBBTaskImplementation()
1101 return m_p->nbAllowedThread();
1110#ifdef ARCANE_USE_ONETBB
1111 o <<
"OneTBBTaskImplementation"
1116 o <<
"TBBTaskImplementation"
1125void TBBTaskImplementation::
1143 std::cout <<
"TBB: TBBTaskImplementation executeParallelFor begin=" << begin
1144 <<
" size=" << size <<
" max_thread=" <<
max_thread
1145 <<
" grain_size=" << options.
grainSize()
1155 ParallelLoopOptions true_options(options);
1157 true_options.setMaxThread(max_thread);
1159 ParallelForExecute pfe(
this,true_options,begin,size,f,stat_info);
1161 tbb::task_arena* used_arena =
nullptr;
1162 if (max_thread<nb_allowed_thread)
1165 used_arena = &(m_p->m_main_arena);
1166 used_arena->execute(pfe);
1172void TBBTaskImplementation::
1192 if (
run_info.options().has_value())
1193 options =
run_info.options().value();
1200 std::cout <<
"TBB: TBBTaskImplementation executeMDParallelFor nb_dim=" <<
RankValue
1202 <<
" grain_size=" << options.
grainSize()
1203 <<
" name=" <<
run_info.traceInfo().traceInfo()
1204 <<
" has_stat_info=" << (
stat_info!=
nullptr)
1231 auto x1 = [&](Integer begin,Integer size)
1251void TBBTaskImplementation::
1263void TBBTaskImplementation::
1264executeParallelFor(Integer begin,Integer size,
const ParallelLoopOptions& options,IRangeFunctor* f)
1266 executeParallelFor(ParallelFor1DLoopInfo(begin,size,f,ForLoopRunInfo(options)));
1288#ifdef ARCANE_USE_ONETBB
1304#ifdef ARCANE_USE_ONETBB
1322launchAndWait(ConstArrayView<ITask*> tasks)
1324 tbb::task_group task_group;
1325 Integer n = tasks.size();
1330 for( Integer i=0; i<n; ++i ){
1331 OneTBBTask* t =
static_cast<OneTBBTask*
>(tasks[i]);
1332 task_group.run(t->taskFunctor());
1335 for( Integer i=0; i<n; ++i ){
1336 OneTBBTask* t =
static_cast<OneTBBTask*
>(tasks[i]);
1345_createChildTask(ITaskFunctor* functor)
1347 OneTBBTask* t =
new OneTBBTask(functor);
1362 task::spawn_root_and_wait(*
this);
1371 Integer n =
tasks.size();
1376 for( Integer i=0; i<n-1; ++i ){
1386ITask* LegacyTBBTask::
1403 TBBTaskImplementation);
1405ARCANE_DI_REGISTER_PROVIDER(TBBTaskImplementation,
1406 DependencyInjection::ProviderProperty(
"TBBTaskImplementation"),
1407 ARCANE_DI_INTERFACES(ITaskImplementation),
1408 ARCANE_DI_EMPTY_CONSTRUCTOR());
#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.
Classes, Types et macros pour gérer la concurrence.
#define ARCANE_REGISTER_APPLICATION_FACTORY(aclass, ainterface, aname)
Enregistre un service de fabrique pour la classe aclass.
Interval d'itération complexe.
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(Integer begin, Integer size)=0
Exécute la méthode associée.
Interface d'un fonctor pour une tâche.
Implémentation d'une fabrique de tâches.
Interface d'une tâche concourante.
Fonctor sur un interval d'itération instancié via une lambda fonction.
void launchAndWait() override
Lance la tâche et bloque jusqu'à ce qu'elle se termine.
Lecteur des fichiers de maillage via la bibliothèque LIMA.
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.
Int32 maxThread() const
Nombre maximal de threads autorisés.
static impl::ForLoopStatInfoList * _threadLocalForLoopInstance()
static bool hasProfiling()
Indique si le profilage est actif.
Structure contenant les informations pour créer un service.
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.
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(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.
Int32 nbAllowedThread() const final
Nombre de threads utilisés au maximum pour gérer les tâches.
Contexte d'éxecution d'une tâche.
static void notifyThreadCreated()
Notifie tous les observateurs de création de thread.
static IObservable * destroyThreadObservable()
Observable appelé lors de la destruction d'un thread pour une tâche.
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.
Classe permettant de récupérer le temps passé entre l'appel au constructeur et au destructeur.
Allocateur mémoire avec alignement mémoire spécifique.
Exception lorsqu'une fonction n'est pas implémentée.
Integer toInteger(Real r)
Converti un Int64 en un Integer.
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
SimpleForLoopRanges< 1 > makeLoopRanges(Int32 n1)
Créé un intervalle d'itération [0,n1[.
Int32 Integer
Type représentant un entier.