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);
700 m_sub_arena_list[0] = m_sub_arena_list[1] =
nullptr;
702 m_sub_arena_list[i] =
new tbb::task_arena(i);
718 void operator()(tbb::blocked_range<Integer>&
range)
const
721 if (TaskFactory::verboseLevel()>=3){
722 std::ostringstream o;
723 o <<
"TBB: INDEX=" << TaskFactory::currentTaskThreadIndex()
724 <<
" id=" << std::this_thread::get_id()
725 <<
" max_allowed=" << m_nb_allowed_thread
726 <<
" range_begin=" <<
range.begin() <<
" range_size=" <<
range.size()
728 std::cout << o.str();
734 ARCANE_FATAL(
"Invalid index for thread idx={0} valid_interval=[0..{1}[",
739 m_stat_info->incrementNbChunk();
740 m_functor->executeFunctor(
range.begin(),CheckedConvert::toInteger(
range.size()));
746 Int32 m_nb_allowed_thread;
754template<
int RankValue>
764 void operator()(tbb::blocked_rangeNd<Int32,RankValue>&
range)
const
767 if (TaskFactory::verboseLevel()>=3){
768 std::ostringstream o;
769 o <<
"TBB: INDEX=" << TaskFactory::currentTaskThreadIndex()
770 <<
" id=" << std::this_thread::get_id()
771 <<
" max_allowed=" << m_nb_allowed_thread
774 Int32
r0 =
static_cast<Int32
>(
range.dim(i).begin());
775 Int32
r1 =
static_cast<Int32
>(
range.dim(i).size());
776 o <<
" range" << i <<
" (begin=" <<
r0 <<
" size=" <<
r1 <<
")";
779 std::cout << o.str();
785 ARCANE_FATAL(
"Invalid index for thread idx={0} valid_interval=[0..{1}[",
790 m_stat_info->incrementNbChunk();
798 Int32 m_nb_allowed_thread;
826 m_grain_size(
grain_size), m_nb_block(0), m_block_size(0), m_nb_block_per_thread(0)
832 m_block_size = m_grain_size;
834 m_nb_block = m_size / m_block_size;
835 if ((m_size % m_block_size)!=0)
840 m_nb_block_per_thread = m_nb_block / m_nb_thread;
841 if ((m_nb_block % m_nb_thread) != 0)
842 ++m_nb_block_per_thread;
846 m_nb_block = m_nb_thread;
847 m_block_size = m_size / m_nb_block;
848 m_nb_block_per_thread = 1;
850 if (TaskFactory::verboseLevel()>=2){
851 std::cout <<
"TBBDeterministicParallelFor: BEGIN=" << m_begin_index <<
" size=" << m_size
852 <<
" grain_size=" << m_grain_size
853 <<
" nb_block=" << m_nb_block <<
" nb_thread=" << m_nb_thread
854 <<
" nb_block_per_thread=" << m_nb_block_per_thread
855 <<
" block_size=" << m_block_size
856 <<
" block_size*nb_block=" << m_block_size*m_nb_block <<
'\n';
870 for( Integer i=0; i<
nb_iter; ++i ){
872 for ( Integer
k=0,
kn=m_nb_block_per_thread;
k<
kn; ++
k ){
890 iter_begin += m_begin_index;
892 if (TaskFactory::verboseLevel()>=3){
893 std::ostringstream o;
894 o <<
"TBB: DoBlock: BLOCK task_id=" << task_id <<
" block_id=" << block_id
895 <<
" iter_begin=" << iter_begin <<
" iter_size=" << iter_size <<
'\n';
896 std::cout << o.str();
901 auto r = tbb::blocked_range<int>(iter_begin,iter_begin + iter_size);
908 TBBTaskImplementation* m_impl;
909 const TBBParallelFor& m_tbb_for;
928 : m_impl(impl), m_begin(begin), m_size(size), m_functor(f), m_options(options), m_stat_info(
stat_info){}
932 void operator()()
const
934 Integer
nb_thread = m_options.maxThread();
936 Integer
gsize = m_options.grainSize();
937 tbb::blocked_range<Integer>
range(m_begin,m_begin+m_size);
938 if (TaskFactory::verboseLevel()>=1)
939 std::cout <<
"TBB: TBBTaskImplementationInit ParallelForExecute begin=" << m_begin
940 <<
" size=" << m_size <<
" gsize=" <<
gsize
941 <<
" partitioner=" << (
int)m_options.partitioner()
943 <<
" has_stat_info=" << (m_stat_info!=
nullptr)
947 range = tbb::blocked_range<Integer>(m_begin,m_begin+m_size,
gsize);
949 if (m_options.partitioner()==ParallelLoopOptions::Partitioner::Static){
950 tbb::parallel_for(
range,
pf,tbb::static_partitioner());
952 else if (m_options.partitioner()==ParallelLoopOptions::Partitioner::Deterministic){
972template<
int RankValue>
990 Int32
gsize = m_options.grainSize();
997 constexpr bool is_verbose =
false;
999 double ratio =
static_cast<double>(
gsize) /
static_cast<double>(
range.nbElement());
1000 if constexpr (is_verbose){
1008 for( ; index>=0; --index ){
1010 if constexpr (is_verbose)
1011 std::cout <<
"Check index=" << index <<
" remaining=" <<
remaining_grain <<
" current=" << current <<
"\n";
1021 for( Int32 i=0; i<index; ++i )
1023 if constexpr (is_verbose){
1034 void operator()()
const
1036 Integer
nb_thread = m_options.maxThread();
1039 if (m_options.partitioner()==ParallelLoopOptions::Partitioner::Static){
1040 tbb::parallel_for(m_tbb_range,
pf,tbb::static_partitioner());
1042 else if (m_options.partitioner()==ParallelLoopOptions::Partitioner::Deterministic){
1050 tbb::parallel_for(m_tbb_range,
pf);
1055 tbb::blocked_rangeNd<Int32,RankValue> m_tbb_range;
1064TBBTaskImplementation::
1065~TBBTaskImplementation()
1103 return m_p->nbAllowedThread();
1112#ifdef ARCANE_USE_ONETBB
1113 o <<
"OneTBBTaskImplementation"
1118 o <<
"TBBTaskImplementation"
1127void TBBTaskImplementation::
1145 std::cout <<
"TBB: TBBTaskImplementation executeParallelFor begin=" << begin
1146 <<
" size=" << size <<
" max_thread=" <<
max_thread
1147 <<
" grain_size=" << options.
grainSize()
1157 ParallelLoopOptions true_options(options);
1159 true_options.setMaxThread(max_thread);
1161 ParallelForExecute pfe(
this,true_options,begin,size,f,stat_info);
1163 tbb::task_arena* used_arena =
nullptr;
1164 if (max_thread<nb_allowed_thread && max_thread<m_p->m_sub_arena_list.size())
1167 used_arena = &(m_p->m_main_arena);
1168 used_arena->execute(pfe);
1174void TBBTaskImplementation::
1194 if (
run_info.options().has_value())
1195 options =
run_info.options().value();
1202 std::cout <<
"TBB: TBBTaskImplementation executeMDParallelFor nb_dim=" <<
RankValue
1204 <<
" grain_size=" << options.
grainSize()
1205 <<
" name=" <<
run_info.traceInfo().traceInfo()
1206 <<
" has_stat_info=" << (
stat_info!=
nullptr)
1233 auto x1 = [&](Integer begin,Integer size)
1253void TBBTaskImplementation::
1265void TBBTaskImplementation::
1266executeParallelFor(Integer begin,Integer size,
const ParallelLoopOptions& options,IRangeFunctor* f)
1268 executeParallelFor(ParallelFor1DLoopInfo(begin,size,f,ForLoopRunInfo(options)));
1290#ifdef ARCANE_USE_ONETBB
1306#ifdef ARCANE_USE_ONETBB
1324launchAndWait(ConstArrayView<ITask*> tasks)
1326 tbb::task_group task_group;
1327 Integer n = tasks.size();
1332 for( Integer i=0; i<n; ++i ){
1333 OneTBBTask* t =
static_cast<OneTBBTask*
>(tasks[i]);
1334 task_group.run(t->taskFunctor());
1337 for( Integer i=0; i<n; ++i ){
1338 OneTBBTask* t =
static_cast<OneTBBTask*
>(tasks[i]);
1347_createChildTask(ITaskFunctor* functor)
1349 OneTBBTask* t =
new OneTBBTask(functor);
1364 task::spawn_root_and_wait(*
this);
1373 Integer n =
tasks.size();
1378 for( Integer i=0; i<n-1; ++i ){
1388ITask* LegacyTBBTask::
1405 TBBTaskImplementation);
1407ARCANE_DI_REGISTER_PROVIDER(TBBTaskImplementation,
1408 DependencyInjection::ProviderProperty(
"TBBTaskImplementation"),
1409 ARCANE_DI_INTERFACES(ITaskImplementation),
1410 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.
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.
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.