Alien  1.3.0
Developer documentation
Loading...
Searching...
No Matches
BasicIndexManager.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2025 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#include "BasicIndexManager.h"
9
10#include <algorithm>
11#include <list>
12#include <map>
13#include <memory>
14#include <utility>
15#include <vector>
16
17#include <arccore/collections/Array2.h>
18#include <arccore/message_passing/ISerializeMessageList.h>
19#include <arccore/message_passing/Messages.h>
20
21#include <arccore/trace/ITraceMng.h>
22
23#include <alien/utils/Precomp.h>
24
25// #define SPLIT_CONTAINER
26/* La version avec SPLIT_CONTAINER fait moins d'appel virtuel mais consomme un peu plus de
27 * mémoire (tableau de vectorisation). Factuellement est sans SPLIT_CONTAINER est plus
28 * rapide de environ 5% NB: Si l'on supprime définitivement SPLIT_CONTAINER, l'API de
29 * IAbstractFamily peut être simplifier des méthodes uids et owners vectorisées (ainsi que
30 * ses implémentations).
31 */
32
33/*---------------------------------------------------------------------------*/
34/*---------------------------------------------------------------------------*/
35
36namespace Alien
37{
38
39/*---------------------------------------------------------------------------*/
40/*---------------------------------------------------------------------------*/
41
42// Utilities
43namespace
44{ // Unnamed namespace to avoid conflicts at linking time.
45
46 const Arccore::Integer KIND_SHIFT = 32;
47}
48
49/*---------------------------------------------------------------------------*/
50/*---------------------------------------------------------------------------*/
51
57{
58 friend class BasicIndexManager;
59
60 public:
62 MyEntryImpl(const String& name, const IAbstractFamily* family,
63 const Integer creationIndex, BasicIndexManager* manager, Integer kind)
64 : m_creation_index(creationIndex)
65 , m_manager(manager)
66 , m_name(name)
67 , m_family(family)
68 , m_kind(kind)
69 , m_is_defined(family->maxLocalId(), false)
70 , m_own_size(0)
71 , m_size(0)
72 {}
73
74 ~MyEntryImpl() override = default;
75
76 Arccore::ConstArrayView<Arccore::Integer> getOwnIndexes() const override
77 {
78 return Arccore::ConstArrayView<Arccore::Integer>(m_own_size, m_all_indices.data());
79 }
80
81 Arccore::ConstArrayView<Arccore::Integer> getOwnLocalIds() const override
82 {
83 return Arccore::ConstArrayView<Arccore::Integer>(m_own_size, m_all_items.data());
84 }
85
86 Arccore::ConstArrayView<Arccore::Integer> getAllIndexes() const override
87 {
88 return Arccore::ConstArrayView<Arccore::Integer>(m_all_indices);
89 }
90
91 Arccore::ConstArrayView<Integer> getAllLocalIds() const override
92 {
93 return Arccore::ConstArrayView<Integer>(m_all_items);
94 }
95
96 void addTag(const String& tagname, const String& tagvalue) override
97 {
98 m_tags[tagname] = tagvalue;
99 }
100
101 void removeTag(const String& tagname) override { m_tags.erase(tagname); }
102
103 bool hasTag(const String& tagname) override
104 {
105 return m_tags.find(tagname) != m_tags.end();
106 }
107
108 String tagValue(const String& tagname) override
109 {
110 auto i = m_tags.find(tagname);
111 if (i == m_tags.end())
112 return String();
113 return i->second;
114 }
115
116 String getName() const override { return m_name; }
117
118 Integer getKind() const override
119 {
120 ALIEN_ASSERT((m_kind >= 0), ("Unexpected negative kind"));
121 if (m_kind < KIND_SHIFT)
122 return -1; // this is an abstract entity
123 else
124 return m_kind % KIND_SHIFT;
125 }
126
127 const IAbstractFamily& getFamily() const override { return *m_family; }
128
129 IIndexManager* manager() const override { return m_manager; }
130
131 protected:
133
134 void reserve(const Integer n) { m_size = n; }
135
137
138 void finalize(const EntryIndexMap& entryIndex)
139 {
140 m_all_items.resize(m_size);
141 m_all_indices.resize(m_size);
142
143 Integer own_i = 0;
144 Integer ghost_i = m_size;
145 for (const auto& i : entryIndex)
146 if (i.m_entry == this) {
147 const Integer local_id = i.m_localid;
148 const Integer index = i.m_index;
149 const bool is_own = m_manager->isOwn(i);
150 if (is_own) {
151 m_all_items[own_i] = local_id;
152 m_all_indices[own_i] = index;
153 ++own_i;
154 }
155 else {
156 --ghost_i;
157 m_all_items[ghost_i] = local_id;
158 m_all_indices[ghost_i] = index;
159 }
160 }
161 m_own_size = own_i;
162 ALIEN_ASSERT((own_i == ghost_i), ("Not merged insertion"));
163
164 // // Tri de la partie own des indices
165 // typedef UniqueArray<Integer>::iterator iterator;
166 // DualRandomIterator<iterator,iterator> begin(m_all_indices.begin(),
167 // m_all_items.begin());
168 // DualRandomIterator<iterator,iterator> end = begin + m_own_size;
169 // Comparator<DualRandomIterator<iterator,iterator> > comparator;
170 // std::sort(begin, end, comparator);
171 }
172
173 void resetFamily(const IAbstractFamily* family) { m_family = family; }
174
175 protected:
176 void reserveLid(const Integer count)
177 {
178 m_defined_lids.reserve(m_defined_lids.size() + count);
179#ifdef SPLIT_CONTAINER
180 m_defined_indexes.reserve(m_defined_indexes.size() + count);
181#endif /* SPLIT_CONTAINER */
182 }
183 bool isDefinedLid(const Integer localId) const { return m_is_defined[localId]; }
184
185 void defineLid(const Integer localId, const Integer pos)
186 {
187 m_is_defined[localId] = true;
188#ifdef SPLIT_CONTAINER
189 m_defined_lids.add(localId);
190 m_defined_indexes.add(pos);
191#else /* SPLIT_CONTAINER */
192 m_defined_lids.add(std::make_pair(localId, pos));
193#endif /* SPLIT_CONTAINER */
194 }
195
196 [[maybe_unused]] void undefineLid(const Integer localId)
197 {
198 m_is_defined[localId] = false;
199 for (Integer i = 0; i < m_defined_lids.size(); ++i) {
200#ifdef SPLIT_CONTAINER
201 if (m_defined_lids[i] == localId)
202#else /* SPLIT_CONTAINER */
203 if (m_defined_lids[i].first == localId)
204#endif /* SPLIT_CONTAINER */
205 {
206 m_defined_lids[i] = m_defined_lids.back();
207 m_defined_lids.resize(m_defined_lids.size() - 1);
208#ifdef SPLIT_CONTAINER
209 m_defined_indexes[i] = m_defined_indexes.back();
210 m_defined_indexes.resize(m_defined_lids.size() - 1);
211#endif /* SPLIT_CONTAINER */
212 }
213 }
214 throw FatalErrorException(
215 A_FUNCINFO, "Inconsistent state : cannot find id to remove");
216 }
217
218#ifdef SPLIT_CONTAINER
219 const UniqueArray<Integer>& definedLids() const
220 {
221 return m_defined_lids;
222 }
223 const UniqueArray<Integer>& definedIndexes() const { return m_defined_indexes; }
224#else /* SPLIT_CONTAINER */
225 const UniqueArray<std::pair<Integer, Integer>>& definedLids() const
226 {
227 return m_defined_lids;
228 }
229#endif /* SPLIT_CONTAINER */
230
231 void freeDefinedLids()
232 {
233#ifdef SPLIT_CONTAINER
234 m_defined_lids.dispose();
235 m_defined_indexes.dispose();
236#else /* SPLIT_CONTAINER */
237 m_defined_lids.dispose();
238#endif /* SPLIT_CONTAINER */
239 std::vector<bool>().swap(m_is_defined);
240 }
241
242 private:
243 std::map<String, String> m_tags;
244 Integer m_creation_index;
245 BasicIndexManager* m_manager;
246 const String m_name;
247 const IAbstractFamily* m_family;
248 const Integer m_kind;
249
250 std::vector<bool> m_is_defined;
251#ifdef SPLIT_CONTAINER
252 UniqueArray<Integer> m_defined_lids;
253 UniqueArray<Integer> m_defined_indexes;
254#else /* SPLIT_CONTAINER */
255 UniqueArray<std::pair<Integer, Integer>> m_defined_lids;
256#endif /* SPLIT_CONTAINER */
257
258 private:
259 UniqueArray<Integer>
261 UniqueArray<Integer> m_all_indices;
264 Integer m_own_size;
265 Integer m_size;
266
267 public:
268 Integer getCreationIndex() const { return m_creation_index; }
269};
270
271/*---------------------------------------------------------------------------*/
272/*---------------------------------------------------------------------------*/
273
275{
276 EntrySendRequest() = default;
277
278 ~EntrySendRequest() = default;
279
280 EntrySendRequest(const EntrySendRequest& esr) = default;
281
282 // Arccore::MessagePassing::ISerializeMessage* comm = nullptr;
283 Arccore::Ref<Arccore::MessagePassing::ISerializeMessage> comm;
284 Integer count = 0;
285
286 void operator=(const EntrySendRequest&) = delete;
287};
288
289/*---------------------------------------------------------------------------*/
290
292{
293 EntryRecvRequest() = default;
294
295 ~EntryRecvRequest() = default;
296
297 // err is unused if ALIEN_ASSERT is empty.
298 explicit EntryRecvRequest(const EntrySendRequest& err ALIEN_UNUSED_PARAM) {}
299
300 Arccore::Ref<Arccore::MessagePassing::ISerializeMessage> comm;
301 UniqueArray<Int64> ids;
302
303 void operator=(const EntryRecvRequest&) = delete;
304};
305
306/*---------------------------------------------------------------------------*/
307/*---------------------------------------------------------------------------*/
309{
310 protected:
311 EntrySet::const_iterator m_iter, m_end;
312
313 public:
314 explicit MyEntryEnumeratorImpl(const EntrySet& entries)
315 : m_iter(entries.begin())
316 , m_end(entries.end())
317 {}
318
319 void moveNext() override { ++m_iter; }
320
321 [[nodiscard]] bool hasNext() const override { return m_iter != m_end; }
322
323 [[nodiscard]] EntryImpl* get() const override { return m_iter->second; }
324};
325/*---------------------------------------------------------------------------*/
326/*---------------------------------------------------------------------------*/
327
329: m_parallel_mng(parallelMng)
330, m_state(Undef)
331{
332 init_mine();
333}
334
335/*---------------------------------------------------------------------------*/
336/*---------------------------------------------------------------------------*/
337
339{
340 // Call non virtual function from dtor
341 init_mine();
342}
343
344/*---------------------------------------------------------------------------*/
345
347{
348 init_mine();
349}
350
352{
353 m_local_owner = m_parallel_mng->commRank();
354
355 m_state = Initialized;
356
357 m_local_entry_count = 0;
358 m_global_entry_count = 0;
359 m_global_entry_offset = 0;
360 m_local_removed_entry_count = 0;
361 m_global_removed_entry_count = 0;
362
363 // Destruction des structure de type entry
364 for (auto& i : m_entry_set) {
365 delete i.second;
366 }
367 m_entry_set.clear();
368
370 m_abstract_families.clear();
372}
373/*---------------------------------------------------------------------------*/
374
375void BasicIndexManager::setTraceMng(ITraceMng* traceMng)
376{
377 m_trace = traceMng;
378}
379
380/*---------------------------------------------------------------------------*/
381
383BasicIndexManager::buildEntry(
384const String& name, const IAbstractFamily* family, const Integer kind)
385{
386 if (m_state != Initialized)
387 throw FatalErrorException(A_FUNCINFO, "Inconsistent state");
388
389 // Recherche de l'entrée d'un nom
390 std::pair<EntrySet::iterator, bool> lookup =
391 m_entry_set.insert(EntrySet::value_type(name, (MyEntryImpl*)nullptr));
392 if (lookup.second) {
393 auto* entry = new MyEntryImpl(name, family, m_creation_index++, this, kind);
394 lookup.first->second = entry;
395 return Entry(entry);
396 }
397 else {
398 throw FatalErrorException(A_FUNCINFO, "Already defined entry");
399 return Entry(nullptr);
400 }
401}
402
403/*---------------------------------------------------------------------------*/
404
406BasicIndexManager::getEntry(const String& name) const
407{
408 auto lookup = m_entry_set.find(name);
409 if (lookup != m_entry_set.end()) {
410 return Entry(lookup->second);
411 }
412 else {
413 throw FatalErrorException(A_FUNCINFO, "Undefined entry requested");
414 return Entry(nullptr);
415 }
416}
417
418/*---------------------------------------------------------------------------*/
419
420void BasicIndexManager::defineIndex(
421const Entry& entry, ConstArrayView<Integer> localIds)
422{
423 if (m_state != Initialized)
424 throw FatalErrorException(A_FUNCINFO, "Inconsistent state");
425
426 ALIEN_ASSERT((entry.manager() == this), ("Incompatible entry from another manager"));
427 auto* myEntry = dynamic_cast<MyEntryImpl*>(entry.internal());
428
429 const IAbstractFamily& family = myEntry->getFamily();
430 SharedArray<Integer> owners = family.owners(localIds);
431 myEntry->reserveLid(localIds.size());
432 for (Integer i = 0, is = localIds.size(); i < is; ++i) {
433 const Integer localId = localIds[i];
434
435 if (not myEntry->isDefinedLid(localId)) { // nouvelle entrée
436 if (owners[i] == m_local_owner) {
437 myEntry->defineLid(
438 localId, +(m_local_removed_entry_count + m_local_entry_count++));
439 }
440 else {
441
442 myEntry->defineLid(
443 localId, -(m_global_removed_entry_count + (++m_global_entry_count)));
444 }
445 }
446 }
447}
448
449/*---------------------------------------------------------------------------*/
450
451/*---------------------------------------------------------------------------*/
452
454{
455 if (m_state != Initialized)
456 throw FatalErrorException(A_FUNCINFO, "Inconsistent state");
457
458 Integer total_size = 0;
459 for (auto& i : m_entry_set) {
460 MyEntryImpl* entry = i.second;
461 total_size += entry->definedLids().size();
462 }
463
464 EntryIndexMap
465 entry_index;
466 entry_index.reserve(total_size);
467
468 for (auto& i : m_entry_set) {
469 MyEntryImpl* entry = i.second;
470
471 const Integer creation_index = entry->getCreationIndex();
472 const IAbstractFamily& family = entry->getFamily();
473 const Integer entry_kind = entry->getKind();
474#ifdef SPLIT_CONTAINER
475 const UniqueArray<Integer>& lids = entry->definedLids();
476 const UniqueArray<Integer>& indexes = entry->definedIndexes();
477 ConstArrayView<Integer> owners = family.owners(lids);
478 ConstArrayView<Int64> uids = family.uids(lids);
479#else /* SPLIT_CONTAINER */
480 const UniqueArray<std::pair<Integer, Integer>>& lids = entry->definedLids();
481#endif /* SPLIT_CONTAINER */
482
483 for (Integer id = 0, is = lids.size(); id < is; ++id) {
484#ifdef SPLIT_CONTAINER
485 const Integer item_lid = lids[id];
486 const Integer item_index = indexes[id];
487 const Integer item_owner = owners[id];
488 const Int64 item_uid = uids[id];
489 entry_index.push_back(InternalEntryIndex(
490 entry, item_lid, entry_kind, item_uid, item_index, creation_index, item_owner));
491#else /* SPLIT_CONTAINER */
492 const Integer localid = lids[id].first;
493 IAbstractFamily::Item item = family.item(localid);
494 entry_index.push_back(InternalEntryIndex(entry, localid, entry_kind,
495 item.uniqueId(), lids[id].second, creation_index, item.owner()));
496#endif /* SPLIT_CONTAINER */
497 }
498 entry->freeDefinedLids();
499 }
500
501 std::sort(entry_index.begin(), entry_index.end(), EntryIndexComparator());
502
503 ALIEN_ASSERT(
504 ((Integer)entry_index.size() == m_local_entry_count + m_global_entry_count),
505 ("Inconsistent global size"));
506
507 if (m_parallel_mng->commSize() > 1)
508 parallel_prepare(entry_index);
509 else
510 sequential_prepare(entry_index);
511
512 // Finalize : fige les données dans les entries
513 for (auto& i : m_entry_set) {
514 i.second->finalize(entry_index);
515 }
516
517 if (m_trace) {
518 m_trace->info() << "Entry ordering :";
519 for (auto& i : m_entry_set) {
520 m_trace->info() << "\tEntry '" << i.first << "' placed at rank "
521 << i.second->getCreationIndex() << " with "
522 << i.second->getOwnLocalIds().size() << " local / "
523 << i.second->getAllLocalIds().size() << " global indexes ";
524 }
525 m_trace->info() << "Total local Entry indexes = " << m_local_entry_count;
526 }
527
528 m_state = Prepared;
529}
530
531/*---------------------------------------------------------------------------*/
532
533void BasicIndexManager::parallel_prepare(EntryIndexMap& entry_index)
534{
535 ALIEN_ASSERT((m_parallel_mng->commSize() > 1), ("Parallel mode expected"));
536
537 /* Algorithme:
538 * 1 - listing des couples Entry-Item non locaux
539 * 2 - Envoi vers les propriétaires des items non locaux
540 * 3 - Prise en compte éventuelle de nouvelles entrées
541 * 4 - Nommage locales
542 * 5 - Retour vers demandeurs des EntryIndex non locaux
543 * 6 - Finalisation de la numérotation (table reindex)
544 */
545
546 // Infos utiles
547 Alien::Ref<ISerializeMessageList> messageList;
548
549 // Structure pour accumuler et structurer la collecte de l'information
550 typedef std::map<EntryImpl*, EntrySendRequest> SendRequestByEntry;
551 typedef std::map<Integer, SendRequestByEntry> SendRequests;
552 SendRequests sendRequests;
553
554 // 1 - Comptage des Items non locaux
555 for (const auto& entryIndex : entry_index) {
556 MyEntryImpl* entryImpl = entryIndex.m_entry;
557 const Integer item_owner = entryIndex.m_owner;
558 if (item_owner != m_local_owner) {
559 sendRequests[item_owner][entryImpl].count++;
560 }
561 }
562
563 // Liste de synthèse des messages (emissions / réceptions)
564 messageList = Arccore::MessagePassing::mpCreateSerializeMessageListRef(m_parallel_mng);
565 // Contruction de la table de communications + préparation des messages d'envoi
566 UniqueArray<Integer> sendToDomains(2 * m_parallel_mng->commSize(), 0);
567
568 for (auto& sendRequest : sendRequests) {
569 const Integer destDomainId = sendRequest.first;
570 SendRequestByEntry& requests = sendRequest.second;
571 for (auto& j : requests) {
572 EntrySendRequest& request = j.second;
573 EntryImpl* entryImpl = j.first;
574 const String nameString = entryImpl->getName();
575
576 // Données pour receveur
577 sendToDomains[2 * destDomainId + 0] += 1;
578 sendToDomains[2 * destDomainId + 1] += request.count;
579
580 // Construction du message du EntrySendRequest
581 request.comm = messageList->createAndAddMessage(MessageRank(destDomainId),
582 Arccore::MessagePassing::ePointToPointMessageType::MsgSend);
583
584 auto sbuf = request.comm->serializer();
585 sbuf->setMode(Alien::ISerializer::ModeReserve); // phase préparatoire
586 sbuf->reserve(nameString); // Chaine de caractère du nom de l'entrée
587 sbuf->reserveInteger(1); // Nb d'item
588 sbuf->reserve(Alien::ISerializer::DT_Int64, request.count); // Les uid
589 sbuf->allocateBuffer(); // allocation mémoire
590 sbuf->setMode(Alien::ISerializer::ModePut);
591 sbuf->put(nameString);
592 sbuf->put(request.count);
593 }
594 }
595
596 // 2 - Accumulation des valeurs à demander
597 for (const auto& entryIndex : entry_index) {
598 MyEntryImpl* entryImpl = entryIndex.m_entry;
599 const Integer item_owner = entryIndex.m_owner;
600 const Int64 item_uid = entryIndex.m_uid;
601 if (item_owner != m_local_owner)
602 sendRequests[item_owner][entryImpl].comm->serializer()->put(item_uid);
603 }
604
605 // Réception des annonces de demandes (les nombres d'entrée + taille)
606 UniqueArray<Integer> recvFromDomains(2 * m_parallel_mng->commSize());
607 Arccore::MessagePassing::mpAllToAll(m_parallel_mng, sendToDomains, recvFromDomains, 2);
608
609 // Table des requetes exterieures (reçoit les uid et renverra les EntryIndex finaux)
610 typedef std::list<EntryRecvRequest> RecvRequests;
611 RecvRequests recvRequests;
612
613 for (Integer isd = 0, nsd = m_parallel_mng->commSize(); isd < nsd; ++isd) {
614 Integer recvCount = recvFromDomains[2 * isd + 0];
615 while (recvCount-- > 0) {
616 auto recvMsg = messageList->createAndAddMessage(MessageRank(isd),
617 Arccore::MessagePassing::ePointToPointMessageType::MsgReceive);
618 recvRequests.push_back(EntryRecvRequest());
619 EntryRecvRequest& recvRequest = recvRequests.back();
620 recvRequest.comm = recvMsg;
621 }
622 }
623
624 // Traitement des communications
625 messageList->processPendingMessages();
626 messageList->waitMessages(Arccore::MessagePassing::WaitAll);
627 messageList.reset();
628
629 // Pour les réponses vers les demandeurs
630 messageList = Arccore::MessagePassing::mpCreateSerializeMessageListRef(m_parallel_mng);
631
632 // 3 - Réception et mise en base local des demandes
633 for (auto& recvRequest : recvRequests) {
634 String nameString;
635 Integer uidCount;
636
637 { // Traitement des arrivées
638 auto sbuf = recvRequest.comm->serializer();
639 sbuf->setMode(Alien::ISerializer::ModeGet);
640
641 sbuf->get(nameString);
642 uidCount = sbuf->getInteger();
643 recvRequest.ids.resize(uidCount);
644 sbuf->getSpan(recvRequest.ids);
645 ALIEN_ASSERT((uidCount == recvRequest.ids.size()), ("Inconsistency detected"));
646
647 /* Si on est sûr que les entrées et l'item demandées doivent
648 * toujours exister (même les pires cas), on peut faire
649 * l'indexation locale avant et envoyer immédiatement (via un
650 * buffer; dans la présente boucle) la réponse.
651 */
652
653 // Reconstruction de l'entrée à partir du nom
654 auto lookup = m_entry_set.find(nameString);
655 // Si pas d'entrée de ce côté => système défectueux ?
656 if (lookup == m_entry_set.end())
657 throw FatalErrorException("Non local Entry Requested : degenerated system ?");
658
659 MyEntryImpl* currentEntry = lookup->second;
660 const Integer current_creation_index = currentEntry->getCreationIndex();
661
662 // Passage de l'uid à l'item associé (travaille sur place : pas de recopie)
663 ArrayView<Int64> ids = recvRequest.ids;
664
665 const IAbstractFamily& family = currentEntry->getFamily();
666 const Integer entry_kind = currentEntry->getKind();
667 UniqueArray<Int32> lids(ids.size());
668 family.uniqueIdToLocalId(lids, ids);
669 // Vérification d'intégrité : toutes les entrées demandées sont définies
670 // localement
671 SharedArray<Integer> owners = family.owners(lids).clone();
672 for (Integer j = 0; j < uidCount; ++j) {
673 const Integer current_item_lid = lids[j];
674 const Int64 current_item_uid = ids[j];
675 const Integer current_item_owner = owners[j];
676
677 if (current_item_owner != m_local_owner)
678 throw FatalErrorException("Non local EntryIndex requested");
679
680 InternalEntryIndex lookup_entry(currentEntry, current_item_lid, entry_kind,
681 current_item_uid, 0, current_creation_index, current_item_owner);
682
683 auto lookup2 = std::lower_bound(
684 entry_index.begin(), entry_index.end(), lookup_entry, EntryIndexComparator());
685
686 if ((lookup2 == entry_index.end()) || !(*lookup2 == lookup_entry))
687 throw FatalErrorException("Not locally defined entry requested");
688
689 // Mise en place de la pre-valeur retour [avant renumérotation locale]
690 // (EntryIndex écrit sur un Int64)
691 ids[j] = lookup2->m_index;
692 }
693 }
694
695 { // Préparation des retours
696 auto dest = recvRequest.comm->destination(); // Attention à l'ordre bizarre
697 auto orig = recvRequest.comm->source(); // de SerializeMessage
698 recvRequest.comm.reset();
699 recvRequest.comm = messageList->createAndAddMessage(dest, Arccore::MessagePassing::ePointToPointMessageType::MsgSend);
700
701 auto sbuf = recvRequest.comm->serializer();
702 sbuf->setMode(Alien::ISerializer::ModeReserve); // phase préparatoire
703 sbuf->reserve(nameString); // Chaine de caractère du nom de l'entrée
704 sbuf->reserveInteger(1); // Nb d'item
705 sbuf->reserveInteger(uidCount); // Les index
706 sbuf->allocateBuffer(); // allocation mémoire
707 sbuf->setMode(Alien::ISerializer::ModePut);
708 sbuf->put(nameString);
709 sbuf->put(uidCount);
710 }
711 }
712
713 // 4 - Indexation locale
714 /* La politique naive ici appliquée est de numéroter tous les
715 * (Entry,Item) locaux d'abord.
716 */
717 // Calcul de des offsets globaux sur Entry (via les tailles locales)
718 UniqueArray<Integer> allLocalSizes(m_parallel_mng->commSize());
719 UniqueArray<Integer> myLocalSize(1);
720 myLocalSize[0] = m_local_entry_count;
721
722 Arccore::MessagePassing::mpAllGather(m_parallel_mng, myLocalSize, allLocalSizes);
723 // Table de ré-indexation (EntryIndex->Integer)
724 Alien::UniqueArray<Integer> entry_reindex(m_local_entry_count + m_global_entry_count);
725 entry_reindex.fill(-1); // valeur de type Erreur par défaut
726
727 // Calcul de la taille des indices par entrée
728 reserveEntries(entry_index);
729
730 // Mise à jour du contenu des entrées
731 m_global_entry_offset = 0;
732 for (Integer i = 0; i < m_parallel_mng->commRank(); ++i) {
733 m_global_entry_offset += allLocalSizes[i];
734 }
735 // Utiliser MPI_Scan ? (equivalent Alien)
736
737 // C'est ici et uniquement ici qu'est matérialisé l'ordre des entrées
738 Integer currentEntryIndex = m_global_entry_offset; // commence par l'offset local
739 for (auto& i : entry_index) {
740 const InternalEntryIndex& entryIndex = i;
741 ALIEN_ASSERT((entryIndex.m_entry != nullptr), ("Unexpected null entry"));
742 const Integer item_owner = entryIndex.m_owner;
743 if (item_owner == m_local_owner) { // Numérotation locale !
744 const Integer newIndex = currentEntryIndex++;
745 entry_reindex[i.m_index + m_global_entry_count] = newIndex; // Table de translation
746 i.m_index = newIndex;
747 }
748 }
749
750 // 5 - Envoie des retours (EntryIndex globaux)
751
752 for (auto& recvRequest : recvRequests) {
753 auto sbuf = recvRequest.comm->serializer();
754 auto& ids = recvRequest.ids;
755 for (Integer j = 0; j < ids.size(); ++j) {
756 sbuf->putInteger(
757 entry_reindex[ids[j] + m_global_entry_count]); // Via la table de réindexation
758 }
759 }
760
761 // Table des buffers de retour
762 typedef std::list<Alien::Ref<Alien::ISerializeMessage>> ReturnedRequests;
763 ReturnedRequests returnedRequests;
764
765 // Acces rapide aux buffers connaissant le proc emetteur et le nom d'une entrée
766 /* Car on ne peut tager les buffers donc l'entrée reçue dans un buffer est non
767 * déterminée
768 * surtout si 2 domaines se communiquent plus d'une entrée
769 */
770 typedef std::map<Integer, EntrySendRequest*> SubFastReturnMap;
771 typedef std::map<String, SubFastReturnMap> FastReturnMap;
772 FastReturnMap fastReturnMap;
773
774 // Préparation des réceptions [sens inverse]
775 for (auto& sendRequest : sendRequests) {
776 const Integer destDomainId = sendRequest.first;
777 SendRequestByEntry& requests = sendRequest.second;
778 for (auto& j : requests) {
779 EntrySendRequest& request = j.second;
780 EntryImpl* entryImpl = j.first;
781 const String nameString = entryImpl->getName();
782
783 // On ne peut pas associer directement le message à cette entrée
784 // : dans le cas d'échange multiple il n'y pas de garantie d'arrivée
785 // à la bonne place
786 auto msg = messageList->createAndAddMessage(MessageRank(destDomainId),
787 Arccore::MessagePassing::ePointToPointMessageType::MsgReceive);
788
789 returnedRequests.push_back(msg);
790
791 fastReturnMap[nameString][destDomainId] = &request;
792 }
793 }
794
795 // Traitement des communications
796 messageList->processPendingMessages();
797 messageList->waitMessages(Arccore::MessagePassing::WaitAll);
798 messageList.reset();
799
800 // 6 - Traitement des réponses
801 // Association aux EntrySendRequest du buffer correspondant
802 for (auto& returnedRequest : returnedRequests) {
803 auto& message = returnedRequest;
804 auto origDomainId = message->destination().value();
805 auto sbuf = message->serializer();
806 sbuf->setMode(Alien::ISerializer::ModeGet);
807 String nameString;
808 sbuf->get(nameString);
809 ALIEN_ASSERT(
810 (fastReturnMap[nameString][origDomainId] != nullptr), ("Inconsistency detected"));
811 EntrySendRequest& request = *fastReturnMap[nameString][origDomainId];
812 request.comm =
813 returnedRequest; // Reconnection pour accès rapide depuis l'EntrySendRequest
814
815 const Integer idCount = sbuf->getInteger();
816 ALIEN_ASSERT((request.count == idCount), ("Inconsistency detected"));
817 }
818
819 // Distribution des reponses
820 // Par parcours dans ordre initial (celui de la demande)
821 for (auto& i : entry_index) {
822 const InternalEntryIndex& entryIndex = i;
823 const Integer item_owner = entryIndex.m_owner;
824 if (item_owner != m_local_owner) {
825 EntryImpl* entryImpl = entryIndex.m_entry;
826 EntrySendRequest& request = sendRequests[item_owner][entryImpl];
827 ALIEN_ASSERT((request.count > 0), ("Unexpected empty request"));
828 --request.count;
829 auto sbuf = request.comm->serializer();
830 const Integer newIndex = sbuf->getInteger();
831
832 entry_reindex[i.m_index + m_global_entry_count] = newIndex;
833 i.m_index = newIndex;
834 }
835 }
836
837 // Calcul de la taille global d'indexation (donc du système associé)
838 m_global_entry_count = 0;
839 for (Integer i = 0; i < m_parallel_mng->commSize(); ++i) {
840 m_global_entry_count += allLocalSizes[i];
841 }
842}
843
844/*---------------------------------------------------------------------------*/
845
846void BasicIndexManager::sequential_prepare(EntryIndexMap& entry_index)
847{
848 ALIEN_ASSERT((m_parallel_mng->commSize() <= 1), ("Sequential mode expected"));
849 ALIEN_ASSERT((m_global_entry_count == 0),
850 ("Unexpected global entries (%d)", m_global_entry_count));
851
852 // Très similaire à la section parallèle :
853 // 4 - Indexation locale
854 /* La politique naive ici appliquée est de numéroter tous les
855 * (Entry,Item) locaux d'abord.
856 */
857
858 // Table de ré-indexation (EntryIndex->Integer)
859 UniqueArray<Integer> entry_reindex(m_local_entry_count + m_local_removed_entry_count);
860 entry_reindex.fill(-1); // valeur de type Erreur par défaut
861
862 // Calcul de la taille des indices par entrée
863 reserveEntries(entry_index);
864
865 // Mise à jour du contenu des entrées
866 // Pas d'offset car séquentiel
867 m_global_entry_offset = 0;
868
869 // C'est ici et uniquement ici qu'est matérialisé l'ordre des entrées
870 Integer currentEntryIndex = m_global_entry_offset; // commence par l'offset local
871 for (auto& i : entry_index) {
872 ALIEN_ASSERT((i.m_entry != nullptr), ("Unexpected null entry"));
873 ALIEN_ASSERT(
874 (i.m_owner == m_local_owner), ("Item cannot be non-local for sequential mode"));
875 // Numérotation locale only !
876 const Integer newIndex = currentEntryIndex++;
877 entry_reindex[i.m_index + m_global_entry_count] = newIndex; // Table de translation
878 i.m_index = newIndex;
879 }
880
881 m_global_entry_count = m_local_entry_count;
882}
883
884/*---------------------------------------------------------------------------*/
885
886void BasicIndexManager::reserveEntries(const EntryIndexMap& entry_index)
887{
888 // Calcul de la taille des indices par entrée
889 std::map<const EntryImpl*, Integer> count_table;
890 for (const auto& i : entry_index) {
891 const EntryImpl* entryImpl = i.m_entry;
892 count_table[entryImpl]++;
893 }
894
895 // Dimensionnement des buffers de chaque entrée
896 for (auto& i : m_entry_set) {
897 MyEntryImpl* entry = i.second;
898 entry->reserve(count_table[entry]);
899 // if (m_trace) m_trace->pinfo() << "Entry " << entry->getName() << " size = "
900 // << count_table[entry];
901 }
902}
903
904/*---------------------------------------------------------------------------*/
905
906/*---------------------------------------------------------------------------*/
907
908/*---------------------------------------------------------------------------*/
909
910UniqueArray<Integer>
912{
913 if (m_state != Prepared)
914 throw FatalErrorException(A_FUNCINFO, "Inconsistent state");
915
916 ALIEN_ASSERT((entry.manager() == this), ("Incompatible entry from another manager"));
917 auto* en = dynamic_cast<MyEntryImpl*>(entry.internal());
918 ALIEN_ASSERT((en != nullptr), ("Unexpected null entry"));
919 const IAbstractFamily& family = en->getFamily();
920 UniqueArray<Integer> allIds(family.maxLocalId(), nullIndex());
921 const ConstArrayView<Integer> allIndices = en->getAllIndexes();
922 const ConstArrayView<Integer> allLocalIds = en->getAllLocalIds();
923 const Integer size = allIndices.size();
924 for (Integer i = 0; i < size; ++i)
925 allIds[allLocalIds[i]] = allIndices[i];
926 return allIds;
927}
928
929/*---------------------------------------------------------------------------*/
930
931UniqueArray2<Integer>
932BasicIndexManager::getIndexes(const VectorIndexSet& entries) const
933{
934 if (m_state != Prepared)
935 throw FatalErrorException(A_FUNCINFO, "Inconsistent state");
936
937 Integer max_family_size = 0;
938 for (Integer entry = 0; entry < entries.size(); ++entry) {
939 // controles uniquement en première passe
940 ALIEN_ASSERT(
941 (entries[entry].manager() == this), ("Incompatible entry from another manager"));
942 auto* en = dynamic_cast<MyEntryImpl*>(entries[entry].internal());
943 ALIEN_ASSERT((en != nullptr), ("Unexpected null entry"));
944 const IAbstractFamily& family = en->getFamily();
945 max_family_size = std::max(max_family_size, family.maxLocalId());
946 }
947
948 UniqueArray2<Integer> allIds(max_family_size, entries.size());
949 allIds.fill(nullIndex());
950
951 for (Integer entry = 0; entry < entries.size(); ++entry) {
952 auto* en = dynamic_cast<MyEntryImpl*>(entries[entry].internal());
953 const ConstArrayView<Integer> allIndices = en->getAllIndexes();
954 const ConstArrayView<Integer> allLocalIds = en->getAllLocalIds();
955 const Integer size = allIndices.size();
956 for (Integer i = 0; i < size; ++i)
957 allIds[allLocalIds[i]][entry] = allIndices[i];
958 }
959 return allIds;
960}
961
962/*---------------------------------------------------------------------------*/
963
965Integer& globalSize, Integer& minLocalIndex, Integer& localSize) const
966{
967 if (m_state != Prepared)
968 throw FatalErrorException(A_FUNCINFO, "Inconsistent state");
969
970 globalSize = m_global_entry_count;
971 minLocalIndex = m_global_entry_offset;
972 localSize = m_local_entry_count;
973}
974
975/*---------------------------------------------------------------------------*/
976
977Integer
979{
980 if (m_state != Prepared)
981 throw FatalErrorException(A_FUNCINFO, "Inconsistent state");
982
983 return m_global_entry_count;
984}
985
986/*---------------------------------------------------------------------------*/
987
988Integer
990{
991 if (m_state != Prepared)
992 throw FatalErrorException(A_FUNCINFO, "Inconsistent state");
993
994 return m_global_entry_offset;
995}
996
997/*---------------------------------------------------------------------------*/
998
999Integer
1001{
1002 if (m_state != Prepared)
1003 throw FatalErrorException(A_FUNCINFO, "Inconsistent state");
1004
1005 return m_local_entry_count;
1006}
1007
1008/*---------------------------------------------------------------------------*/
1009
1012{
1013 return EntryEnumerator(new MyEntryEnumeratorImpl(m_entry_set));
1014}
1015
1016/*---------------------------------------------------------------------------*/
1017
1018bool BasicIndexManager::EntryIndexComparator::operator()(
1021{
1022 const MyEntryImpl* aEntry = a.m_entry;
1023 const MyEntryImpl* bEntry = b.m_entry;
1024 if (a.m_kind != b.m_kind)
1025 return a.m_kind < b.m_kind;
1026 else if (a.m_uid != b.m_uid)
1027 return a.m_uid < b.m_uid;
1028 else
1029 return aEntry->getCreationIndex() < bEntry->getCreationIndex();
1030 // return a.m_creation_index < b.m_creation_index;
1031}
1032
1033/*---------------------------------------------------------------------------*/
1034
1035IIndexManager::ScalarIndexSet
1037 ConstArrayView<Integer> localIds,
1038 const IAbstractFamily& family)
1039{
1040 ScalarIndexSet en = buildEntry(name, &family, addNewAbstractFamily(&family));
1041 defineIndex(en, localIds);
1042 return en;
1043}
1044
1045/*---------------------------------------------------------------------------*/
1046
1047IIndexManager::ScalarIndexSet
1048BasicIndexManager::buildScalarIndexSet(const String& name, const IAbstractFamily& family)
1049{
1050 UniqueArray<Int32> localIds = family.allLocalIds();
1051 Entry en = buildEntry(name, &family, addNewAbstractFamily(&family));
1052 defineIndex(en, localIds.view());
1053 return en;
1054}
1055
1056/*---------------------------------------------------------------------------*/
1057
1058IIndexManager::VectorIndexSet
1060 ConstArrayView<Integer> localIds,
1061 const IAbstractFamily& family, Integer n)
1062{
1063 VectorIndexSet ens(n);
1064 for (Integer i = 0; i < n; ++i) {
1065 ens[i] = buildEntry(
1066 String::format("{0}[{1}]", name, i), &family, addNewAbstractFamily(&family));
1067 defineIndex(ens[i], localIds);
1068 }
1069 return ens;
1070}
1071
1072/*---------------------------------------------------------------------------*/
1073
1074IIndexManager::VectorIndexSet
1076const String& name, const IAbstractFamily& family, Integer n)
1077{
1078 UniqueArray<Int32> localIds = family.allLocalIds();
1079
1080 VectorIndexSet ens(n);
1081 for (Integer i = 0; i < n; ++i) {
1082 ens[i] = buildEntry(
1083 String::format("{0}[{1}]", name, i), &family, addNewAbstractFamily(&family));
1084 defineIndex(ens[i], localIds.view());
1085 }
1086 return ens;
1087}
1088
1089/*---------------------------------------------------------------------------*/
1090
1092{
1093 auto finder = m_abstract_family_to_kind_map.find(family);
1094 if (finder == m_abstract_family_to_kind_map.end())
1095 return; // pas connu => on ne fait rien
1096 if (m_abstract_families[finder->second])
1097 throw FatalErrorException(A_FUNCINFO, "Already known as kept alive abstract family");
1098
1099 IAbstractFamily* new_family = family->clone();
1100 m_abstract_families[finder->second].reset(new_family);
1101 for (auto& i : m_entry_set) {
1102 MyEntryImpl* entry = i.second;
1103 if (&entry->getFamily() == family)
1104 entry->resetFamily(new_family);
1105 }
1106}
1107
1108/*---------------------------------------------------------------------------*/
1109
1110Integer
1111BasicIndexManager::addNewAbstractFamily(const IAbstractFamily* family)
1112{
1113 auto finder = m_abstract_family_to_kind_map.find(family);
1114 if (finder == m_abstract_family_to_kind_map.end()) {
1115 const Integer newKind = m_abstract_family_base_kind++;
1116 ALIEN_ASSERT((newKind < KIND_SHIFT), ("Unexpected kind overflow"));
1117 m_abstract_family_to_kind_map[family] = newKind;
1118 m_abstract_families[newKind] =
1119 std::shared_ptr<IAbstractFamily>(); // this place will be used when the family
1120 // memory management will be delegated to
1121 // this class
1122 return newKind;
1123 }
1124 else {
1125 return finder->second;
1126 }
1127}
1128
1129/*---------------------------------------------------------------------------*/
1130/*---------------------------------------------------------------------------*/
1131
1132} // namespace Alien
1133
1134/*---------------------------------------------------------------------------*/
1135/*---------------------------------------------------------------------------*/
Squelette de l'implementation locale de Entry La vraie implémentation est MyAbstractEntryImpl....
Arccore::ConstArrayView< Integer > getAllLocalIds() const override
Retourne la liste des Items de l'Entry (own + ghost).
const IAbstractFamily & getFamily() const override
Retourne la famille abstraite de l'Entry.
void finalize(const EntryIndexMap &entryIndex)
Fige les données de l'entry (fin de phase prepare).
Integer getKind() const override
Retourne le type de support de l'Entry.
IIndexManager * manager() const override
Référentiel du manager associé
Arccore::ConstArrayView< Arccore::Integer > getAllIndexes() const override
Retourne la liste des Index de l'Entry (own + ghost).
Arccore::ConstArrayView< Arccore::Integer > getOwnLocalIds() const override
Retourne la liste des Items de l'Entry.
String getName() const override
Retourne le nom de l'entrée.
void reserve(const Integer n)
Préparation des buffers d'indices et d'items.
Arccore::ConstArrayView< Arccore::Integer > getOwnIndexes() const override
Retourne la liste des Index de l'Entry.
MyEntryImpl(const String &name, const IAbstractFamily *family, const Integer creationIndex, BasicIndexManager *manager, Integer kind)
Constructeur par défaut.
UniqueArray< Integer > m_all_items
LocalIds des items gérés par cette entrée rangés own puis ghost.
Integer m_own_size
Nombre d'items own dans les tableaux m_all_*.
std::map< Arccore::String, MyEntryImpl * > EntrySet
Table des Entry connues localement.
Arccore::UniqueArray< Arccore::Integer > getIndexes(const ScalarIndexSet &entry) const override
Fournit une table de translation indexé par les items.
void keepAlive(const IAbstractFamily *family) override
Permet de gérer la mort d'une famille associée à l'index-manager.
VectorIndexSet buildVectorIndexSet(const Arccore::String &name, Arccore::IntegerConstArrayView localIds, const IIndexManager::IAbstractFamily &family, Arccore::Integer n) override
Construit une nouvelle entrée vectoriellesur un ensemble d'entités abstraites.
Arccore::Integer minLocalIndex() const override
Retourne l'indice minimum local.
void setTraceMng(Alien::ITraceMng *traceMng) override
Définit le gestionnaire de trace.
Arccore::Integer m_abstract_family_base_kind
Famille des familles abstraites associées aux familles du maillage.
std::map< const IAbstractFamily *, Arccore::Integer > m_abstract_family_to_kind_map
IAbstractFamily extérieures.
Arccore::Integer m_local_owner
Identifiant du 'propriétaire' courant.
Arccore::Integer localSize() const override
Retourne l'indice minimum local.
Arccore::Integer nullIndex() const override
return value of null index
std::map< Arccore::Integer, std::shared_ptr< IAbstractFamily > > m_abstract_families
Table des IAbstractFamily ici gérées.
void init_mine()
Init datastructure with a non virtual function.
Entry getEntry(const Arccore::String &name) const override
Retourne l'entrée associée à un nom.
Arccore::Integer globalSize() const override
Retourne la taille globale.
void stats(Arccore::Integer &globalSize, Arccore::Integer &minLocalIndex, Arccore::Integer &localSize) const override
Statistiques d'indexation.
ScalarIndexSet buildScalarIndexSet(const Arccore::String &name, Arccore::IntegerConstArrayView localIds, const IIndexManager::IAbstractFamily &family) override
Construit une nouvelle entrée scalaire sur un ensemble d'entités abstraites.
BasicIndexManager(Alien::IMessagePassingMng *parallelMng)
Constructeur de la classe.
Arccore::Integer m_creation_index
Index de creation des entrées.
Arccore::MessagePassing::IMessagePassingMng * parallelMng() const override
Donne le gestionnaire parallèle ayant servi à l'indexation.
EntryEnumerator enumerateEntry() const override
Construction d'un enumerateur sur les Entry.
void prepare() override
Préparation : fixe l'indexation (fin des définitions).
void init() override
Initialisation.
~BasicIndexManager() override
Destructeur de la classe.
Interface for abstract families of items.
virtual SafeConstArrayView< Integer > owners(ConstArrayView< Integer > localIds) const =0
Owners of the given local ids.
Interface d'implementation de EntryEnumerator.
Classe d'énumération des Entry connues.
Interface d'implémentation de Entry.
virtual Arccore::String getName() const =0
Retourne le nom de l'entrée.
Classe de représentation des Entry.
EntryImpl * internal() const
Accès interne à l'implementation.
IIndexManager * manager() const
Référentiel du manager associé
Interface des familles abstraites pour l'indexation de items.
virtual Arccore::SharedArray< Arccore::Int64 > uids(Arccore::ConstArrayView< Arccore::Int32 > localIds) const =0
Retourne l'ensemble des uniqueIds d'un ensemble d'item décrits par leur localIds.
virtual IAbstractFamily * clone() const =0
Construit un clone de cet objet.
virtual Arccore::Int32 maxLocalId() const =0
Identifiant maximal des localIds pour cette famille.
virtual Item item(Arccore::Int32 localId) const =0
Retourne un objet Item à partir de son localId.
virtual Arccore::SharedArray< Arccore::Integer > owners(Arccore::ConstArrayView< Arccore::Int32 > localIds) const =0
IIndexManager()=default
Constructeur par défaut.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
Definition BackEnd.h:17