Arcane  v3.14.10.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
HybridParallelSuperMng.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2024 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/* HybridParallelSuperMng.cc (C) 2000-2024 */
9/* */
10/* Gestionnaire de parallélisme utilisant MPI et mémoire partagée. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/ApplicationInfo.h"
15#include "arcane/utils/NullThreadMng.h"
16#include "arcane/utils/FatalErrorException.h"
17#include "arcane/utils/ITraceMng.h"
18#include "arcane/utils/PlatformUtils.h"
19#include "arcane/utils/ValueConvert.h"
20#include "arcane/utils/TraceClassConfig.h"
21#include "arcane/utils/ArgumentException.h"
22#include "arcane/utils/CommandLineArguments.h"
23
24#include "arcane/parallel/IStat.h"
25
26#include "arcane/parallel/mpi/MpiAdapter.h"
27#include "arcane/parallel/mpi/MpiParallelMng.h"
28#include "arcane/parallel/mpi/MpiParallelDispatch.h"
29#include "arcane/parallel/mpi/MpiLock.h"
30#include "arcane/parallel/mpi/MpiErrorHandler.h"
31
32#include "arcane/parallel/thread/SharedMemoryMessageQueue.h"
33#include "arcane/parallel/thread/SharedMemoryParallelMng.h"
34#include "arcane/parallel/thread/SharedMemoryParallelSuperMng.h"
35#include "arcane/parallel/thread/internal/SharedMemoryThreadMng.h"
36
37#include "arcane/parallel/mpithread/HybridParallelMng.h"
38#include "arcane/parallel/mpithread/HybridParallelDispatch.h"
39
40#include "arcane/core/FactoryService.h"
41#include "arcane/core/AbstractService.h"
42#include "arcane/core/IApplication.h"
43#include "arcane/core/ParallelSuperMngDispatcher.h"
44#include "arcane/core/ApplicationBuildInfo.h"
45#include "arcane/core/ServiceBuilder.h"
46
47#include "arcane/core/IMainFactory.h"
48
50
51/*---------------------------------------------------------------------------*/
52/*---------------------------------------------------------------------------*/
53
55{
56
57/*---------------------------------------------------------------------------*/
58/*---------------------------------------------------------------------------*/
64{
65 public:
68 Parallel::IStat* stat,MpiLock* mpi_lock);
70
71
72 public:
73
74 void build();
75 Ref<IParallelMng> _createParallelMng(Int32 local_rank,ITraceMng* tm) override;
76
77 public:
78
80 Parallel::IStat* m_stat = nullptr;
82 MpiLock* m_mpi_lock = nullptr;
83 ISharedMemoryMessageQueue* m_message_queue = nullptr;
84 IThreadBarrier* m_thread_barrier = nullptr;
85 Int32 m_local_nb_rank = -1;
86 MpiThreadAllDispatcher* m_all_dispatchers = nullptr;
87 // Cet objet est partagé par tous les HybridParallelMng.
88 UniqueArray<HybridParallelMng*>* m_parallel_mng_list = nullptr;
89 Mutex* m_internal_create_mutex = nullptr;
90 IParallelMngContainerFactory* m_sub_builder_factory = nullptr;
91 private:
93 Int32 m_mpi_comm_rank = -1;
94 Int32 m_mpi_comm_size = -1;
95 private:
96 void _setMPICommunicator();
97};
98
99/*---------------------------------------------------------------------------*/
100/*---------------------------------------------------------------------------*/
101
102HybridParallelMngContainer::
103HybridParallelMngContainer(IApplication* app,Int32 nb_local_rank,
105 Parallel::IStat* stat,MpiLock* mpi_lock)
106: m_application(app)
107, m_stat(stat)
108, m_thread_mng(new SharedMemoryThreadMng())
109, m_mpi_lock(mpi_lock)
110, m_local_nb_rank(nb_local_rank)
111, m_parallel_mng_list(new UniqueArray<HybridParallelMng*>())
112, m_sub_builder_factory(factory)
113, m_mpi_communicator(mpi_comm)
114{
115 _setMPICommunicator();
116}
117
118/*---------------------------------------------------------------------------*/
119/*---------------------------------------------------------------------------*/
120
121HybridParallelMngContainer::
122~HybridParallelMngContainer()
123{
124 // TODO: regarder s'il faut détruire le communicateur
125 m_thread_barrier->destroy();
126 delete m_message_queue;
127 delete m_thread_mng;
128 delete m_all_dispatchers;
129 delete m_parallel_mng_list;
130 delete m_internal_create_mutex;
131}
132
133/*---------------------------------------------------------------------------*/
134/*---------------------------------------------------------------------------*/
135
136void HybridParallelMngContainer::
137build()
138{
139 m_internal_create_mutex = new Mutex();
140
141 m_all_dispatchers = new MpiThreadAllDispatcher();
142 m_all_dispatchers->resize(m_local_nb_rank);
143
144 m_parallel_mng_list->resize(m_local_nb_rank);
145 m_parallel_mng_list->fill(nullptr);
146
147 m_message_queue = new SharedMemoryMessageQueue();
148 m_message_queue->init(m_local_nb_rank);
149
150 m_thread_barrier = platform::getThreadImplementationService()->createBarrier();
151 m_thread_barrier->init(m_local_nb_rank);
152}
153
154/*---------------------------------------------------------------------------*/
155/*---------------------------------------------------------------------------*/
156
157void HybridParallelMngContainer::
158_setMPICommunicator()
159{
160 MPI_Comm comm = static_cast<MPI_Comm>(m_mpi_communicator);
161
162 if (comm==MPI_COMM_NULL)
163 ARCANE_THROW(ArgumentException,"Null MPI Communicator");
164 m_mpi_communicator = comm;
165
166 int rank = 0;
167 MPI_Comm_rank(m_mpi_communicator,&rank);
168 int size = 0;
169 MPI_Comm_size(m_mpi_communicator,&size);
170
171 m_mpi_comm_rank = rank;
172 m_mpi_comm_size = size;
173}
174
175/*---------------------------------------------------------------------------*/
176/*---------------------------------------------------------------------------*/
177
179_createParallelMng(Int32 local_rank,ITraceMng* tm)
180{
181 if (local_rank<0 || local_rank>=m_local_nb_rank)
182 ARCANE_THROW(ArgumentException,"Bad value '{0}' for local_rank (max={1})",
183 local_rank,m_local_nb_rank);
184
185 // Cette méthode n'est pas réentrante.
186 Mutex::ScopedLock sl(m_internal_create_mutex);
187
189 bool is_parallel = nb_process > 1;
190
191 // Le communicateur passé en argument reste notre propriété.
193 bi.is_parallel = is_parallel;
194 bi.stat = m_stat;
195 bi.trace_mng = tm;
196 bi.thread_mng = m_thread_mng;
197 bi.is_mpi_comm_owned = false;
198 bi.mpi_lock = m_mpi_lock;
199
200 if (m_mpi_lock)
201 tm->info() << "MPI implementation need serialized threads : using locks";
202
204
205 mpi_pm->build();
206 mpi_pm->initialize();
207 mpi_pm->adapter()->enableDebugRequest(false);
208
210 build_info.local_rank = local_rank;
211 build_info.local_nb_rank = m_local_nb_rank;
212 build_info.mpi_parallel_mng = mpi_pm;
213 build_info.trace_mng = tm;
214 build_info.thread_mng = m_thread_mng;
215 build_info.message_queue = m_message_queue;
216 build_info.thread_barrier = m_thread_barrier;
217 build_info.parallel_mng_list = m_parallel_mng_list;
218 build_info.all_dispatchers = m_all_dispatchers;
219 build_info.sub_builder_factory = m_sub_builder_factory;
221
222 // NOTE: Cette instance sera détruite par l'appelant de cette méthode
224 pm->build();
225 (*m_parallel_mng_list)[local_rank] = pm;
226
227 return makeRef<IParallelMng>(pm);
228}
229
230/*---------------------------------------------------------------------------*/
231/*---------------------------------------------------------------------------*/
232
233/*---------------------------------------------------------------------------*/
234/*---------------------------------------------------------------------------*/
235
237: public AbstractService
239{
240 public:
242 : AbstractService(sbi), m_application(sbi.application()){}
243 public:
246 {
247 auto x = new HybridParallelMngContainer(m_application,nb_rank,mpi_communicator,
248 this,m_stat,m_mpi_lock);
249 x->build();
251 }
252 private:
253 IApplication* m_application;
254 public:
255 MpiLock* m_mpi_lock = nullptr;
256 Parallel::IStat* m_stat = nullptr;
257};
258
259/*---------------------------------------------------------------------------*/
260/*---------------------------------------------------------------------------*/
261
262ARCANE_REGISTER_SERVICE(HybridParallelMngContainerFactory,
263 ServiceProperty("HybridParallelMngContainerFactory",ST_Application),
265
266/*---------------------------------------------------------------------------*/
267/*---------------------------------------------------------------------------*/
268
269/*---------------------------------------------------------------------------*/
270/*---------------------------------------------------------------------------*/
276{
277 public:
278
280 ~HybridParallelSuperMng() override;
281
282 void initialize() override;
283 void build() override;
284
285 IApplication* application() const override { return m_application; }
286 IThreadMng* threadMng() const override { return m_container->m_thread_mng; }
287 bool isParallel() const override { return true; }
288 Int32 commRank() const override { return m_mpi_comm_rank; }
289 Int32 commSize() const override { return m_mpi_comm_size; }
290 Int32 traceRank() const override { return m_mpi_comm_rank * m_container->m_local_nb_rank; }
291 void* getMPICommunicator() override { return &m_mpi_communicator; }
292 MP::Communicator communicator() const override { return m_communicator; }
293 Ref<IParallelMng> internalCreateWorldParallelMng(Int32 local_rank) override;
294 void tryAbort() override;
295 bool isMasterIO() const override { return commRank()==0; }
296 Integer masterIORank() const override { return 0; }
297 Integer nbLocalSubDomain() override { return m_container->m_local_nb_rank; }
298 void barrier() override;
299
300 public:
301
302 public:
303
304 HybridParallelMngContainer* m_container = nullptr;
305 Ref<IParallelMngContainerFactory> m_builder_factory;
306 Ref<IParallelMngContainer> m_main_builder;
307
309 Parallel::IStat* m_stat;
310 Int32 m_mpi_comm_rank = -1;
311 Int32 m_mpi_comm_size = -1;
312 MPI_Comm m_mpi_communicator;
313 MP::Communicator m_communicator;
314 Int32 m_local_nb_rank = A_NULL_RANK;
315 MpiLock* m_mpi_lock;
316 MpiAdapter* m_mpi_adapter;
317 MpiDatatypeList* m_datatype_list;
318 MpiErrorHandler m_error_handler;
319};
320
321/*---------------------------------------------------------------------------*/
322/*---------------------------------------------------------------------------*/
323
324HybridParallelSuperMng::
325HybridParallelSuperMng(const ServiceBuildInfo& sbi)
326: m_application(sbi.application())
327, m_stat(nullptr)
328, m_mpi_comm_size(0)
329, m_mpi_communicator(MPI_COMM_NULL)
330, m_local_nb_rank(A_NULL_RANK)
331, m_mpi_lock(nullptr)
332, m_mpi_adapter(nullptr)
333, m_datatype_list(nullptr)
334{
336}
337
338/*---------------------------------------------------------------------------*/
339/*---------------------------------------------------------------------------*/
340
341HybridParallelSuperMng::
342~HybridParallelSuperMng()
343{
344 m_error_handler.removeHandler();
345 _finalize();
346 delete m_datatype_list;
347 if (m_mpi_adapter)
348 arcaneCallFunctionAndTerminateIfThrow([&]() { m_mpi_adapter->destroy(); });
349 delete m_mpi_lock;
350 delete m_stat;
351 MPI_Barrier(m_mpi_communicator);
352 MPI_Comm_free(&m_mpi_communicator);
353 m_mpi_communicator = MPI_COMM_NULL;
355}
356
357/*---------------------------------------------------------------------------*/
358/*---------------------------------------------------------------------------*/
359
364
365/*---------------------------------------------------------------------------*/
366/*---------------------------------------------------------------------------*/
367
369build()
370{
371 if (!arcaneHasThread())
372 ARCANE_FATAL("Can not create HybridParallelSuperMng because threads are disabled");
373
374 Request::setNullRequest(Request(0,nullptr,MPI_REQUEST_NULL));
375 Communicator::setNullCommunicator(Communicator(MPI_COMM_NULL));
376
377 int rank, size;
378 int* argc = nullptr;
379 char*** argv = nullptr;
380
382 const CommandLineArguments& cmd_line_args = app_info.commandLineArguments();
383 argc = cmd_line_args.commandLineArgc();
384 argv = cmd_line_args.commandLineArgv();
385
386 bool need_serialize = false;
387
388 // Essaie avec MPI_THREAD_MULTIPLE
389 // ce qui permet d'appeler MPI depuis plusieurs threads en même temps
390 // Si ce niveau n'existe pas, il faut au moins le niveau
391 // MPI_THREAD_SERIALIZED ce qui permet d'appeler MPI depuis plusieurs
392 // threads mais un seul à la fois. Il faut donc dans ce cas mettre
393 // des verrous autour des appels MPI. Dans notre cas, les verrous
394 // ne sont utiliser que pour les communications point à point car
395 // pour les opérations collectives il n'y a qu'un seul thread qui les fait
396 // à la fois.
398 int thread_provided = 0;
399
400 Real start_time = platform::getRealTime();
402 Real end_time = platform::getRealTime();
404
407 need_serialize = true;
408 else{
409 // Le niveau de thread requis n'est pas disponible.
410 // Lance un fatal mais seulement un seul processeur.
411 int my_rank = 0;
413 if (my_rank!=0)
414 ARCANE_FATAL("MPI thread level provided!=wanted ({0}!={1})",
416 }
417 }
418
419 // decommenter pour forcer l'usage des verrous pour test.
420 // need_serialize = true;
421
422 if (need_serialize)
423 m_mpi_lock = new MpiLock();
424
425 MPI_Comm_dup(MPI_COMM_WORLD,&m_mpi_communicator);
426 m_communicator = Communicator(m_mpi_communicator);
427 MPI_Comm_rank(m_mpi_communicator,&rank);
428 MPI_Comm_size(m_mpi_communicator,&size);
429
430 m_mpi_comm_rank = rank;
431 m_mpi_comm_size = size;
433
434 m_error_handler.registerHandler(m_mpi_communicator);
435
436 Integer n = app->applicationBuildInfo().nbSharedMemorySubDomain();
437 if (n==0)
438 ARCANE_FATAL("Number of shared memory sub-domains is not defined");
439 m_local_nb_rank = n;
440
441 if (rank==0){
442 ITraceMng* tm = app->traceMng();
443 tm->info() << "MPI has non blocking collective";
444 tm->info() << "MPI: sizeof(MPI_Count)=" << sizeof(MPI_Count);
445 tm->info() << "MPI: is Cuda Aware?=" << arcaneIsCudaAwareMPI();
446 tm->info() << "MPI: init_time (seconds)=" << (end_time-start_time);
447 }
448
449 /*cout << "ThreadSuperParallelMng: nb_sub_domain=" << m_local_nb_rank
450 << " env=" << s
451 << " mpi_rank=" << m_mpi_comm_rank << "/" << m_mpi_comm_size
452 << " first_rank=" << m_current_rank << '\n';*/
453
454 ITraceMng* tm = app->traceMng();
455 m_datatype_list = new MpiDatatypeList(false);
456 auto* adapter = new MpiAdapter(tm,m_stat->toArccoreStat(),m_communicator,nullptr);
457 m_mpi_adapter = adapter;
458 auto c = createBuiltInDispatcher<Byte>(tm,nullptr,m_mpi_adapter,m_datatype_list);
459 auto i32 = createBuiltInDispatcher<Int32>(tm,nullptr,m_mpi_adapter,m_datatype_list);
460 auto i64 = createBuiltInDispatcher<Int64>(tm,nullptr,m_mpi_adapter,m_datatype_list);
461 auto r = createBuiltInDispatcher<Real>(tm,nullptr,m_mpi_adapter,m_datatype_list);
462 _setDispatchers(c,i32,i64,r);
463
465 String service_name = "HybridParallelMngContainerFactory";
466 m_builder_factory = sb.createReference(service_name);
467 auto* true_builder = dynamic_cast<HybridParallelMngContainerFactory*>(m_builder_factory.get());
469 true_builder->m_stat = m_stat;
470 true_builder->m_mpi_lock = m_mpi_lock;
471
472 Ref<IParallelMngContainer> x = m_builder_factory->_createParallelMngBuilder(n,m_communicator);
473 m_main_builder = x;
474 m_container = dynamic_cast<HybridParallelMngContainer*>(x.get());
475 ARCANE_CHECK_POINTER(m_container);
476}
477
478/*---------------------------------------------------------------------------*/
479/*---------------------------------------------------------------------------*/
480
482internalCreateWorldParallelMng(Int32 local_rank)
483{
484 if (local_rank<0 || local_rank>=m_local_nb_rank)
485 throw ArgumentException(A_FUNCINFO,"Bad value for local_rank");
486
487 Int32 current_global_rank = local_rank + m_local_nb_rank * commRank();
489 app_tm->info() << "Create SharedMemoryParallelMng rank=" << current_global_rank;
490
491 ITraceMng* tm = nullptr;
492 if (local_rank==0){
493 // Le premier sous-domaine créé utilise le traceMng() par défaut.
494 tm = app_tm;
495 }
496 else{
498 }
499
500 Ref<IParallelMng> pm = m_container->_createParallelMng(local_rank,tm);
501 return pm;
502}
503
504/*---------------------------------------------------------------------------*/
505/*---------------------------------------------------------------------------*/
506
508tryAbort()
509{
510 m_application->traceMng()->flush();
511 MPI_Abort(m_communicator,2);
512}
513
514/*---------------------------------------------------------------------------*/
515/*---------------------------------------------------------------------------*/
516
518barrier()
519{
520 MPI_Barrier(m_communicator);
521}
522
523/*---------------------------------------------------------------------------*/
524/*---------------------------------------------------------------------------*/
525
527 ServiceProperty("HybridParallelSuperMng",ST_Application),
529
530// Ancien nom
532 ServiceProperty("MpiThreadParallelSuperMng",ST_Application),
534
535/*---------------------------------------------------------------------------*/
536/*---------------------------------------------------------------------------*/
537
538/*---------------------------------------------------------------------------*/
539/*---------------------------------------------------------------------------*/
548{
549 public:
552 {
553 Request::setNullRequest(Request(0,nullptr,MPI_REQUEST_NULL));
554 Communicator::setNullCommunicator(Communicator(MPI_COMM_NULL));
555 }
556
558 {
559 //arcaneFinalizeMPI();
560 }
561
562 void build() override
563 {
565 }
566};
567
568/*---------------------------------------------------------------------------*/
569/*---------------------------------------------------------------------------*/
570
571ARCANE_REGISTER_SERVICE(MpiSharedMemoryParallelSuperMng,
572 ServiceProperty("MpiSharedMemoryParallelSuperMng",ST_Application),
574
575/*---------------------------------------------------------------------------*/
576/*---------------------------------------------------------------------------*/
577
578} // End namespace Arcane::MessagePassing
579
580/*---------------------------------------------------------------------------*/
581/*---------------------------------------------------------------------------*/
#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_THROW(exception_class,...)
Macro pour envoyer une exception avec formattage.
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
#define ARCANE_SERVICE_INTERFACE(ainterface)
Macro pour déclarer une interface lors de l'enregistrement d'un service.
Classe de base d'un service.
Informations sur une application.
Arguments de la ligne de commande.
Interface de l'application.
virtual ITraceMng * createAndInitializeTraceMng(ITraceMng *parent_trace, const String &file_suffix)=0
Créé et initialise une instance de ITraceMng.
virtual const ApplicationInfo & applicationInfo() const =0
Informations sur l'exécutable.
virtual ITraceMng * traceMng() const =0
Gestionnaire de traces.
Interface d'une fabrique de conteneur de 'IParallelMng'.
virtual void build()=0
Construit l'instance.
Classe abstraite du superviseur de parallélisme.
Interface d'un gestionnaire de thread.
Definition IThreadMng.h:30
Lecteur des fichiers de maillage via la bibliothèque LIMA.
Definition Lima.cc:120
Ref< IParallelMngContainer > _createParallelMngBuilder(Int32 nb_rank, MP::Communicator mpi_communicator) override
Créé un conteneur pour nb_local_rank rangs locaux et avec comme communicateur communicator.
Conteneur des informations du gestionnaire de message en mode hybride.
IApplication * m_application
Gestionnaire principal.
Ref< IParallelMng > _createParallelMng(Int32 local_rank, ITraceMng *tm) override
Créé le IParallelMng pour le rang local local_rank.
Gestionnaire du parallélisme utilisant les threads.
Superviseur du parallélisme utilisant MPI et Threads.
void tryAbort() override
Tente de faire un abort.
Int32 commRank() const override
Retourne le numéro du process (compris entre 0 et nbProcess()-1)
MP::Communicator communicator() const override
Communicateur MPI associé à ce gestionnaire.
void build() override
Construit les membres l'instance.
void * getMPICommunicator() override
Adresse du communicateur MPI associé à ce gestionnaire.
IThreadMng * threadMng() const override
Gestionnaire de thread.
IApplication * application() const override
Retourne le gestionnaire principal.
void barrier() override
Gestionnaire de parallèlisme pour l'ensemble des ressources allouées.
Ref< IParallelMng > internalCreateWorldParallelMng(Int32 local_rank) override
Créé un gestionnaire de parallélisme pour l'ensemble des coeurs alloués.
Integer masterIORank() const override
Rang de l'instance gérant les entrées/sorties (pour laquelle isMasterIO() est vrai)
void initialize() override
Initialise l'instance.
Integer nbLocalSubDomain() override
Nombre de sous-domaines à créér localement.
bool isMasterIO() const override
true si l'instance est un gestionnaire maître des entrées/sorties.
Int32 commSize() const override
Retourne le nombre total de process utilisés.
bool isParallel() const override
Retourne true si l'exécution est parallèle.
Int32 traceRank() const override
Rang de cette instance pour les traces.
IApplication * m_application
Gestionnaire principal.
Interface d'une file de messages avec les threads.
Superviseur en mémoire partagé avec initialisation MPI.
void build() override
Construit les membres l'instance.
Superviseur du parallélisme utilisant les threads.
void build() override
Construit les membres l'instance.
Gère les MPI_Datatype associées aux types Arcane.
Interface des messages pour le type Type.
Gestionnaire du parallélisme utilisant MPI.
Redirige la gestion des messages des sous-domaines suivant le type de l'argument.
Statistiques sur le parallélisme.
Structure contenant les informations pour créer un service.
Propriétés de création d'un service.
Exception lorsqu'un argument est invalide.
virtual void destroy()=0
Détruit la barrière.
virtual void init(Integer nb_thread)=0
Initialise la barrière pour nb_thread.
Interface du gestionnaire de traces.
Communicateur pour l'échange de message.
void destroy()
Détruit l'instance. Elle ne doit plus être utilisée par la suite.
Requête d'un message.
Definition Request.h:77
Chaîne de caractères unicode.
ITraceMng * traceMng() const
Gestionnaire de trace.
TraceMessage info() const
Flot pour un message d'information.
Vecteur 1D de données avec sémantique par valeur (style STL).
#define ARCANE_REGISTER_SERVICE(aclass, a_service_property,...)
Macro pour enregistrer un service.
Déclarations des types et méthodes utilisés par les mécanismes d'échange de messages.
Definition Parallel.h:94
IStat * createDefaultStat()
Créé une instance par défaut.
IThreadImplementation * getThreadImplementationService()
Service utilisé pour gérer les threads.
ARCANE_MPI_EXPORT void arcaneInitializeMPI(int *argc, char ***argv, int wanted_thread_level)
Definition ArcaneMpi.cc:202
bool arcaneHasThread()
Vrai si arcane est compilé avec le support des threads ET qu'ils sont actifs.
Definition Misc.cc:182
ARCANE_MPI_EXPORT bool arcaneIsCudaAwareMPI()
Indique si le runtime actuel de MPI a le support de CUDA.
Definition ArcaneMpi.cc:40
@ ST_Application
Le service s'utilise au niveau de l'application.
void arcaneCallFunctionAndTerminateIfThrow(std::function< void()> function)
ARCANE_MPI_EXPORT void arcaneFinalizeMPI()
Definition ArcaneMpi.cc:208
Infos pour construire un HybridParallelMng.
Infos pour construire un MpiParallelMng.