Arcane  4.2.1.0
Developer documentation
Loading...
Searching...
No Matches
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/* Implementation of a generic buffer for data synchronization. */
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 // Calculates the offset for each data item from each rank
184 // ensuring that the offset is a multiple of 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 // Size needed for data \a d for rank \a i
192 // Padding is applied to this size to achieve
193 // a specific alignment.
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 // Recopy the current values of the ghost cells into the verification buffer.
337 MutableMemoryView var_values = dataView();
338 Int32 nb_rank = nbRank();
339 for (Int32 i = 0; i < nb_rank; ++i) {
341 MutableMemoryView local_buffer = m_compare_sync_buffer_info.dataLocalBuffer(i, 0);
342 m_buffer_copier->copyToBufferAsync(indexes, local_buffer, var_values);
343 }
344 // Normally no need to perform a barrier, because there will be the
345 // sends on the same queue and then a barrier.
346 }
347}
348
349/*---------------------------------------------------------------------------*/
350/*---------------------------------------------------------------------------*/
351
362{
363 if (!m_is_compare_sync_values)
364 return {};
365 ConstMemoryView reference_buffer = m_compare_sync_buffer_info.globalBuffer();
366 ConstMemoryView receive_buffer = m_ghost_buffer_info.globalBuffer();
367 Span<const std::byte> reference_bytes = reference_buffer.bytes();
368 Span<const std::byte> receive_bytes = receive_buffer.bytes();
369 Int64 reference_size = reference_bytes.size();
370 Int64 receive_size = receive_bytes.size();
371 if (reference_size != receive_size)
372 ARCANE_FATAL("Incoherent buffer size ref={0} receive={1}", reference_size, receive_size);
373 // TODO: handle the case where memory is on the device
374
376 bool is_same = std::memcmp(reference_bytes.data(), receive_bytes.data(), reference_size) == 0;
378 return result;
379}
380
381/*---------------------------------------------------------------------------*/
382/*---------------------------------------------------------------------------*/
383
384/*---------------------------------------------------------------------------*/
385/*---------------------------------------------------------------------------*/
386
391prepareSynchronize([[maybe_unused]] bool is_compare_sync)
392{
394}
395
396/*---------------------------------------------------------------------------*/
397/*---------------------------------------------------------------------------*/
398
400copyReceiveAsync(Int32 rank_index)
401{
402 IBufferCopier* copier = m_buffer_copier.get();
403 m_ghost_buffer_info.checkValid();
404
405 ConstArrayView<Int32> local_ids = m_ghost_buffer_info.localIds(rank_index);
406 Int32 data_index = 0;
407 for (MutableMemoryView var_values : m_data_views) {
408 ConstMemoryView local_buffer = m_ghost_buffer_info.dataLocalBuffer(rank_index, data_index);
409 _checkAlignment(local_buffer.data());
410 if (!local_buffer.bytes().empty())
411 copier->copyFromBufferAsync(local_ids, local_buffer, var_values);
412 ++data_index;
413 }
414}
415
416/*---------------------------------------------------------------------------*/
417/*---------------------------------------------------------------------------*/
418
420copySendAsync(Int32 rank_index)
421{
422 IBufferCopier* copier = m_buffer_copier.get();
423 m_ghost_buffer_info.checkValid();
424
425 ConstArrayView<Int32> local_ids = m_share_buffer_info.localIds(rank_index);
426 Int32 data_index = 0;
427 for (ConstMemoryView var_values : m_data_views) {
428 MutableMemoryView local_buffer = m_share_buffer_info.dataLocalBuffer(rank_index, data_index);
429 _checkAlignment(local_buffer.data());
430 if (!local_buffer.bytes().empty())
431 copier->copyToBufferAsync(local_ids, local_buffer, var_values);
432 ++data_index;
433 }
434}
435
436/*---------------------------------------------------------------------------*/
437/*---------------------------------------------------------------------------*/
438
439} // namespace Arcane
440
441/*---------------------------------------------------------------------------*/
442/*---------------------------------------------------------------------------*/
#define ARCANE_CHECK_POINTER(ptr)
Macro returning the pointer ptr if it is not null or throwing an exception if it is null.
#define ARCANE_FATAL(...)
Macro throwing a FatalErrorException.
Constant view of an array of type T.
constexpr Integer size() const noexcept
Number of elements in the array.
Constant view on a contiguous memory region containing fixed-size elements.
constexpr SpanType bytes() const
View in byte form.
constexpr const std::byte * data() const
Pointer to the memory region.
Int64 localBufferSize(Int32 rank_index) const
Size (in bytes) of the local buffer for rank rank_index.
Int64 displacement(Int32 rank_index) const
Displacement in globalBuffer() for the index-th rank.
ConstArrayView< Int32 > localIds(Int32 index) const
Local IDs of entities for rank index.
Int64 m_total_size
Total size (in bytes) of the buffer.
SmallArray< Int64 > m_local_buffer_size
Size (in bytes) of each local buffer.
MutableMemoryView m_memory_view
View onto the memory area of the buffer.
MutableMemoryView localBuffer(Int32 rank_index) const
Buffer for the index-th rank.
ConstArrayView< Int32 > m_datatype_sizes
Size (in bytes) of the type of each data item.
UniqueArray2< Int64 > m_displacements
Offset (in bytes) in globalBuffer() for each data item.
MutableMemoryView dataLocalBuffer(Int32 rank_index, Int32 data_index) const
Buffer for the index-th rank and the data_index-th data item.
void setGlobalBuffer(MutableMemoryView v)
Positions the global buffer.
void initialize(ConstArrayView< Int32 > datatype_sizes, const DataSynchronizeBufferInfoList *buffer_info)
Initializes the buffer information.
void barrier() final
Waits until the copies (copySendAsync() and copyReceiveAsync()) are finished.
Int32 targetRank(Int32 index) const final
Target rank of the index-th rank.
void _allocateBuffers()
Calculates and allocates the buffers necessary for sends and receives for 1D variable synchronization...
BufferInfo m_compare_sync_buffer_info
Buffer for testing if synchronization modified the values of ghost cells.
Int32 nbRank() const final
Number of ranks.
BufferInfo m_share_buffer_info
Buffer for all data of shared entities used for sending.
void _compute(ConstArrayView< Int32 > datatype_sizes)
Computes the information for the synchronization.
BufferInfo m_ghost_buffer_info
Buffer for all data of ghost entities used for reception.
Ref< MemoryBuffer > m_memory
Buffer containing the concatenated data for sending and receiving.
Information for sending (share) or receiving (ghost) messages.
Int32 nbItem(Int32 index) const
Number of entities for rank index.
Information necessary to synchronize entities across a group.
Information about the result of a synchronization.
void barrier() override
Blocks until the copies are finished.
Interface for copying elements between two regions with indexing.
virtual void barrier()=0
Waits until the copies (copySendAsync() and copyReceiveAsync()) are finished.
virtual void copyAllSend()
Copies all data into the send buffer.
virtual void copyAllReceive()
Copies all data from the receive buffer.
virtual void copyReceiveAsync(Int32 index)=0
Copies into the data from the receive buffer of the index-th rank.
virtual void copySendAsync(Int32 index)=0
Copies the data of the index-th rank into the send buffer.
virtual Int32 nbRank() const =0
Number of ranks.
SmallArray< Int32 > m_datatype_sizes
Array containing the sizes of the data types.
void prepareSynchronize(bool is_compare_sync) override
void copyReceiveAsync(Int32 rank_index) final
Copies into the data from the receive buffer of the index-th rank.
SmallArray< MutableMemoryView > m_data_views
View onto the data variables.
void copySendAsync(Int32 rank_index) final
Copies the data of the index-th rank into the send buffer.
Mutable view on a contiguous memory region containing fixed-size elements.
constexpr Int32 datatypeSize() const
Size of the associated data type (1 by default).
constexpr std::byte * data() const
Pointer to the memory region.
constexpr SpanType bytes() const
View in byte form.
Reference to an instance.
DataSynchronizeResult finalizeSynchronize()
Finalizes the synchronization.
void prepareSynchronize(bool is_compare_sync) override
Prepares the synchronization.
FixedArray< Int32, 1 > m_datatype_sizes
Array containing the sizes of the data types.
void copyReceiveAsync(Int32 index) final
Copies into the data from the receive buffer of the index-th rank.
void copySendAsync(Int32 index) final
Copies the data of the index-th rank into the send buffer.
MutableMemoryView dataView()
Memory area containing the values of the data to be synchronized.
constexpr __host__ __device__ pointer data() const noexcept
Pointer to the start of the view.
Definition Span.h:537
constexpr __host__ __device__ bool empty() const noexcept
Returns true if the array is empty (zero dimension).
Definition Span.h:490
constexpr __host__ __device__ SizeType size() const noexcept
Returns the size of the array.
Definition Span.h:325
View of an array of elements of type T.
Definition Span.h:633
constexpr __host__ __device__ Span< T, DynExtent > subspan(Int64 abegin, Int64 asize) const
Sub-view starting from element abegin and containing asize elements.
Definition Span.h:722
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
MutableMemoryView makeMutableMemoryView(void *ptr, Int32 datatype_size, Int64 nb_element)
Creates a mutable memory view.
Definition MemoryView.cc:26
std::int64_t Int64
Signed integer type of 64 bits.
@ Different
Different values before and after synchronization.
@ Same
Same values before and after synchronization.
std::int32_t Int32
Signed integer type of 32 bits.