Arcane  v3.15.0.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
ConcurrencyUtils.h
Aller à la documentation de ce fichier.
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* ConcurrencyUtils.h (C) 2000-2025 */
9/* */
10/* Classes gérant la concurrence (tâches, boucles parallèles, ...) */
11/*---------------------------------------------------------------------------*/
12#ifndef ARCANE_UTILS_CONCURRENCYUTILS_H
13#define ARCANE_UTILS_CONCURRENCYUTILS_H
14/*---------------------------------------------------------------------------*/
15/*---------------------------------------------------------------------------*/
16
18#include "arcane/utils/RangeFunctor.h"
19#include "arcane/utils/FatalErrorException.h"
20#include "arcane/utils/ForLoopTraceInfo.h"
21#include "arcane/utils/ParallelLoopOptions.h"
22
23#include <optional>
24
25/*---------------------------------------------------------------------------*/
26/*---------------------------------------------------------------------------*/
27
28namespace Arcane
29{
30
31/*---------------------------------------------------------------------------*/
32/*---------------------------------------------------------------------------*/
33
34class TaskFactoryInternal;
35
36/*---------------------------------------------------------------------------*/
37/*---------------------------------------------------------------------------*/
38/*
39 * TODO:
40 * - Vérifier les fuites memoires
41 * - BIEN INDIQUER QU'IL NE FAUT PLUS UTILISER UNE TACHE APRES LE WAIT!!!
42 * - Regarder mecanisme pour les exceptions.
43 * - Surcharger les For et Foreach sans specifier le block_size
44 */
45
46
47/*---------------------------------------------------------------------------*/
48/*---------------------------------------------------------------------------*/
55class ARCANE_UTILS_EXPORT ForLoopRunInfo
56{
57 public:
58
60
61 public:
62
63 ForLoopRunInfo() = default;
64 explicit ForLoopRunInfo(const ParallelLoopOptions& options)
65 : m_options(options) {}
67 : m_options(options), m_trace_info(trace_info) {}
69 : m_trace_info(trace_info) {}
70
71 public:
72
73 std::optional<ParallelLoopOptions> options() const { return m_options; }
74 ThatClass& addOptions(const ParallelLoopOptions& v) { m_options = v; return (*this); }
75 const ForLoopTraceInfo& traceInfo() const { return m_trace_info; }
76 ThatClass& addTraceInfo(const ForLoopTraceInfo& v) { m_trace_info = v; return (*this); }
77
83 void setExecStat(ForLoopOneExecStat* v) { m_exec_stat = v; }
84
86 ForLoopOneExecStat* execStat() const { return m_exec_stat; }
87
88 protected:
89
90 std::optional<ParallelLoopOptions> m_options;
91 ForLoopTraceInfo m_trace_info;
92 ForLoopOneExecStat* m_exec_stat = nullptr;
93};
94
95/*---------------------------------------------------------------------------*/
96/*---------------------------------------------------------------------------*/
101class ARCANE_UTILS_EXPORT TaskContext
102{
103 public:
104 explicit TaskContext(ITask* atask) : m_task(atask) {}
105 public:
107 ITask* task() const { return m_task; }
108 private:
109 ITask* m_task;
110};
111
112/*---------------------------------------------------------------------------*/
113/*---------------------------------------------------------------------------*/
119class ARCANE_UTILS_EXPORT ITaskFunctor
120{
121 public:
122 virtual ~ITaskFunctor() = default;
123 protected:
124 ITaskFunctor(const ITaskFunctor&) = default;
125 ITaskFunctor() = default;
126 public:
128 virtual void executeFunctor(const TaskContext& tc) =0;
129 virtual ITaskFunctor* clone(void* buffer,Integer size) =0;
130};
131
132/*---------------------------------------------------------------------------*/
133/*---------------------------------------------------------------------------*/
139template<typename InstanceType>
141: public ITaskFunctor
142{
143 public:
144 typedef void (InstanceType::*FunctorType)();
145 public:
146 TaskFunctor(InstanceType* instance,FunctorType func)
147 : m_instance(instance), m_function(func)
148 {
149 }
150 TaskFunctor(const TaskFunctor& rhs) = default;
151 TaskFunctor& operator=(const TaskFunctor& rhs) = delete;
152 public:
154 void executeFunctor(const TaskContext& /*tc*/) override
155 {
156 (m_instance->*m_function)();
157 }
158 ITaskFunctor* clone(void* buffer,Integer size) override
159 {
160 if (sizeof(*this)>(size_t)size)
161 ARCANE_FATAL("INTERNAL: task functor buffer is too small");
162 return new (buffer) TaskFunctor<InstanceType>(*this);
163 }
164 private:
165 InstanceType* m_instance;
166 FunctorType m_function;
167};
168
169/*---------------------------------------------------------------------------*/
170/*---------------------------------------------------------------------------*/
176template<typename InstanceType>
178: public ITaskFunctor
179{
180 public:
181 typedef void (InstanceType::*FunctorType)(const TaskContext& tc);
182 public:
183 TaskFunctorWithContext(InstanceType* instance,FunctorType func)
184 : ITaskFunctor(), m_instance(instance), m_function(func)
185 {
186 }
187 public:
189 void executeFunctor(const TaskContext& tc) override
190 {
191 (m_instance->*m_function)(tc);
192 }
193 ITaskFunctor* clone(void* buffer,Integer size) override
194 {
195 if (sizeof(*this)>(size_t)size)
196 ARCANE_FATAL("INTERNAL: task functor buffer is too small");
197 return new (buffer) TaskFunctorWithContext<InstanceType>(*this);
198 }
199 private:
200 InstanceType* m_instance;
201 FunctorType m_function;
202};
203
204/*---------------------------------------------------------------------------*/
205/*---------------------------------------------------------------------------*/
212class ARCANE_UTILS_EXPORT ITask
213{
214 friend class TaskFactory;
215
216 public:
217
218 virtual ~ITask(){}
219
220 public:
227 virtual void launchAndWait() =0;
233
234 protected:
235
236 virtual ITask* _createChildTask(ITaskFunctor* functor) =0;
237};
238
239/*---------------------------------------------------------------------------*/
240/*---------------------------------------------------------------------------*/
250class ARCANE_UTILS_EXPORT ITaskImplementation
251{
252 public:
253 virtual ~ITaskImplementation(){}
254 public:
263 virtual void initialize(Int32 nb_thread) =0;
269 virtual void terminate() =0;
276
278 virtual void executeParallelFor(Integer begin,Integer size,const ParallelLoopOptions& options,IRangeFunctor* f) =0;
279
281 virtual void executeParallelFor(Integer begin,Integer size,Integer block_size,IRangeFunctor* f) =0;
282
284 virtual void executeParallelFor(Integer begin,Integer size,IRangeFunctor* f) =0;
285
288
292 IMDRangeFunctor<1>* functor) =0;
296 IMDRangeFunctor<2>* functor) =0;
300 IMDRangeFunctor<3>* functor) =0;
304 IMDRangeFunctor<4>* functor) =0;
305
307 virtual bool isActive() const =0;
308
310 virtual Int32 nbAllowedThread() const =0;
311
313 virtual Int32 currentTaskThreadIndex() const =0;
314
316 virtual Int32 currentTaskIndex() const =0;
317
319 virtual void printInfos(std::ostream& o) const =0;
320};
321
322/*---------------------------------------------------------------------------*/
323/*---------------------------------------------------------------------------*/
328class ARCANE_UTILS_EXPORT TaskFactory
329{
330 friend TaskFactoryInternal;
331
332 public:
333
334 TaskFactory() = delete;
335
336 public:
337
343 template<typename InstanceType> static ITask*
344 createTask(InstanceType* instance,void (InstanceType::*function)(const TaskContext& tc))
345 {
346 TaskFunctorWithContext<InstanceType> functor(instance,function);
347 return m_impl->createRootTask(&functor);
348 }
349
355 template<typename InstanceType> static ITask*
356 createTask(InstanceType* instance,void (InstanceType::*function)())
357 {
358 TaskFunctor<InstanceType> functor(instance,function);
359 return m_impl->createRootTask(&functor);
360 }
361
368 template<typename InstanceType> static ITask*
369 createChildTask(ITask* parent_task,InstanceType* instance,void (InstanceType::*function)(const TaskContext& tc))
370 {
372 TaskFunctorWithContext<InstanceType> functor(instance,function);
373 return parent_task->_createChildTask(&functor);
374 }
375
382 template<typename InstanceType> static ITask*
383 createChildTask(ITask* parent_task,InstanceType* instance,void (InstanceType::*function)())
384 {
386 TaskFunctor<InstanceType> functor(instance,function);
387 return parent_task->_createChildTask(&functor);
388 }
389
391 static void executeParallelFor(Integer begin,Integer size,const ParallelLoopOptions& options,IRangeFunctor* f)
392 {
393 m_impl->executeParallelFor(begin,size,options,f);
394 }
395
397 static void executeParallelFor(Integer begin,Integer size,Integer block_size,IRangeFunctor* f)
398 {
399 m_impl->executeParallelFor(begin,size,block_size,f);
400 }
401
403 static void executeParallelFor(Integer begin,Integer size,IRangeFunctor* f)
404 {
405 m_impl->executeParallelFor(begin,size,f);
406 }
407
410 {
411 m_impl->executeParallelFor(loop_info);
412 }
413
416 const ParallelLoopOptions& options,
417 IMDRangeFunctor<1>* functor)
418 {
419 m_impl->executeParallelFor(loop_ranges,ForLoopRunInfo(options),functor);
420 }
421
425 IMDRangeFunctor<1>* functor)
426 {
427 m_impl->executeParallelFor(loop_ranges,run_info,functor);
428 }
429
432 const ParallelLoopOptions& options,
433 IMDRangeFunctor<2>* functor)
434 {
435 m_impl->executeParallelFor(loop_ranges,ForLoopRunInfo(options),functor);
436 }
437
441 IMDRangeFunctor<2>* functor)
442 {
443 m_impl->executeParallelFor(loop_ranges,run_info,functor);
444 }
445
448 const ParallelLoopOptions& options,
449 IMDRangeFunctor<3>* functor)
450 {
451 m_impl->executeParallelFor(loop_ranges,ForLoopRunInfo(options),functor);
452 }
453
457 IMDRangeFunctor<3>* functor)
458 {
459 m_impl->executeParallelFor(loop_ranges,run_info,functor);
460 }
461
464 const ParallelLoopOptions& options,
465 IMDRangeFunctor<4>* functor)
466 {
467 m_impl->executeParallelFor(loop_ranges,ForLoopRunInfo(options),functor);
468 }
469
473 IMDRangeFunctor<4>* functor)
474 {
475 m_impl->executeParallelFor(loop_ranges,run_info,functor);
476 }
477
479 static Int32 nbAllowedThread()
480 {
481 return m_impl->nbAllowedThread();
482 }
483
492 {
493 return m_impl->currentTaskThreadIndex();
494 }
495
509 static Int32 currentTaskIndex()
510 {
511 return m_impl->currentTaskIndex();
512 }
513
514 public:
515
518 {
519 m_default_loop_options = v;
520 }
521
524 {
525 return m_default_loop_options;
526 }
527
528 public:
529
535 static bool isActive()
536 {
537 return m_impl->isActive();
538 }
539
546 static void printInfos(std::ostream& o)
547 {
548 return m_impl->printInfos(o);
549 }
550
559 ARCANE_DEPRECATED_REASON("Y2024: This method is internal to Arcane. Do not use it")
560 static IObservable* createThreadObservable();
561
570 ARCANE_DEPRECATED_REASON("Y2024: This method is internal to Arcane. Do not use it")
571 static IObservable* destroyThreadObservable();
572
578 static void terminate();
579
580 public:
581
583 static void setVerboseLevel(Integer v) { m_verbose_level = v; }
584
586 static Integer verboseLevel() { return m_verbose_level; }
587
588 public:
589
591 ARCANE_DEPRECATED_REASON("Y2024: This method is internal to Arcane. "
592 "Use TaskFactoryInternal::setImplementation() instead")
594
595 private:
596
598 static Int32 m_verbose_level;
599 static ParallelLoopOptions m_default_loop_options;
600};
601
602/*---------------------------------------------------------------------------*/
603/*---------------------------------------------------------------------------*/
610class ARCANE_UTILS_EXPORT ParallelFor1DLoopInfo
611{
612 public:
613
615
616 public:
617
618 ParallelFor1DLoopInfo(Int32 begin,Int32 size,IRangeFunctor* functor)
619 : m_begin(begin), m_size(size), m_functor(functor) {}
620 ParallelFor1DLoopInfo(Int32 begin,Int32 size,IRangeFunctor* functor,const ForLoopRunInfo& run_info)
621 : m_run_info(run_info), m_begin(begin), m_size(size), m_functor(functor) {}
622 ParallelFor1DLoopInfo(Int32 begin,Int32 size, Int32 block_size,IRangeFunctor* functor)
623 : m_begin(begin), m_size(size), m_functor(functor)
624 {
625 ParallelLoopOptions opts(TaskFactory::defaultParallelLoopOptions());
626 opts.setGrainSize(block_size);
627 m_run_info.addOptions(opts);
628 }
629
630 public:
631
632 Int32 beginIndex() const { return m_begin; }
633 Int32 size() const { return m_size; }
634 IRangeFunctor* functor() const { return m_functor; }
635 ForLoopRunInfo& runInfo() { return m_run_info; }
636 const ForLoopRunInfo& runInfo() const { return m_run_info; }
637
638 private:
639
640 ForLoopRunInfo m_run_info;
641 Int32 m_begin = 0;
642 Int32 m_size = 0;
643 IRangeFunctor* m_functor = nullptr;
644};
645
646/*---------------------------------------------------------------------------*/
647/*---------------------------------------------------------------------------*/
652template<int RankValue,typename LambdaType,typename... ReducerArgs> inline void
656 const ReducerArgs&... reducer_args)
657{
658 // Modif Arcane 3.7.9 (septembre 2022)
659 // Effectue une copie pour privatiser au thread courant les valeurs de la lambda.
660 // Cela est nécessaire pour que objets comme les reducers soient bien pris
661 // en compte.
662 // TODO: regarder si on pourrait faire la copie uniquement une fois par thread
663 // si cette copie devient couteuse.
664 // NOTE: A partir de la version 3.12.15 (avril 2024), avec la nouvelle version
665 // des réducteurs (Reduce2), cette privatisation n'est plus utile. Une fois
666 // qu'on aura supprimer les anciennes classes gérant les réductions (Reduce),
667 // on pourra supprimer cette privatisation
669 {
670 using Type = typename std::remove_reference<LambdaType>::type;
673 };
675 TaskFactory::executeParallelFor(loop_ranges,run_info,&ipf);
676}
677
678/*---------------------------------------------------------------------------*/
679/*---------------------------------------------------------------------------*/
684template<int RankValue,typename LambdaType,typename... ReducerArgs> inline void
692
693/*---------------------------------------------------------------------------*/
694/*---------------------------------------------------------------------------*/
699template <int RankValue, typename LambdaType, typename... ReducerArgs> inline void
708
709/*---------------------------------------------------------------------------*/
710/*---------------------------------------------------------------------------*/
715template <int RankValue, typename LambdaType, typename... ReducerArgs> inline void
724
725/*---------------------------------------------------------------------------*/
726/*---------------------------------------------------------------------------*/
731template<int RankValue,typename LambdaType> inline void
738
739/*---------------------------------------------------------------------------*/
740/*---------------------------------------------------------------------------*/
745template<int RankValue,typename LambdaType> inline void
753
754/*---------------------------------------------------------------------------*/
755/*---------------------------------------------------------------------------*/
756
757} // End namespace Arcane
758
759/*---------------------------------------------------------------------------*/
760/*---------------------------------------------------------------------------*/
761
762#endif
#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_FATAL(...)
Macro envoyant une exception FatalErrorException.
Déclarations des types utilisés dans Arcane.
Classe pour gérer le profiling d'une seule exécution d'une boucle.
Definition Profiling.h:93
Informations d'exécution d'une boucle.
ForLoopOneExecStat * execStat() const
Pointeur contenant les statistiques d'exécution.
void setExecStat(ForLoopOneExecStat *v)
Positionne le pointeur conservant les statistiques d'exécution.
Informations de trace pour une boucle 'for'.
Interface d'un observable.
Interface d'un fonctor sur un interval d'itération.
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.
virtual void executeParallelFor(Integer begin, Integer size, const ParallelLoopOptions &options, IRangeFunctor *f)=0
Exécute le fonctor f en concurrence.
virtual void executeParallelFor(Integer begin, Integer size, IRangeFunctor *f)=0
Exécute le fonctor f en concurrence.
virtual void executeParallelFor(const ParallelFor1DLoopInfo &loop_info)=0
Exécute la boucle loop_info en concurrence.
virtual Int32 nbAllowedThread() const =0
Nombre de threads utilisés au maximum pour gérer les tâches.
virtual void executeParallelFor(const ComplexForLoopRanges< 2 > &loop_ranges, const ForLoopRunInfo &run_info, IMDRangeFunctor< 2 > *functor)=0
Exécute une boucle 2D en concurrence.
virtual void executeParallelFor(Integer begin, Integer size, Integer block_size, IRangeFunctor *f)=0
Exécute le fonctor f en concurrence.
virtual void executeParallelFor(const ComplexForLoopRanges< 3 > &loop_ranges, const ForLoopRunInfo &run_info, IMDRangeFunctor< 3 > *functor)=0
Exécute une boucle 3D en concurrence.
virtual ITask * createRootTask(ITaskFunctor *f)=0
Créé une tâche racine. L'implémentation doit recopier la valeur de f qui est soit un TaskFunctor,...
virtual Int32 currentTaskIndex() const =0
Implémentation de TaskFactory::currentTaskIndex()
virtual bool isActive() const =0
Indique si l'implémentation est active.
virtual void executeParallelFor(const ComplexForLoopRanges< 4 > &loop_ranges, const ForLoopRunInfo &run_info, IMDRangeFunctor< 4 > *functor)=0
Exécute une boucle 4D en concurrence.
virtual void executeParallelFor(const ComplexForLoopRanges< 1 > &loop_ranges, const ForLoopRunInfo &run_info, IMDRangeFunctor< 1 > *functor)=0
Exécute une boucle 1D en concurrence.
virtual void printInfos(std::ostream &o) const =0
Affiche les informations sur le runtime utilisé
virtual void terminate()=0
virtual Int32 currentTaskThreadIndex() const =0
Implémentation de TaskFactory::currentTaskThreadIndex()
virtual void initialize(Int32 nb_thread)=0
Interface d'une tâche concourante.
virtual void launchAndWait()=0
Lance la tâche et bloque jusqu'à ce qu'elle se termine.
virtual void launchAndWait(ConstArrayView< ITask * > tasks)=0
Lance les tâches filles tasks et bloque jusqu'à ce qu'elles se terminent.
Fonctor sur un interval d'itération instancié via une lambda fonction.
Lecteur des fichiers de maillage via la bibliothèque LIMA.
Definition Lima.cc:149
Caractéristiques d'un boucle 1D multi-thread.
Options d'exécution d'une boucle parallèle en multi-thread.
Contexte d'éxecution d'une tâche.
ITask * task() const
Tâche courante.
API interne à Arcane de 'TaskFactory'.
Fabrique pour les tâches.
static Int32 currentTaskIndex()
Indice (entre 0 et nbAllowedThread()-1) de la tâche actuelle.
static void executeParallelFor(const ParallelFor1DLoopInfo &loop_info)
Exécute la boucle loop_info en concurrence.
static Int32 nbAllowedThread()
Nombre de threads utilisés au maximum pour gérer les tâches.
static void executeParallelFor(Integer begin, Integer size, IRangeFunctor *f)
Exécute le fonctor f en concurrence.
static ITask * createTask(InstanceType *instance, void(InstanceType::*function)())
Créé une tâche. Lors de l'exécution, la tâche appellera la méthode function via l'instance instance.
static const ParallelLoopOptions & defaultParallelLoopOptions()
Valeurs par défaut d'exécution d'une boucle parallèle.
static void executeParallelFor(const ComplexForLoopRanges< 1 > &loop_ranges, const ParallelLoopOptions &options, IMDRangeFunctor< 1 > *functor)
Exécute une boucle simple.
static void executeParallelFor(const ComplexForLoopRanges< 1 > &loop_ranges, const ForLoopRunInfo &run_info, IMDRangeFunctor< 1 > *functor)
Exécute une boucle simple.
static void executeParallelFor(const ComplexForLoopRanges< 2 > &loop_ranges, const ForLoopRunInfo &run_info, IMDRangeFunctor< 2 > *functor)
Exécute une boucle 2D.
static Integer verboseLevel()
Niveau de verbosité
static void executeParallelFor(const ComplexForLoopRanges< 4 > &loop_ranges, const ParallelLoopOptions &options, IMDRangeFunctor< 4 > *functor)
Exécute une boucle 4D.
static void executeParallelFor(const ComplexForLoopRanges< 2 > &loop_ranges, const ParallelLoopOptions &options, IMDRangeFunctor< 2 > *functor)
Exécute une boucle 2D.
static void setDefaultParallelLoopOptions(const ParallelLoopOptions &v)
Positionne les valeurs par défaut d'exécution d'une boucle parallèle.
static void executeParallelFor(Integer begin, Integer size, const ParallelLoopOptions &options, IRangeFunctor *f)
Exécute le fonctor f en concurrence.
static void executeParallelFor(Integer begin, Integer size, Integer block_size, IRangeFunctor *f)
Exécute le fonctor f en concurrence.
static void executeParallelFor(const ComplexForLoopRanges< 3 > &loop_ranges, const ParallelLoopOptions &options, IMDRangeFunctor< 3 > *functor)
Exécute une boucle 3D.
static ITask * createChildTask(ITask *parent_task, InstanceType *instance, void(InstanceType::*function)(const TaskContext &tc))
Créé une tâche fille.
ARCANE_DEPRECATED_REASON("Y2024: This method is internal to Arcane. " "Use TaskFactoryInternal::setImplementation() instead") static void _internalSetImplementation(ITaskImplementation *task_impl)
static Int32 currentTaskThreadIndex()
Indice (entre 0 et nbAllowedThread()-1) du thread exécutant la tâche actuelle.
static ITask * createChildTask(ITask *parent_task, InstanceType *instance, void(InstanceType::*function)())
Créé une tâche fille.
static bool isActive()
Indique si les tâches sont actives. Les tâches sont actives si une implémentation est disponible et s...
static ITask * createTask(InstanceType *instance, void(InstanceType::*function)(const TaskContext &tc))
Créé une tâche. Lors de l'exécution, la tâche appellera la méthode function via l'instance instance.
static void executeParallelFor(const ComplexForLoopRanges< 4 > &loop_ranges, const ForLoopRunInfo &run_info, IMDRangeFunctor< 4 > *functor)
Exécute une boucle 4D.
static void printInfos(std::ostream &o)
Affiche les informations sur l'implémentation.
static void executeParallelFor(const ComplexForLoopRanges< 3 > &loop_ranges, const ForLoopRunInfo &run_info, IMDRangeFunctor< 3 > *functor)
Exécute une boucle 3D.
Fonctor pour une tâche prenant un TaskContext en argument.
void executeFunctor(const TaskContext &tc) override
Exécute la méthode associé
Fonctor sans argument pour une tâche.
void executeFunctor(const TaskContext &) override
Exécute la méthode associé
void arcaneParallelFor(Integer i0, Integer size, InstanceType *itype, void(InstanceType::*lambda_function)(Integer i0, Integer size))
Applique en concurrence la fonction lambda lambda_function sur l'intervalle d'itération [i0,...
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
void arcaneSequentialFor(LoopBoundType< 1, IndexType > bounds, const Lambda &func, ReducerArgs... reducer_args)
Applique le fonctor func sur une boucle 1D.
Type
Type of JSON value.
Definition rapidjson.h:665