Arcane  v3.16.8.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
DataSynchronizeBuffer.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/* DataSynchronizeBuffer.cc (C) 2000-2025 */
9/* */
10/* Implémentation d'un buffer générique pour la synchronisation de données. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/impl/internal/DataSynchronizeBuffer.h"
15
16#include "arcane/utils/FatalErrorException.h"
17#include "arcane/utils/internal/MemoryBuffer.h"
18
19#include "arcane/impl/DataSynchronizeInfo.h"
20#include "arcane/impl/internal/IBufferCopier.h"
21
22#include "arcane/accelerator/core/Runner.h"
23#include "arcane/utils/FixedArray.h"
24#include "arccore/trace/ITraceMng.h"
25
26#include <cstddef>
27
28/*---------------------------------------------------------------------------*/
29/*---------------------------------------------------------------------------*/
30
31namespace Arcane
32{
33
34/*---------------------------------------------------------------------------*/
35/*---------------------------------------------------------------------------*/
36
37namespace
38{
40 constexpr Int64 ALIGNEMENT_SIZE = 64;
41 Int64 _applyPadding(Int64 original_size)
42 {
43 Int64 modulo = original_size % ALIGNEMENT_SIZE;
44 Int64 new_size = original_size;
45 if (modulo != 0)
46 new_size += (ALIGNEMENT_SIZE - modulo);
47 if ((new_size % ALIGNEMENT_SIZE) != 0)
48 ARCANE_FATAL("Bad padding");
49 return new_size;
50 }
51 void _checkAlignment(const void* address)
52 {
53 auto a = reinterpret_cast<intptr_t>(address);
54 intptr_t max_align = alignof(std::max_align_t);
55 intptr_t modulo = a % max_align;
56 if (modulo != 0)
57 ARCANE_FATAL("Address '{0}' is not aligned (align={1}, modulo={2})", address, max_align, modulo);
58 }
59} // namespace
60
61/*---------------------------------------------------------------------------*/
62/*---------------------------------------------------------------------------*/
63
66{
67 Int32 nb_rank = nbRank();
68 for (Int32 i = 0; i < nb_rank; ++i)
70 barrier();
71}
72
73/*---------------------------------------------------------------------------*/
74/*---------------------------------------------------------------------------*/
75
78{
79 Int32 nb_rank = nbRank();
80 for (Int32 i = 0; i < nb_rank; ++i)
82 barrier();
83}
84
85/*---------------------------------------------------------------------------*/
86/*---------------------------------------------------------------------------*/
87
88/*---------------------------------------------------------------------------*/
89/*---------------------------------------------------------------------------*/
90
92barrier()
93{
94 m_queue.barrier();
95}
96
97/*---------------------------------------------------------------------------*/
98/*---------------------------------------------------------------------------*/
99
103{
104 if (v.datatypeSize() != 1)
105 ARCANE_FATAL("Global buffer has to use a datatype of size 1 (current={0})", v.datatypeSize());
106 m_memory_view = v;
107}
108
109/*---------------------------------------------------------------------------*/
110/*---------------------------------------------------------------------------*/
111
113displacement(Int32 rank_index) const
114{
115 return m_displacements[rank_index][0];
116}
117
118/*---------------------------------------------------------------------------*/
119/*---------------------------------------------------------------------------*/
120
122localBufferSize(Int32 rank_index) const
123{
124 return m_local_buffer_size[rank_index];
125}
126
127/*---------------------------------------------------------------------------*/
128/*---------------------------------------------------------------------------*/
129
131localBuffer(Int32 rank_index) const
132{
133 std::byte* data = m_memory_view.data();
134 data += m_displacements[rank_index][0];
135 const Int64 nb_byte = m_local_buffer_size[rank_index];
136 return makeMutableMemoryView(data, 1, nb_byte);
137}
138
139/*---------------------------------------------------------------------------*/
140/*---------------------------------------------------------------------------*/
141
143dataLocalBuffer(Int32 rank_index, Int32 data_index) const
144{
145 std::byte* data = m_memory_view.data();
146 data += m_displacements[rank_index][data_index];
147 const Int32 nb_item = m_buffer_info->nbItem(rank_index);
148 return makeMutableMemoryView(data, m_datatype_sizes[data_index], nb_item);
149}
150
151/*---------------------------------------------------------------------------*/
152/*---------------------------------------------------------------------------*/
153
155localIds(Int32 index) const
156{
157 return m_buffer_info->localIds(index);
158}
159
160/*---------------------------------------------------------------------------*/
161/*---------------------------------------------------------------------------*/
171initialize(ConstArrayView<Int32> datatype_sizes, const DataSynchronizeBufferInfoList* buffer_info)
172{
173 ARCANE_CHECK_POINTER(buffer_info);
174 m_buffer_info = buffer_info;
175 m_datatype_sizes = datatype_sizes;
176 const Int32 nb_data = datatype_sizes.size();
177 const Int32 nb_rank = buffer_info->nbRank();
178 m_displacements.resize(nb_rank, nb_data);
179 m_local_buffer_size.resize(nb_rank);
180
181 // Calcul l'offset pour chaque donnée de chaque rang
182 // en garantissant que l'offset est un multiple de ALIGNMENT_SIZE
183 Int64 data_offset = 0;
184 m_total_size = 0;
185 for (Int32 i = 0; i < nb_rank; ++i) {
186 const Int32 nb_item = buffer_info->nbItem(i);
187 Int64 local_buf_nb_byte = 0;
188 for (Int32 d = 0; d < nb_data; ++d) {
189 // Taille nécessaire pour la donnée \a d pour le rang \a i
190 // On fait un padding sur cette taille pour avoir
191 // un alignment spécifique.
192 const Int64 nb_byte = _applyPadding(nb_item * datatype_sizes[d]);
193 m_displacements[i][d] = data_offset;
194 local_buf_nb_byte += nb_byte;
195 data_offset += nb_byte;
196 }
197 m_local_buffer_size[i] = local_buf_nb_byte;
198 m_total_size += local_buf_nb_byte;
199 }
200}
201
202/*---------------------------------------------------------------------------*/
203/*---------------------------------------------------------------------------*/
204
205/*---------------------------------------------------------------------------*/
206/*---------------------------------------------------------------------------*/
207
208DataSynchronizeBufferBase::
209DataSynchronizeBufferBase(DataSynchronizeInfo* sync_info, Ref<IBufferCopier> copier)
210: m_sync_info(sync_info)
211, m_buffer_copier(copier)
212{
213}
214
215/*---------------------------------------------------------------------------*/
216/*---------------------------------------------------------------------------*/
217
219targetRank(Int32 index) const
220{
221 return m_sync_info->targetRank(index);
222}
223
224/*---------------------------------------------------------------------------*/
225/*---------------------------------------------------------------------------*/
226
228barrier()
229{
230 m_buffer_copier->barrier();
231}
232
233/*---------------------------------------------------------------------------*/
234/*---------------------------------------------------------------------------*/
240_compute(ConstArrayView<Int32> datatype_sizes)
241{
242 m_nb_rank = m_sync_info->size();
243
244 m_ghost_buffer_info.initialize(datatype_sizes, &m_sync_info->receiveInfo());
245 m_share_buffer_info.initialize(datatype_sizes, &m_sync_info->sendInfo());
246 m_compare_sync_buffer_info.initialize(datatype_sizes, &m_sync_info->receiveInfo());
247
249}
250
251/*---------------------------------------------------------------------------*/
252/*---------------------------------------------------------------------------*/
265{
266 const Int64 total_ghost_buffer = m_ghost_buffer_info.totalSize();
267 const Int64 total_share_buffer = m_share_buffer_info.totalSize();
268 Int64 total_compare_buffer = 0;
269 if (m_is_compare_sync_values)
270 total_compare_buffer = m_compare_sync_buffer_info.totalSize();
271
272 Int64 total_size = total_ghost_buffer + total_share_buffer + total_compare_buffer;
273 m_memory->resize(total_size);
274
275 Int64 share_offset = total_ghost_buffer;
276 Int64 check_sync_offset = share_offset + total_share_buffer;
277
278 Span<std::byte> buffer_span = m_memory->bytes();
279 auto s1 = buffer_span.subspan(0, share_offset);
280 m_ghost_buffer_info.setGlobalBuffer(makeMutableMemoryView(s1.data(), 1, total_ghost_buffer));
281 auto s2 = buffer_span.subspan(share_offset, total_share_buffer);
282 m_share_buffer_info.setGlobalBuffer(makeMutableMemoryView(s2.data(), 1, total_share_buffer));
283 if (m_is_compare_sync_values) {
284 auto s3 = buffer_span.subspan(check_sync_offset, total_ghost_buffer);
285 m_compare_sync_buffer_info.setGlobalBuffer(makeMutableMemoryView(s3.data(), 1, total_ghost_buffer));
286 }
287}
288
289/*---------------------------------------------------------------------------*/
290/*---------------------------------------------------------------------------*/
291
292/*---------------------------------------------------------------------------*/
293/*---------------------------------------------------------------------------*/
294
297{
298 m_ghost_buffer_info.checkValid();
299
300 MutableMemoryView var_values = dataView();
301 ConstArrayView<Int32> indexes = m_ghost_buffer_info.localIds(index);
302 ConstMemoryView local_buffer = m_ghost_buffer_info.dataLocalBuffer(index, 0);
303
304 m_buffer_copier->copyFromBufferAsync(indexes, local_buffer, var_values);
305}
306
307/*---------------------------------------------------------------------------*/
308/*---------------------------------------------------------------------------*/
309
311copySendAsync(Int32 index)
312{
313 m_share_buffer_info.checkValid();
314
315 ConstMemoryView var_values = dataView();
316 ConstArrayView<Int32> indexes = m_share_buffer_info.localIds(index);
317 MutableMemoryView local_buffer = m_share_buffer_info.dataLocalBuffer(index, 0);
318 m_buffer_copier->copyToBufferAsync(indexes, local_buffer, var_values);
319}
320
321/*---------------------------------------------------------------------------*/
322/*---------------------------------------------------------------------------*/
323
325prepareSynchronize(bool is_compare_sync)
326{
327 m_is_compare_sync_values = is_compare_sync;
328
330
331 if (is_compare_sync) {
332 // Recopie dans le buffer de vérification les valeurs actuelles des mailles
333 // fantômes.
334 MutableMemoryView var_values = dataView();
335 Int32 nb_rank = nbRank();
336 for (Int32 i = 0; i < nb_rank; ++i) {
338 MutableMemoryView local_buffer = m_compare_sync_buffer_info.dataLocalBuffer(i, 0);
339 m_buffer_copier->copyToBufferAsync(indexes, local_buffer, var_values);
340 }
341 // Normalement pas besoin de faire une barrière, car ensuite il y aura les
342 // envois sur la même \a queue et ensuite une barrière.
343 }
344}
345
346/*---------------------------------------------------------------------------*/
347/*---------------------------------------------------------------------------*/
358{
359 if (!m_is_compare_sync_values)
360 return {};
361 ConstMemoryView reference_buffer = m_compare_sync_buffer_info.globalBuffer();
362 ConstMemoryView receive_buffer = m_ghost_buffer_info.globalBuffer();
363 Span<const std::byte> reference_bytes = reference_buffer.bytes();
364 Span<const std::byte> receive_bytes = receive_buffer.bytes();
365 Int64 reference_size = reference_bytes.size();
366 Int64 receive_size = receive_bytes.size();
367 if (reference_size != receive_size)
368 ARCANE_FATAL("Incoherent buffer size ref={0} receive={1}", reference_size, receive_size);
369 // TODO: gérer le cas où la mémoire est sur le device
370
372 bool is_same = std::memcmp(reference_bytes.data(), receive_bytes.data(), reference_size) == 0;
374 return result;
375}
376
377/*---------------------------------------------------------------------------*/
378/*---------------------------------------------------------------------------*/
379
380/*---------------------------------------------------------------------------*/
381/*---------------------------------------------------------------------------*/
387prepareSynchronize([[maybe_unused]] bool is_compare_sync)
388{
390}
391
392/*---------------------------------------------------------------------------*/
393/*---------------------------------------------------------------------------*/
394
396copyReceiveAsync(Int32 rank_index)
397{
398 IBufferCopier* copier = m_buffer_copier.get();
399 m_ghost_buffer_info.checkValid();
400
401 ConstArrayView<Int32> local_ids = m_ghost_buffer_info.localIds(rank_index);
402 Int32 data_index = 0;
403 for (MutableMemoryView var_values : m_data_views) {
404 ConstMemoryView local_buffer = m_ghost_buffer_info.dataLocalBuffer(rank_index, data_index);
405 _checkAlignment(local_buffer.data());
406 if (!local_buffer.bytes().empty())
407 copier->copyFromBufferAsync(local_ids, local_buffer, var_values);
408 ++data_index;
409 }
410}
411
412/*---------------------------------------------------------------------------*/
413/*---------------------------------------------------------------------------*/
414
416copySendAsync(Int32 rank_index)
417{
418 IBufferCopier* copier = m_buffer_copier.get();
419 m_ghost_buffer_info.checkValid();
420
421 ConstArrayView<Int32> local_ids = m_share_buffer_info.localIds(rank_index);
422 Int32 data_index = 0;
423 for (ConstMemoryView var_values : m_data_views) {
424 MutableMemoryView local_buffer = m_share_buffer_info.dataLocalBuffer(rank_index, data_index);
425 _checkAlignment(local_buffer.data());
426 if (!local_buffer.bytes().empty())
427 copier->copyToBufferAsync(local_ids, local_buffer, var_values);
428 ++data_index;
429 }
430}
431
432/*---------------------------------------------------------------------------*/
433/*---------------------------------------------------------------------------*/
434
435} // namespace Arcane
436
437/*---------------------------------------------------------------------------*/
438/*---------------------------------------------------------------------------*/
#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.
Vue constante d'un tableau de type T.
constexpr Integer size() const noexcept
Nombre d'éléments du tableau.
Vue constante sur une zone mémoire contigue contenant des éléments de taille fixe.
Definition MemoryView.h:38
constexpr SpanType bytes() const
Vue sous forme d'octets.
Definition MemoryView.h:107
constexpr const std::byte * data() const
Pointeur sur la zone mémoire.
Definition MemoryView.h:110
Int64 localBufferSize(Int32 rank_index) const
Taille (en octet) du buffer local pour le rang rank_index.
Int64 displacement(Int32 rank_index) const
Déplacement dans globalBuffer() pour le index-ème rang.
ConstArrayView< Int32 > localIds(Int32 index) const
Numéros locaux des entités pour le rang index.
Int64 m_total_size
Taille total (en octet) du buffer.
SmallArray< Int64 > m_local_buffer_size
Taille (en octet) de chaque buffer local.
MutableMemoryView m_memory_view
Vue sur la zone mémoire du buffer.
MutableMemoryView localBuffer(Int32 rank_index) const
Buffer pour le index-ème rang.
ConstArrayView< Int32 > m_datatype_sizes
Taille (en octet) du type de chaque donnée.
UniqueArray2< Int64 > m_displacements
Offset (en octet) dans globalBuffer() de chaque donnée.
MutableMemoryView dataLocalBuffer(Int32 rank_index, Int32 data_index) const
Buffer pour le index-ème rang et la data_index-ème donnée.
void setGlobalBuffer(MutableMemoryView v)
Positionne le buffer global.
void initialize(ConstArrayView< Int32 > datatype_sizes, const DataSynchronizeBufferInfoList *buffer_info)
Initialise les informations du buffer.
void barrier() final
Attend que les copies (copySendAsync() et copyReceiveAsync()) soient terminées.
Int32 targetRank(Int32 index) const final
Rang cible du index-ème rang.
void _allocateBuffers()
Calcul et alloue les tampons nécessaires aux envois et réceptions pour les synchronisations des varia...
BufferInfo m_compare_sync_buffer_info
Buffer pour tester si la synchronisation a modifié les valeurs des mailles fantômes.
Int32 nbRank() const final
Nombre de rangs.
BufferInfo m_share_buffer_info
Buffer pour toutes les données des entités partagées qui serviront en envoi.
void _compute(ConstArrayView< Int32 > datatype_sizes)
Calcule les informations pour la synchronisation.
BufferInfo m_ghost_buffer_info
Buffer pour toutes les données des entités fantômes qui serviront en réception.
Ref< MemoryBuffer > m_memory
Buffer contenant les données concaténées en envoi et réception.
Informations pour les messages d'envoi (share) ou de réception (ghost)
Int32 nbItem(Int32 index) const
Nombre d'entités pour le rang index.
Informations nécessaires pour synchroniser les entités sur un groupe.
Informations sur le résultat d'une synchronisation.
void barrier() override
Bloque tant que les copies ne sont pas terminées.
Interface pour copier des éléments entre deux zones avec indexation.
virtual void barrier()=0
Attend que les copies (copySendAsync() et copyReceiveAsync()) soient terminées.
virtual void copyAllSend()
Recopie dans le buffer d'envoi toute les données.
virtual void copyAllReceive()
Recopie toutes les données depuis le buffer de réception.
virtual void copyReceiveAsync(Int32 index)=0
Recopie dans les données depuis le buffer de réception du index-ème rang.
virtual void copySendAsync(Int32 index)=0
Recopie dans le buffer d'envoi les données du index-ème rang.
virtual Int32 nbRank() const =0
Nombre de rangs.
SmallArray< Int32 > m_datatype_sizes
Tableau contenant les tailles des types de donnée.
void prepareSynchronize(bool is_compare_sync) override
void copyReceiveAsync(Int32 rank_index) final
Recopie dans les données depuis le buffer de réception du index-ème rang.
SmallArray< MutableMemoryView > m_data_views
Vue sur les données de la variable.
void copySendAsync(Int32 rank_index) final
Recopie dans le buffer d'envoi les données du index-ème rang.
Vue modifiable sur une zone mémoire contigue contenant des éléments de taille fixe.
Definition MemoryView.h:156
constexpr Int32 datatypeSize() const
Taille du type de donnée associé (1 par défaut)
Definition MemoryView.h:224
constexpr std::byte * data() const
Pointeur sur la zone mémoire.
Definition MemoryView.h:218
constexpr SpanType bytes() const
Vue sous forme d'octets.
Definition MemoryView.h:215
Référence à une instance.
DataSynchronizeResult finalizeSynchronize()
Termine la synchronisation.
void prepareSynchronize(bool is_compare_sync) override
Prépare la synchronisation.
FixedArray< Int32, 1 > m_datatype_sizes
Tableau contenant les tailles des types de donnée.
void copyReceiveAsync(Int32 index) final
Recopie dans les données depuis le buffer de réception du index-ème rang.
void copySendAsync(Int32 index) final
Recopie dans le buffer d'envoi les données du index-ème rang.
MutableMemoryView dataView()
Zone mémoire contenant les valeurs de la donnée à synchroniser.
constexpr __host__ __device__ bool empty() const noexcept
Retourne true si le tableau est vide (dimension nulle)
Definition Span.h:375
constexpr __host__ __device__ SizeType size() const noexcept
Retourne la taille du tableau.
Definition Span.h:212
constexpr __host__ __device__ pointer data() const noexcept
Pointeur sur le début de la vue.
Definition Span.h:422
Vue d'un tableau d'éléments de type T.
Definition Span.h:513
constexpr __host__ __device__ Span< T, DynExtent > subspan(Int64 abegin, Int64 asize) const
Sous-vue à partir de l'élément abegin et contenant asize éléments.
Definition Span.h:593
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
MutableMemoryView makeMutableMemoryView(void *ptr, Int32 datatype_size, Int64 nb_element)
Créé une vue mémoire modifiable.
std::int64_t Int64
Type entier signé sur 64 bits.
@ Different
Valeurs différentes avant et après la synchronisation.
@ Same
Même valeurs avant et après la synchronisation.
std::int32_t Int32
Type entier signé sur 32 bits.