14#include "arcane/impl/internal/VariableSynchronizerComputeList.h"
16#include "arcane/utils/ITraceMng.h"
17#include "arcane/utils/FatalErrorException.h"
18#include "arcane/utils/PlatformUtils.h"
19#include "arcane/utils/OStringStream.h"
20#include "arcane/utils/ValueConvert.h"
22#include "arcane/core/IParallelMng.h"
23#include "arcane/core/IItemFamily.h"
24#include "arcane/core/ItemPrinter.h"
26#include "arcane/impl/DataSynchronizeInfo.h"
27#include "arcane/impl/internal/VariableSynchronizer.h"
40VariableSynchronizerComputeList::
43, m_synchronizer(var_sync)
44, m_parallel_mng(var_sync->m_parallel_mng)
45, m_item_group(var_sync->m_item_group)
46, m_is_verbose(var_sync->m_is_verbose)
48 if (
auto v = Convert::Type<Int32>::tryParseFromEnvironment(
"ARCANE_DEBUG_VARIABLESYNCHRONIZERCOMPUTELIST",
true))
49 m_is_debug = (v.value() != 0);
74void VariableSynchronizerComputeList::
77 const bool is_debug = m_is_debug;
78 IItemFamily* item_family = m_item_group.itemFamily();
79 Int32 my_rank = m_parallel_mng->commRank();
80 Int32 nb_rank = m_parallel_mng->commSize();
82 m_is_verbose =
traceMng()->verbosityLevel() >= 4;
87 info() <<
"Compute synchronize informations group=" << m_item_group.name()
88 <<
" family=" << item_family->
fullName()
89 <<
" group size=" << m_item_group.size();
97 impl::ItemBase item_internal = item.
itemBase();
102 if (owner == A_NULL_RANK || owner >= nb_rank) {
105 bad_items_uid.
add(uid);
109 info() <<
"Add entity uid=" << uid
110 <<
" lid=" << item_internal.
localId() <<
" to the subdomain " << owner;
112 boundary_items[owner].
add(item_internal.
localId());
115 for (
Int64 uid : bad_items_uid) {
116 info() <<
"ERROR: The entity uid=" << uid
117 <<
" group=" << m_item_group.name() <<
" doesn't belong to "
118 <<
"any subdomain or belong to an invalid subdomain";
120 ARCANE_FATAL(
"Error while creating synchronization information nb_error={0}", nb_error);
130 info() <<
"End compute synchronize information group=" << m_item_group.name()
138void VariableSynchronizerComputeList::
141 const bool is_debug = m_is_debug;
146 IItemFamily* item_family = m_item_group.itemFamily();
150 info(4) <<
"VariableSynchronizer::createList() begin for group=" << m_item_group.name();
153 Real time_before_all_gather = 0.0;
154 Real time_after_all_gather = 0.0;
155 Real time_before_sendrecv = 0.0;
156 Real time_after_sendrecv = 0.0;
157 Real time_after_sendrecv_wait = 0.0;
164 for (
Integer i = 0; i < nb_rank; ++i) {
165 if (boundary_items[i].empty())
167 communicating_ghost_ranks.
add(i);
170 for (
Integer z = 0, zs = boundary_items[i].size(); z < zs; ++z) {
171 Item item = items_internal[boundary_items[i][z]];
177 Integer nb_comm_rank = communicating_ghost_ranks.
size();
186 debug() <<
"communicating sub domains my=" << nb_comm_rank
187 <<
" max=" << max_comm_rank;
193 for (
Integer i = 0; i < nb_comm_rank; ++i) {
194 Int32 current_rank = communicating_ghost_ranks[i];
196 ghost_group_list[i] = ghost_grp;
197 nb_ghost[current_rank] = ghost_grp.
size();
203 Integer gather_size = 1 + (max_comm_rank * 2);
214 local_ghost_info[pos++] = nb_comm_rank;
215 debug() <<
"Send local info " << nb_comm_rank;
216 for (
Integer index = 0, s = communicating_ghost_ranks.
size(); index < s; ++index) {
217 local_ghost_info[pos++] = communicating_ghost_ranks[index];
218 local_ghost_info[pos++] = ghost_group_list[index].
size();
219 debug() <<
"Send local info i=" << index <<
" target=" << communicating_ghost_ranks[index]
220 <<
" nb=" << ghost_group_list[index].
size();
224 info() <<
"AllGather size() " << local_ghost_info.
size()
225 <<
' ' << global_ghost_info.
size()
228 pm->
allGather(local_ghost_info, global_ghost_info);
235 for (
Integer index = 0, s = nb_rank; index < s; ++index) {
236 Integer pos = gather_size * index;
237 Integer sub_size = global_ghost_info[pos++];
238 for (
Integer sub_index = 0; sub_index < sub_size; ++sub_index) {
239 Integer proc_id = global_ghost_info[pos++];
240 Integer nb_elem = global_ghost_info[pos++];
241 if (proc_id == my_rank) {
243 info() <<
"Get for share group " << index <<
' ' << nb_elem;
253 Integer nb_send = communicating_ghost_ranks.
size();
254 ghost_rank_info.
resize(nb_send);
255 for (
Integer i = 0; i < nb_send; ++i) {
257 ghost_rank_info[i].setInfos(communicating_ghost_ranks[i], gr);
277 info() <<
"Infos before auto add: send " << nb_send <<
" recv " << nb_recv;
278 for (
Integer i = 0; i < ghost_rank_info.
size(); ++i) {
280 info() <<
"Ghost: " << i << asdi.nbItem() <<
' ' << asdi.rank();
282 for (
Integer i = 0; i < share_rank_info.
size(); ++i) {
284 info() <<
"Shared: " << i <<
' ' << asdi.nbItem() <<
' ' << asdi.rank();
288 for (
Integer i = 0; i < nb_send; ++i) {
289 Integer proc_id = ghost_rank_info[i].rank();
291 for (; z < nb_recv; ++z)
292 if (share_rank_info[z].rank() == proc_id)
296 debug() <<
"Add communication with the subdomain " << proc_id;
301 for (
Integer i = 0; i < nb_recv; ++i) {
302 Integer proc_id = share_rank_info[i].rank();
304 for (; z < nb_send; ++z)
305 if (ghost_rank_info[z].rank() == proc_id)
309 debug() <<
"Add communication with subdomain " << proc_id;
314 if (ghost_rank_info.
size() != share_rank_info.
size()) {
315 ARCANE_FATAL(
"Problem with the number of subdomain shared ({0}) and ghosts ({1})",
316 share_rank_info.
size(), ghost_rank_info.
size());
319 std::sort(std::begin(share_rank_info), std::end(share_rank_info));
320 std::sort(std::begin(ghost_rank_info), std::end(ghost_rank_info));
330 info(4) <<
"Number of communicating processors: " << nb_comm_proc;
337 for (
Integer i = 0; i < ghost_rank_info.
size(); ++i) {
339 debug() <<
"Ghost: " << i <<
" " << asdi.nbItem() <<
' ' << asdi.rank();
341 for (
Integer i = 0; i < share_rank_info.
size(); ++i) {
343 debug() <<
"Shared: " << i <<
" " << asdi.nbItem() <<
' ' << asdi.rank();
345 Integer current_send_index = 0;
346 Integer current_recv_index = 0;
347 for (
Integer i = 0; i < nb_comm_proc * 2; ++i) {
350 if (current_send_index != nb_comm_proc)
351 send_proc = ghost_rank_info[current_send_index].rank();
352 if (current_recv_index != nb_comm_proc)
353 recv_proc = ghost_rank_info[current_recv_index].rank();
355 if (send_proc == recv_proc) {
356 if (send_proc < my_rank)
361 else if (send_proc < recv_proc)
372 for (
Integer z = 0, zs = nb_local; z < zs; ++z) {
374 const Item& elem = items_internal[asdi_local_ids[z]];
375 uids[z] = elem.
uniqueId().asInt64();
378 info() <<
"Number of elements that will be sent to the subdomain " << send_proc
379 <<
" " << nb_local <<
" elements";
380 for (
Integer z = 0; z < nb_local; ++z) {
381 info() <<
"Unique id " << uids[z];
384 debug() <<
"Send proc " << send_proc;
386 requests.
add(pm->send(uids, send_proc,
false));
387 ++current_send_index;
393 debug() <<
"Recv proc " << recv_proc;
395 if (!items_unique_id.
empty())
396 pm->
recv(items_unique_id, recv_proc);
403 debug() <<
"Creating shared entities for the subdomain " << recv_proc
404 <<
" with " << items_local_id.
size() <<
" entities";
407 asdi.setLocalIds(share_group);
409 for (
Integer z = 0, zs = share_group.
size(); z < zs; ++z) {
410 const Item& item = items_internal[share_group[z]];
414 ++current_recv_index;
419 info() <<
"Wait requests n=" << requests.
size()
429 _checkValid(ghost_rank_info, share_rank_info);
433 for (
Integer i = 0, n = sync_info->size(); i < n; ++i) {
439 info(4) <<
"VariableSynchronize:: end compute list group=" << m_item_group.name()
440 <<
" t_init=" <<
Trace::Precision(4, time_before_all_gather - time_begin,
true)
441 <<
" t_allgather=" <<
Trace::Precision(4, time_after_all_gather - time_before_all_gather,
true)
442 <<
" t_sendrecv=" <<
Trace::Precision(4, time_after_sendrecv_wait - time_before_sendrecv,
true)
443 <<
" t_wait=" <<
Trace::Precision(4, time_after_sendrecv_wait - time_after_sendrecv,
true);
449void VariableSynchronizerComputeList::
453 const bool is_debug = m_is_debug;
456 bool has_error =
false;
458 Int32 my_rank = m_parallel_mng->commRank();
459 IItemFamily* item_family = m_item_group.itemFamily();
468 marked_elem.fill(
false);
473 marked_elem[item.
localId()] =
true;
480 for (Integer i_comm = 0; i_comm < nb_comm_proc; ++i_comm) {
481 GhostRankInfo& ghost_info = ghost_rank_info[i_comm];
482 ShareRankInfo& share_info = share_rank_info[i_comm];
483 if (ghost_info.rank() != share_info.rank()) {
484 ARCANE_FATAL(
"Inconsistency between the subdomain numbers ghost_rank={0} share_rank={1}",
485 ghost_info.rank(), share_info.rank());
487 Integer current_proc = ghost_info.rank();
491 if (share_grp.empty() && ghost_grp.empty()) {
492 error() <<
"Shared and ghosts groups null for the subdomain " << current_proc;
496 if (current_proc == my_rank) {
497 error() <<
"Error in the communication pattern: "
498 <<
"the processor can't communicate with itself";
504 for (Integer z = 0, zs = ghost_grp.size(); z < zs; ++z) {
505 const Item& elem = items_internal[ghost_grp[z]];
506 bool is_marked = marked_elem[elem.localId()];
509 if (nb_error < max_error)
510 error() <<
"The entity " << ItemPrinter(elem) <<
" belongs to another ghost group "
511 <<
"or is owned by the subdomain.";
515 marked_elem[elem.localId()] =
true;
518 m_synchronizer->m_sync_info->add(VariableSyncInfo(share_grp, ghost_grp, current_proc));
524 if (!marked_elem[item.localId()]) {
525 if (nb_error < max_error) {
526 error() <<
"The entity " << ItemPrinter(item)
527 <<
" doesn't belong to the subdomain or any ghost group.";
536 if (nb_error >= max_error)
537 error() << nb_error <<
" total elements are incorrectly dealt with";
540 ARCANE_FATAL(
"Error while creating the exchange structures of the family={0}",
547void VariableSynchronizerComputeList::
550 DataSynchronizeInfo* sync_info = m_synchronizer->m_sync_info.get();
551 Integer nb_comm = sync_info->size();
552 info() <<
"SYNC LIST FOR GROUP : " << m_item_group.fullName() <<
" N=" << nb_comm;
554 IItemFamily* item_family = m_item_group.itemFamily();
555 ItemInfoListView items_internal(item_family);
556 for (Integer i = 0; i < nb_comm; ++i) {
557 Int32 target_rank = sync_info->targetRank(i);
558 ostr() <<
" TARGET=" << target_rank <<
'\n';
560 ostr() <<
"\t\tSHARE(lid,uid) n=" << share_ids.
size() <<
" :";
561 for (Integer z = 0, zs = share_ids.size(); z < zs; ++z) {
562 Item item = items_internal[share_ids[z]];
563 ostr() <<
" (" << item.localId() <<
"," << item.uniqueId() <<
")";
567 ostr() <<
"\t\tGHOST(lid,uid) n=" << ghost_ids.
size() <<
" :";
568 for (Integer z = 0, zs = ghost_ids.size(); z < zs; ++z) {
569 Item item = items_internal[ghost_ids[z]];
570 ostr() <<
" (" << item.localId() <<
"," << item.uniqueId() <<
")";
574 info() << ostr.str();
#define ARCANE_FATAL(...)
Macro throwing a FatalErrorException.
Integer size() const
Number of elements in the vector.
Modifiable view of an array of type T.
constexpr Integer size() const noexcept
Returns the size of the array.
constexpr bool empty() const noexcept
Returns true if the array is empty (zero dimension).
void fill(ConstReferenceType value)
Fills the array with the value value.
void resize(Int64 s)
Changes the number of elements in the array to s.
void add(ConstReferenceType val)
Adds element val to the end of the array.
constexpr Integer size() const noexcept
Number of elements in the array.
Int32 nbItem(Int32 index) const
Number of entities for rank index.
Information necessary to synchronize entities across a group.
Int32 targetRank(Int32 index) const
Rank of the index-th target.
void recompute()
Notifies the instance that the values have changed.
const DataSynchronizeBufferInfoList & receiveInfo() const
Receive (ghost) information.
Interface of an entity family.
virtual Int32 maxLocalId() const =0
virtual String fullName() const =0
Full family name (with the mesh's name).
virtual void itemsUniqueIdToLocalId(Int32ArrayView local_ids, Int64ConstArrayView unique_ids, bool do_fatal=true) const =0
Converts an array of unique numbers to local numbers.
Interface of the parallelism manager for a subdomain.
virtual Int32 commRank() const =0
Rank of this instance in the communicator.
virtual void recv(ArrayView< char > values, Int32 rank)=0
virtual Int32 commSize() const =0
Number of instances in the communicator.
virtual void allGather(ConstArrayView< char > send_buf, ArrayView< char > recv_buf)=0
Performs an all-gather operation across all processors. This is a collective operation....
virtual void waitAllRequests(ArrayView< Request > rvalues)=0
Blocks while waiting for the rvalues requests to complete.
virtual char reduce(eReduceType rt, char v)=0
Performs a reduction of type rt on the real v and returns the value.
ItemUniqueId uniqueId() const
Unique number of the entity.
Int32 owner() const
Number of the owning subdomain of the entity.
Int32 localId() const
Local number (in the subdomain) of the entity.
View of a list to obtain information about entities.
Utility class for printing information about an entity.
Base class for a mesh element.
constexpr Int32 localId() const
Local identifier of the entity in the processor subdomain.
ItemUniqueId uniqueId() const
Unique identifier across all domains.
constexpr bool isOwn() const
true if the entity belongs to the subdomain
impl::ItemBase itemBase() const
Internal part of the entity.
1D vector of data with reference semantics.
TraceMessageDbg debug(Trace::eDebugLevel=Trace::Medium) const
Flow for a debug message.
TraceMessage info() const
Flow for an information message.
ITraceMng * traceMng() const
Trace manager.
Formatting real numbers with a given precision.
1D data vector with value semantics (STL style).
void _createList(UniqueArray< SharedArray< Int32 > > &boundary_items)
Interface of a variable synchronization service.
@ ReduceMax
Maximum of values.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
ArrayView< Int64 > Int64ArrayView
C equivalent of a 1D array of 64-bit integers.
UniqueArray< Int64 > Int64UniqueArray
Dynamic 1D array of 64-bit integers.
std::int64_t Int64
Signed integer type of 64 bits.
Int32 Integer
Type representing an integer.
ConstArrayView< Int32 > Int32ConstArrayView
C equivalent of a 1D array of 32-bit integers.
UniqueArray< Int32 > Int32UniqueArray
Dynamic 1D array of 32-bit integers.
double Real
Type representing a real number.
std::int32_t Int32
Signed integer type of 32 bits.