Arcane  v3.16.0.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
MpiNeighborVariableSynchronizeDispatcher.cc
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/* MpiNeighborVariableSynchronizeDispatcher.cc (C) 2000-2025 */
9/* */
10/* Synchronisations des variables via MPI_Neighbor_alltoallv. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/FatalErrorException.h"
15#include "arcane/utils/NotSupportedException.h"
16#include "arcane/utils/CheckedConvert.h"
17#include "arcane/utils/MemoryView.h"
18
19#include "arcane/parallel/mpi/MpiParallelMng.h"
20#include "arcane/parallel/mpi/MpiTimeInterval.h"
21#include "arcane/parallel/mpi/IVariableSynchronizerMpiCommunicator.h"
22#include "arcane/parallel/IStat.h"
23
24#include "arcane/impl/IDataSynchronizeBuffer.h"
25#include "arcane/impl/IDataSynchronizeImplementation.h"
26#include "arcane/impl/DataSynchronizeInfo.h"
27
28#include "arccore/message_passing_mpi/internal/MpiAdapter.h"
29
30/*---------------------------------------------------------------------------*/
31/*---------------------------------------------------------------------------*/
32/*
33 * Cette implémentation utilise la fonction MPI_Neighbor_alltoallv pour
34 * les synchronisations. Cette fonction est disponible dans la version 3.1
35 * de MPI.
36 */
37/*---------------------------------------------------------------------------*/
38/*---------------------------------------------------------------------------*/
39
40namespace Arcane
41{
42
43/*---------------------------------------------------------------------------*/
44/*---------------------------------------------------------------------------*/
45/*
46 * \brief Implémentation de la synchronisations des variables via
47 * MPI_Neighbor_alltoallv().
48 */
49class MpiNeighborVariableSynchronizerDispatcher
51{
52 public:
53
54 class Factory;
55 explicit MpiNeighborVariableSynchronizerDispatcher(Factory* f);
56
57 public:
58
59 void compute() override;
60 void beginSynchronize(IDataSynchronizeBuffer* buf) override;
61 void endSynchronize(IDataSynchronizeBuffer* buf) override;
62
63 private:
64
65 MpiParallelMng* m_mpi_parallel_mng = nullptr;
66 UniqueArray<int> m_mpi_send_counts;
67 UniqueArray<int> m_mpi_receive_counts;
68 UniqueArray<int> m_mpi_send_displacements;
69 UniqueArray<int> m_mpi_receive_displacements;
70 Ref<IVariableSynchronizerMpiCommunicator> m_synchronizer_communicator;
71};
72
73/*---------------------------------------------------------------------------*/
74/*---------------------------------------------------------------------------*/
75
78{
79 public:
80
81 Factory(MpiParallelMng* mpi_pm, Ref<IVariableSynchronizerMpiCommunicator> synchronizer_communicator)
82 : m_mpi_parallel_mng(mpi_pm)
83 , m_synchronizer_communicator(synchronizer_communicator)
84 {}
85
86 Ref<IDataSynchronizeImplementation> createInstance() override
87 {
88 auto* x = new MpiNeighborVariableSynchronizerDispatcher(this);
90 }
91
92 public:
93
94 MpiParallelMng* m_mpi_parallel_mng = nullptr;
95 Ref<IVariableSynchronizerMpiCommunicator> m_synchronizer_communicator;
96};
97
98/*---------------------------------------------------------------------------*/
99/*---------------------------------------------------------------------------*/
100
102arcaneCreateMpiNeighborVariableSynchronizerFactory(MpiParallelMng* mpi_pm,
104{
105 auto* x = new MpiNeighborVariableSynchronizerDispatcher::Factory(mpi_pm, sync_communicator);
107}
108
109/*---------------------------------------------------------------------------*/
110/*---------------------------------------------------------------------------*/
111
112MpiNeighborVariableSynchronizerDispatcher::
113MpiNeighborVariableSynchronizerDispatcher(Factory* f)
114: m_mpi_parallel_mng(f->m_mpi_parallel_mng)
115, m_synchronizer_communicator(f->m_synchronizer_communicator)
116{
117}
118
119/*---------------------------------------------------------------------------*/
120/*---------------------------------------------------------------------------*/
121
122void MpiNeighborVariableSynchronizerDispatcher::
123beginSynchronize(IDataSynchronizeBuffer* buf)
124{
125 // Ne fait rien au niveau MPI dans cette partie car cette implémentation
126 // ne supporte pas encore l'asynchronisme.
127 // On se contente de recopier les valeurs des variables dans le buffer d'envoi
128 // pour permettre ensuite de modifier les valeurs de la variable entre
129 // le beginSynchronize() et le endSynchronize().
130
131 double send_copy_time = 0.0;
132 {
133 MpiTimeInterval tit(&send_copy_time);
134
135 // Recopie les buffers d'envoi
136 buf->copyAllSend();
137 }
138 Int64 total_share_size = buf->totalSendSize();
139 m_mpi_parallel_mng->stat()->add("SyncSendCopy", send_copy_time, total_share_size);
140}
141
142/*---------------------------------------------------------------------------*/
143/*---------------------------------------------------------------------------*/
144
145void MpiNeighborVariableSynchronizerDispatcher::
146endSynchronize(IDataSynchronizeBuffer* buf)
147{
148 const Int32 nb_message = buf->nbRank();
149
150 auto* sync_communicator = m_synchronizer_communicator.get();
151 ARCANE_CHECK_POINTER(sync_communicator);
152
153 MPI_Comm communicator = sync_communicator->communicator();
154 if (communicator == MPI_COMM_NULL)
155 ARCANE_FATAL("Invalid null communicator");
156
157 MpiParallelMng* pm = m_mpi_parallel_mng;
158 const MPI_Datatype mpi_dt = MP::Mpi::MpiBuiltIn::datatype(Byte());
159
160 double copy_time = 0.0;
161 double wait_time = 0.0;
162
163 if (!buf->hasGlobalBuffer())
164 ARCANE_THROW(NotSupportedException,"Can not use MPI_Neighbor_alltoallv when hasGlobalBufer() is false");
165
166 for (Integer i = 0; i < nb_message; ++i) {
167 Int32 nb_send = CheckedConvert::toInt32(buf->sendBuffer(i).bytes().size());
168 Int32 nb_receive = CheckedConvert::toInt32(buf->receiveBuffer(i).bytes().size());
169 Int32 send_displacement = CheckedConvert::toInt32(buf->sendDisplacement(i));
170 Int32 receive_displacement = CheckedConvert::toInt32(buf->receiveDisplacement(i));
171
172 m_mpi_send_counts[i] = nb_send;
173 m_mpi_receive_counts[i] = nb_receive;
174 m_mpi_send_displacements[i] = send_displacement;
175 m_mpi_receive_displacements[i] = receive_displacement;
176 }
177
178 {
179 MpiTimeInterval tit(&wait_time);
180 auto send_buf = buf->globalSendBuffer();
181 auto receive_buf = buf->globalReceiveBuffer();
182 MPI_Neighbor_alltoallv(send_buf.data(), m_mpi_send_counts.data(), m_mpi_send_displacements.data(), mpi_dt,
183 receive_buf.data(), m_mpi_receive_counts.data(), m_mpi_receive_displacements.data(), mpi_dt,
184 communicator);
185 }
186
187 // Recopie les valeurs recues
188 {
189 MpiTimeInterval tit(&copy_time);
190 buf->copyAllReceive();
191 }
192
193 Int64 total_ghost_size = buf->totalReceiveSize();
194 Int64 total_share_size = buf->totalSendSize();
195 Int64 total_size = total_ghost_size + total_share_size;
196 pm->stat()->add("SyncCopy", copy_time, total_ghost_size);
197 pm->stat()->add("SyncWait", wait_time, total_size);
198}
199
200/*---------------------------------------------------------------------------*/
201/*---------------------------------------------------------------------------*/
202
203void MpiNeighborVariableSynchronizerDispatcher::
204compute()
205{
206 DataSynchronizeInfo* sync_info = _syncInfo();
207 ARCANE_CHECK_POINTER(sync_info);
208
209 auto* sync_communicator = m_synchronizer_communicator.get();
210 ARCANE_CHECK_POINTER(sync_communicator);
211
212 const Int32 nb_message = sync_info->size();
213
214 // Certaines versions de OpenMPI (avant la 4.1) plantent s'ils n'y a pas
215 // de messages et qu'un des tableaux suivant est vide. Pour contourner
216 // ce problème on alloue un tableau de taille 1.
217 Int32 size = nb_message;
218 if (size==0)
219 size = 1;
220
221 m_mpi_send_counts.resize(size);
222 m_mpi_receive_counts.resize(size);
223 m_mpi_send_displacements.resize(size);
224 m_mpi_receive_displacements.resize(size);
225
226 m_mpi_send_counts.fill(0);
227 m_mpi_receive_counts.fill(0);
228 m_mpi_send_displacements.fill(0);
229 m_mpi_receive_displacements.fill(0);
230}
231
232/*---------------------------------------------------------------------------*/
233/*---------------------------------------------------------------------------*/
234
235/*---------------------------------------------------------------------------*/
236/*---------------------------------------------------------------------------*/
237
238} // End namespace Arcane
239
240/*---------------------------------------------------------------------------*/
241/*---------------------------------------------------------------------------*/
#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.
Buffer générique pour la synchronisation de données.
Interface d'une fabrique dispatcher générique.
Gestionnaire du parallélisme utilisant MPI.
Référence à une instance.
Vecteur 1D de données avec sémantique par valeur (style STL).
Int32 toInt32(Int64 v)
Converti un Int64 en un Int32.
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
std::int64_t Int64
Type entier signé sur 64 bits.
Int32 Integer
Type représentant un entier.
unsigned char Byte
Type d'un octet.
Definition BaseTypes.h:43
auto makeRef(InstanceType *t) -> Ref< InstanceType >
Créé une référence sur un pointeur.
std::int32_t Int32
Type entier signé sur 32 bits.