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;
86 info() <<
"Compute synchronize informations group=" << m_item_group.name()
87 <<
" family=" << item_family->
fullName()
88 <<
" group size=" << m_item_group.size()
89 <<
" is_verbose=" << m_is_verbose;
96 impl::ItemBase item_internal = item.
itemBase();
101 if (owner == A_NULL_RANK || owner >= nb_rank) {
104 bad_items_uid.
add(uid);
108 info() <<
"Add entity uid=" << uid
109 <<
" lid=" << item_internal.
localId() <<
" to the subdomain " << owner;
111 boundary_items[owner].
add(item_internal.
localId());
114 for (
Int64 uid : bad_items_uid) {
115 info() <<
"ERROR: The entity uid=" << uid
116 <<
" group=" << m_item_group.name() <<
" doesn't belong to "
117 <<
"any subdomain or belong to an invalid subdomain";
119 ARCANE_FATAL(
"Error while creating synchronization information nb_error={0}", nb_error);
128 info() <<
"End compute synchronize information group=" << m_item_group.name()
135void VariableSynchronizerComputeList::
138 const bool is_debug = m_is_debug;
143 IItemFamily* item_family = m_item_group.itemFamily();
147 info(4) <<
"VariableSynchronizer::createList() begin for group=" << m_item_group.name();
150 Real time_before_all_gather = 0.0;
151 Real time_after_all_gather = 0.0;
152 Real time_before_sendrecv = 0.0;
153 Real time_after_sendrecv = 0.0;
154 Real time_after_sendrecv_wait = 0.0;
161 for (
Integer i = 0; i < nb_rank; ++i) {
162 if (boundary_items[i].empty())
164 communicating_ghost_ranks.
add(i);
167 for (
Integer z = 0, zs = boundary_items[i].size(); z < zs; ++z) {
168 Item item = items_internal[boundary_items[i][z]];
174 Integer nb_comm_rank = communicating_ghost_ranks.
size();
183 debug() <<
"communicating sub domains my=" << nb_comm_rank
184 <<
" max=" << max_comm_rank;
190 for (
Integer i = 0; i < nb_comm_rank; ++i) {
191 Int32 current_rank = communicating_ghost_ranks[i];
193 ghost_group_list[i] = ghost_grp;
194 nb_ghost[current_rank] = ghost_grp.
size();
200 Integer gather_size = 1 + (max_comm_rank * 2);
211 local_ghost_info[pos++] = nb_comm_rank;
212 debug() <<
"Send local info " << nb_comm_rank;
213 for (
Integer index = 0, s = communicating_ghost_ranks.
size(); index < s; ++index) {
214 local_ghost_info[pos++] = communicating_ghost_ranks[index];
215 local_ghost_info[pos++] = ghost_group_list[index].
size();
216 debug() <<
"Send local info i=" << index <<
" target=" << communicating_ghost_ranks[index]
217 <<
" nb=" << ghost_group_list[index].
size();
221 info() <<
"AllGather size() " << local_ghost_info.
size()
222 <<
' ' << global_ghost_info.
size()
225 pm->
allGather(local_ghost_info, global_ghost_info);
232 for (
Integer index = 0, s = nb_rank; index < s; ++index) {
233 Integer pos = gather_size * index;
234 Integer sub_size = global_ghost_info[pos++];
235 for (
Integer sub_index = 0; sub_index < sub_size; ++sub_index) {
236 Integer proc_id = global_ghost_info[pos++];
237 Integer nb_elem = global_ghost_info[pos++];
238 if (proc_id == my_rank) {
240 info() <<
"Get for share group " << index <<
' ' << nb_elem;
250 Integer nb_send = communicating_ghost_ranks.
size();
251 ghost_rank_info.
resize(nb_send);
252 for (
Integer i = 0; i < nb_send; ++i) {
254 ghost_rank_info[i].setInfos(communicating_ghost_ranks[i], gr);
274 info() <<
"Infos before auto add: send " << nb_send <<
" recv " << nb_recv;
275 for (
Integer i = 0; i < ghost_rank_info.
size(); ++i) {
277 info() <<
"Ghost: " << i << asdi.nbItem() <<
' ' << asdi.rank();
279 for (
Integer i = 0; i < share_rank_info.
size(); ++i) {
281 info() <<
"Shared: " << i <<
' ' << asdi.nbItem() <<
' ' << asdi.rank();
285 for (
Integer i = 0; i < nb_send; ++i) {
286 Integer proc_id = ghost_rank_info[i].rank();
288 for (; z < nb_recv; ++z)
289 if (share_rank_info[z].rank() == proc_id)
293 debug() <<
"Add communication with the subdomain " << proc_id;
298 for (
Integer i = 0; i < nb_recv; ++i) {
299 Integer proc_id = share_rank_info[i].rank();
301 for (; z < nb_send; ++z)
302 if (ghost_rank_info[z].rank() == proc_id)
306 debug() <<
"Add communication with subdomain " << proc_id;
311 if (ghost_rank_info.
size() != share_rank_info.
size()) {
312 ARCANE_FATAL(
"Problem with the number of subdomain shared ({0}) and ghosts ({1})",
313 share_rank_info.
size(), ghost_rank_info.
size());
316 std::sort(std::begin(share_rank_info), std::end(share_rank_info));
317 std::sort(std::begin(ghost_rank_info), std::end(ghost_rank_info));
327 info(4) <<
"Number of communicating processors: " << nb_comm_proc;
334 for (
Integer i = 0; i < ghost_rank_info.
size(); ++i) {
336 debug() <<
"Ghost: " << i <<
" " << asdi.nbItem() <<
' ' << asdi.rank();
338 for (
Integer i = 0; i < share_rank_info.
size(); ++i) {
340 debug() <<
"Shared: " << i <<
" " << asdi.nbItem() <<
' ' << asdi.rank();
342 Integer current_send_index = 0;
343 Integer current_recv_index = 0;
344 for (
Integer i = 0; i < nb_comm_proc * 2; ++i) {
347 if (current_send_index != nb_comm_proc)
348 send_proc = ghost_rank_info[current_send_index].rank();
349 if (current_recv_index != nb_comm_proc)
350 recv_proc = ghost_rank_info[current_recv_index].rank();
352 if (send_proc == recv_proc) {
353 if (send_proc < my_rank)
358 else if (send_proc < recv_proc)
369 for (
Integer z = 0, zs = nb_local; z < zs; ++z) {
371 const Item& elem = items_internal[asdi_local_ids[z]];
372 uids[z] = elem.
uniqueId().asInt64();
375 info() <<
"Number of elements that will be sent to the subdomain " << send_proc
376 <<
" " << nb_local <<
" elements";
377 for (
Integer z = 0; z < nb_local; ++z) {
378 info() <<
"Unique id " << uids[z];
381 debug() <<
"Send proc " << send_proc;
383 requests.
add(pm->send(uids, send_proc,
false));
384 ++current_send_index;
390 debug() <<
"Recv proc " << recv_proc;
392 if (!items_unique_id.
empty())
393 pm->
recv(items_unique_id, recv_proc);
400 debug() <<
"Creating shared entities for the subdomain " << recv_proc
401 <<
" with " << items_local_id.
size() <<
" entities";
404 asdi.setLocalIds(share_group);
406 for (
Integer z = 0, zs = share_group.
size(); z < zs; ++z) {
407 const Item& item = items_internal[share_group[z]];
411 ++current_recv_index;
416 info() <<
"Wait requests n=" << requests.
size()
426 _checkValid(ghost_rank_info, share_rank_info);
430 for (
Integer i = 0, n = sync_info->size(); i < n; ++i) {
436 info() <<
"VariableSynchronize:: end compute list group=" << m_item_group.name()
437 <<
" t_init=" <<
Trace::Precision(4, time_before_all_gather - time_begin,
true)
438 <<
" t_allgather=" <<
Trace::Precision(4, time_after_all_gather - time_before_all_gather,
true)
439 <<
" t_sendrecv=" <<
Trace::Precision(4, time_after_sendrecv_wait - time_before_sendrecv,
true)
440 <<
" t_wait=" <<
Trace::Precision(4, time_after_sendrecv_wait - time_after_sendrecv,
true);
446void VariableSynchronizerComputeList::
450 const bool is_debug = m_is_debug;
453 bool has_error =
false;
455 Int32 my_rank = m_parallel_mng->commRank();
456 IItemFamily* item_family = m_item_group.itemFamily();
465 marked_elem.fill(
false);
470 marked_elem[item.
localId()] =
true;
477 for (Integer i_comm = 0; i_comm < nb_comm_proc; ++i_comm) {
478 GhostRankInfo& ghost_info = ghost_rank_info[i_comm];
479 ShareRankInfo& share_info = share_rank_info[i_comm];
480 if (ghost_info.rank() != share_info.rank()) {
481 ARCANE_FATAL(
"Inconsistency between the subdomain numbers ghost_rank={0} share_rank={1}",
482 ghost_info.rank(), share_info.rank());
484 Integer current_proc = ghost_info.rank();
488 if (share_grp.empty() && ghost_grp.empty()) {
489 error() <<
"Shared and ghosts groups null for the subdomain " << current_proc;
493 if (current_proc == my_rank) {
494 error() <<
"Error in the communication pattern: "
495 <<
"the processor can't communicate with itself";
501 for (Integer z = 0, zs = ghost_grp.size(); z < zs; ++z) {
502 const Item& elem = items_internal[ghost_grp[z]];
503 bool is_marked = marked_elem[elem.localId()];
506 if (nb_error < max_error)
507 error() <<
"The entity " << ItemPrinter(elem) <<
" belongs to another ghost group "
508 <<
"or is owned by the subdomain.";
512 marked_elem[elem.localId()] =
true;
515 m_synchronizer->m_sync_info->add(VariableSyncInfo(share_grp, ghost_grp, current_proc));
521 if (!marked_elem[item.localId()]) {
522 if (nb_error < max_error) {
523 error() <<
"The entity " << ItemPrinter(item)
524 <<
" doesn't belong to the subdomain or any ghost group.";
533 if (nb_error >= max_error)
534 error() << nb_error <<
" total elements are incorrectly dealt with";
537 ARCANE_FATAL(
"Error while creating the exchange structures of the family={0}",
544void VariableSynchronizerComputeList::
547 DataSynchronizeInfo* sync_info = m_synchronizer->m_sync_info.get();
548 Integer nb_comm = sync_info->size();
549 info() <<
"SYNC LIST FOR GROUP : " << m_item_group.fullName() <<
" N=" << nb_comm;
551 IItemFamily* item_family = m_item_group.itemFamily();
552 ItemInfoListView items_internal(item_family);
553 for (Integer i = 0; i < nb_comm; ++i) {
554 Int32 target_rank = sync_info->targetRank(i);
555 ostr() <<
" TARGET=" << target_rank <<
'\n';
557 ostr() <<
"\t\tSHARE(lid,uid) n=" << share_ids.
size() <<
" :";
558 for (Integer z = 0, zs = share_ids.size(); z < zs; ++z) {
559 Item item = items_internal[share_ids[z]];
560 ostr() <<
" (" << item.localId() <<
"," << item.uniqueId() <<
")";
564 ostr() <<
"\t\tGHOST(lid,uid) n=" << ghost_ids.
size() <<
" :";
565 for (Integer z = 0, zs = ghost_ids.size(); z < zs; ++z) {
566 Item item = items_internal[ghost_ids[z]];
567 ostr() <<
" (" << item.localId() <<
"," << item.uniqueId() <<
")";
571 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.