Arcane  v3.16.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
59 using ThatClass = ForLoopRunInfo;
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>
140class TaskFunctor
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>
177class TaskFunctorWithContext
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.
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.
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 */
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
614 using ThatClass = ParallelFor1DLoopInfo;
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 {
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.
Vue constante d'un tableau de type T.
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 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.
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 void setVerboseLevel(Integer v)
Positionne le niveau de verbosité (0 pour pas d'affichage qui est le défaut)
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é
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 -*-
Int32 Integer
Type représentant un entier.
void arcaneSequentialFor(LoopBoundType< 1, IndexType > bounds, const Lambda &func, ReducerArgs... reducer_args)
Applique le fonctor func sur une boucle 1D.
std::int32_t Int32
Type entier signé sur 32 bits.