Arcane  4.2.3.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
MpiParallelMng.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2026 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/* MpiParallelMng.cc (C) 2000-2026 */
9/* */
10/* Gestionnaire de parallélisme utilisant MPI. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/Collection.h"
15#include "arcane/utils/Enumerator.h"
16#include "arcane/utils/ScopedPtr.h"
17#include "arcane/utils/PlatformUtils.h"
18#include "arcane/utils/TimeoutException.h"
19#include "arcane/utils/NotImplementedException.h"
20#include "arcane/utils/ArgumentException.h"
21#include "arcane/utils/ITraceMng.h"
22#include "arcane/utils/ValueConvert.h"
23#include "arcane/utils/Exception.h"
24#include "arcane/utils/HPReal.h"
25
26#include "arcane/core/IIOMng.h"
27#include "arcane/core/Timer.h"
28#include "arcane/core/IItemFamily.h"
29#include "arcane/core/IParallelTopology.h"
30#include "arcane/core/parallel/IStat.h"
31#include "arcane/core/internal/SerializeMessage.h"
32#include "arcane/core/internal/ParallelMngInternal.h"
33#include "arcane/core/internal/MachineShMemWinMemoryAllocator.h"
34
35#include "arcane/parallel/mpi/MpiParallelMng.h"
36#include "arcane/parallel/mpi/MpiParallelDispatch.h"
37#include "arcane/parallel/mpi/MpiTimerMng.h"
38#include "arcane/parallel/mpi/MpiSerializeMessage.h"
39#include "arcane/parallel/mpi/MpiParallelNonBlockingCollective.h"
40#include "arcane/parallel/mpi/MpiDatatype.h"
41#include "arcane/parallel/mpi/IVariableSynchronizerMpiCommunicator.h"
42
43#include "arcane/impl/ParallelReplication.h"
44#include "arcane/impl/SequentialParallelMng.h"
45#include "arcane/impl/internal/ParallelMngUtilsFactoryBase.h"
46#include "arcane/impl/internal/VariableSynchronizer.h"
47
48#include "arccore/message_passing_mpi/internal/MpiMessagePassingMng.h"
49#include "arccore/message_passing_mpi/internal/MpiSerializeDispatcher.h"
50#include "arccore/message_passing_mpi/internal/MpiRequestList.h"
51#include "arccore/message_passing_mpi/internal/MpiAdapter.h"
52#include "arccore/message_passing_mpi/internal/MpiLock.h"
53#include "arccore/message_passing_mpi/internal/MpiMachineShMemWinBaseInternalCreator.h"
54#include "arccore/message_passing_mpi/internal/MpiContigMachineShMemWinBaseInternal.h"
55#include "arccore/message_passing_mpi/internal/MpiMachineShMemWinBaseInternal.h"
56#include "arccore/message_passing/Dispatchers.h"
58#include "arccore/message_passing/internal/SerializeMessageList.h"
59
60#include "arcane_packages.h"
61
62//#define ARCANE_TRACE_MPI
63
64/*---------------------------------------------------------------------------*/
65/*---------------------------------------------------------------------------*/
66
67namespace Arcane
68{
69using namespace Arcane::MessagePassing;
70using namespace Arcane::MessagePassing::Mpi;
72
73/*---------------------------------------------------------------------------*/
74/*---------------------------------------------------------------------------*/
75
76extern "C++" IIOMng*
77arcaneCreateIOMng(IParallelMng* psm);
78
79#if defined(ARCANE_HAS_MPI_NEIGHBOR)
80// Défini dans MpiNeighborVariableSynchronizeDispatcher
82arcaneCreateMpiNeighborVariableSynchronizerFactory(MpiParallelMng* mpi_pm,
83 Ref<IVariableSynchronizerMpiCommunicator> synchronizer_communicator);
84#endif
86arcaneCreateMpiBlockVariableSynchronizerFactory(MpiParallelMng* mpi_pm, Int32 block_size, Int32 nb_sequence);
88arcaneCreateMpiVariableSynchronizerFactory(MpiParallelMng* mpi_pm);
90arcaneCreateMpiDirectSendrecvVariableSynchronizerFactory(MpiParallelMng* mpi_pm);
92arcaneCreateMpiLegacyVariableSynchronizerFactory(MpiParallelMng* mpi_pm);
93#if defined(ARCANE_HAS_PACKAGE_NCCL)
95arcaneCreateNCCLVariableSynchronizerFactory(IParallelMng* mpi_pm);
96#endif
97
98/*---------------------------------------------------------------------------*/
99/*---------------------------------------------------------------------------*/
100
101MpiParallelMngBuildInfo::
102MpiParallelMngBuildInfo(MPI_Comm comm, MPI_Comm machine_comm)
103: is_parallel(false)
104, comm_rank(MessagePassing::A_NULL_RANK)
105, comm_nb_rank(0)
106, mpi_comm(comm)
107, mpi_machine_comm(machine_comm)
108, is_mpi_comm_owned(true)
109{
110 ::MPI_Comm_rank(comm, &comm_rank);
111 ::MPI_Comm_size(comm, &comm_nb_rank);
112}
113
114/*---------------------------------------------------------------------------*/
115/*---------------------------------------------------------------------------*/
116
117/*---------------------------------------------------------------------------*/
118/*---------------------------------------------------------------------------*/
122class VariableSynchronizerMpiCommunicator
124{
125 public:
126 explicit VariableSynchronizerMpiCommunicator(MpiParallelMng* pm)
127 : m_mpi_parallel_mng(pm){}
128 ~VariableSynchronizerMpiCommunicator() override
129 {
130 _checkFreeCommunicator();
131 }
132 MPI_Comm communicator() const override
133 {
134 return m_topology_communicator;
135 }
136 void compute(VariableSynchronizer* var_syncer) override
137 {
138 Int32ConstArrayView comm_ranks = var_syncer->communicatingRanks();
139 const Int32 nb_message = comm_ranks.size();
140
141 MpiParallelMng* pm = m_mpi_parallel_mng;
142
143 MPI_Comm old_comm = pm->communicator();
144
145 UniqueArray<int> destinations(nb_message);
146 for( Integer i=0; i<nb_message; ++i ){
147 destinations[i] = comm_ranks[i];
148 }
149
150 _checkFreeCommunicator();
151
152 int r = MPI_Dist_graph_create_adjacent(old_comm, nb_message, destinations.data(), MPI_UNWEIGHTED,
153 nb_message, destinations.data(), MPI_UNWEIGHTED,
154 MPI_INFO_NULL, 0, &m_topology_communicator);
155
156 if (r!=MPI_SUCCESS)
157 ARCANE_FATAL("Error '{0}' in MPI_Dist_graph_create",r);
158
159 // Vérifie que l'ordre des rangs pour l'implémentation MPI est le même que celui qu'on a dans
160 // le VariableSynchronizer.
161 {
162 int indegree = 0;
163 int outdegree = 0;
164 int weighted = 0;
165 MPI_Dist_graph_neighbors_count(m_topology_communicator,&indegree,&outdegree,&weighted);
166
167 if (indegree!=nb_message)
168 ARCANE_FATAL("Bad value '{0}' for 'indegree' (expected={1})",indegree,nb_message);
169 if (outdegree!=nb_message)
170 ARCANE_FATAL("Bad value '{0}' for 'outdegree' (expected={1})",outdegree,nb_message);
171
172 UniqueArray<int> srcs(indegree);
173 UniqueArray<int> dsts(outdegree);
174
175 MPI_Dist_graph_neighbors(m_topology_communicator,indegree,srcs.data(),MPI_UNWEIGHTED,outdegree,dsts.data(),MPI_UNWEIGHTED);
176
177 for(int k=0; k<outdegree; ++k){
178 int x = dsts[k];
179 if (x!=comm_ranks[k])
180 ARCANE_FATAL("Invalid destination rank order k={0} v={1} expected={2}",k,x,comm_ranks[k]);
181 }
182
183 for(int k=0; k<indegree; ++k ){
184 int x = srcs[k];
185 if (x!=comm_ranks[k])
186 ARCANE_FATAL("Invalid source rank order k={0} v={1} expected={2}",k,x,comm_ranks[k]);
187 }
188 }
189 }
190
191 private:
192
193 MpiParallelMng* m_mpi_parallel_mng = nullptr;
194 MPI_Comm m_topology_communicator = MPI_COMM_NULL;
195
196 private:
197
198 void _checkFreeCommunicator()
199 {
200 if (m_topology_communicator!=MPI_COMM_NULL)
201 MPI_Comm_free(&m_topology_communicator);
202 m_topology_communicator = MPI_COMM_NULL;
203 }
204};
205
206/*---------------------------------------------------------------------------*/
207/*---------------------------------------------------------------------------*/
214class MpiVariableSynchronizer
215: public VariableSynchronizer
216{
217 public:
218 MpiVariableSynchronizer(IParallelMng* pm,const ItemGroup& group,
219 Ref<IDataSynchronizeImplementationFactory> implementation_factory,
221 : VariableSynchronizer(pm,group,implementation_factory)
222 , m_topology_info(topology_info)
223 {
224 }
225 public:
226 void compute() override
227 {
229 // Si non nul, calcule la topologie
230 if (m_topology_info.get())
231 m_topology_info->compute(this);
232 }
233 private:
235};
236
237/*---------------------------------------------------------------------------*/
238/*---------------------------------------------------------------------------*/
239
240class MpiParallelMngUtilsFactory
242{
243 public:
244 MpiParallelMngUtilsFactory()
245 : m_synchronizer_version(2)
246 {
247 if (platform::getEnvironmentVariable("ARCANE_SYNCHRONIZE_VERSION")=="1")
248 m_synchronizer_version = 1;
249 if (platform::getEnvironmentVariable("ARCANE_SYNCHRONIZE_VERSION")=="2")
250 m_synchronizer_version = 2;
251 if (platform::getEnvironmentVariable("ARCANE_SYNCHRONIZE_VERSION")=="3")
252 m_synchronizer_version = 3;
253 if (platform::getEnvironmentVariable("ARCANE_SYNCHRONIZE_VERSION")=="4"){
254 m_synchronizer_version = 4;
255 String v = platform::getEnvironmentVariable("ARCANE_SYNCHRONIZE_BLOCK_SIZE");
256 if (!v.null()){
257 Int32 block_size = 0;
258 if (!builtInGetValue(block_size,v))
259 m_synchronize_block_size = block_size;
260 m_synchronize_block_size = std::clamp(m_synchronize_block_size,0,1000000000);
261 }
262 v = platform::getEnvironmentVariable("ARCANE_SYNCHRONIZE_NB_SEQUENCE");
263 if (!v.null()){
264 Int32 nb_sequence = 0;
265 if (!builtInGetValue(nb_sequence,v))
266 m_synchronize_nb_sequence = nb_sequence;
267 m_synchronize_nb_sequence = std::clamp(m_synchronize_nb_sequence,1,1024*1024);
268 }
269 }
270 if (platform::getEnvironmentVariable("ARCANE_SYNCHRONIZE_VERSION")=="5")
271 m_synchronizer_version = 5;
272 if (platform::getEnvironmentVariable("ARCANE_SYNCHRONIZE_VERSION")=="6")
273 m_synchronizer_version = 6;
274 }
275 public:
276
278 {
279 return _createSynchronizer(pm,family->allItems());
280 }
281
283 {
284 return _createSynchronizer(pm,group);
285 }
286
287 private:
288
289 Ref<IVariableSynchronizer> _createSynchronizer(IParallelMng* pm,const ItemGroup& group)
290 {
292 MpiParallelMng* mpi_pm = ARCANE_CHECK_POINTER(dynamic_cast<MpiParallelMng*>(pm));
293 ITraceMng* tm = pm->traceMng();
295 // N'affiche les informations que pour le groupe de toutes les mailles pour éviter d'afficher
296 // plusieurs fois le même message.
297 bool do_print = (group.isAllItems() && group.itemKind()==IK_Cell);
298 if (m_synchronizer_version == 2){
299 if (do_print)
300 tm->info() << "Using MpiSynchronizer V2";
301 generic_factory = arcaneCreateMpiVariableSynchronizerFactory(mpi_pm);
302 }
303 else if (m_synchronizer_version == 3 ){
304 if (do_print)
305 tm->info() << "Using MpiSynchronizer V3";
306 generic_factory = arcaneCreateMpiDirectSendrecvVariableSynchronizerFactory(mpi_pm);
307 }
308 else if (m_synchronizer_version == 4){
309 if (do_print)
310 tm->info() << "Using MpiSynchronizer V4 block_size=" << m_synchronize_block_size
311 << " nb_sequence=" << m_synchronize_nb_sequence;
312 generic_factory = arcaneCreateMpiBlockVariableSynchronizerFactory(mpi_pm,m_synchronize_block_size,m_synchronize_nb_sequence);
313 }
314 else if (m_synchronizer_version == 5){
315 if (do_print)
316 tm->info() << "Using MpiSynchronizer V5";
317 topology_info = createRef<VariableSynchronizerMpiCommunicator>(mpi_pm);
318#if defined(ARCANE_HAS_MPI_NEIGHBOR)
319 generic_factory = arcaneCreateMpiNeighborVariableSynchronizerFactory(mpi_pm,topology_info);
320#else
321 throw NotSupportedException(A_FUNCINFO,"Synchronize implementation V5 is not supported with this version of MPI");
322#endif
323 }
324#if defined(ARCANE_HAS_PACKAGE_NCCL)
325 else if (m_synchronizer_version == 6){
326 if (do_print)
327 tm->info() << "Using NCCLSynchronizer";
328 generic_factory = arcaneCreateNCCLVariableSynchronizerFactory(mpi_pm);
329 }
330#endif
331 else{
332 if (do_print)
333 tm->info() << "Using MpiSynchronizer V1";
334 generic_factory = arcaneCreateMpiLegacyVariableSynchronizerFactory(mpi_pm);
335 }
336 if (!generic_factory.get())
337 ARCANE_FATAL("No factory created");
338 return createRef<MpiVariableSynchronizer>(pm,group,generic_factory,topology_info);
339 }
340
341 private:
342
343 Integer m_synchronizer_version = 1;
344 Int32 m_synchronize_block_size = 32000;
345 Int32 m_synchronize_nb_sequence = 1;
346};
347
348/*---------------------------------------------------------------------------*/
349/*---------------------------------------------------------------------------*/
350
351/*---------------------------------------------------------------------------*/
352/*---------------------------------------------------------------------------*/
353
355: public ParallelMngInternal
356{
357 public:
358
359 explicit Impl(MpiParallelMng* pm)
360 : ParallelMngInternal(pm)
361 , m_parallel_mng(pm)
362 , m_alloc(makeRef(new MachineShMemWinMemoryAllocator(pm)))
363 {}
364
365 ~Impl() override = default;
366
367 public:
368
369 Int32 masterParallelIORank() const override { return m_parallel_mng->commRank(); }
370 Int32 nbSendersToMasterParallelIO() const override { return 1; }
371
373 {
374 m_parallel_mng->traceMng()->info() << "initializeWindowCreator() MPI";
375 m_parallel_mng->adapter()->initializeWindowCreator(m_parallel_mng->machineCommunicator());
376 }
377
379 {
380 if (m_shmem_available == 1) {
381 return true;
382 }
383
384 if (m_shmem_available == 0) {
385 Ref<IParallelTopology> topo = m_parallel_mng->_internalUtilsFactory()->createTopology(m_parallel_mng);
386 if (topo->machineRanks().size() == m_parallel_mng->adapter()->windowCreator()->machineRanks().size()) {
387 m_shmem_available = 1;
388 return true;
389 }
390 // Problème avec MPI. Peut intervenir si MPICH est compilé en mode ch3:sock.
391 m_shmem_available = 2;
392 return false;
393 }
394
395 return false;
396 }
397
399 {
400 return makeRef(m_parallel_mng->adapter()->windowCreator()->createWindow(sizeof_segment, sizeof_type));
401 }
402
404 {
405 return makeRef(m_parallel_mng->adapter()->windowCreator()->createDynamicWindow(sizeof_segment, sizeof_type));
406 }
407
409 {
410 return MemoryAllocationOptions{ m_alloc.get() };
411 }
412
414 {
415 return m_parallel_mng->adapter()->windowCreator()->machineRanks();
416 }
417
418 void machineBarrier() override
419 {
420 m_parallel_mng->adapter()->windowCreator()->machineBarrier();
421 }
422
423 private:
424
425 MpiParallelMng* m_parallel_mng;
427
428 // 0 = Attribut non initialisé
429 // 1 = Mémoire partagée dispo
430 // 2 = Mémoire partagée non dispo
431 Int8 m_shmem_available = 0;
432};
433
434/*---------------------------------------------------------------------------*/
435/*---------------------------------------------------------------------------*/
436
437/*---------------------------------------------------------------------------*/
438/*---------------------------------------------------------------------------*/
439
440MpiParallelMng::
441MpiParallelMng(const MpiParallelMngBuildInfo& bi)
442: ParallelMngDispatcher(ParallelMngDispatcherBuildInfo(bi.commRank(),bi.commSize(),MP::Communicator(bi.mpiComm())))
443, m_trace(bi.trace_mng)
444, m_thread_mng(bi.thread_mng)
445, m_world_parallel_mng(bi.world_parallel_mng)
446, m_timer_mng(bi.timer_mng)
447, m_replication(new ParallelReplication())
448, m_is_parallel(bi.is_parallel)
449, m_comm_rank(bi.commRank())
450, m_comm_size(bi.commSize())
451, m_stat(bi.stat)
452, m_communicator(bi.mpiComm())
453, m_machine_communicator(bi.mpiMachineComm())
454, m_is_communicator_owned(bi.is_mpi_comm_owned)
455, m_mpi_lock(bi.mpi_lock)
456, m_non_blocking_collective(nullptr)
457, m_utils_factory(createRef<MpiParallelMngUtilsFactory>())
458, m_parallel_mng_internal(new Impl(this))
459{
460 if (!m_world_parallel_mng){
461 m_trace->debug()<<"[MpiParallelMng] No m_world_parallel_mng found, reverting to ourselves!";
462 m_world_parallel_mng = this;
463 }
464}
465
466/*---------------------------------------------------------------------------*/
467/*---------------------------------------------------------------------------*/
468
469MpiParallelMng::
470~MpiParallelMng()
471{
472 delete m_parallel_mng_internal;
473 delete m_non_blocking_collective;
474 m_sequential_parallel_mng.reset();
475 if (m_is_communicator_owned){
476 MpiLock::Section ls(m_mpi_lock);
477 MPI_Comm_free(&m_communicator);
478 MPI_Comm_free(&m_machine_communicator);
479 }
480 delete m_replication;
481 delete m_io_mng;
482 if (m_is_timer_owned)
483 delete m_timer_mng;
484 arcaneCallFunctionAndTerminateIfThrow([&]() { m_adapter->destroy(); });
485 delete m_datatype_list;
486}
487
488/*---------------------------------------------------------------------------*/
489/*---------------------------------------------------------------------------*/
490
491namespace
492{
493
494/*---------------------------------------------------------------------------*/
495/*---------------------------------------------------------------------------*/
496// Classe pour créer les différents dispatchers
497class DispatchCreator
498{
499 public:
500 DispatchCreator(ITraceMng* tm,IMessagePassingMng* mpm,MpiAdapter* adapter,MpiDatatypeList* datatype_list)
501 : m_tm(tm), m_mpm(mpm), m_adapter(adapter), m_datatype_list(datatype_list){}
502 public:
503 template<typename DataType> MpiParallelDispatchT<DataType>*
504 create()
505 {
506 MpiDatatype* dt = m_datatype_list->datatype(DataType());
507 return new MpiParallelDispatchT<DataType>(m_tm,m_mpm,m_adapter,dt);
508 }
509
510 ITraceMng* m_tm;
511 IMessagePassingMng* m_mpm;
512 MpiAdapter* m_adapter;
513 MpiDatatypeList* m_datatype_list;
514};
515
516/*---------------------------------------------------------------------------*/
517/*---------------------------------------------------------------------------*/
518
519class ControlDispatcherDecorator
520: public ParallelMngDispatcher::DefaultControlDispatcher
521{
522 public:
523
524 ControlDispatcherDecorator(ParallelMngDispatcher* pm, MpiAdapter* adapter)
525 : ParallelMngDispatcher::DefaultControlDispatcher(pm)
526 , m_adapter(adapter)
527 {}
528
529 IMessagePassingMng* commSplit(bool keep) override
530 {
531 return m_adapter->commSplit(keep);
532 }
533 MP::IProfiler* profiler() const override { return m_adapter->profiler(); }
534 void setProfiler(MP::IProfiler* p) override { m_adapter->setProfiler(p); }
535
536 private:
537 MpiAdapter* m_adapter;
538};
539}
540
541/*---------------------------------------------------------------------------*/
542/*---------------------------------------------------------------------------*/
543
545build()
546{
547 ITraceMng* tm = traceMng();
548 if (!m_timer_mng){
549 m_timer_mng = new MpiTimerMng(tm);
550 m_is_timer_owned = true;
551 }
552
553 // Créé le gestionnaire séquentiel associé.
554 {
556 bi.setTraceMng(traceMng());
557 bi.setCommunicator(communicator());
558 bi.setThreadMng(threadMng());
559 m_sequential_parallel_mng = arcaneCreateSequentialParallelMngRef(bi);
560 }
561
562 // Indique que les reduces doivent être fait dans l'ordre des processeurs
563 // afin de garantir une exécution déterministe
564 bool is_ordered_reduce = false;
565 if (platform::getEnvironmentVariable("ARCANE_ORDERED_REDUCE")=="TRUE")
566 is_ordered_reduce = true;
567 m_datatype_list = new MpiDatatypeList(is_ordered_reduce);
568
569 ARCANE_CHECK_POINTER(m_stat);
570
571 MpiAdapter* adapter = new MpiAdapter(m_trace,m_stat->toArccoreStat(),m_communicator,m_mpi_lock);
572 m_adapter = adapter;
573 auto mpm = _messagePassingMng();
574
575 // NOTE: cette instance sera détruite par le ParallelMngDispatcher
576 auto* control_dispatcher = new ControlDispatcherDecorator(this,m_adapter);
577 _setControlDispatcher(control_dispatcher);
578
579 // NOTE: cette instance sera détruite par le ParallelMngDispatcher
580 auto* serialize_dispatcher = new MpiSerializeDispatcher(m_adapter, mpm);
581 m_mpi_serialize_dispatcher = serialize_dispatcher;
582 _setSerializeDispatcher(serialize_dispatcher);
583
584 DispatchCreator creator(m_trace,mpm,m_adapter,m_datatype_list);
585 this->createDispatchers(creator);
586
587 m_io_mng = arcaneCreateIOMng(this);
588
589 m_non_blocking_collective = new MpiParallelNonBlockingCollective(tm,this,adapter);
590 m_non_blocking_collective->build();
591 if (m_mpi_lock)
592 m_trace->info() << "Using mpi with locks.";
593
594 m_parallel_mng_internal->initializeWindowCreator();
595}
596
597/*---------------------------------------------------------------------------*/
598/*---------------------------------------------------------------------------*/
599
600/*----------------------------------------------------------------------------*/
601/*---------------------------------------------------------------------------*/
602
605{
606 Trace::Setter mci(m_trace,"Mpi");
607 if (m_is_initialized){
608 m_trace->warning() << "MpiParallelMng already initialized";
609 return;
610 }
611
612 m_trace->info() << "Initialisation de MpiParallelMng";
613 m_sequential_parallel_mng->initialize();
614
615 m_adapter->setTimeMetricCollector(timeMetricCollector());
616
617 m_is_initialized = true;
618}
619
620/*---------------------------------------------------------------------------*/
621/*---------------------------------------------------------------------------*/
622
623void MpiParallelMng::
624sendSerializer(ISerializer* s,Int32 rank)
625{
626 Trace::Setter mci(m_trace,"Mpi");
627 Timer::Phase tphase(timeStats(),TP_Communication);
629 m_mpi_serialize_dispatcher->legacySendSerializer(s,{MessageRank(rank),mpi_tag,Blocking});
630}
631
632/*---------------------------------------------------------------------------*/
633/*---------------------------------------------------------------------------*/
634
637{
638 return m_utils_factory->createSendSerializeMessage(this, rank)._release();
639}
640
641/*---------------------------------------------------------------------------*/
642/*---------------------------------------------------------------------------*/
643
644Request MpiParallelMng::
645sendSerializer(ISerializer* s,Int32 rank,[[maybe_unused]] ByteArray& bytes)
646{
647 Trace::Setter mci(m_trace,"Mpi");
648 Timer::Phase tphase(timeStats(),TP_Communication);
650 return m_mpi_serialize_dispatcher->legacySendSerializer(s,{MessageRank(rank),mpi_tag,NonBlocking});
651}
652
653/*---------------------------------------------------------------------------*/
654/*---------------------------------------------------------------------------*/
655
656void MpiParallelMng::
657broadcastSerializer(ISerializer* values,Int32 rank)
658{
659 Timer::Phase tphase(timeStats(),TP_Communication);
660 m_mpi_serialize_dispatcher->broadcastSerializer(values,MessageRank(rank));
661}
662
663/*---------------------------------------------------------------------------*/
664/*---------------------------------------------------------------------------*/
665
666void MpiParallelMng::
667recvSerializer(ISerializer* values,Int32 rank)
668{
669 Trace::Setter mci(m_trace,"Mpi");
670 Timer::Phase tphase(timeStats(),TP_Communication);
672 m_mpi_serialize_dispatcher->legacyReceiveSerializer(values,MessageRank(rank),mpi_tag);
673}
674
675/*---------------------------------------------------------------------------*/
676/*---------------------------------------------------------------------------*/
677
680{
681 return m_utils_factory->createReceiveSerializeMessage(this, rank)._release();
682}
683
684/*---------------------------------------------------------------------------*/
685/*---------------------------------------------------------------------------*/
686
688probe(const PointToPointMessageInfo& message) -> MessageId
689{
690 return m_adapter->probeMessage(message);
691}
692
693/*---------------------------------------------------------------------------*/
694/*---------------------------------------------------------------------------*/
695
698{
699 return m_adapter->legacyProbeMessage(message);
700}
701
702/*---------------------------------------------------------------------------*/
703/*---------------------------------------------------------------------------*/
704
705Request MpiParallelMng::
706sendSerializer(const ISerializer* s,const PointToPointMessageInfo& message)
707{
708 return m_mpi_serialize_dispatcher->sendSerializer(s,message);
709}
710
711/*---------------------------------------------------------------------------*/
712/*---------------------------------------------------------------------------*/
713
714Request MpiParallelMng::
715receiveSerializer(ISerializer* s,const PointToPointMessageInfo& message)
716{
717 return m_mpi_serialize_dispatcher->receiveSerializer(s,message);
718}
719
720/*---------------------------------------------------------------------------*/
721/*---------------------------------------------------------------------------*/
722
725{
726 for( Integer i=0, is=requests.size(); i<is; ++i )
727 m_adapter->freeRequest(requests[i]);
728}
729
730/*---------------------------------------------------------------------------*/
731/*---------------------------------------------------------------------------*/
732
733void MpiParallelMng::
734_checkFinishedSubRequests()
735{
736 m_mpi_serialize_dispatcher->checkFinishedSubRequests();
737}
738
739/*---------------------------------------------------------------------------*/
740/*---------------------------------------------------------------------------*/
741
742Ref<IParallelMng> MpiParallelMng::
743sequentialParallelMngRef()
744{
745 return m_sequential_parallel_mng;
746}
747
750{
751 return m_sequential_parallel_mng.get();
752}
753
754/*---------------------------------------------------------------------------*/
755/*---------------------------------------------------------------------------*/
756
759{
760 if (m_stat)
761 m_stat->print(m_trace);
762}
763
764/*---------------------------------------------------------------------------*/
765/*---------------------------------------------------------------------------*/
766
768barrier()
769{
770 traceMng()->flush();
771 m_adapter->barrier();
772}
773
774/*---------------------------------------------------------------------------*/
775/*---------------------------------------------------------------------------*/
776
779{
780 m_adapter->waitAllRequests(requests);
781 _checkFinishedSubRequests();
782}
783
784/*---------------------------------------------------------------------------*/
785/*---------------------------------------------------------------------------*/
786
789{
790 return _waitSomeRequests(requests, false);
791}
792
793/*---------------------------------------------------------------------------*/
794/*---------------------------------------------------------------------------*/
795
798{
799 return _waitSomeRequests(requests, true);
800}
801
802/*---------------------------------------------------------------------------*/
803/*---------------------------------------------------------------------------*/
804
805UniqueArray<Integer> MpiParallelMng::
806_waitSomeRequests(ArrayView<Request> requests, bool is_non_blocking)
807{
808 UniqueArray<Integer> results;
809 UniqueArray<bool> done_indexes(requests.size());
810
811 m_adapter->waitSomeRequests(requests, done_indexes, is_non_blocking);
812 for (int i = 0 ; i < requests.size() ; i++) {
813 if (done_indexes[i])
814 results.add(i);
815 }
816 return results;
817}
818
819/*---------------------------------------------------------------------------*/
820/*---------------------------------------------------------------------------*/
821
822ISerializeMessageList* MpiParallelMng::
823_createSerializeMessageList()
824{
825 return new MP::internal::SerializeMessageList(messagePassingMng());
826}
827
828/*---------------------------------------------------------------------------*/
829/*---------------------------------------------------------------------------*/
830
833{
834 return m_utils_factory->createGetVariablesValuesOperation(this)._release();
835}
836
837/*---------------------------------------------------------------------------*/
838/*---------------------------------------------------------------------------*/
839
842{
843 return m_utils_factory->createTransferValuesOperation(this)._release();
844}
845
846/*---------------------------------------------------------------------------*/
847/*---------------------------------------------------------------------------*/
848
851{
852 return m_utils_factory->createExchanger(this)._release();
853}
854
855/*---------------------------------------------------------------------------*/
856/*---------------------------------------------------------------------------*/
857
860{
861 return m_utils_factory->createSynchronizer(this,family)._release();
862}
863
864/*---------------------------------------------------------------------------*/
865/*---------------------------------------------------------------------------*/
866
868createSynchronizer(const ItemGroup& group)
869{
870 return m_utils_factory->createSynchronizer(this,group)._release();
871}
872
873/*---------------------------------------------------------------------------*/
874/*---------------------------------------------------------------------------*/
875
878{
879 return m_utils_factory->createTopology(this)._release();
880}
881
882/*---------------------------------------------------------------------------*/
883/*---------------------------------------------------------------------------*/
884
886replication() const
887{
888 return m_replication;
889}
890
891/*---------------------------------------------------------------------------*/
892/*---------------------------------------------------------------------------*/
893
896{
897 delete m_replication;
898 m_replication = v;
899}
900
901/*---------------------------------------------------------------------------*/
902/*---------------------------------------------------------------------------*/
903
904IParallelMng* MpiParallelMng::
905_createSubParallelMng(MPI_Comm sub_communicator)
906{
907 // Si nul, ce rang ne fait pas partie du sous-communicateur
908 if (sub_communicator==MPI_COMM_NULL)
909 return nullptr;
910
911 int sub_rank = -1;
912 MPI_Comm_rank(sub_communicator,&sub_rank);
913
914 MPI_Comm sub_machine_communicator = MPI_COMM_NULL;
915 MPI_Comm_split_type(sub_communicator, MPI_COMM_TYPE_SHARED, sub_rank, MPI_INFO_NULL, &sub_machine_communicator);
916
917 MpiParallelMngBuildInfo bi(sub_communicator, sub_machine_communicator);
918 bi.is_parallel = isParallel();
919 bi.stat = m_stat;
920 bi.timer_mng = m_timer_mng;
921 bi.thread_mng = m_thread_mng;
922 bi.trace_mng = m_trace;
923 bi.world_parallel_mng = m_world_parallel_mng;
924 bi.mpi_lock = m_mpi_lock;
925
926 IParallelMng* sub_pm = new MpiParallelMng(bi);
927 sub_pm->build();
928 return sub_pm;
929}
930
931/*---------------------------------------------------------------------------*/
932/*---------------------------------------------------------------------------*/
933
934Ref<IParallelMng> MpiParallelMng::
935_createSubParallelMngRef(Int32 color, Int32 key)
936{
937 if (color < 0)
938 color = MPI_UNDEFINED;
939 MPI_Comm sub_communicator = MPI_COMM_NULL;
940 MPI_Comm_split(m_communicator, color, key, &sub_communicator);
941 IParallelMng* sub_pm = _createSubParallelMng(sub_communicator);
942 return makeRef(sub_pm);
943}
944
945/*---------------------------------------------------------------------------*/
946/*---------------------------------------------------------------------------*/
947
948Ref<IParallelMng> MpiParallelMng::
949_createSubParallelMngRef(bool is_kept)
950{
951 return _createSubParallelMngRef((is_kept) ? 1 : -1, commRank());
952}
953
954/*---------------------------------------------------------------------------*/
955/*---------------------------------------------------------------------------*/
956
957IParallelMng* MpiParallelMng::
958_createSubParallelMng(Int32ConstArrayView kept_ranks)
959{
960 MPI_Group mpi_group = MPI_GROUP_NULL;
961 MPI_Comm_group(m_communicator, &mpi_group);
962 Integer nb_sub_rank = kept_ranks.size();
963 UniqueArray<int> mpi_kept_ranks(nb_sub_rank);
964 for (Integer i = 0; i < nb_sub_rank; ++i)
965 mpi_kept_ranks[i] = (int)kept_ranks[i];
966
967 MPI_Group final_group = MPI_GROUP_NULL;
968 MPI_Group_incl(mpi_group, nb_sub_rank, mpi_kept_ranks.data(), &final_group);
969 MPI_Comm sub_communicator = MPI_COMM_NULL;
970
971 MPI_Comm_create(m_communicator, final_group, &sub_communicator);
972 MPI_Group_free(&final_group);
973 return _createSubParallelMng(sub_communicator);
974}
975
976/*---------------------------------------------------------------------------*/
977/*---------------------------------------------------------------------------*/
986: public MpiRequestList
987{
988 using Base = MpiRequestList;
989 public:
990 explicit RequestList(MpiParallelMng* pm)
991 : Base(pm->m_adapter), m_parallel_mng(pm){}
992 public:
993 void _wait(Parallel::eWaitType wait_type) override
994 {
995 Base::_wait(wait_type);
996 m_parallel_mng->_checkFinishedSubRequests();
997 };
998 private:
999 MpiParallelMng* m_parallel_mng;
1000};
1001
1002/*---------------------------------------------------------------------------*/
1003/*---------------------------------------------------------------------------*/
1004
1010
1011/*---------------------------------------------------------------------------*/
1012/*---------------------------------------------------------------------------*/
1013
1016{
1017 return m_utils_factory;
1018}
1019
1020/*---------------------------------------------------------------------------*/
1021/*---------------------------------------------------------------------------*/
1022
1023bool MpiParallelMng::
1024_isAcceleratorAware() const
1025{
1027}
1028
1029/*---------------------------------------------------------------------------*/
1030/*---------------------------------------------------------------------------*/
1031
1032} // End namespace Arcane
1033
1034/*---------------------------------------------------------------------------*/
1035/*---------------------------------------------------------------------------*/
#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.
Liste des fonctions d'échange de message.
Vue modifiable d'un tableau d'un type T.
constexpr Integer size() const noexcept
Retourne la taille du tableau.
const T * data() const
Accès à la racine du tableau hors toute protection.
void add(ConstReferenceType val)
Ajoute l'élément val à la fin du tableau.
Vue constante d'un tableau de type T.
constexpr Integer size() const noexcept
Nombre d'éléments du tableau.
Opérations pour accéder aux valeurs de variables d'un autre sous-domaine.
Interface du gestionnaire des entrées sorties.
Definition IIOMng.h:36
Interface d'une famille d'entités.
Definition IItemFamily.h:86
virtual ItemGroup allItems() const =0
Groupe de toutes les entités.
Échange d'informations entre processeurs.
Interface du gestionnaire de parallélisme pour un sous-domaine.
virtual ITraceMng * traceMng() const =0
Gestionnaire de traces.
virtual void build()=0
Construit l'instance.
Informations sur la réplication des sous-domaines en parallèle.
Informations sur la topologie d'allocation des coeurs de calcul.
Interface du gestionnaire de traces.
virtual void flush()=0
Flush tous les flots.
virtual TraceMessage info()=0
Flot pour un message d'information.
Envoie de valeurs sur différents processeurs.
Interface d'un communicateur MPI spécifique pour les synchronisations.
Interface d'un service de synchronisation de variable.
Groupe d'entités de maillage.
Definition ItemGroup.h:49
eItemKind itemKind() const
Genre du groupe. Il s'agit du genre de ses éléments.
Definition ItemGroup.h:109
bool isAllItems() const
Indique si le groupe est celui de toutes les entités.
Definition ItemGroup.cc:610
Communicateur pour l'échange de message.
Interface d'un message de sérialisation entre IMessagePassingMng.
Informations sur la source d'un message.
void _wait(eWaitType wait_type) override
Effectue l'attente ou le test.
Request receiveSerializer(ISerializer *s, const PointToPointMessageInfo &message) override
Message de réception.
Request sendSerializer(const ISerializer *s, const PointToPointMessageInfo &message) override
Message d'envoi.
Informations pour envoyer/recevoir un message point à point.
Requête d'un message.
Definition Request.h:77
Message de sérialisation utilisant un BasicSerializer.
static MessageTag defaultTag()
Tag par défaut pour les messages de sérialisation.
Gère les MPI_Datatype associées aux types Arcane.
Ref< IVariableSynchronizer > createSynchronizer(IParallelMng *pm, IItemFamily *family) override
Retourne une interface pour synchroniser des variables sur le groupe de la famille family.
Ref< IVariableSynchronizer > createSynchronizer(IParallelMng *pm, const ItemGroup &group) override
Retourne une interface pour synchroniser des variables sur le groupe group.
void initializeWindowCreator() override
Méthode permettant d'initialiser le windowCreator spécifique à l'implémentation.
Ref< IContigMachineShMemWinBaseInternal > createContigMachineShMemWinBase(Int64 sizeof_segment, Int32 sizeof_type) override
Méthode permettant de créer une fenêtre mémoire sur le noeud.
Ref< IMachineShMemWinBaseInternal > createMachineShMemWinBase(Int64 sizeof_segment, Int32 sizeof_type) override
Méthode permettant de créer une fenêtre mémoire dynamique sur le noeud.
bool isMachineShMemWinAvailable() override
Méthode permettant de savoir si le mode mémoire partagée est supporté.
ConstArrayView< Int32 > machineRanks() override
Méthode permettant de récupérer les rangs des sous-domaines du noeud de calcul.
void machineBarrier() override
Méthode permettant de faire une barrière pour les sous-domaines du noeud de calcul.
Int32 masterParallelIORank() const override
Int32 nbSendersToMasterParallelIO() const override
MemoryAllocationOptions machineShMemWinMemoryAllocator() override
Méthode permettant de récupérer un allocateur en mémoire partagée.
Spécialisation de MpiRequestList pour MpiParallelMng.
void _wait(Parallel::eWaitType wait_type) override
Effectue l'attente ou le test.
Gestionnaire du parallélisme utilisant MPI.
IParallelMng * worldParallelMng() const override
Gestionnaire de parallélisme sur l'ensemble des ressources allouées.
MessageSourceInfo legacyProbe(const PointToPointMessageInfo &message) override
Sonde si des messages sont disponibles.
void barrier() override
Effectue une barière.
UniqueArray< Integer > waitSomeRequests(ArrayView< Request > requests) override
Bloque en attendant qu'une des requêtes rvalues soit terminée.
void waitAllRequests(ArrayView< Request > requests) override
Bloque en attendant que les requêtes rvalues soient terminées.
MessageId probe(const PointToPointMessageInfo &message) override
Sonde si des messages sont disponibles.
void build() override
Construit l'instance.
void printStats() override
Affiche des statistiques liées à ce gestionnaire du parallélisme.
bool m_is_initialized
true si déjà initialisé
Int32 commRank() const override
Rang de cette instance dans le communicateur.
IParallelMng * sequentialParallelMng() override
Retourne un gestionnaire de parallélisme séquentiel.
IThreadMng * threadMng() const override
Gestionnaire de threads.
ITimerMng * timerMng() const override
Gestionnaire de timers.
void initialize() override
Initialise le gestionnaire du parallélisme.
IVariableSynchronizer * createSynchronizer(IItemFamily *family) override
Retourne une interface pour synchroniser des variables sur le groupe de la famille family.
ISerializeMessage * createSendSerializer(Int32 rank) override
Créé un message non bloquant pour envoyer des données sérialisées au rang rank.
bool isParallel() const override
Retourne true si l'exécution est parallèle.
Ref< IParallelMngUtilsFactory > _internalUtilsFactory() const override
Fabrique des fonctions utilitaires.
ITraceMng * traceMng() const override
Gestionnaire de trace associé à cette instance.
IParallelTopology * createTopology() override
Créé une instance contenant les infos sur la topologie des rangs de ce gestionnnaire.
Communicator communicator() const override
Communicateur MPI associé à cette instance.
IParallelExchanger * createExchanger() override
Retourne une interface pour transférer des messages entre processeurs.
IParallelReplication * replication() const override
Informations sur la réplication.
void setReplication(IParallelReplication *v) override
Positionne les Informations sur la réplication.
Ref< Parallel::IRequestList > createRequestListRef() override
Créé une liste de requêtes pour ce gestionnaire.
ITransferValuesParallelOperation * createTransferValuesOperation() override
Retourne une opération pour transférer des valeurs entre sous-domaine.
UniqueArray< Integer > testSomeRequests(ArrayView< Request > requests) override
Test si une des requêtes rvalues est terminée.
IGetVariablesValuesParallelOperation * createGetVariablesValuesOperation() override
Retourne une opération pour récupérer les valeurs d'une variable sur les entités d'un autre sous-doma...
ISerializeMessage * createReceiveSerializer(Int32 rank) override
Créé un message non bloquant pour recevoir des données sérialisées du rang rank.
void freeRequests(ArrayView< Parallel::Request > requests) override
Libère les requêtes.
Gestionnaire du parallélisme utilisant MPI.
Gestionnaire de timer utisant la bibliothèque MPI.
Definition MpiTimerMng.h:39
void compute() override
Recalcule les infos de synchronisation.
Redirige la gestion des messages des sous-domaines suivant le type de l'argument.
IMessagePassingMng * messagePassingMng() const override
Gestionnaire de message de Arccore associé
ITimeMetricCollector * timeMetricCollector() const override
Interface pour collecter les temps d'exécution (peut être nul).
ITimeStats * timeStats() const override
Gestionnaire de statistiques associé (peut être nul).
Classe de base d'une fabrique pour les fonctions utilitaires de IParallelMng.
Informations sur la réplication des sous-domaines en parallèle.
InstanceType * get() const
Instance associée ou nullptr si aucune.
Référence à une instance.
Chaîne de caractères unicode.
bool null() const
Retourne true si la chaîne est nulle.
Definition String.cc:305
Positionne la phase de l'action en cours d'exécution.
Definition Timer.h:128
Positionne une classe de message.
Vecteur 1D de données avec sémantique par valeur (style STL).
MPI_Comm communicator() const override
Récupère le communicateur spécifique de la topologie.
void compute(VariableSynchronizer *var_syncer) override
Calcul le communicateur spécifique.
Interface d'un service de synchronisation de variable.
void compute() override
Création de la liste des éléments de synchronisation.
Int32ConstArrayView communicatingRanks() override
Rangs des sous-domaines avec lesquels on communique.
Déclarations des types et méthodes utilisés par les mécanismes d'échange de messages.
String getEnvironmentVariable(const String &name)
Variable d'environnement du nom name.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
std::int8_t Int8
Type entier signé sur 8 bits.
Ref< TrueType > createRef(Args &&... args)
Créé une instance de type TrueType avec les arguments Args et retourne une référence dessus.
ARCANE_MPI_EXPORT bool arcaneIsAcceleratorAwareMPI()
Indique si le runtime actuel de MPI a le support des accélérateurs.
Definition ArcaneMpi.cc:85
std::int64_t Int64
Type entier signé sur 64 bits.
Int32 Integer
Type représentant un entier.
Array< Byte > ByteArray
Tableau dynamique à une dimension de caractères.
Definition UtilsTypes.h:115
ConstArrayView< Int32 > Int32ConstArrayView
Equivalent C d'un tableau à une dimension d'entiers 32 bits.
Definition UtilsTypes.h:480
@ IK_Cell
Entité de maillage de genre maille.
void arcaneCallFunctionAndTerminateIfThrow(std::function< void()> function)
auto makeRef(InstanceType *t) -> Ref< InstanceType >
Créé une référence sur un pointeur.
std::int32_t Int32
Type entier signé sur 32 bits.
Infos pour construire un MpiParallelMng.
Infos pour construire un SequentialParallelMng.