Arcane  v3.15.0.0
Documentation utilisateur
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/*---------------------------------------------------------------------------*/
49/*!
50 * \brief Informations d'exécution d'une boucle.
51 *
52 * Cette classe permet de gérer les informations d'exécutions communes à toutes
53 * les boucles.
54 */
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) {}
66 ForLoopRunInfo(const ParallelLoopOptions& options,const ForLoopTraceInfo& trace_info)
67 : m_options(options), m_trace_info(trace_info) {}
68 explicit ForLoopRunInfo(const ForLoopTraceInfo& 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
78 /*!
79 * \brief Positionne le pointeur conservant les statistiques d'exécution.
80 *
81 * Ce pointeur \a v doit rester valide durant toute l'exécution de la boucle.
82 */
83 void setExecStat(ForLoopOneExecStat* v) { m_exec_stat = v; }
84
85 //! Pointeur contenant les statistiques d'exécution.
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/*---------------------------------------------------------------------------*/
97/*!
98 * \brief Contexte d'éxecution d'une tâche.
99 * \ingroup Concurrency
100 */
101class ARCANE_UTILS_EXPORT TaskContext
102{
103 public:
104 explicit TaskContext(ITask* atask) : m_task(atask) {}
105 public:
106 //! Tâche courante.
107 ITask* task() const { return m_task; }
108 private:
109 ITask* m_task;
110};
111
112/*---------------------------------------------------------------------------*/
113/*---------------------------------------------------------------------------*/
114/*!
115 * \internal
116 * \brief Interface d'un fonctor pour une tâche.
117 * \ingroup Concurrency
118 */
119class ARCANE_UTILS_EXPORT ITaskFunctor
120{
121 public:
122 virtual ~ITaskFunctor() = default;
123 protected:
124 ITaskFunctor(const ITaskFunctor&) = default;
125 ITaskFunctor() = default;
126 public:
127 //! Exécute la méthode associé
128 virtual void executeFunctor(const TaskContext& tc) =0;
129 virtual ITaskFunctor* clone(void* buffer,Integer size) =0;
130};
131
132/*---------------------------------------------------------------------------*/
133/*---------------------------------------------------------------------------*/
134/*!
135 * \internal
136 * \brief Fonctor sans argument pour une tâche.
137 * \ingroup Concurrency
138 */
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:
153 //! Exécute la méthode associé
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/*---------------------------------------------------------------------------*/
171/*!
172 * \internal
173 * \brief Fonctor pour une tâche prenant un TaskContext en argument.
174 * \ingroup Concurrency
175 */
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:
188 //! Exécute la méthode associé
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/*---------------------------------------------------------------------------*/
206/*!
207 * \ingroup Concurrency
208 * \brief Interface d'une tâche concourante.
209 *
210 * Les tâches sont créées via TaskFactory.
211 */
212class ARCANE_UTILS_EXPORT ITask
213{
214 friend class TaskFactory;
215
216 public:
217
218 virtual ~ITask(){}
219
220 public:
221 /*!
222 * \brief Lance la tâche et bloque jusqu'à ce qu'elle se termine.
223 *
224 * Après appel à cette fonction, la tâche est détruite et ne doit
225 * plus être utilisée.
226 */
227 virtual void launchAndWait() =0;
228 /*!
229 * \brief Lance les tâches filles \a tasks et bloque
230 * jusqu'à ce qu'elles se terminent.
231 */
232 virtual void launchAndWait(ConstArrayView<ITask*> tasks) =0;
233
234 protected:
235
236 virtual ITask* _createChildTask(ITaskFunctor* functor) =0;
237};
238
239/*---------------------------------------------------------------------------*/
240/*---------------------------------------------------------------------------*/
241/*!
242 * \internal
243 * \brief Implémentation d'une fabrique de tâches.
244 *
245 * \ingroup Concurrency
246 *
247 * Cette classe est interne à Arcane. Pour gérer les tâches, il
248 * faut utiliser la classe TaskFactory.
249 */
250class ARCANE_UTILS_EXPORT ITaskImplementation
251{
252 public:
253 virtual ~ITaskImplementation(){}
254 public:
255 /*!
256 * \internal.
257 * Initialise l'implémentation avec au maximum \a nb_thread.
258 * Si \a nb_thread vaut 0, l'implémentation peut choisir
259 * le nombre de thread automatiquement.
260 * Cette méthode est interne à Arcane et ne doit être appelée
261 * que lors de l'initialisation de l'exécution.
262 */
263 virtual void initialize(Int32 nb_thread) =0;
264 /*!
265 * \internal.
266 * Termine l'utilisation de l'implémentation.
267 * Cette méthode doit être appelée en fin de calcul uniquement.
268 */
269 virtual void terminate() =0;
270 /*!
271 * \brief Créé une tâche racine.
272 * L'implémentation doit recopier la valeur de \a f qui est soit
273 * un TaskFunctor, soit un TaskFunctorWithContext.
274 */
276
277 //! Exécute le fonctor \a f en concurrence.
278 virtual void executeParallelFor(Integer begin,Integer size,const ParallelLoopOptions& options,IRangeFunctor* f) =0;
279
280 //! Exécute le fonctor \a f en concurrence.
281 virtual void executeParallelFor(Integer begin,Integer size,Integer block_size,IRangeFunctor* f) =0;
282
283 //! Exécute le fonctor \a f en concurrence.
284 virtual void executeParallelFor(Integer begin,Integer size,IRangeFunctor* f) =0;
285
286 //! Exécute la boucle \a loop_info en concurrence.
287 virtual void executeParallelFor(const ParallelFor1DLoopInfo& loop_info) =0;
288
289 //! Exécute une boucle 1D en concurrence
290 virtual void executeParallelFor(const ComplexForLoopRanges<1>& loop_ranges,
291 const ForLoopRunInfo& run_info,
292 IMDRangeFunctor<1>* functor) =0;
293 //! Exécute une boucle 2D en concurrence
294 virtual void executeParallelFor(const ComplexForLoopRanges<2>& loop_ranges,
295 const ForLoopRunInfo& run_info,
296 IMDRangeFunctor<2>* functor) =0;
297 //! Exécute une boucle 3D en concurrence
298 virtual void executeParallelFor(const ComplexForLoopRanges<3>& loop_ranges,
299 const ForLoopRunInfo& run_info,
300 IMDRangeFunctor<3>* functor) =0;
301 //! Exécute une boucle 4D en concurrence
302 virtual void executeParallelFor(const ComplexForLoopRanges<4>& loop_ranges,
303 const ForLoopRunInfo& run_info,
304 IMDRangeFunctor<4>* functor) =0;
305
306 //! Indique si l'implémentation est active.
307 virtual bool isActive() const =0;
308
309 //! Nombre de threads utilisés au maximum pour gérer les tâches.
310 virtual Int32 nbAllowedThread() const =0;
311
312 //! Implémentation de TaskFactory::currentTaskThreadIndex()
313 virtual Int32 currentTaskThreadIndex() const =0;
314
315 //! Implémentation de TaskFactory::currentTaskIndex()
316 virtual Int32 currentTaskIndex() const =0;
317
318 //! Affiche les informations sur le runtime utilisé
319 virtual void printInfos(std::ostream& o) const =0;
320};
321
322/*---------------------------------------------------------------------------*/
323/*---------------------------------------------------------------------------*/
324/*!
325 * \brief Fabrique pour les tâches.
326 * \ingroup Concurrency
327 */
328class ARCANE_UTILS_EXPORT TaskFactory
329{
330 friend TaskFactoryInternal;
331
332 public:
333
334 TaskFactory() = delete;
335
336 public:
337
338 /*!
339 * \brief Créé une tâche.
340 * Lors de l'exécution, la tâche appellera la méthode \a function via
341 * l'instance \a instance.
342 */
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
350 /*!
351 * \brief Créé une tâche.
352 * Lors de l'exécution, la tâche appellera la méthode \a function via
353 * l'instance \a instance.
354 */
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
362 /*!
363 * \brief Créé une tâche fille.
364 *
365 * Lors de l'exécution, la tâche appellera la méthode \a function via
366 * l'instance \a instance.
367 */
368 template<typename InstanceType> static ITask*
369 createChildTask(ITask* parent_task,InstanceType* instance,void (InstanceType::*function)(const TaskContext& tc))
370 {
371 ARCANE_CHECK_POINTER(parent_task);
372 TaskFunctorWithContext<InstanceType> functor(instance,function);
373 return parent_task->_createChildTask(&functor);
374 }
375
376 /*!
377 * \brief Créé une tâche fille.
378 *
379 * Lors de l'exécution, la tâche appellera la méthode \a function via
380 * l'instance \a instance.
381 */
382 template<typename InstanceType> static ITask*
383 createChildTask(ITask* parent_task,InstanceType* instance,void (InstanceType::*function)())
384 {
385 ARCANE_CHECK_POINTER(parent_task);
386 TaskFunctor<InstanceType> functor(instance,function);
387 return parent_task->_createChildTask(&functor);
388 }
389
390 //! Exécute le fonctor \a f en concurrence.
391 static void executeParallelFor(Integer begin,Integer size,const ParallelLoopOptions& options,IRangeFunctor* f)
392 {
393 m_impl->executeParallelFor(begin,size,options,f);
394 }
395
396 //! Exécute le fonctor \a f en concurrence.
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
402 //! Exécute le fonctor \a f en concurrence.
403 static void executeParallelFor(Integer begin,Integer size,IRangeFunctor* f)
404 {
405 m_impl->executeParallelFor(begin,size,f);
406 }
407
408 //! Exécute la boucle \a loop_info en concurrence.
409 static void executeParallelFor(const ParallelFor1DLoopInfo& loop_info)
410 {
411 m_impl->executeParallelFor(loop_info);
412 }
413
414 //! Exécute une boucle simple
415 static void executeParallelFor(const ComplexForLoopRanges<1>& loop_ranges,
416 const ParallelLoopOptions& options,
417 IMDRangeFunctor<1>* functor)
418 {
419 m_impl->executeParallelFor(loop_ranges,ForLoopRunInfo(options),functor);
420 }
421
422 //! Exécute une boucle simple
423 static void executeParallelFor(const ComplexForLoopRanges<1>& loop_ranges,
424 const ForLoopRunInfo& run_info,
425 IMDRangeFunctor<1>* functor)
426 {
427 m_impl->executeParallelFor(loop_ranges,run_info,functor);
428 }
429
430 //! Exécute une boucle 2D
431 static void executeParallelFor(const ComplexForLoopRanges<2>& loop_ranges,
432 const ParallelLoopOptions& options,
433 IMDRangeFunctor<2>* functor)
434 {
435 m_impl->executeParallelFor(loop_ranges,ForLoopRunInfo(options),functor);
436 }
437
438 //! Exécute une boucle 2D
439 static void executeParallelFor(const ComplexForLoopRanges<2>& loop_ranges,
440 const ForLoopRunInfo& run_info,
441 IMDRangeFunctor<2>* functor)
442 {
443 m_impl->executeParallelFor(loop_ranges,run_info,functor);
444 }
445
446 //! Exécute une boucle 3D
447 static void executeParallelFor(const ComplexForLoopRanges<3>& loop_ranges,
448 const ParallelLoopOptions& options,
449 IMDRangeFunctor<3>* functor)
450 {
451 m_impl->executeParallelFor(loop_ranges,ForLoopRunInfo(options),functor);
452 }
453
454 //! Exécute une boucle 3D
455 static void executeParallelFor(const ComplexForLoopRanges<3>& loop_ranges,
456 const ForLoopRunInfo& run_info,
457 IMDRangeFunctor<3>* functor)
458 {
459 m_impl->executeParallelFor(loop_ranges,run_info,functor);
460 }
461
462 //! Exécute une boucle 4D
463 static void executeParallelFor(const ComplexForLoopRanges<4>& loop_ranges,
464 const ParallelLoopOptions& options,
465 IMDRangeFunctor<4>* functor)
466 {
467 m_impl->executeParallelFor(loop_ranges,ForLoopRunInfo(options),functor);
468 }
469
470 //! Exécute une boucle 4D
471 static void executeParallelFor(const ComplexForLoopRanges<4>& loop_ranges,
472 const ForLoopRunInfo& run_info,
473 IMDRangeFunctor<4>* functor)
474 {
475 m_impl->executeParallelFor(loop_ranges,run_info,functor);
476 }
477
478 //! Nombre de threads utilisés au maximum pour gérer les tâches.
479 static Int32 nbAllowedThread()
480 {
481 return m_impl->nbAllowedThread();
482 }
483
484 /*!
485 * \brief Indice (entre 0 et nbAllowedThread()-1) du thread exécutant la tâche actuelle.
486 *
487 * Pour des raisons de performance, il est préférable d'appeler cette méthode
488 * le moins possible. L'idéal est de ne le faire qu'au début de l'exécution de la tâche
489 * et ensuite d'utiliser la valeur retournée.
490 */
492 {
493 return m_impl->currentTaskThreadIndex();
494 }
495
496 /*!
497 * \brief Indice (entre 0 et nbAllowedThread()-1) de la tâche actuelle.
498 *
499 * Cet indice est le même que currentTaskThreadIndex() sauf dans le cas
500 * où on se trouve dans un executeParallelFor() avec un partitionnement
501 * déterministe (ParallelLoopOptions::Partitioner::Deterministic).
502 * Dans ce dernier cas, le numéro de la tâche est assigné de manière
503 * déterministe qui ne dépend que du nombre de threads alloués pour la
504 * tâche et de ParallelLoopOptions::grainSize().
505 *
506 * Si le thread courant n'exécute pas une tâche associé à cette implémentation,
507 * retourne (-1).
508 */
509 static Int32 currentTaskIndex()
510 {
511 return m_impl->currentTaskIndex();
512 }
513
514 public:
515
516 //! Positionne les valeurs par défaut d'exécution d'une boucle parallèle
518 {
519 m_default_loop_options = v;
520 }
521
522 //! Valeurs par défaut d'exécution d'une boucle parallèle
524 {
525 return m_default_loop_options;
526 }
527
528 public:
529
530 /*!
531 * \brief Indique si les tâches sont actives.
532 * Les tâches sont actives si une implémentation est disponible et si le nombre
533 * de threads demandé est strictement supérieur à 1.
534 */
535 static bool isActive()
536 {
537 return m_impl->isActive();
538 }
539
540 /*!
541 * \brief Affiche les informations sur l'implémentation.
542 *
543 * Les informations sont par exemple le numéro de version ou le nom
544 * de l'implémentation.
545 */
546 static void printInfos(std::ostream& o)
547 {
548 return m_impl->printInfos(o);
549 }
550
551 /*!
552 * \brief Observable appelé lors de la création d'un thread pour une tâche.
553 *
554 * \warning L'instance de l'observable est créée lors du premier appel
555 * à cette méthode. Elle n'est donc pas thread-safe. De même,
556 * la modification de l'observable (ajout/suppression d'observateur)
557 * n'est pas thread-safe.
558 */
559 ARCANE_DEPRECATED_REASON("Y2024: This method is internal to Arcane. Do not use it")
560 static IObservable* createThreadObservable();
561
562 /*!
563 * \brief Observable appelé lors de la destruction d'un thread pour une tâche.
564 *
565 * \warning L'instance de l'observable est créée lors du premier appel
566 * à cette méthode. Elle n'est donc pas thread-safe. De même,
567 * la modification de l'observable (ajout/suppression d'observateur)
568 * n'est pas thread-safe.
569 */
570 ARCANE_DEPRECATED_REASON("Y2024: This method is internal to Arcane. Do not use it")
571 static IObservable* destroyThreadObservable();
572
573 /*!
574 * \internal
575 * \brief Indique qu'on n'utilisera plus les threads.
576 * Cette méthode ne doit pas être appelée lorsque des tâches sont actives.
577 */
578 static void terminate();
579
580 public:
581
582 //! Positionne le niveau de verbosité (0 pour pas d'affichage qui est le défaut)
583 static void setVerboseLevel(Integer v) { m_verbose_level = v; }
584
585 //! Niveau de verbosité
586 static Integer verboseLevel() { return m_verbose_level; }
587
588 public:
589
590 //! \internal
591 ARCANE_DEPRECATED_REASON("Y2024: This method is internal to Arcane. "
592 "Use TaskFactoryInternal::setImplementation() instead")
593 static void _internalSetImplementation(ITaskImplementation* task_impl);
594
595 private:
596
597 static ITaskImplementation* m_impl;
598 static Int32 m_verbose_level;
599 static ParallelLoopOptions m_default_loop_options;
600};
601
602/*---------------------------------------------------------------------------*/
603/*---------------------------------------------------------------------------*/
604/*!
605 * \brief Caractéristiques d'un boucle 1D multi-thread.
606 *
607 * Cette classe permet de spécifier les options d'une boucle à paralléliser
608 * en mode multi-thread.
609 */
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/*---------------------------------------------------------------------------*/
648/*!
649 * \brief Applique en concurrence la fonction lambda \a lambda_function
650 * sur l'intervalle d'itération donné par \a loop_ranges.
651 */
652template<int RankValue,typename LambdaType,typename... ReducerArgs> inline void
654 const ForLoopRunInfo& run_info,
655 const LambdaType& lambda_function,
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
668 auto xfunc = [&lambda_function,reducer_args...] (const ComplexForLoopRanges<RankValue>& sub_bounds)
669 {
670 using Type = typename std::remove_reference<LambdaType>::type;
671 Type private_lambda(lambda_function);
672 arcaneSequentialFor(sub_bounds,private_lambda,reducer_args...);
673 };
674 LambdaMDRangeFunctor<RankValue,decltype(xfunc)> ipf(xfunc);
675 TaskFactory::executeParallelFor(loop_ranges,run_info,&ipf);
676}
677
678/*---------------------------------------------------------------------------*/
679/*---------------------------------------------------------------------------*/
680/*!
681 * \brief Applique en concurrence la fonction lambda \a lambda_function
682 * sur l'intervalle d'itération donné par \a loop_ranges.
683 */
684template<int RankValue,typename LambdaType,typename... ReducerArgs> inline void
686 const ParallelLoopOptions& options,
687 const LambdaType& lambda_function,
688 const ReducerArgs&... reducer_args)
689{
690 arcaneParallelFor(loop_ranges,ForLoopRunInfo(options),lambda_function,reducer_args...);
691}
692
693/*---------------------------------------------------------------------------*/
694/*---------------------------------------------------------------------------*/
695/*!
696 * \brief Applique en concurrence la fonction lambda \a lambda_function
697 * sur l'intervalle d'itération donné par \a loop_ranges.
698 */
699template <int RankValue, typename LambdaType, typename... ReducerArgs> inline void
701 const ForLoopRunInfo& run_info,
702 const LambdaType& lambda_function,
703 const ReducerArgs&... reducer_args)
704{
705 ComplexForLoopRanges<RankValue> complex_loop_ranges{ loop_ranges };
706 arcaneParallelFor(complex_loop_ranges, run_info, lambda_function, reducer_args...);
707}
708
709/*---------------------------------------------------------------------------*/
710/*---------------------------------------------------------------------------*/
711/*!
712 * \brief Applique en concurrence la fonction lambda \a lambda_function
713 * sur l'intervalle d'itération donné par \a loop_ranges.
714 */
715template <int RankValue, typename LambdaType, typename... ReducerArgs> inline void
717 const ParallelLoopOptions& options,
718 const LambdaType& lambda_function,
719 const ReducerArgs&... reducer_args)
720{
721 ComplexForLoopRanges<RankValue> complex_loop_ranges{ loop_ranges };
722 arcaneParallelFor(complex_loop_ranges, ForLoopRunInfo(options), lambda_function, reducer_args...);
723}
724
725/*---------------------------------------------------------------------------*/
726/*---------------------------------------------------------------------------*/
727/*!
728 * \brief Applique en concurrence la fonction lambda \a lambda_function
729 * sur l'intervalle d'itération donné par \a loop_ranges.
730 */
731template<int RankValue,typename LambdaType> inline void
733 const LambdaType& lambda_function)
734{
735 ParallelLoopOptions options;
736 arcaneParallelFor(loop_ranges,options,lambda_function);
737}
738
739/*---------------------------------------------------------------------------*/
740/*---------------------------------------------------------------------------*/
741/*!
742 * \brief Applique en concurrence la fonction lambda \a lambda_function
743 * sur l'intervalle d'itération donné par \a loop_ranges.
744 */
745template<int RankValue,typename LambdaType> inline void
747 const LambdaType& lambda_function)
748{
749 ParallelLoopOptions options;
750 ComplexForLoopRanges<RankValue> complex_loop_ranges{loop_ranges};
751 arcaneParallelFor(complex_loop_ranges,options,lambda_function);
752}
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.
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 fonctor sur un interval d'itération multi-dimensionnel de dimension RankValue.
Interface d'un observable.
Interface d'un fonctor sur un interval d'itération.
virtual void executeFunctor(const TaskContext &tc)=0
Exécute la méthode associé
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 Int32 currentTaskThreadIndex() const =0
Implémentation de TaskFactory::currentTaskThreadIndex()
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.
Caractéristiques d'un boucle 1D multi-thread.
Options d'exécution d'une boucle parallèle en multi-thread.
void setGrainSize(Integer v)
Positionne la taille (approximative) d'un intervalle d'itération.
Interval d'itération simple.
Contexte d'éxecution d'une tâche.
ITask * task() const
Tâche courante.
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.
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.
void executeFunctor(const TaskContext &tc) override
Exécute la méthode associé
void executeFunctor(const TaskContext &) override
Exécute la méthode associé
Vue constante d'un tableau de type T.
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.