diff --git a/arcane/src/arcane/impl/DataSynchronizeBuffer.cc b/arcane/src/arcane/impl/DataSynchronizeBuffer.cc index eebe7d721..e77a2f644 100644 --- a/arcane/src/arcane/impl/DataSynchronizeBuffer.cc +++ b/arcane/src/arcane/impl/DataSynchronizeBuffer.cc @@ -1,13 +1,13 @@ // -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- //----------------------------------------------------------------------------- -// Copyright 2000-2024 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) +// Copyright 2000-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) // See the top-level COPYRIGHT file for details. // SPDX-License-Identifier: Apache-2.0 //----------------------------------------------------------------------------- /*---------------------------------------------------------------------------*/ -/* DataSynchronizeBuffer.cc (C) 2000-2024 */ +/* DataSynchronizeBuffer.cc (C) 2000-2025 */ /* */ -/* Implémentation d'un buffer générique pour la synchronisation de donnéess. */ +/* Implémentation d'un buffer générique pour la synchronisation de données. */ /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ @@ -20,6 +20,10 @@ #include "arcane/impl/internal/IBufferCopier.h" #include "arcane/accelerator/core/Runner.h" +#include "arcane/utils/FixedArray.h" +#include "arccore/trace/ITraceMng.h" + +#include /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ @@ -30,6 +34,33 @@ namespace Arcane /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ +namespace +{ + //! Alignement pour les buffers et les sous-parties des buffers + constexpr Int64 ALIGNEMENT_SIZE = 64; + Int64 _applyPadding(Int64 original_size) + { + Int64 modulo = original_size % ALIGNEMENT_SIZE; + Int64 new_size = original_size; + if (modulo != 0) + new_size += (ALIGNEMENT_SIZE - modulo); + if ((new_size % ALIGNEMENT_SIZE) != 0) + ARCANE_FATAL("Bad padding"); + return new_size; + } + void _checkAlignment(const void* address) + { + auto a = reinterpret_cast(address); + intptr_t max_align = alignof(std::max_align_t); + intptr_t modulo = a % max_align; + if (modulo != 0) + ARCANE_FATAL("Address '{0}' is not aligned (align={1}, modulo={2})", address, max_align, modulo); + } +} // namespace + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + void IDataSynchronizeBuffer:: copyAllSend() { @@ -66,21 +97,55 @@ barrier() /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ +//! Positionne le buffer global. +void DataSynchronizeBufferBase::BufferInfo:: +setGlobalBuffer(MutableMemoryView v) +{ + if (v.datatypeSize() != 1) + ARCANE_FATAL("Global buffer has to use a datatype of size 1 (current={0})", v.datatypeSize()); + m_memory_view = v; +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + Int64 DataSynchronizeBufferBase::BufferInfo:: -displacement(Int32 index) const +displacement(Int32 rank_index) const +{ + return m_displacements[rank_index][0]; +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +Int64 DataSynchronizeBufferBase::BufferInfo:: +localBufferSize(Int32 rank_index) const +{ + return m_local_buffer_size[rank_index]; +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +MutableMemoryView DataSynchronizeBufferBase::BufferInfo:: +localBuffer(Int32 rank_index) const { - return m_buffer_info->bufferDisplacement(index) * m_datatype_size; + std::byte* data = m_memory_view.data(); + data += m_displacements[rank_index][0]; + const Int64 nb_byte = m_local_buffer_size[rank_index]; + return makeMutableMemoryView(data, 1, nb_byte); } /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ MutableMemoryView DataSynchronizeBufferBase::BufferInfo:: -localBuffer(Int32 index) +dataLocalBuffer(Int32 rank_index, Int32 data_index) const { - Int64 displacement = m_buffer_info->bufferDisplacement(index); - Int32 local_size = m_buffer_info->nbItem(index); - return m_memory_view.subView(displacement, local_size); + std::byte* data = m_memory_view.data(); + data += m_displacements[rank_index][data_index]; + const Int32 nb_item = m_buffer_info->nbItem(rank_index); + return makeMutableMemoryView(data, m_datatype_sizes[data_index], nb_item); } /*---------------------------------------------------------------------------*/ @@ -92,6 +157,48 @@ localIds(Int32 index) const return m_buffer_info->localIds(index); } +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ +/*! + * \brief Initialise les informations du buffer. + * + * Calcul l'offset de chaque donnée de chaque rang dans le buffer global. + * + * \note \a datatype_sizes est conservé sous forme de vue et ne doit donc pas + * être modifié et rester valide durant la synchronisation. + */ +void DataSynchronizeBufferBase::BufferInfo:: +initialize(ConstArrayView datatype_sizes, const DataSynchronizeBufferInfoList* buffer_info) +{ + ARCANE_CHECK_POINTER(buffer_info); + m_buffer_info = buffer_info; + m_datatype_sizes = datatype_sizes; + const Int32 nb_data = datatype_sizes.size(); + const Int32 nb_rank = buffer_info->nbRank(); + m_displacements.resize(nb_rank, nb_data); + m_local_buffer_size.resize(nb_rank); + + // Calcul l'offset pour chaque donnée de chaque rang + // en garantissant que l'offset est un multiple de ALIGNMENT_SIZE + Int64 data_offset = 0; + m_total_size = 0; + for (Int32 i = 0; i < nb_rank; ++i) { + const Int32 nb_item = buffer_info->nbItem(i); + Int64 local_buf_nb_byte = 0; + for (Int32 d = 0; d < nb_data; ++d) { + // Taille nécessaire pour la donnée \a d pour le rang \a i + // On fait un padding sur cette taille pour avoir + // un alignment spécifique. + const Int64 nb_byte = _applyPadding(nb_item * datatype_sizes[d]); + m_displacements[i][d] = data_offset; + local_buf_nb_byte += nb_byte; + data_offset += nb_byte; + } + m_local_buffer_size[i] = local_buf_nb_byte; + m_total_size += local_buf_nb_byte; + } +} + /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ @@ -126,22 +233,19 @@ barrier() /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /*! - * \brief Calcul et alloue les tampons nécessaire aux envois et réceptions + * \brief Calcul et alloue les tampons nécessaires aux envois et réceptions * pour les synchronisations des variables 1D. */ void DataSynchronizeBufferBase:: -_compute(Int32 datatype_size) +_compute(ConstArrayView datatype_sizes) { m_nb_rank = m_sync_info->size(); - m_ghost_buffer_info.m_datatype_size = datatype_size; - m_ghost_buffer_info.m_buffer_info = &m_sync_info->receiveInfo(); - m_share_buffer_info.m_datatype_size = datatype_size; - m_share_buffer_info.m_buffer_info = &m_sync_info->sendInfo(); - m_compare_sync_buffer_info.m_datatype_size = datatype_size; - m_compare_sync_buffer_info.m_buffer_info = &m_sync_info->receiveInfo(); + m_ghost_buffer_info.initialize(datatype_sizes, &m_sync_info->receiveInfo()); + m_share_buffer_info.initialize(datatype_sizes, &m_sync_info->sendInfo()); + m_compare_sync_buffer_info.initialize(datatype_sizes, &m_sync_info->receiveInfo()); - _allocateBuffers(datatype_size); + _allocateBuffers(); } /*---------------------------------------------------------------------------*/ @@ -150,32 +254,35 @@ _compute(Int32 datatype_size) * \brief Calcul et alloue les tampons nécessaires aux envois et réceptions * pour les synchronisations des variables 1D. * + * Il faut avoir appelé _compute() avant pour calculer les tailles et offset + * pour chaque buffer. + * * \todo: ne pas converver les tampons pour chaque type de donnée des variables * car leur conservation est couteuse en terme de memoire. */ void DataSynchronizeBufferBase:: -_allocateBuffers(Int32 datatype_size) +_allocateBuffers() { - Int64 total_ghost_buffer = m_sync_info->receiveInfo().totalNbItem(); - Int64 total_share_buffer = m_sync_info->sendInfo().totalNbItem(); - - Int32 full_dim2_size = datatype_size; - Int64 total_size = total_ghost_buffer + total_share_buffer; + const Int64 total_ghost_buffer = m_ghost_buffer_info.totalSize(); + const Int64 total_share_buffer = m_share_buffer_info.totalSize(); + Int64 total_compare_buffer = 0; if (m_is_compare_sync_values) - total_size += total_ghost_buffer; - m_memory->resize(total_size * full_dim2_size); + total_compare_buffer = m_compare_sync_buffer_info.totalSize(); + + Int64 total_size = total_ghost_buffer + total_share_buffer + total_compare_buffer; + m_memory->resize(total_size); - Int64 share_offset = total_ghost_buffer * full_dim2_size; - Int64 check_sync_offset = share_offset + total_share_buffer * full_dim2_size; + Int64 share_offset = total_ghost_buffer; + Int64 check_sync_offset = share_offset + total_share_buffer; Span buffer_span = m_memory->bytes(); auto s1 = buffer_span.subspan(0, share_offset); - m_ghost_buffer_info.m_memory_view = makeMutableMemoryView(s1.data(), full_dim2_size, total_ghost_buffer); - auto s2 = buffer_span.subspan(share_offset, total_share_buffer * full_dim2_size); - m_share_buffer_info.m_memory_view = makeMutableMemoryView(s2.data(), full_dim2_size, total_share_buffer); + m_ghost_buffer_info.setGlobalBuffer(makeMutableMemoryView(s1.data(), 1, total_ghost_buffer)); + auto s2 = buffer_span.subspan(share_offset, total_share_buffer); + m_share_buffer_info.setGlobalBuffer(makeMutableMemoryView(s2.data(), 1, total_share_buffer)); if (m_is_compare_sync_values) { - auto s3 = buffer_span.subspan(check_sync_offset, total_ghost_buffer * full_dim2_size); - m_compare_sync_buffer_info.m_memory_view = makeMutableMemoryView(s3.data(), full_dim2_size, total_ghost_buffer); + auto s3 = buffer_span.subspan(check_sync_offset, total_ghost_buffer); + m_compare_sync_buffer_info.setGlobalBuffer(makeMutableMemoryView(s3.data(), 1, total_ghost_buffer)); } } @@ -192,7 +299,7 @@ copyReceiveAsync(Int32 index) MutableMemoryView var_values = dataView(); ConstArrayView indexes = m_ghost_buffer_info.localIds(index); - ConstMemoryView local_buffer = m_ghost_buffer_info.localBuffer(index); + ConstMemoryView local_buffer = m_ghost_buffer_info.dataLocalBuffer(index, 0); m_buffer_copier->copyFromBufferAsync(indexes, local_buffer, var_values); } @@ -207,7 +314,7 @@ copySendAsync(Int32 index) ConstMemoryView var_values = dataView(); ConstArrayView indexes = m_share_buffer_info.localIds(index); - MutableMemoryView local_buffer = m_share_buffer_info.localBuffer(index); + MutableMemoryView local_buffer = m_share_buffer_info.dataLocalBuffer(index, 0); m_buffer_copier->copyToBufferAsync(indexes, local_buffer, var_values); } @@ -215,23 +322,25 @@ copySendAsync(Int32 index) /*---------------------------------------------------------------------------*/ void SingleDataSynchronizeBuffer:: -prepareSynchronize(Int32 datatype_size, bool is_compare_sync) +prepareSynchronize(bool is_compare_sync) { m_is_compare_sync_values = is_compare_sync; - _compute(datatype_size); - if (!is_compare_sync) - return; - // Recopie dans le buffer de vérification les valeurs actuelles des mailles - // fantômes. - MutableMemoryView var_values = dataView(); - Int32 nb_rank = nbRank(); - for (Int32 i = 0; i < nb_rank; ++i) { - ConstArrayView indexes = m_compare_sync_buffer_info.localIds(i); - MutableMemoryView local_buffer = m_compare_sync_buffer_info.localBuffer(i); - m_buffer_copier->copyToBufferAsync(indexes, local_buffer, var_values); + + _compute(m_datatype_sizes.view()); + + if (is_compare_sync) { + // Recopie dans le buffer de vérification les valeurs actuelles des mailles + // fantômes. + MutableMemoryView var_values = dataView(); + Int32 nb_rank = nbRank(); + for (Int32 i = 0; i < nb_rank; ++i) { + ConstArrayView indexes = m_compare_sync_buffer_info.localIds(i); + MutableMemoryView local_buffer = m_compare_sync_buffer_info.dataLocalBuffer(i, 0); + m_buffer_copier->copyToBufferAsync(indexes, local_buffer, var_values); + } + // Normalement pas besoin de faire une barrière, car ensuite il y aura les + // envois sur la même \a queue et ensuite une barrière. } - // Normalement pas besoin de faire une barrière car ensuite il y aura les - // envois sur la même \a queue et ensuite une barrière. } /*---------------------------------------------------------------------------*/ @@ -270,34 +379,33 @@ finalizeSynchronize() /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ - +/*! + * Les comparaisons ne sont pas supportées si on utilise les synchronisations + * multiples. + */ void MultiDataSynchronizeBuffer:: -prepareSynchronize(Int32 datatype_size, [[maybe_unused]] bool is_compare_sync) +prepareSynchronize([[maybe_unused]] bool is_compare_sync) { - _compute(datatype_size); + _compute(m_datatype_sizes); } /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ void MultiDataSynchronizeBuffer:: -copyReceiveAsync(Int32 index) +copyReceiveAsync(Int32 rank_index) { IBufferCopier* copier = m_buffer_copier.get(); m_ghost_buffer_info.checkValid(); - Int64 data_offset = 0; - Span local_buffer_bytes = m_ghost_buffer_info.localBuffer(index).bytes(); - Int32ConstArrayView indexes = m_ghost_buffer_info.localIds(index); - const Int64 nb_element = indexes.size(); + ConstArrayView local_ids = m_ghost_buffer_info.localIds(rank_index); + Int32 data_index = 0; for (MutableMemoryView var_values : m_data_views) { - Int32 datatype_size = var_values.datatypeSize(); - Int64 current_size_in_bytes = nb_element * datatype_size; - Span sub_local_buffer_bytes = local_buffer_bytes.subSpan(data_offset, current_size_in_bytes); - ConstMemoryView local_buffer = makeConstMemoryView(sub_local_buffer_bytes.data(), datatype_size, nb_element); - if (current_size_in_bytes != 0) - copier->copyFromBufferAsync(indexes, local_buffer, var_values); - data_offset += current_size_in_bytes; + ConstMemoryView local_buffer = m_ghost_buffer_info.dataLocalBuffer(rank_index, data_index); + _checkAlignment(local_buffer.data()); + if (!local_buffer.bytes().empty()) + copier->copyFromBufferAsync(local_ids, local_buffer, var_values); + ++data_index; } } @@ -305,23 +413,19 @@ copyReceiveAsync(Int32 index) /*---------------------------------------------------------------------------*/ void MultiDataSynchronizeBuffer:: -copySendAsync(Int32 index) +copySendAsync(Int32 rank_index) { IBufferCopier* copier = m_buffer_copier.get(); m_ghost_buffer_info.checkValid(); - Int64 data_offset = 0; - Span local_buffer_bytes = m_share_buffer_info.localBuffer(index).bytes(); - Int32ConstArrayView indexes = m_share_buffer_info.localIds(index); - const Int64 nb_element = indexes.size(); + ConstArrayView local_ids = m_share_buffer_info.localIds(rank_index); + Int32 data_index = 0; for (ConstMemoryView var_values : m_data_views) { - Int32 datatype_size = var_values.datatypeSize(); - Int64 current_size_in_bytes = nb_element * datatype_size; - Span sub_local_buffer_bytes = local_buffer_bytes.subSpan(data_offset, current_size_in_bytes); - MutableMemoryView local_buffer = makeMutableMemoryView(sub_local_buffer_bytes.data(), datatype_size, nb_element); - if (current_size_in_bytes != 0) - copier->copyToBufferAsync(indexes, local_buffer, var_values); - data_offset += current_size_in_bytes; + MutableMemoryView local_buffer = m_share_buffer_info.dataLocalBuffer(rank_index, data_index); + _checkAlignment(local_buffer.data()); + if (!local_buffer.bytes().empty()) + copier->copyToBufferAsync(local_ids, local_buffer, var_values); + ++data_index; } } diff --git a/arcane/src/arcane/impl/DataSynchronizeDispatcher.cc b/arcane/src/arcane/impl/DataSynchronizeDispatcher.cc index bc235d3b8..0143fedd1 100644 --- a/arcane/src/arcane/impl/DataSynchronizeDispatcher.cc +++ b/arcane/src/arcane/impl/DataSynchronizeDispatcher.cc @@ -1,11 +1,11 @@ // -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- //----------------------------------------------------------------------------- -// Copyright 2000-2023 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) +// Copyright 2000-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) // See the top-level COPYRIGHT file for details. // SPDX-License-Identifier: Apache-2.0 //----------------------------------------------------------------------------- /*---------------------------------------------------------------------------*/ -/* DataSynchronizeDispatcher.cc (C) 2000-2023 */ +/* DataSynchronizeDispatcher.cc (C) 2000-2025 */ /* */ /* Gestion de la synchronisation d'une instance de 'IData'. */ /*---------------------------------------------------------------------------*/ @@ -30,7 +30,6 @@ #include "arcane/impl/DataSynchronizeInfo.h" #include "arcane/impl/internal/DataSynchronizeBuffer.h" -#include "arcane/impl/internal/IBufferCopier.h" /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ @@ -125,7 +124,7 @@ class ARCANE_IMPL_EXPORT DataSynchronizeDispatcher explicit DataSynchronizeDispatcher(const DataSynchronizeDispatcherBuildInfo& bi) : DataSynchronizeDispatcherBase(bi) - , m_sync_buffer(m_sync_info.get(), bi.bufferCopier()) + , m_sync_buffer(bi.parallelMng()->traceMng(), m_sync_info.get(), bi.bufferCopier()) { } @@ -156,7 +155,6 @@ beginSynchronize(INumericDataInternal* data, bool is_compare_sync) ARCANE_CHECK_POINTER(data); MutableMemoryView mem_view = data->memoryView(); - Int32 full_datatype_size = mem_view.datatypeSize(); if (m_is_in_sync) ARCANE_FATAL("_beginSynchronize() has already been called"); @@ -166,7 +164,7 @@ beginSynchronize(INumericDataInternal* data, bool is_compare_sync) if (m_is_empty_sync) return; m_sync_buffer.setDataView(mem_view); - m_sync_buffer.prepareSynchronize(full_datatype_size, is_compare_sync); + m_sync_buffer.prepareSynchronize(is_compare_sync); m_synchronize_implementation->beginSynchronize(&m_sync_buffer); } @@ -311,7 +309,6 @@ synchronize(ConstArrayView vars) m_sync_buffer.setNbData(nb_var); // Récupère les emplacements mémoire des données des variables et leur taille - Int32 all_datatype_size = 0; { Int32 index = 0; for (IVariable* var : vars) { @@ -319,7 +316,6 @@ synchronize(ConstArrayView vars) if (!numapi) ARCANE_FATAL("Variable '{0}' can not be synchronized because it is not a numeric data", var->name()); MutableMemoryView mem_view = numapi->memoryView(); - all_datatype_size += mem_view.datatypeSize(); m_sync_buffer.setDataView(index, mem_view); ++index; } @@ -327,7 +323,7 @@ synchronize(ConstArrayView vars) // TODO: à passer en paramètre de la fonction bool is_compare_sync = false; - m_sync_buffer.prepareSynchronize(all_datatype_size, is_compare_sync); + m_sync_buffer.prepareSynchronize(is_compare_sync); m_synchronize_implementation->beginSynchronize(&m_sync_buffer); m_synchronize_implementation->endSynchronize(&m_sync_buffer); diff --git a/arcane/src/arcane/impl/DataSynchronizeInfo.h b/arcane/src/arcane/impl/DataSynchronizeInfo.h index 10dd754ca..d009f884e 100644 --- a/arcane/src/arcane/impl/DataSynchronizeInfo.h +++ b/arcane/src/arcane/impl/DataSynchronizeInfo.h @@ -1,11 +1,11 @@ // -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- //----------------------------------------------------------------------------- -// Copyright 2000-2023 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) +// Copyright 2000-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) // See the top-level COPYRIGHT file for details. // SPDX-License-Identifier: Apache-2.0 //----------------------------------------------------------------------------- /*---------------------------------------------------------------------------*/ -/* DataSynchronizeInfo.h (C) 2000-2024 */ +/* DataSynchronizeInfo.h (C) 2000-2025 */ /* */ /* Informations pour synchroniser les données. */ /*---------------------------------------------------------------------------*/ @@ -15,16 +15,12 @@ /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ -#include "arcane/utils/UniqueArray.h" -#include "arcane/utils/Ref.h" #include "arccore/base/ReferenceCounterImpl.h" #include "arcane/core/ArcaneTypes.h" #include "arcane/core/Parallel.h" #include "arcane/core/VariableCollection.h" -#include "arcane/impl/IDataSynchronizeImplementation.h" - #include /*---------------------------------------------------------------------------*/ @@ -32,6 +28,7 @@ namespace Arcane { +class DataSynchronizeInfo; //! Comparaison des valeurs des entités fantômes avant/après une synchronisation enum class eDataSynchronizeCompareStatus @@ -51,7 +48,6 @@ enum class eDataSynchronizeCompareStatus */ class DataSynchronizeResult { - public: public: eDataSynchronizeCompareStatus compareStatus() const { return m_compare_status; } @@ -115,11 +111,11 @@ class ARCANE_IMPL_EXPORT VariableSyncInfo /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /*! - * \brief Informations pour les message d'envoi (share) ou de réception (ghost) + * \brief Informations pour les messages d'envoi (share) ou de réception (ghost) */ class DataSynchronizeBufferInfoList { - friend class DataSynchronizeInfo; + friend DataSynchronizeInfo; private: @@ -143,9 +139,15 @@ class DataSynchronizeBufferInfoList private: + /*! + * \brief Offsets dans le buffer global pour chaque rang. + * + * Ce tableau est rempli par DataSynchronizeInfo::recompute(). + */ UniqueArray m_displacements_base; Int64 m_total_nb_item = 0; const DataSynchronizeInfo* m_sync_info = nullptr; + //! Si vrai, il s'agit du buffer d'envoi, sinon de réception. bool m_is_share = false; }; @@ -205,10 +207,10 @@ class ARCANE_IMPL_EXPORT DataSynchronizeInfo Int32 targetRank(Int32 index) const { return m_ranks_info[index].targetRank(); } //! Rangs de toutes les cibles - Int32ConstArrayView communicatingRanks() const { return m_communicating_ranks; } - + ConstArrayView communicatingRanks() const { return m_communicating_ranks; } + //! Notifie l'instance que les indices locaux ont changé - void changeLocalIds(Int32ConstArrayView old_to_new_ids); + void changeLocalIds(ConstArrayView old_to_new_ids); //! Notifie l'instance que les valeurs ont changé void recompute(); diff --git a/arcane/src/arcane/impl/internal/DataSynchronizeBuffer.h b/arcane/src/arcane/impl/internal/DataSynchronizeBuffer.h index c77e56e38..54190b67e 100644 --- a/arcane/src/arcane/impl/internal/DataSynchronizeBuffer.h +++ b/arcane/src/arcane/impl/internal/DataSynchronizeBuffer.h @@ -1,13 +1,13 @@ // -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- //----------------------------------------------------------------------------- -// Copyright 2000-2023 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) +// Copyright 2000-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) // See the top-level COPYRIGHT file for details. // SPDX-License-Identifier: Apache-2.0 //----------------------------------------------------------------------------- /*---------------------------------------------------------------------------*/ -/* DataSynchronizeBuffer.h (C) 2000-2023 */ +/* DataSynchronizeBuffer.h (C) 2000-2025 */ /* */ -/* Implémentation d'un buffer générique pour la synchronisation de donnéess. */ +/* Implémentation d'un buffer générique pour la synchronisation de données. */ /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ #ifndef ARCANE_IMPL_DATASYNCHRONIZEBUFFER_H @@ -17,10 +17,12 @@ #include "arcane/utils/MemoryView.h" #include "arcane/utils/Array.h" +#include "arcane/utils/Array2.h" #include "arcane/utils/SmallArray.h" #include "arcane/utils/TraceAccessor.h" #include "arcane/impl/IDataSynchronizeBuffer.h" +#include "arcane/utils/FixedArray.h" /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ @@ -37,27 +39,45 @@ class MemoryBuffer; /*! * \internal * \brief Classe de base de l'implémentation de IDataSynchronizeBuffer. + * + * Cette implémentation utilise un seul buffer mémoire pour gérer les trois + * parties de la synchronisation : le buffer d'envoi, le buffer de réception + * et le buffer pour les comparer si la synchronisation a modifié des valeurs + * (ce dernier est optionnel). + * Chaque buffer est ensuite séparé en N parties, appelées sous-buffer, + * avec N le nombre de rangs qui communiquent. Enfin, chaque sous-buffer est + * lui-même séparé en P parties, avec P le nombre de données à communiquer. */ class ARCANE_IMPL_EXPORT DataSynchronizeBufferBase : public IDataSynchronizeBuffer { + /*! + * \brief Buffer pour un élément de la synchronisation (envoi, réception ou comparaison) + */ class BufferInfo { - friend DataSynchronizeBufferBase; - public: //! Buffer global - MutableMemoryView globalBuffer() { return m_memory_view; } + MutableMemoryView globalBuffer() const { return m_memory_view; } + + //! Positionne le buffer global. + void setGlobalBuffer(MutableMemoryView v); //! Buffer pour le \a index-ème rang - MutableMemoryView localBuffer(Int32 index); + MutableMemoryView localBuffer(Int32 rank_index) const; + + //! Buffer pour le \a index-ème rang et la \a data_index-ème donnée + MutableMemoryView dataLocalBuffer(Int32 rank_index, Int32 data_index) const; //! Déplacement dans \a globalBuffer() pour le \a index-ème rang - Int64 displacement(Int32 index) const; + Int64 displacement(Int32 rank_index) const; + + //! Taille (en octet) du buffer local pour le rang \a rank_index. + Int64 localBufferSize(Int32 rank_index) const; //! Taille totale en octet du buffer global - Int64 totalSize() const { return m_memory_view.bytes().size(); } + Int64 totalSize() const { return m_total_size; } //! Numéros locaux des entités pour le rang \a index ConstArrayView localIds(Int32 index) const; @@ -67,10 +87,24 @@ class ARCANE_IMPL_EXPORT DataSynchronizeBufferBase ARCANE_CHECK_POINTER(m_buffer_info); } + void initialize(ConstArrayView datatype_sizes, const DataSynchronizeBufferInfoList* buffer_info); + private: + /*! + * \brief Vue sur la zone mémoire du buffer. + * + * Cette variable n'est valide qu'après allocation de tous les buffers. + */ MutableMemoryView m_memory_view; - Int32 m_datatype_size = 0; + //! Offset (en octet) dans globalBuffer() de chaque donnée + UniqueArray2 m_displacements; + //! Taille (en octet) de chaque buffer local. + SmallArray m_local_buffer_size; + //! Taille (en octet) du type de chaque donnée. + ConstArrayView m_datatype_sizes; + //! Taille total (en octet) du buffer + Int64 m_total_size = 0; const DataSynchronizeBufferInfoList* m_buffer_info = nullptr; }; @@ -112,20 +146,20 @@ class ARCANE_IMPL_EXPORT DataSynchronizeBufferBase * \brief Prépare la synchronisation. * * Prépare la synchronisation et alloue les buffers si nécessaire. - * \a datatype_size est la taille (en octet) du type de la donnée. + * * Si \a is_compare_sync est vrai, on compare après la synchronisation les * valeurs des entités fantômes avec leur valeur d'avant la synchronisation. * - * Il faut avoir appeler setSynchronizeBuffer() au moins une fois avant d'appeler + * Il faut avoir appelé setSynchronizeBuffer() au moins une fois avant d'appeler * cette méthode pour positionner la zone mémoire allouée. */ - virtual void prepareSynchronize(Int32 datatype_size, bool is_compare_sync) = 0; + virtual void prepareSynchronize(bool is_compare_sync) = 0; protected: - void _allocateBuffers(Int32 datatype_size); + void _allocateBuffers(); //! Calcule les informations pour la synchronisation - void _compute(Int32 datatype_size); + void _compute(ConstArrayView datatype_sizes); protected: @@ -154,12 +188,14 @@ class ARCANE_IMPL_EXPORT DataSynchronizeBufferBase * \brief Implémentation de IDataSynchronizeBuffer pour une donnée */ class ARCANE_IMPL_EXPORT SingleDataSynchronizeBuffer -: public DataSynchronizeBufferBase +: public TraceAccessor +, public DataSynchronizeBufferBase { public: - SingleDataSynchronizeBuffer(DataSynchronizeInfo* sync_info, Ref copier) - : DataSynchronizeBufferBase(sync_info, copier) + SingleDataSynchronizeBuffer(ITraceMng* tm, DataSynchronizeInfo* sync_info, Ref copier) + : TraceAccessor(tm) + , DataSynchronizeBufferBase(sync_info, copier) {} public: @@ -169,10 +205,14 @@ class ARCANE_IMPL_EXPORT SingleDataSynchronizeBuffer public: - void setDataView(MutableMemoryView v) { m_data_view = v; } + void setDataView(MutableMemoryView v) + { + m_data_view = v; + m_datatype_sizes[0] = v.datatypeSize(); + } //! Zone mémoire contenant les valeurs de la donnée à synchroniser MutableMemoryView dataView() { return m_data_view; } - void prepareSynchronize(Int32 datatype_size, bool is_compare_sync) override; + void prepareSynchronize(bool is_compare_sync) override; /*! * \brief Termine la synchronisation. @@ -183,6 +223,8 @@ class ARCANE_IMPL_EXPORT SingleDataSynchronizeBuffer //! Vue sur les données de la variable MutableMemoryView m_data_view; + //! Tableau contenant les tailles des types de donnée + FixedArray m_datatype_sizes; }; /*---------------------------------------------------------------------------*/ @@ -205,23 +247,30 @@ class ARCANE_IMPL_EXPORT MultiDataSynchronizeBuffer public: - void copyReceiveAsync(Int32 index) final; - void copySendAsync(Int32 index) final; + void copyReceiveAsync(Int32 rank_index) final; + void copySendAsync(Int32 rank_index) final; public: void setNbData(Int32 nb_data) { m_data_views.resize(nb_data); + m_datatype_sizes.resize(nb_data); + } + void setDataView(Int32 index, MutableMemoryView v) + { + m_data_views[index] = v; + m_datatype_sizes[index] = v.datatypeSize(); } - void setDataView(Int32 index, MutableMemoryView v) { m_data_views[index] = v; } - void prepareSynchronize(Int32 datatype_size, bool is_compare_sync) override; + void prepareSynchronize(bool is_compare_sync) override; private: //! Vue sur les données de la variable SmallArray m_data_views; + //! Tableau contenant les tailles des types de donnée + SmallArray m_datatype_sizes; }; /*---------------------------------------------------------------------------*/ diff --git a/arcane/src/arcane/tests/CMakeLists.txt b/arcane/src/arcane/tests/CMakeLists.txt index 3e6c3af68..8e3988c40 100644 --- a/arcane/src/arcane/tests/CMakeLists.txt +++ b/arcane/src/arcane/tests/CMakeLists.txt @@ -561,8 +561,10 @@ arcane_add_test_message_passing_hybrid(parallelmng_sub_all NB_MPI 2 NB_SHM 2 ARG # ---------------------------------------------------------------------------- -ARCANE_ADD_TEST_PARALLEL(parallel testParallel-1.arc 4) -ARCANE_ADD_TEST_PARALLEL(parallel2 testParallel-2.arc 4) +arcane_add_test_parallel(parallel testParallel-1.arc 4) +arcane_add_accelerator_test_parallel(parallel testParallel-1.arc 4) +arcane_add_test_parallel(parallel2 testParallel-2.arc 4) +arcane_add_accelerator_test_parallel(parallel2 testParallel-2.arc 4) arcane_add_test_parallel(parallel2_synchronize testParallel-synchronize1.arc 4) arcane_add_test_parallel_thread(parallel2_synchronize testParallel-synchronize1.arc 4) arcane_add_test_parallel(parallel2_synchronize_compare testParallel-synchronize1.arc 4 -We,ARCANE_AUTO_COMPARE_SYNCHRONIZE,3)