Arcane  4.2.1.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-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/* DataSynchronizeBuffer.cc (C) 2000-2026 */
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 "arcane/utils/ITraceMng.h"
25
26#include <cstddef>
27#include <cstring>
28
29/*---------------------------------------------------------------------------*/
30/*---------------------------------------------------------------------------*/
31
32namespace Arcane
33{
34
35/*---------------------------------------------------------------------------*/
36/*---------------------------------------------------------------------------*/
37
38namespace
39{
41 constexpr Int64 ALIGNEMENT_SIZE = 64;
42 Int64 _applyPadding(Int64 original_size)
43 {
44 Int64 modulo = original_size % ALIGNEMENT_SIZE;
45 Int64 new_size = original_size;
46 if (modulo != 0)
47 new_size += (ALIGNEMENT_SIZE - modulo);
48 if ((new_size % ALIGNEMENT_SIZE) != 0)
49 ARCANE_FATAL("Bad padding");
50 return new_size;
51 }
52 void _checkAlignment(const void* address)
53 {
54 auto a = reinterpret_cast<intptr_t>(address);
55 intptr_t max_align = alignof(std::max_align_t);
56 intptr_t modulo = a % max_align;
57 if (modulo != 0)
58 ARCANE_FATAL("Address '{0}' is not aligned (align={1}, modulo={2})", address, max_align, modulo);
59 }
60} // namespace
61
62/*---------------------------------------------------------------------------*/
63/*---------------------------------------------------------------------------*/
64
67{
68 Int32 nb_rank = nbRank();
69 for (Int32 i = 0; i < nb_rank; ++i)
71 barrier();
72}
73
74/*---------------------------------------------------------------------------*/
75/*---------------------------------------------------------------------------*/
76
79{
80 Int32 nb_rank = nbRank();
81 for (Int32 i = 0; i < nb_rank; ++i)
83 barrier();
84}
85
86/*---------------------------------------------------------------------------*/
87/*---------------------------------------------------------------------------*/
88
89/*---------------------------------------------------------------------------*/
90/*---------------------------------------------------------------------------*/
91
93barrier()
94{
95 m_queue.barrier();
96}
97
98/*---------------------------------------------------------------------------*/
99/*---------------------------------------------------------------------------*/
100
104{
105 if (v.datatypeSize() != 1)
106 ARCANE_FATAL("Global buffer has to use a datatype of size 1 (current={0})", v.datatypeSize());
107 m_memory_view = v;
108}
109
110/*---------------------------------------------------------------------------*/
111/*---------------------------------------------------------------------------*/
112
114displacement(Int32 rank_index) const
115{
116 return m_displacements[rank_index][0];
117}
118
119/*---------------------------------------------------------------------------*/
120/*---------------------------------------------------------------------------*/
121
123localBufferSize(Int32 rank_index) const
124{
125 return m_local_buffer_size[rank_index];
126}
127
128/*---------------------------------------------------------------------------*/
129/*---------------------------------------------------------------------------*/
130
132localBuffer(Int32 rank_index) const
133{
134 std::byte* data = m_memory_view.data();
135 data += m_displacements[rank_index][0];
136 const Int64 nb_byte = m_local_buffer_size[rank_index];
137 return makeMutableMemoryView(data, 1, nb_byte);
138}
139
140/*---------------------------------------------------------------------------*/
141/*---------------------------------------------------------------------------*/
142
144dataLocalBuffer(Int32 rank_index, Int32 data_index) const
145{
146 std::byte* data = m_memory_view.data();
147 data += m_displacements[rank_index][data_index];
148 const Int32 nb_item = m_buffer_info->nbItem(rank_index);
149 return makeMutableMemoryView(data, m_datatype_sizes[data_index], nb_item);
150}
151
152/*---------------------------------------------------------------------------*/
153/*---------------------------------------------------------------------------*/
154
156localIds(Int32 index) const
157{
158 return m_buffer_info->localIds(index);
159}
160
161/*---------------------------------------------------------------------------*/
162/*---------------------------------------------------------------------------*/
163
173initialize(ConstArrayView<Int32> datatype_sizes, const DataSynchronizeBufferInfoList* buffer_info)
174{
175 ARCANE_CHECK_POINTER(buffer_info);
176 m_buffer_info = buffer_info;
177 m_datatype_sizes = datatype_sizes;
178 const Int32 nb_data = datatype_sizes.size();
179 const Int32 nb_rank = buffer_info->nbRank();
180 m_displacements.resize(nb_rank, nb_data);
181 m_local_buffer_size.resize(nb_rank);
182
183 // Calcul l'offset pour chaque donnée de chaque rang
184 // en garantissant que l'offset est un multiple de ALIGNMENT_SIZE
185 Int64 data_offset = 0;
186 m_total_size = 0;
187 for (Int32 i = 0; i < nb_rank; ++i) {
188 const Int32 nb_item = buffer_info->nbItem(i);
189 Int64 local_buf_nb_byte = 0;
190 for (Int32 d = 0; d < nb_data; ++d) {
191 // Taille nécessaire pour la donnée \a d pour le rang \a i
192 // On fait un padding sur cette taille pour avoir
193 // un alignment spécifique.
194 const Int64 nb_byte = _applyPadding(nb_item * datatype_sizes[d]);
195 m_displacements[i][d] = data_offset;
196 local_buf_nb_byte += nb_byte;
197 data_offset += nb_byte;
198 }
199 m_local_buffer_size[i] = local_buf_nb_byte;
200 m_total_size += local_buf_nb_byte;
201 }
202}
203
204/*---------------------------------------------------------------------------*/
205/*---------------------------------------------------------------------------*/
206
207/*---------------------------------------------------------------------------*/
208/*---------------------------------------------------------------------------*/
209
210DataSynchronizeBufferBase::
211DataSynchronizeBufferBase(DataSynchronizeInfo* sync_info, Ref<IBufferCopier> copier)
212: m_sync_info(sync_info)
213, m_buffer_copier(copier)
214{
215}
216
217/*---------------------------------------------------------------------------*/
218/*---------------------------------------------------------------------------*/
219
221targetRank(Int32 index) const
222{
223 return m_sync_info->targetRank(index);
224}
225
226/*---------------------------------------------------------------------------*/
227/*---------------------------------------------------------------------------*/
228
230barrier()
231{
232 m_buffer_copier->barrier();
233}
234
235/*---------------------------------------------------------------------------*/
236/*---------------------------------------------------------------------------*/
237
243_compute(ConstArrayView<Int32> datatype_sizes)
244{
245 m_nb_rank = m_sync_info->size();
246
247 m_ghost_buffer_info.initialize(datatype_sizes, &m_sync_info->receiveInfo());
248 m_share_buffer_info.initialize(datatype_sizes, &m_sync_info->sendInfo());
249 m_compare_sync_buffer_info.initialize(datatype_sizes, &m_sync_info->receiveInfo());
250
252}
253
254/*---------------------------------------------------------------------------*/
255/*---------------------------------------------------------------------------*/
256
269{
270 const Int64 total_ghost_buffer = m_ghost_buffer_info.totalSize();
271 const Int64 total_share_buffer = m_share_buffer_info.totalSize();
272 Int64 total_compare_buffer = 0;
273 if (m_is_compare_sync_values)
274 total_compare_buffer = m_compare_sync_buffer_info.totalSize();
275
276 Int64 total_size = total_ghost_buffer + total_share_buffer + total_compare_buffer;
277 m_memory->resize(total_size);
278
279 Int64 share_offset = total_ghost_buffer;
280 Int64 check_sync_offset = share_offset + total_share_buffer;
281
282 Span<std::byte> buffer_span = m_memory->bytes();
283 auto s1 = buffer_span.subspan(0, share_offset);
284 m_ghost_buffer_info.setGlobalBuffer(makeMutableMemoryView(s1.data(), 1, total_ghost_buffer));
285 auto s2 = buffer_span.subspan(share_offset, total_share_buffer);
286 m_share_buffer_info.setGlobalBuffer(makeMutableMemoryView(s2.data(), 1, total_share_buffer));
287 if (m_is_compare_sync_values) {
288 auto s3 = buffer_span.subspan(check_sync_offset, total_ghost_buffer);
289 m_compare_sync_buffer_info.setGlobalBuffer(makeMutableMemoryView(s3.data(), 1, total_ghost_buffer));
290 }
291}
292
293/*---------------------------------------------------------------------------*/
294/*---------------------------------------------------------------------------*/
295
296/*---------------------------------------------------------------------------*/
297/*---------------------------------------------------------------------------*/
298
301{
302 m_ghost_buffer_info.checkValid();
303
304 MutableMemoryView var_values = dataView();
305 ConstArrayView<Int32> indexes = m_ghost_buffer_info.localIds(index);
306 ConstMemoryView local_buffer = m_ghost_buffer_info.dataLocalBuffer(index, 0);
307
308 m_buffer_copier->copyFromBufferAsync(indexes, local_buffer, var_values);
309}
310
311/*---------------------------------------------------------------------------*/
312/*---------------------------------------------------------------------------*/
313
315copySendAsync(Int32 index)
316{
317 m_share_buffer_info.checkValid();
318
319 ConstMemoryView var_values = dataView();
320 ConstArrayView<Int32> indexes = m_share_buffer_info.localIds(index);
321 MutableMemoryView local_buffer = m_share_buffer_info.dataLocalBuffer(index, 0);
322 m_buffer_copier->copyToBufferAsync(indexes, local_buffer, var_values);
323}
324
325/*---------------------------------------------------------------------------*/
326/*---------------------------------------------------------------------------*/
327
329prepareSynchronize(bool is_compare_sync)
330{
331 m_is_compare_sync_values = is_compare_sync;
332
334
335 if (is_compare_sync) {
336 // Recopie dans le buffer de vérification les valeurs actuelles des mailles
337 // fantômes.
338 MutableMemoryView var_values = dataView();
339 Int32 nb_rank = nbRank();
340 for (Int32 i = 0; i < nb_rank; ++i) {
342 MutableMemoryView local_buffer = m_compare_sync_buffer_info.dataLocalBuffer(i, 0);
343 m_buffer_copier->copyToBufferAsync(indexes, local_buffer, var_values);
344 }
345 // Normalement pas besoin de faire une barrière, car ensuite il y aura les
346 // envois sur la même \a queue et ensuite une barrière.
347 }
348}
349
350/*---------------------------------------------------------------------------*/
351/*---------------------------------------------------------------------------*/
352
363{
364 if (!m_is_compare_sync_values)
365 return {};
366 ConstMemoryView reference_buffer = m_compare_sync_buffer_info.globalBuffer();
367 ConstMemoryView receive_buffer = m_ghost_buffer_info.globalBuffer();
368 Span<const std::byte> reference_bytes = reference_buffer.bytes();
369 Span<const std::byte> receive_bytes = receive_buffer.bytes();
370 Int64 reference_size = reference_bytes.size();
371 Int64 receive_size = receive_bytes.size();
372 if (reference_size != receive_size)
373 ARCANE_FATAL("Incoherent buffer size ref={0} receive={1}", reference_size, receive_size);
374 // TODO: gérer le cas où la mémoire est sur le device
375
377 bool is_same = std::memcmp(reference_bytes.data(), receive_bytes.data(), reference_size) == 0;
379 return result;
380}
381
382/*---------------------------------------------------------------------------*/
383/*---------------------------------------------------------------------------*/
384
385/*---------------------------------------------------------------------------*/
386/*---------------------------------------------------------------------------*/
387
393prepareSynchronize([[maybe_unused]] bool is_compare_sync)
394{
396}
397
398/*---------------------------------------------------------------------------*/
399/*---------------------------------------------------------------------------*/
400
402copyReceiveAsync(Int32 rank_index)
403{
404 IBufferCopier* copier = m_buffer_copier.get();
405 m_ghost_buffer_info.checkValid();
406
407 ConstArrayView<Int32> local_ids = m_ghost_buffer_info.localIds(rank_index);
408 Int32 data_index = 0;
409 for (MutableMemoryView var_values : m_data_views) {
410 ConstMemoryView local_buffer = m_ghost_buffer_info.dataLocalBuffer(rank_index, data_index);
411 _checkAlignment(local_buffer.data());
412 if (!local_buffer.bytes().empty())
413 copier->copyFromBufferAsync(local_ids, local_buffer, var_values);
414 ++data_index;
415 }
416}
417
418/*---------------------------------------------------------------------------*/
419/*---------------------------------------------------------------------------*/
420
422copySendAsync(Int32 rank_index)
423{
424 IBufferCopier* copier = m_buffer_copier.get();
425 m_ghost_buffer_info.checkValid();
426
427 ConstArrayView<Int32> local_ids = m_share_buffer_info.localIds(rank_index);
428 Int32 data_index = 0;
429 for (ConstMemoryView var_values : m_data_views) {
430 MutableMemoryView local_buffer = m_share_buffer_info.dataLocalBuffer(rank_index, data_index);
431 _checkAlignment(local_buffer.data());
432 if (!local_buffer.bytes().empty())
433 copier->copyToBufferAsync(local_ids, local_buffer, var_values);
434 ++data_index;
435 }
436}
437
438/*---------------------------------------------------------------------------*/
439/*---------------------------------------------------------------------------*/
440
441} // namespace Arcane
442
443/*---------------------------------------------------------------------------*/
444/*---------------------------------------------------------------------------*/
#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.
constexpr SpanType bytes() const
Vue sous forme d'octets.
constexpr const std::byte * data() const
Pointeur sur la zone mémoire.
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.
constexpr Int32 datatypeSize() const
Taille du type de donnée associé (1 par défaut).
constexpr std::byte * data() const
Pointeur sur la zone mémoire.
constexpr SpanType bytes() const
Vue sous forme d'octets.
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__ pointer data() const noexcept
Pointeur sur le début de la vue.
Definition Span.h:537
constexpr __host__ __device__ bool empty() const noexcept
Retourne true si le tableau est vide (dimension nulle).
Definition Span.h:490
constexpr __host__ __device__ SizeType size() const noexcept
Retourne la taille du tableau.
Definition Span.h:325
Vue d'un tableau d'éléments de type T.
Definition Span.h:633
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:721
-- 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.
Definition MemoryView.cc:26
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.