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"
77#if (TBB_VERSION_MAJOR > 2022) || (TBB_VERSION_MAJOR == 2022 && TBB_VERSION_MINOR > 0) || defined __TBB_blocked_nd_range_H
81template <
typename Value,
unsigned int N>
82using blocked_nd_range = tbb::blocked_nd_range<Value, N>;
86template <
typename Value,
unsigned int N>
87using blocked_nd_range = tbb::blocked_rangeNd<Value, N>;
125 explicit ScopedExecInfo(
const ForLoopRunInfo& run_info)
126 : m_run_info(run_info)
132 ForLoopOneExecStat* ptr = run_info.execStat();
134 m_stat_info_ptr = ptr;
135 m_use_own_run_info =
false;
138 m_stat_info_ptr = isStatActive() ? &m_stat_info :
nullptr;
142#ifdef PRINT_STAT_INFO
143 if (m_stat_info_ptr){
144 bool is_valid = m_run_info.traceInfo().isValid();
146 std::cout <<
"ADD_OWN_RUN_INFO nb_chunk=" << m_stat_info_ptr->nbChunk()
150 std::cout <<
"ADD_OWN_RUN_INFO nb_chunk=" << m_stat_info_ptr->nbChunk()
151 <<
" trace_name=" << m_run_info.traceInfo().traceInfo().name() <<
"\n";
154 if (m_stat_info_ptr && m_use_own_run_info){
161 ForLoopOneExecStat* statInfo()
const {
return m_stat_info_ptr; }
162 bool isOwn()
const {
return m_use_own_run_info; }
165 ForLoopOneExecStat m_stat_info;
166 ForLoopOneExecStat* m_stat_info_ptr =
nullptr;
167 ForLoopRunInfo m_run_info;
169 bool m_use_own_run_info =
true;
175inline int _currentTaskTreadIndex()
181 return tbb::this_task_arena::current_thread_index();
184inline blocked_nd_range<Int32, 1>
187 return {{r.lowerBound<0>(), r.upperBound<0>()}};
190inline blocked_nd_range<Int32, 2>
193 return {{r.lowerBound<0>(), r.upperBound<0>()},
194 {r.lowerBound<1>(), r.upperBound<1>()}};
198inline blocked_nd_range<Int32, 3>
201 return {{r.lowerBound<0>(), r.upperBound<0>()},
202 {r.lowerBound<1>(), r.upperBound<1>()},
203 {r.lowerBound<2>(), r.upperBound<2>()}};
206inline blocked_nd_range<Int32, 4>
209 return {{r.lowerBound<0>(), r.upperBound<0>()},
210 {r.lowerBound<1>(), r.upperBound<1>()},
211 {r.lowerBound<2>(), r.upperBound<2>()},
212 {r.lowerBound<3>(), r.upperBound<3>()}};
218inline blocked_nd_range<Int32, 2>
221 return {{r.dim(0).begin(), r.dim(0).end(), grain_sizes[0]},
222 {r.dim(1).begin(), r.dim(1).end(), grain_sizes[1]}};
225inline blocked_nd_range<Int32, 3>
228 return {{r.dim(0).begin(), r.dim(0).end(), grain_sizes[0]},
229 {r.dim(1).begin(), r.dim(1).end(), grain_sizes[1]},
230 {r.dim(2).begin(), r.dim(2).end(), grain_sizes[2]}};
233inline blocked_nd_range<Int32, 4>
236 return {{r.dim(0).begin(), r.dim(0).end(), grain_sizes[0]},
237 {r.dim(1).begin(), r.dim(1).end(), grain_sizes[1]},
238 {r.dim(2).begin(), r.dim(2).end(), grain_sizes[2]},
239 {r.dim(3).begin(), r.dim(3).end(), grain_sizes[3]}};
246_fromTBBRange(
const blocked_nd_range<Int32, 2>& r)
249 using ArrayExtentType =
typename BoundsType::ArrayExtentType;
251 BoundsType lower_bounds(ArrayExtentType(r.dim(0).begin(),r.dim(1).begin()));
252 auto s0 =
static_cast<Int32>(r.dim(0).size());
253 auto s1 =
static_cast<Int32>(r.dim(1).size());
254 BoundsType sizes(ArrayExtentType(s0,s1));
255 return { lower_bounds, sizes };
259_fromTBBRange(
const blocked_nd_range<Int32, 3>& r)
262 using ArrayExtentType =
typename BoundsType::ArrayExtentType;
264 BoundsType lower_bounds(ArrayExtentType(r.dim(0).begin(),r.dim(1).begin(),r.dim(2).begin()));
265 auto s0 =
static_cast<Int32>(r.dim(0).size());
266 auto s1 =
static_cast<Int32>(r.dim(1).size());
267 auto s2 =
static_cast<Int32>(r.dim(2).size());
268 BoundsType sizes(ArrayExtentType(s0,s1,s2));
269 return { lower_bounds, sizes };
273_fromTBBRange(
const blocked_nd_range<Int32, 4>& r)
276 using ArrayExtentType =
typename BoundsType::ArrayExtentType;
278 BoundsType lower_bounds(ArrayExtentType(r.dim(0).begin(),r.dim(1).begin(),r.dim(2).begin(),r.dim(3).begin()));
279 auto s0 =
static_cast<Int32>(r.dim(0).size());
280 auto s1 =
static_cast<Int32>(r.dim(1).size());
281 auto s2 =
static_cast<Int32>(r.dim(2).size());
282 auto s3 =
static_cast<Int32>(r.dim(3).size());
283 BoundsType sizes(ArrayExtentType(s0,s1,s2,s3));
284 return { lower_bounds, sizes };
292#ifdef ARCANE_USE_ONETBB
297class OneTBBTaskFunctor
300 OneTBBTaskFunctor(ITaskFunctor* functor,ITask* task)
301 : m_functor(functor), m_task(task) {}
303 void operator()()
const
306 ITaskFunctor* tf = m_functor;
308 TaskContext task_context(m_task);
310 tf->executeFunctor(task_context);
314 mutable ITaskFunctor* m_functor;
325 static const int FUNCTOR_CLASS_SIZE = 32;
327 OneTBBTask(ITaskFunctor* f)
330 m_functor = f->clone(functor_buf,FUNCTOR_CLASS_SIZE);
333 OneTBBTaskFunctor taskFunctor() {
return OneTBBTaskFunctor(m_functor,
this); }
334 void launchAndWait()
override;
335 void launchAndWait(ConstArrayView<ITask*> tasks)
override;
337 virtual ITask* _createChildTask(ITaskFunctor* functor)
override;
339 ITaskFunctor* m_functor;
340 char functor_buf[FUNCTOR_CLASS_SIZE];
342using TBBTask = OneTBBTask;
357 static const int FUNCTOR_CLASS_SIZE = 32;
362 m_functor = f->clone(functor_buf,FUNCTOR_CLASS_SIZE);
365 tbb::task* execute()
override
382 char functor_buf[FUNCTOR_CLASS_SIZE];
398class TBBTaskImplementation
403 template<
int RankValue>
412 TaskThreadInfo() : m_task_index(-1){}
414 void setTaskIndex(
Integer v) { m_task_index = v; }
415 Integer taskIndex()
const {
return m_task_index; }
426 class TaskInfoLockGuard
430 : m_tti(tti), m_old_task_index(-1)
433 m_old_task_index = tti->taskIndex();
434 tti->setTaskIndex(task_index);
440 m_tti->setTaskIndex(m_old_task_index);
460#ifdef ARCANE_USE_ONETBB
461 OneTBBTask* t =
new OneTBBTask(f);
529 bool m_is_active = false;
534 template<
int RankValue>
void
544class TBBTaskImplementation::Impl
547 :
public tbb::task_scheduler_observer
552#ifdef ARCANE_USE_ONETBB
553 tbb::task_scheduler_observer(p->m_main_arena),
558 void on_scheduler_entry(
bool is_worker)
override
560 m_p->notifyThreadCreated(is_worker);
562 void on_scheduler_exit(
bool is_worker)
override
564 m_p->notifyThreadDestroyed(is_worker);
571 m_task_observer(this),
574#ifdef ARCANE_USE_ONETBB
575 m_nb_allowed_thread = tbb::info::default_concurrency();
577 m_nb_allowed_thread = tbb::task_scheduler_init::default_num_threads();
583#ifndef ARCANE_USE_ONETBB
584 m_scheduler_init(nb_thread),
586 m_main_arena(nb_thread),
587 m_task_observer(this),
590 m_nb_allowed_thread = nb_thread;
595 TaskThreadInfo* threadTaskInfo(
Integer index) {
return &m_thread_task_infos[index]; }
597 Int32 m_nb_allowed_thread;
602 for(
auto x : m_sub_arena_list ){
607 m_sub_arena_list.clear();
608 m_main_arena.terminate();
609#ifdef ARCANE_USE_ONETBB
610 m_task_observer.observe(
false);
611 oneapi::tbb::finalize(m_task_scheduler_handle);
613 m_scheduler_init.terminate();
614 m_task_observer.observe(
false);
618 void notifyThreadCreated(
bool is_worker)
620 std::thread::id my_thread_id = std::this_thread::get_id();
622#ifdef ARCANE_USE_ONETBB
629 if (m_constructed_thread_map.contains(my_thread_id))
631 m_constructed_thread_map.insert(my_thread_id);
636 std::ostringstream ostr;
637 ostr <<
"TBB: CREATE THREAD"
638 <<
" nb_allowed=" << m_nb_allowed_thread
639#ifdef ARCANE_USE_ONETBB
640 <<
" tbb_default_allowed=" << tbb::info::default_concurrency()
642 <<
" tbb_default_allowed=" << tbb::task_scheduler_init::default_num_threads()
644 <<
" id=" << my_thread_id
645 <<
" arena_id=" << _currentTaskTreadIndex()
646 <<
" is_worker=" << is_worker
648 std::cout << ostr.str();
654 void notifyThreadDestroyed([[maybe_unused]]
bool is_worker)
656#ifdef ARCANE_USE_ONETBB
666 std::scoped_lock sl(m_thread_created_mutex);
668 std::cout <<
"TBB: DESTROY THREAD"
669 <<
" id=" << std::this_thread::get_id()
670 <<
" arena_id=" << _currentTaskTreadIndex()
671 <<
" is_worker=" << is_worker
679#ifdef ARCANE_USE_ONETBB
680#if TBB_VERSION_MAJOR>2021 || (TBB_VERSION_MAJOR==2021 && TBB_VERSION_MINOR>5)
681 oneapi::tbb::task_scheduler_handle m_task_scheduler_handle = oneapi::tbb::attach();
683 oneapi::tbb::task_scheduler_handle m_task_scheduler_handle = tbb::task_scheduler_handle::get();
686 tbb::task_scheduler_init m_scheduler_init;
689 tbb::task_arena m_main_arena;
694 std::mutex m_thread_created_mutex;
696#ifdef ARCANE_USE_ONETBB
697 tbb::concurrent_set<std::thread::id> m_constructed_thread_map;
702 std::cout <<
"TBB: TBBTaskImplementationInit nb_allowed_thread=" << m_nb_allowed_thread
703 <<
" id=" << std::this_thread::get_id()
704 <<
" version=" << TBB_VERSION_MAJOR <<
"." << TBB_VERSION_MINOR
707 m_thread_task_infos.
resize(m_nb_allowed_thread);
708 m_task_observer.observe(
true);
709 Integer max_arena_size = m_nb_allowed_thread;
712 if (max_arena_size>512)
713 max_arena_size = 512;
714 if (max_arena_size<2)
718 for(
Integer i=2; i<max_arena_size; ++i )
732 : m_functor(f), m_stat_info(stat_info), m_nb_allowed_thread(nb_allowed_thread){}
735 void operator()(tbb::blocked_range<Integer>& range)
const
739 std::ostringstream o;
741 <<
" id=" << std::this_thread::get_id()
742 <<
" max_allowed=" << m_nb_allowed_thread
743 <<
" range_begin=" << range.begin() <<
" range_size=" << range.size()
745 std::cout << o.str();
749 int tbb_index = _currentTaskTreadIndex();
750 if (tbb_index<0 || tbb_index>=m_nb_allowed_thread)
751 ARCANE_FATAL(
"Invalid index for thread idx={0} valid_interval=[0..{1}[",
752 tbb_index,m_nb_allowed_thread);
756 m_stat_info->incrementNbChunk();
763 Int32 m_nb_allowed_thread;
771template<
int RankValue>
772class TBBMDParallelFor
777 : m_functor(f), m_stat_info(stat_info), m_nb_allowed_thread(nb_allowed_thread){}
781 void operator()(blocked_nd_range<Int32, RankValue>& range)
const
785 std::ostringstream o;
787 <<
" id=" << std::this_thread::get_id()
788 <<
" max_allowed=" << m_nb_allowed_thread
790 for(
Int32 i=0; i<RankValue; ++i ){
791 Int32 r0 =
static_cast<Int32>(range.dim(i).begin());
792 Int32 r1 =
static_cast<Int32>(range.dim(i).size());
793 o <<
" range" << i <<
" (begin=" << r0 <<
" size=" << r1 <<
")";
796 std::cout << o.str();
800 int tbb_index = _currentTaskTreadIndex();
801 if (tbb_index<0 || tbb_index>=m_nb_allowed_thread)
802 ARCANE_FATAL(
"Invalid index for thread idx={0} valid_interval=[0..{1}[",
803 tbb_index,m_nb_allowed_thread);
807 m_stat_info->incrementNbChunk();
808 m_functor->executeFunctor(_fromTBBRange(range));
815 Int32 m_nb_allowed_thread;
837class TBBDeterministicParallelFor
842 : m_impl(impl), m_tbb_for(tbb_for), m_nb_thread(nb_thread), m_begin_index(begin_index), m_size(size),
843 m_grain_size(grain_size), m_nb_block(0), m_block_size(0), m_nb_block_per_thread(0)
849 m_block_size = m_grain_size;
851 m_nb_block = m_size / m_block_size;
852 if ((m_size % m_block_size)!=0)
857 m_nb_block_per_thread = m_nb_block / m_nb_thread;
858 if ((m_nb_block % m_nb_thread) != 0)
859 ++m_nb_block_per_thread;
863 m_nb_block = m_nb_thread;
864 m_block_size = m_size / m_nb_block;
865 m_nb_block_per_thread = 1;
868 std::cout <<
"TBBDeterministicParallelFor: BEGIN=" << m_begin_index <<
" size=" << m_size
869 <<
" grain_size=" << m_grain_size
870 <<
" nb_block=" << m_nb_block <<
" nb_thread=" << m_nb_thread
871 <<
" nb_block_per_thread=" << m_nb_block_per_thread
872 <<
" block_size=" << m_block_size
873 <<
" block_size*nb_block=" << m_block_size*m_nb_block <<
'\n';
887 for(
Integer i=0; i<nb_iter; ++i ){
888 Integer task_id = range.begin() + i;
889 for (
Integer k=0, kn=m_nb_block_per_thread; k<kn; ++k ){
890 Integer block_id = task_id + (k * m_nb_thread);
891 if (block_id<m_nb_block)
892 _doBlock(task_id,block_id);
901 Integer iter_begin = block_id * m_block_size;
902 Integer iter_size = m_block_size;
903 if ((block_id+1)==m_nb_block){
905 iter_size = m_size - iter_begin;
907 iter_begin += m_begin_index;
909 if (TaskFactory::verboseLevel()>=3){
910 std::ostringstream o;
911 o <<
"TBB: DoBlock: BLOCK task_id=" << task_id <<
" block_id=" << block_id
912 <<
" iter_begin=" << iter_begin <<
" iter_size=" << iter_size <<
'\n';
913 std::cout << o.str();
918 auto r = tbb::blocked_range<int>(iter_begin,iter_begin + iter_size);
925 TBBTaskImplementation* m_impl;
926 const TBBParallelFor& m_tbb_for;
945 : m_impl(impl), m_begin(begin), m_size(size), m_functor(f), m_options(options), m_stat_info(stat_info){}
949 void operator()()
const
951 Integer nb_thread = m_options.maxThread();
953 Integer gsize = m_options.grainSize();
954 tbb::blocked_range<Integer> range(m_begin,m_begin+m_size);
956 std::cout <<
"TBB: TBBTaskImplementationInit ParallelForExecute begin=" << m_begin
957 <<
" size=" << m_size <<
" gsize=" << gsize
958 <<
" partitioner=" << (int)m_options.partitioner()
959 <<
" nb_thread=" << nb_thread
960 <<
" has_stat_info=" << (m_stat_info!=
nullptr)
964 range = tbb::blocked_range<Integer>(m_begin,m_begin+m_size,gsize);
967 tbb::parallel_for(range,pf,tbb::static_partitioner());
970 tbb::blocked_range<Integer> range2(0,nb_thread,1);
972 tbb::parallel_for(range2,dpf);
975 tbb::parallel_for(range,pf);
978 TBBTaskImplementation* m_impl =
nullptr;
989template<
int RankValue>
994 MDParallelForExecute(TBBTaskImplementation* impl,
999 , m_tbb_range(_toTBBRange(range))
1001 , m_options(options)
1002 , m_stat_info(stat_info)
1007 Int32 gsize = m_options.grainSize();
1014 constexpr bool is_verbose =
false;
1015 std::array<Int32,RankValue> range_extents = range.extents().asStdArray();
1016 double ratio =
static_cast<double>(gsize) /
static_cast<double>(range.nbElement());
1017 if constexpr (is_verbose){
1018 std::cout <<
"GSIZE=" << gsize <<
" rank=" << RankValue <<
" ratio=" << ratio;
1019 for(
Int32 i=0; i<RankValue; ++i )
1020 std::cout <<
" range" << i <<
"=" << range_extents[i];
1023 Int32 index = RankValue - 1;
1024 Int32 remaining_grain = gsize;
1025 for( ; index>=0; --index ){
1026 Int32 current = range_extents[index];
1027 if constexpr (is_verbose)
1028 std::cout <<
"Check index=" << index <<
" remaining=" << remaining_grain <<
" current=" << current <<
"\n";
1029 if (remaining_grain>current){
1030 all_grain_sizes[index] = current;
1031 remaining_grain /= current;
1034 all_grain_sizes[index] = remaining_grain;
1038 for(
Int32 i=0; i<index; ++i )
1039 all_grain_sizes[i] = 1;
1040 if constexpr (is_verbose){
1041 for(
Int32 i=0; i<RankValue; ++i )
1042 std::cout <<
" grain" << i <<
"=" << all_grain_sizes[i];
1045 m_tbb_range = _toTBBRangeWithGrain(m_tbb_range,all_grain_sizes);
1051 void operator()()
const
1053 Integer nb_thread = m_options.maxThread();
1057 tbb::parallel_for(m_tbb_range,pf,tbb::static_partitioner());
1067 tbb::parallel_for(m_tbb_range,pf);
1071 TBBTaskImplementation* m_impl =
nullptr;
1072 blocked_nd_range<Int32, RankValue> m_tbb_range;
1081TBBTaskImplementation::
1082~TBBTaskImplementation()
1095 m_is_active = (nb_thread!=1);
1097 m_p =
new Impl(nb_thread);
1120 return m_p->nbAllowedThread();
1129#ifdef ARCANE_USE_ONETBB
1130 o <<
"OneTBBTaskImplementation"
1131 <<
" version=" << TBB_VERSION_STRING
1132 <<
" interface=" << TBB_INTERFACE_VERSION
1133 <<
" runtime_interface=" << TBB_runtime_interface_version();
1135 o <<
"TBBTaskImplementation"
1136 <<
" version=" << TBB_VERSION_MAJOR <<
"." << TBB_VERSION_MINOR
1137 <<
" interface=" << TBB_INTERFACE_VERSION;
1144void TBBTaskImplementation::
1147 ScopedExecInfo sei(loop_info.runInfo());
1151 Int32 begin = loop_info.beginIndex();
1152 Int32 size = loop_info.size();
1157 Integer nb_allowed_thread = m_p->nbAllowedThread();
1159 max_thread = nb_allowed_thread;
1162 std::cout <<
"TBB: TBBTaskImplementation executeParallelFor begin=" << begin
1163 <<
" size=" << size <<
" max_thread=" << max_thread
1164 <<
" grain_size=" << options.
grainSize()
1165 <<
" nb_allowed=" << nb_allowed_thread <<
'\n';
1168 if (max_thread==1 || max_thread==0){
1174 ParallelLoopOptions true_options(options);
1176 true_options.setMaxThread(max_thread);
1178 ParallelForExecute pfe(
this,true_options,begin,size,f,stat_info);
1180 tbb::task_arena* used_arena =
nullptr;
1181 if (max_thread<nb_allowed_thread && max_thread<m_p->m_sub_arena_list.size())
1184 used_arena = &(m_p->m_main_arena);
1185 used_arena->execute(pfe);
1194 _executeParallelFor(loop_info);
1211 if (run_info.options().has_value())
1212 options = run_info.options().value();
1214 ScopedExecInfo sei(run_info);
1219 std::cout <<
"TBB: TBBTaskImplementation executeMDParallelFor nb_dim=" << RankValue
1220 <<
" nb_element=" << loop_ranges.nbElement()
1221 <<
" grain_size=" << options.
grainSize()
1222 <<
" name=" << run_info.traceInfo().traceInfo()
1223 <<
" has_stat_info=" << (stat_info!=
nullptr)
1229 if (max_thread==1 || max_thread==0){
1230 functor->executeFunctor(loop_ranges);
1238 Integer nb_allowed_thread = m_p->nbAllowedThread();
1240 max_thread = nb_allowed_thread;
1241 tbb::task_arena* used_arena =
nullptr;
1242 if (max_thread<nb_allowed_thread)
1243 used_arena = m_p->m_sub_arena_list[max_thread];
1245 used_arena = &(m_p->m_main_arena);
1248 if constexpr (RankValue==1){
1249 auto range_1d = _toTBBRange(loop_ranges);
1259 used_arena->execute(pfe);
1263 used_arena->execute(pfe);
1296 return m_p->threadTaskInfo(thread_id);
1307#ifdef ARCANE_USE_ONETBB
1308 if (thread_id<0 || thread_id>=m_p->nbAllowedThread())
1313 Int32 task_index = tti->taskIndex();
1323#ifdef ARCANE_USE_ONETBB
1331 tbb::task_group task_group;
1332 task_group.run(taskFunctor());
1341launchAndWait(ConstArrayView<ITask*> tasks)
1343 tbb::task_group task_group;
1350 OneTBBTask* t =
static_cast<OneTBBTask*
>(tasks[i]);
1351 task_group.run(t->taskFunctor());
1355 OneTBBTask* t =
static_cast<OneTBBTask*
>(tasks[i]);
1364_createChildTask(ITaskFunctor* functor)
1366 OneTBBTask* t =
new OneTBBTask(functor);
1381 task::spawn_root_and_wait(*
this);
1395 for(
Integer i=0; i<n-1; ++i ){
1396 TBBTask* t =
static_cast<TBBTask*
>(tasks[i]);
1399 spawn_and_wait_for_all(*
static_cast<TBBTask*
>(tasks[n-1]));
1405ITask* LegacyTBBTask::
1408 TBBTask* t =
new(allocate_child()) TBBTask(functor);
1422 TBBTaskImplementation);
1424ARCANE_DI_REGISTER_PROVIDER(TBBTaskImplementation,
1425 DependencyInjection::ProviderProperty(
"TBBTaskImplementation"),
1426 ARCANE_DI_INTERFACES(ITaskImplementation),
1427 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.
Allocateur mémoire avec alignement mémoire spécifique.
void resize(Int64 s)
Change le nombre d'éléments du tableau à s.
Interval d'itération complexe.
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.
virtual void notifyAllObservers()=0
Notifie tous les observateurs.
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.
virtual void executeFunctor(const TaskContext &tc)=0
Exécute la méthode associé
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.
Exception lorsqu'une fonction n'est pas implémentée.
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.
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.
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.
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.
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).
Classe permettant de récupérer le temps passé entre l'appel au constructeur et au destructeur.
Integer toInteger(Real r)
Converti un Int64 en un Integer.
-*- 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.