Arcane  v3.14.10.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-2023 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-2023 */
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/MpiAdapter.h"
21#include "arcane/parallel/mpi/MpiTimeInterval.h"
22#include "arcane/parallel/mpi/IVariableSynchronizerMpiCommunicator.h"
23#include "arcane/parallel/IStat.h"
24
25#include "arcane/impl/IDataSynchronizeBuffer.h"
26#include "arcane/impl/IDataSynchronizeImplementation.h"
27#include "arcane/impl/DataSynchronizeInfo.h"
28
29/*---------------------------------------------------------------------------*/
30/*---------------------------------------------------------------------------*/
31/*
32 * Cette implémentation utilise la fonction MPI_Neighbor_alltoallv pour
33 * les synchronisations. Cette fonction est disponible dans la version 3.1
34 * de MPI.
35 */
36/*---------------------------------------------------------------------------*/
37/*---------------------------------------------------------------------------*/
38
39namespace Arcane
40{
41
42/*---------------------------------------------------------------------------*/
43/*---------------------------------------------------------------------------*/
44/*
45 * \brief Implémentation de la synchronisations des variables via
46 * MPI_Neighbor_alltoallv().
47 */
50{
51 public:
52
53 class Factory;
55
56 public:
57
58 void compute() override;
59 void beginSynchronize(IDataSynchronizeBuffer* buf) override;
60 void endSynchronize(IDataSynchronizeBuffer* buf) override;
61
62 private:
63
64 MpiParallelMng* m_mpi_parallel_mng = nullptr;
65 UniqueArray<int> m_mpi_send_counts;
66 UniqueArray<int> m_mpi_receive_counts;
67 UniqueArray<int> m_mpi_send_displacements;
68 UniqueArray<int> m_mpi_receive_displacements;
69 Ref<IVariableSynchronizerMpiCommunicator> m_synchronizer_communicator;
70};
71
72/*---------------------------------------------------------------------------*/
73/*---------------------------------------------------------------------------*/
74
77{
78 public:
79
81 : m_mpi_parallel_mng(mpi_pm)
82 , m_synchronizer_communicator(synchronizer_communicator)
83 {}
84
85 Ref<IDataSynchronizeImplementation> createInstance() override
86 {
89 }
90
91 public:
92
93 MpiParallelMng* m_mpi_parallel_mng = nullptr;
94 Ref<IVariableSynchronizerMpiCommunicator> m_synchronizer_communicator;
95};
96
97/*---------------------------------------------------------------------------*/
98/*---------------------------------------------------------------------------*/
99
101arcaneCreateMpiNeighborVariableSynchronizerFactory(MpiParallelMng* mpi_pm,
103{
106}
107
108/*---------------------------------------------------------------------------*/
109/*---------------------------------------------------------------------------*/
110
111MpiNeighborVariableSynchronizerDispatcher::
112MpiNeighborVariableSynchronizerDispatcher(Factory* f)
113: m_mpi_parallel_mng(f->m_mpi_parallel_mng)
114, m_synchronizer_communicator(f->m_synchronizer_communicator)
115{
116}
117
118/*---------------------------------------------------------------------------*/
119/*---------------------------------------------------------------------------*/
120
121void MpiNeighborVariableSynchronizerDispatcher::
122beginSynchronize(IDataSynchronizeBuffer* buf)
123{
124 // Ne fait rien au niveau MPI dans cette partie car cette implémentation
125 // ne supporte pas encore l'asynchronisme.
126 // On se contente de recopier les valeurs des variables dans le buffer d'envoi
127 // pour permettre ensuite de modifier les valeurs de la variable entre
128 // le beginSynchronize() et le endSynchronize().
129
130 double send_copy_time = 0.0;
131 {
132 MpiTimeInterval tit(&send_copy_time);
133
134 // Recopie les buffers d'envoi
135 buf->copyAllSend();
136 }
137 Int64 total_share_size = buf->totalSendSize();
138 m_mpi_parallel_mng->stat()->add("SyncSendCopy", send_copy_time, total_share_size);
139}
140
141/*---------------------------------------------------------------------------*/
142/*---------------------------------------------------------------------------*/
143
144void MpiNeighborVariableSynchronizerDispatcher::
145endSynchronize(IDataSynchronizeBuffer* buf)
146{
147 const Int32 nb_message = buf->nbRank();
148
149 auto* sync_communicator = m_synchronizer_communicator.get();
150 ARCANE_CHECK_POINTER(sync_communicator);
151
152 MPI_Comm communicator = sync_communicator->communicator();
153 if (communicator == MPI_COMM_NULL)
154 ARCANE_FATAL("Invalid null communicator");
155
156 MpiParallelMng* pm = m_mpi_parallel_mng;
157 const MPI_Datatype mpi_dt = MP::Mpi::MpiBuiltIn::datatype(Byte());
158
159 double copy_time = 0.0;
160 double wait_time = 0.0;
161
162 if (!buf->hasGlobalBuffer())
163 ARCANE_THROW(NotSupportedException,"Can not use MPI_Neighbor_alltoallv when hasGlobalBufer() is false");
164
165 for (Integer i = 0; i < nb_message; ++i) {
166 Int32 nb_send = CheckedConvert::toInt32(buf->sendBuffer(i).bytes().size());
167 Int32 nb_receive = CheckedConvert::toInt32(buf->receiveBuffer(i).bytes().size());
168 Int32 send_displacement = CheckedConvert::toInt32(buf->sendDisplacement(i));
169 Int32 receive_displacement = CheckedConvert::toInt32(buf->receiveDisplacement(i));
170
171 m_mpi_send_counts[i] = nb_send;
172 m_mpi_receive_counts[i] = nb_receive;
173 m_mpi_send_displacements[i] = send_displacement;
174 m_mpi_receive_displacements[i] = receive_displacement;
175 }
176
177 {
178 MpiTimeInterval tit(&wait_time);
179 auto send_buf = buf->globalSendBuffer();
180 auto receive_buf = buf->globalReceiveBuffer();
181 MPI_Neighbor_alltoallv(send_buf.data(), m_mpi_send_counts.data(), m_mpi_send_displacements.data(), mpi_dt,
182 receive_buf.data(), m_mpi_receive_counts.data(), m_mpi_receive_displacements.data(), mpi_dt,
183 communicator);
184 }
185
186 // Recopie les valeurs recues
187 {
188 MpiTimeInterval tit(&copy_time);
189 buf->copyAllReceive();
190 }
191
192 Int64 total_ghost_size = buf->totalReceiveSize();
193 Int64 total_share_size = buf->totalSendSize();
194 Int64 total_size = total_ghost_size + total_share_size;
195 pm->stat()->add("SyncCopy", copy_time, total_ghost_size);
196 pm->stat()->add("SyncWait", wait_time, total_size);
197}
198
199/*---------------------------------------------------------------------------*/
200/*---------------------------------------------------------------------------*/
201
202void MpiNeighborVariableSynchronizerDispatcher::
203compute()
204{
205 DataSynchronizeInfo* sync_info = _syncInfo();
206 ARCANE_CHECK_POINTER(sync_info);
207
208 auto* sync_communicator = m_synchronizer_communicator.get();
209 ARCANE_CHECK_POINTER(sync_communicator);
210
211 const Int32 nb_message = sync_info->size();
212
213 // Certaines versions de OpenMPI (avant la 4.1) plantent s'ils n'y a pas
214 // de messages et qu'un des tableaux suivant est vide. Pour contourner
215 // ce problème on alloue un tableau de taille 1.
216 Int32 size = nb_message;
217 if (size==0)
218 size = 1;
219
220 m_mpi_send_counts.resize(size);
221 m_mpi_receive_counts.resize(size);
222 m_mpi_send_displacements.resize(size);
223 m_mpi_receive_displacements.resize(size);
224
225 m_mpi_send_counts.fill(0);
226 m_mpi_receive_counts.fill(0);
227 m_mpi_send_displacements.fill(0);
228 m_mpi_receive_displacements.fill(0);
229}
230
231/*---------------------------------------------------------------------------*/
232/*---------------------------------------------------------------------------*/
233
234/*---------------------------------------------------------------------------*/
235/*---------------------------------------------------------------------------*/
236
237} // End namespace Arcane
238
239/*---------------------------------------------------------------------------*/
240/*---------------------------------------------------------------------------*/
#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.
virtual IStat * stat()=0
Gestionnaire des statistiques.
Lecteur des fichiers de maillage via la bibliothèque LIMA.
Definition Lima.cc:120
Gestionnaire du parallélisme utilisant MPI.
Parallel::IStat * stat() override
Gestionnaire des statistiques.
virtual void add(const String &name, double elapsed_time, Int64 msg_size)=0
Ajoute une statistique.
const T * data() const
Accès à la racine du tableau hors toute protection.
void resize(Int64 s)
Change le nombre d'éléments du tableau à s.
void fill(ConstReferenceType value)
Remplit le tableau avec la valeur value.
Int32 toInt32(Int64 v)
Converti un Int64 en un Int32.
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
unsigned char Byte
Type d'un octet.
Definition UtilsTypes.h:142