13#include "Teuchos_StandardParameterEntryValidators.hpp"
23 if (sendType == DISTRIBUTOR_ISEND) {
25 }
else if (sendType == DISTRIBUTOR_SEND) {
27 }
else if (sendType == DISTRIBUTOR_ALLTOALL) {
30#if defined(HAVE_TPETRA_MPI)
31 else if (sendType == DISTRIBUTOR_IALLTOFEWV) {
35#if defined(HAVE_TPETRACORE_MPI_ADVANCE)
36 else if (sendType == DISTRIBUTOR_MPIADVANCE_ALLTOALL) {
37 return "MpiAdvanceAlltoall";
38 }
else if (sendType == DISTRIBUTOR_MPIADVANCE_NBRALLTOALLV) {
39 return "MpiAdvanceNbralltoallv";
43 TEUCHOS_TEST_FOR_EXCEPTION(
true, std::invalid_argument,
45 "EDistributorSendType enum value "
52 if (s ==
"Isend")
return DISTRIBUTOR_ISEND;
53 if (s ==
"Send")
return DISTRIBUTOR_SEND;
54 if (s ==
"Alltoall")
return DISTRIBUTOR_ALLTOALL;
55#if defined(HAVE_TPETRA_MPI)
56 if (s ==
"Ialltofewv")
return DISTRIBUTOR_IALLTOFEWV;
58#if defined(HAVE_TPETRACORE_MPI_ADVANCE)
59 if (s ==
"MpiAdvanceAlltoall")
return DISTRIBUTOR_MPIADVANCE_ALLTOALL;
60 if (s ==
"MpiAdvanceNbralltoallv")
return DISTRIBUTOR_MPIADVANCE_NBRALLTOALLV;
62 TEUCHOS_TEST_FOR_EXCEPTION(
true, std::invalid_argument,
"Invalid string to convert to EDistributorSendType enum value: " << s);
68 if (std::find(valids.begin(), valids.end(), s) == valids.end()) {
69 TEUCHOS_TEST_FOR_EXCEPTION(
true, std::invalid_argument,
"Invalid string for EDistributorSendType enum value: " << s);
77 case Details::DISTRIBUTOR_NOT_INITIALIZED:
78 return "Not initialized yet";
79 case Details::DISTRIBUTOR_INITIALIZED_BY_CREATE_FROM_SENDS:
80 return "By createFromSends";
81 case Details::DISTRIBUTOR_INITIALIZED_BY_CREATE_FROM_RECVS:
82 return "By createFromRecvs";
83 case Details::DISTRIBUTOR_INITIALIZED_BY_CREATE_FROM_SENDS_N_RECVS:
84 return "By createFromSendsAndRecvs";
85 case Details::DISTRIBUTOR_INITIALIZED_BY_REVERSE:
86 return "By createReverseDistributor";
87 case Details::DISTRIBUTOR_INITIALIZED_BY_COPY:
88 return "By copy constructor";
94DistributorPlan::DistributorPlan(Teuchos::RCP<
const Teuchos::Comm<int>> comm)
97#if defined(HAVE_TPETRACORE_MPI_ADVANCE)
98 mpixComm_(Teuchos::null)
101 howInitialized_(DISTRIBUTOR_NOT_INITIALIZED)
102 , reversePlan_(Teuchos::null)
104 , sendMessageToSelf_(false)
105 , numSendsToOtherProcs_(0)
108 , totalReceiveLength_(0) {
111DistributorPlan::DistributorPlan(
const DistributorPlan& otherPlan)
112 : comm_(otherPlan.comm_)
114#if defined(HAVE_TPETRACORE_MPI_ADVANCE)
115 mpixComm_(otherPlan.mpixComm_)
118 howInitialized_(DISTRIBUTOR_INITIALIZED_BY_COPY)
119 , reversePlan_(otherPlan.reversePlan_)
120 , sendType_(otherPlan.sendType_)
121 , sendMessageToSelf_(otherPlan.sendMessageToSelf_)
122 , numSendsToOtherProcs_(otherPlan.numSendsToOtherProcs_)
123 , procIdsToSendTo_(otherPlan.procIdsToSendTo_)
124 , startsTo_(otherPlan.startsTo_)
125 , lengthsTo_(otherPlan.lengthsTo_)
126 , maxSendLength_(otherPlan.maxSendLength_)
127 , indicesTo_(otherPlan.indicesTo_)
128 , numReceives_(otherPlan.numReceives_)
129 , totalReceiveLength_(otherPlan.totalReceiveLength_)
130 , lengthsFrom_(otherPlan.lengthsFrom_)
131 , procsFrom_(otherPlan.procsFrom_)
132 , startsFrom_(otherPlan.startsFrom_)
133 , indicesFrom_(otherPlan.indicesFrom_)
134#if defined(HAVE_TPETRACORE_MPI)
135 , roots_(otherPlan.roots_)
140size_t DistributorPlan::createFromSends(
const Teuchos::ArrayView<const int>& exportProcIDs) {
142 using Teuchos::outArg;
143 using Teuchos::REDUCE_MAX;
144 using Teuchos::reduceAll;
145 const char rawPrefix[] =
"Tpetra::DistributorPlan::createFromSends";
146 Tpetra::Details::ProfilingRegion pr(
"Tpetra::DistributorPlan::createFromSends");
148 const size_t numExports = exportProcIDs.size();
149 const int myProcID = comm_->getRank();
150 const int numProcs = comm_->getSize();
194 for (
size_t i = 0; i < numExports; ++i) {
195 const int exportID = exportProcIDs[i];
196 if (exportID >= numProcs || exportID < 0) {
202 reduceAll<int, int>(*comm_, REDUCE_MAX, badID, outArg(gbl_badID));
203 TEUCHOS_TEST_FOR_EXCEPTION(gbl_badID >= 0, std::runtime_error, rawPrefix <<
"Proc " << gbl_badID <<
", perhaps among other processes, got a bad "
219 Teuchos::Array<size_t> starts(numProcs + 1, 0);
222 size_t numActive = 0;
223 int needSendBuff = 0;
225 for (
size_t i = 0; i < numExports; ++i) {
226 const int exportID = exportProcIDs[i];
241 if (needSendBuff == 0 && starts[exportID] > 1 &&
242 exportID != exportProcIDs[i - 1]) {
249#if defined(HAVE_TPETRA_PRINT_EFFICIENCY_WARNINGS)
251 int global_needSendBuff;
252 reduceAll<int, int>(*comm_, REDUCE_MAX, needSendBuff,
253 outArg(global_needSendBuff));
255 global_needSendBuff != 0,
256 "::createFromSends: Grouping export IDs together by process rank often "
257 "improves performance.");
263 if (starts[myProcID] != 0) {
264 sendMessageToSelf_ =
true;
266 sendMessageToSelf_ =
false;
271 numSendsToOtherProcs_ = 0;
274 for (
int i = 0; i < numProcs; ++i) {
276 ++numSendsToOtherProcs_;
282 indicesTo_.resize(0);
285 procIdsToSendTo_.assign(numSendsToOtherProcs_, 0);
286 startsTo_.assign(numSendsToOtherProcs_, 0);
287 lengthsTo_.assign(numSendsToOtherProcs_, 0);
294 size_t procIndex = 0;
295 for (
size_t i = 0; i < numSendsToOtherProcs_; ++i) {
296 while (exportProcIDs[procIndex] < 0) {
299 startsTo_[i] = procIndex;
300 int procID = exportProcIDs[procIndex];
301 procIdsToSendTo_[i] = procID;
302 procIndex += starts[procID];
307 if (numSendsToOtherProcs_ > 0) {
308 sort2(procIdsToSendTo_.begin(), procIdsToSendTo_.end(), startsTo_.begin());
312 for (
size_t i = 0; i < numSendsToOtherProcs_; ++i) {
313 int procID = procIdsToSendTo_[i];
314 lengthsTo_[i] = starts[procID];
315 if ((procID != myProcID) && (lengthsTo_[i] > maxSendLength_)) {
316 maxSendLength_ = lengthsTo_[i];
326 if (starts[0] == 0) {
327 numSendsToOtherProcs_ = 0;
329 numSendsToOtherProcs_ = 1;
331 for (Teuchos::Array<size_t>::iterator i = starts.begin() + 1,
332 im1 = starts.begin();
333 i != starts.end(); ++i) {
334 if (*i != 0) ++numSendsToOtherProcs_;
340 for (Teuchos::Array<size_t>::reverse_iterator ip1 = starts.rbegin(),
341 i = starts.rbegin() + 1;
342 i != starts.rend(); ++i) {
350 indicesTo_.resize(numActive);
352 for (
size_t i = 0; i < numExports; ++i) {
353 if (exportProcIDs[i] >= 0) {
355 indicesTo_[starts[exportProcIDs[i]]] = i;
357 ++starts[exportProcIDs[i]];
369 for (
int proc = numProcs - 1; proc != 0; --proc) {
370 starts[proc] = starts[proc - 1];
373 starts[numProcs] = numActive;
380 procIdsToSendTo_.resize(numSendsToOtherProcs_);
381 startsTo_.resize(numSendsToOtherProcs_);
382 lengthsTo_.resize(numSendsToOtherProcs_);
389 for (
int proc = 0; proc < numProcs; ++proc) {
390 if (starts[proc + 1] != starts[proc]) {
391 lengthsTo_[snd] = starts[proc + 1] - starts[proc];
392 startsTo_[snd] = starts[proc];
394 if ((proc != myProcID) && (lengthsTo_[snd] > maxSendLength_)) {
395 maxSendLength_ = lengthsTo_[snd];
397 procIdsToSendTo_[snd] = proc;
403 if (sendMessageToSelf_) {
404 --numSendsToOtherProcs_;
410#if defined(HAVE_TPETRA_MPI)
411 maybeInitializeRoots();
416 howInitialized_ = Details::DISTRIBUTOR_INITIALIZED_BY_CREATE_FROM_SENDS;
418 return totalReceiveLength_;
421void DistributorPlan::createFromRecvs(
const Teuchos::ArrayView<const int>& remoteProcIDs) {
422 *
this = *getReversePlan();
423 howInitialized_ = Details::DISTRIBUTOR_INITIALIZED_BY_CREATE_FROM_RECVS;
426void DistributorPlan::createFromSendsAndRecvs(
const Teuchos::ArrayView<const int>& exportProcIDs,
427 const Teuchos::ArrayView<const int>& remoteProcIDs) {
435 howInitialized_ = Tpetra::Details::DISTRIBUTOR_INITIALIZED_BY_CREATE_FROM_SENDS_N_RECVS;
437 int myProcID = comm_->getRank();
438 int numProcs = comm_->getSize();
440 const size_t numExportIDs = exportProcIDs.size();
441 Teuchos::Array<size_t> starts(numProcs + 1, 0);
443 size_t numActive = 0;
444 int needSendBuff = 0;
446 for (
size_t i = 0; i < numExportIDs; i++) {
447 if (needSendBuff == 0 && i && (exportProcIDs[i] < exportProcIDs[i - 1]))
449 if (exportProcIDs[i] >= 0) {
450 ++starts[exportProcIDs[i]];
455 sendMessageToSelf_ = (starts[myProcID] != 0) ? 1 : 0;
457 numSendsToOtherProcs_ = 0;
461 if (starts[0] == 0) {
462 numSendsToOtherProcs_ = 0;
464 numSendsToOtherProcs_ = 1;
466 for (Teuchos::Array<size_t>::iterator i = starts.begin() + 1,
467 im1 = starts.begin();
468 i != starts.end(); ++i) {
469 if (*i != 0) ++numSendsToOtherProcs_;
475 for (Teuchos::Array<size_t>::reverse_iterator ip1 = starts.rbegin(),
476 i = starts.rbegin() + 1;
477 i != starts.rend(); ++i) {
485 indicesTo_.resize(numActive);
487 for (
size_t i = 0; i < numExportIDs; ++i) {
488 if (exportProcIDs[i] >= 0) {
490 indicesTo_[starts[exportProcIDs[i]]] = i;
492 ++starts[exportProcIDs[i]];
495 for (
int proc = numProcs - 1; proc != 0; --proc) {
496 starts[proc] = starts[proc - 1];
499 starts[numProcs] = numActive;
500 procIdsToSendTo_.resize(numSendsToOtherProcs_);
501 startsTo_.resize(numSendsToOtherProcs_);
502 lengthsTo_.resize(numSendsToOtherProcs_);
505 for (
int proc = 0; proc < numProcs; ++proc) {
506 if (starts[proc + 1] != starts[proc]) {
507 lengthsTo_[snd] = starts[proc + 1] - starts[proc];
508 startsTo_[snd] = starts[proc];
510 if ((proc != myProcID) && (lengthsTo_[snd] > maxSendLength_)) {
511 maxSendLength_ = lengthsTo_[snd];
513 procIdsToSendTo_[snd] = proc;
519 numSendsToOtherProcs_ = 0;
522 for (
int i = 0; i < numProcs; ++i) {
524 ++numSendsToOtherProcs_;
530 indicesTo_.resize(0);
533 procIdsToSendTo_.assign(numSendsToOtherProcs_, 0);
534 startsTo_.assign(numSendsToOtherProcs_, 0);
535 lengthsTo_.assign(numSendsToOtherProcs_, 0);
542 size_t procIndex = 0;
543 for (
size_t i = 0; i < numSendsToOtherProcs_; ++i) {
544 while (exportProcIDs[procIndex] < 0) {
547 startsTo_[i] = procIndex;
548 int procID = exportProcIDs[procIndex];
549 procIdsToSendTo_[i] = procID;
550 procIndex += starts[procID];
555 if (numSendsToOtherProcs_ > 0) {
556 sort2(procIdsToSendTo_.begin(), procIdsToSendTo_.end(), startsTo_.begin());
560 for (
size_t i = 0; i < numSendsToOtherProcs_; ++i) {
561 int procID = procIdsToSendTo_[i];
562 lengthsTo_[i] = starts[procID];
563 if ((procID != myProcID) && (lengthsTo_[i] > maxSendLength_)) {
564 maxSendLength_ = lengthsTo_[i];
569 numSendsToOtherProcs_ -= sendMessageToSelf_;
570 std::vector<int> recv_list;
571 recv_list.reserve(numSendsToOtherProcs_);
574 for (
int i = 0; i < remoteProcIDs.size(); i++) {
575 if (remoteProcIDs[i] > last_pid) {
576 recv_list.push_back(remoteProcIDs[i]);
577 last_pid = remoteProcIDs[i];
578 }
else if (remoteProcIDs[i] < last_pid)
579 throw std::runtime_error(
"Tpetra::Distributor:::createFromSendsAndRecvs expected RemotePIDs to be in sorted order");
581 numReceives_ = recv_list.size();
583 procsFrom_.assign(numReceives_, 0);
584 lengthsFrom_.assign(numReceives_, 0);
585 indicesFrom_.assign(numReceives_, 0);
586 startsFrom_.assign(numReceives_, 0);
588 for (
size_t i = 0, j = 0; i < numReceives_; ++i) {
590 procsFrom_[i] = recv_list[i];
592 for (; j < (size_t)remoteProcIDs.size() &&
593 remoteProcIDs[jlast] == remoteProcIDs[j];
597 lengthsFrom_[i] = j - jlast;
599 totalReceiveLength_ = remoteProcIDs.size();
600 indicesFrom_.clear();
601 numReceives_ -= sendMessageToSelf_;
603#if defined(HAVE_TPETRA_MPI)
604 maybeInitializeRoots();
608Teuchos::RCP<DistributorPlan> DistributorPlan::getReversePlan()
const {
609 if (reversePlan_.is_null()) createReversePlan();
613void DistributorPlan::createReversePlan()
const {
614 reversePlan_ = Teuchos::rcp(
new DistributorPlan(comm_));
615 reversePlan_->howInitialized_ = Details::DISTRIBUTOR_INITIALIZED_BY_REVERSE;
616 reversePlan_->sendType_ = sendType_;
618#if defined(HAVE_TPETRACORE_MPI)
622 if (DISTRIBUTOR_IALLTOFEWV == sendType_) {
623 if (Behavior::verbose()) {
624 std::stringstream ss;
625 ss << __FILE__ <<
":" << __LINE__ <<
" WARNING (Ialltofewv send type): using default for reversed Ialltofewv\n";
626 std::cerr << ss.str();
636 size_t totalSendLength =
637 std::accumulate(lengthsTo_.begin(), lengthsTo_.end(), 0);
642 size_t maxReceiveLength = 0;
643 const int myProcID = comm_->getRank();
644 for (
size_t i = 0; i < numReceives_; ++i) {
645 if (procsFrom_[i] != myProcID) {
647 if (lengthsFrom_[i] > maxReceiveLength) {
648 maxReceiveLength = lengthsFrom_[i];
653 reversePlan_->sendMessageToSelf_ = sendMessageToSelf_;
654 reversePlan_->numSendsToOtherProcs_ = numReceives_;
655 reversePlan_->procIdsToSendTo_ = procsFrom_;
656 reversePlan_->startsTo_ = startsFrom_;
657 reversePlan_->lengthsTo_ = lengthsFrom_;
658 reversePlan_->maxSendLength_ = maxReceiveLength;
659 reversePlan_->indicesTo_ = indicesFrom_;
660 reversePlan_->numReceives_ = numSendsToOtherProcs_;
661 reversePlan_->totalReceiveLength_ = totalSendLength;
662 reversePlan_->lengthsFrom_ = lengthsTo_;
663 reversePlan_->procsFrom_ = procIdsToSendTo_;
664 reversePlan_->startsFrom_ = startsTo_;
665 reversePlan_->indicesFrom_ = indicesTo_;
667#if defined(HAVE_TPETRACORE_MPI_ADVANCE)
669 reversePlan_->initializeMpiAdvance();
672#if defined(HAVE_TPETRA_MPI)
673 reversePlan_->maybeInitializeRoots();
677void DistributorPlan::computeReceives() {
678 using Teuchos::Array;
679 using Teuchos::ArrayRCP;
681 using Teuchos::CommRequest;
682 using Teuchos::CommStatus;
683 using Teuchos::ireceive;
686 using Teuchos::receive;
687 using Teuchos::reduce;
688 using Teuchos::REDUCE_SUM;
689 using Teuchos::scatter;
691 using Teuchos::waitAll;
692 Tpetra::Details::ProfilingRegion pr(
"Tpetra::DistributorPlan::computeReceives");
694 const int myRank = comm_->getRank();
695 const int numProcs = comm_->getSize();
697 const int mpiTag = DEFAULT_MPI_TAG;
705 Array<int> toProcsFromMe(numProcs, 0);
706#ifdef HAVE_TPETRA_DEBUG
707 bool counting_error =
false;
709 for (
size_t i = 0; i < (numSendsToOtherProcs_ + (sendMessageToSelf_ ? 1 : 0)); ++i) {
710#ifdef HAVE_TPETRA_DEBUG
711 if (toProcsFromMe[procIdsToSendTo_[i]] != 0) {
712 counting_error =
true;
715 toProcsFromMe[procIdsToSendTo_[i]] = 1;
717#ifdef HAVE_TPETRA_DEBUG
720 "Tpetra::Distributor::computeReceives: There was an error on at least "
721 "one process in counting the number of messages send by that process to "
722 "the other processs. Please report this bug to the Tpetra developers.",
779 Array<int> numRecvsOnEachProc;
780 if (myRank == root) {
781 numRecvsOnEachProc.resize(numProcs);
783 int numReceivesAsInt = 0;
784 reduce<int, int>(toProcsFromMe.getRawPtr(),
785 numRecvsOnEachProc.getRawPtr(),
786 numProcs, REDUCE_SUM, root, *comm_);
787 scatter<int, int>(numRecvsOnEachProc.getRawPtr(), 1,
788 &numReceivesAsInt, 1, root, *comm_);
789 numReceives_ =
static_cast<size_t>(numReceivesAsInt);
795 lengthsFrom_.assign(numReceives_, 0);
796 procsFrom_.assign(numReceives_, 0);
812 const size_t actualNumReceives = numReceives_ - (sendMessageToSelf_ ? 1 : 0);
818 Array<RCP<CommRequest<int>>> requests(actualNumReceives);
819 Array<ArrayRCP<size_t>> lengthsFromBuffers(actualNumReceives);
820 Array<RCP<CommStatus<int>>> statuses(actualNumReceives);
825 const int anySourceProc = MPI_ANY_SOURCE;
827 const int anySourceProc = -1;
831 for (
size_t i = 0; i < actualNumReceives; ++i) {
836 lengthsFromBuffers[i].resize(1);
837 lengthsFromBuffers[i][0] = as<size_t>(0);
838 requests[i] = ireceive<int, size_t>(lengthsFromBuffers[i], anySourceProc,
850 for (
size_t i = 0; i < numSendsToOtherProcs_ + (sendMessageToSelf_ ? 1 : 0); ++i) {
851 if (procIdsToSendTo_[i] != myRank) {
855 const size_t*
const lengthsTo_i = &lengthsTo_[i];
856 send<int, size_t>(lengthsTo_i, 1, as<int>(procIdsToSendTo_[i]), mpiTag, *comm_);
864 lengthsFrom_[numReceives_ - 1] = lengthsTo_[i];
865 procsFrom_[numReceives_ - 1] = myRank;
875 waitAll(*comm_, requests(), statuses());
876 for (
size_t i = 0; i < actualNumReceives; ++i) {
877 lengthsFrom_[i] = *lengthsFromBuffers[i];
878 procsFrom_[i] = statuses[i]->getSourceRank();
884 sort2(procsFrom_.begin(), procsFrom_.end(), lengthsFrom_.begin());
887 totalReceiveLength_ =
888 std::accumulate(lengthsFrom_.begin(), lengthsFrom_.end(), 0);
889 indicesFrom_.clear();
892 startsFrom_.reserve(numReceives_);
893 for (
size_t i = 0, j = 0; i < numReceives_; ++i) {
894 startsFrom_.push_back(j);
895 j += lengthsFrom_[i];
898 if (sendMessageToSelf_) {
903void DistributorPlan::setParameterList(
const Teuchos::RCP<Teuchos::ParameterList>& plist) {
905 using Teuchos::FancyOStream;
906 using Teuchos::getIntegralValue;
907 using Teuchos::ParameterList;
908 using Teuchos::parameterList;
911 if (!plist.is_null()) {
912 RCP<const ParameterList> validParams = getValidParameters();
913 plist->validateParametersAndSetDefaults(*validParams);
916 getIntegralValue<Details::EDistributorSendType>(*plist,
"Send type");
919 sendType_ = sendType;
921#if defined(HAVE_TPETRACORE_MPI_ADVANCE)
922 initializeMpiAdvance();
927 this->setMyParamList(plist);
929#if defined(HAVE_TPETRA_MPI)
930 maybeInitializeRoots();
936 Teuchos::Array<std::string> sendTypes;
937 sendTypes.push_back(
"Isend");
938 sendTypes.push_back(
"Send");
939 sendTypes.push_back(
"Alltoall");
940#if defined(HAVE_TPETRA_MPI)
941 sendTypes.push_back(
"Ialltofewv");
943#if defined(HAVE_TPETRACORE_MPI_ADVANCE)
944 sendTypes.push_back(
"MpiAdvanceAlltoall");
945 sendTypes.push_back(
"MpiAdvanceNbralltoallv");
951 Teuchos::Array<EDistributorSendType> res;
952 res.push_back(DISTRIBUTOR_ISEND);
953 res.push_back(DISTRIBUTOR_SEND);
954 res.push_back(DISTRIBUTOR_ALLTOALL);
955#if defined(HAVE_TPETRA_MPI)
956 res.push_back(DISTRIBUTOR_IALLTOFEWV);
958#if defined(HAVE_TPETRACORE_MPI_ADVANCE)
959 res.push_back(DISTRIBUTOR_MPIADVANCE_ALLTOALL);
960 res.push_back(DISTRIBUTOR_MPIADVANCE_NBRALLTOALLV);
965Teuchos::RCP<const Teuchos::ParameterList>
966DistributorPlan::getValidParameters()
const {
967 using Teuchos::Array;
968 using Teuchos::ParameterList;
969 using Teuchos::parameterList;
971 using Teuchos::setStringToIntegralParameter;
973 Array<std::string> sendTypes = distributorSendTypes();
974 const Array<Details::EDistributorSendType> sendTypeEnums = distributorSendTypeEnums();
976 const std::string validatedSendType = validSendTypeOrThrow(Behavior::defaultSendType());
978 RCP<ParameterList> plist = parameterList(
"Tpetra::Distributor");
980 setStringToIntegralParameter<Details::EDistributorSendType>(
"Send type",
982 "When using MPI, the variant of send to use in "
983 "do[Reverse]Posts()",
984 sendTypes(), sendTypeEnums(), plist.getRawPtr());
985 plist->set(
"Timer Label",
"",
"Label for Time Monitor output");
987 return Teuchos::rcp_const_cast<const ParameterList>(plist);
990#if defined(HAVE_TPETRACORE_MPI_ADVANCE)
993struct MpixCommDeallocator {
994 void free(MPIX_Comm** comm)
const {
995 MPIX_Comm_free(comm);
999void DistributorPlan::initializeMpiAdvance() {
1001 TEUCHOS_ASSERT(mpixComm_.is_null());
1004 Teuchos::RCP<const Teuchos::MpiComm<int>> mpiComm = Teuchos::rcp_dynamic_cast<const Teuchos::MpiComm<int>>(comm_);
1005 Teuchos::RCP<const Teuchos::OpaqueWrapper<MPI_Comm>> rawComm = mpiComm->getRawMpiComm();
1007 if (sendType_ == DISTRIBUTOR_MPIADVANCE_ALLTOALL ||
1008 sendType_ == DISTRIBUTOR_MPIADVANCE_NBRALLTOALLV) {
1009 MPIX_Comm** mpixComm =
new (MPIX_Comm*);
1010 err = MPIX_Comm_init(mpixComm, (*rawComm)());
1011 mpixComm_ = Teuchos::RCP(mpixComm,
1012 MpixCommDeallocator(),
1017 TEUCHOS_ASSERT(err == 0);
1021#if defined(HAVE_TPETRA_MPI)
1023void DistributorPlan::maybeInitializeRoots() {
1025 if (DISTRIBUTOR_IALLTOFEWV != sendType_) {
1030 ProfilingRegion region_maybeInitializeRoots(
"Tpetra::DistributorPlan::maybeInitializeRoots");
1033 const int numRecvs = (int)(getNumReceives() + (hasSelfMessage() ? 1 : 0));
1034 std::vector<int> sendbuf(comm_->getSize(), numRecvs);
1035 std::vector<int> recvbuf(comm_->getSize());
1040 Teuchos::RCP<const Teuchos::MpiComm<int>> mpiComm = Teuchos::rcp_dynamic_cast<const Teuchos::MpiComm<int>>(comm_);
1041 Teuchos::RCP<const Teuchos::OpaqueWrapper<MPI_Comm>> rawComm = mpiComm->getRawMpiComm();
1042 MPI_Comm comm = (*rawComm)();
1043 MPI_Alltoall(sendbuf.data(), 1, MPI_INT, recvbuf.data(), 1, MPI_INT, comm);
1046 for (
size_t root = 0; root < recvbuf.size(); ++root) {
1047 if (recvbuf[root] > 0) {
1048 roots_.push_back(root);
1054 int slow = !getIndicesTo().is_null() ? 1 : 0;
1055 MPI_Allreduce(MPI_IN_PLACE, &slow, 1, MPI_INT, MPI_LOR, comm);
1059 std::stringstream ss;
1060 ss << __FILE__ <<
":" << __LINE__ <<
" " << comm_->getRank() <<
": WARNING: Ialltoallv send mode set, at least one rank's data is not grouped by rank. Setting to \"Send\"" << std::endl;
1061 std::cerr << ss.str();
1066 sendType_ = DISTRIBUTOR_SEND;
1072 if (roots_.size() * roots_.size() >=
size_t(comm_->getSize())) {
1074 std::stringstream ss;
1075 ss << __FILE__ <<
":" << __LINE__ <<
" " << comm_->getRank() <<
": WARNING (Ialltoallv send type): too many roots (" << roots_.size() <<
") for " << comm_->getSize() <<
" ranks. Setting send-type to \"Send\"" << std::endl;
1076 std::cerr << ss.str();
1079 sendType_ = DISTRIBUTOR_SEND;
1084DistributorPlan::SubViewLimits DistributorPlan::getImportViewLimits(
size_t numPackets)
const {
1085 const size_t actualNumReceives = getNumReceives() + (hasSelfMessage() ? 1 : 0);
1087 IndexView importStarts(actualNumReceives);
1088 IndexView importLengths(actualNumReceives);
1091 for (
size_t i = 0; i < actualNumReceives; ++i) {
1092 importStarts[i] = offset;
1093 offset += getLengthsFrom()[i] * numPackets;
1094 importLengths[i] = getLengthsFrom()[i] * numPackets;
1096 return std::make_pair(importStarts, importLengths);
1099DistributorPlan::SubViewLimits DistributorPlan::getImportViewLimits(
const Teuchos::ArrayView<const size_t>& numImportPacketsPerLID)
const {
1100 const size_t actualNumReceives = getNumReceives() + (hasSelfMessage() ? 1 : 0);
1102 IndexView importStarts(actualNumReceives);
1103 IndexView importLengths(actualNumReceives);
1106 size_t curLIDoffset = 0;
1107 for (
size_t i = 0; i < actualNumReceives; ++i) {
1108 size_t totalPacketsFrom_i = 0;
1109 for (
size_t j = 0; j < getLengthsFrom()[i]; ++j) {
1110 totalPacketsFrom_i += numImportPacketsPerLID[curLIDoffset + j];
1112 curLIDoffset += getLengthsFrom()[i];
1113 importStarts[i] = offset;
1114 offset += totalPacketsFrom_i;
1115 importLengths[i] = totalPacketsFrom_i;
1117 return std::make_pair(importStarts, importLengths);
1120DistributorPlan::SubViewLimits DistributorPlan::getExportViewLimits(
size_t numPackets)
const {
1121 if (getIndicesTo().is_null()) {
1122 const size_t actualNumSends = getNumSends() + (hasSelfMessage() ? 1 : 0);
1123 IndexView exportStarts(actualNumSends);
1124 IndexView exportLengths(actualNumSends);
1125 for (
size_t pp = 0; pp < actualNumSends; ++pp) {
1126 exportStarts[pp] = getStartsTo()[pp] * numPackets;
1127 exportLengths[pp] = getLengthsTo()[pp] * numPackets;
1129 return std::make_pair(exportStarts, exportLengths);
1131 const size_t numIndices = getIndicesTo().size();
1132 IndexView exportStarts(numIndices);
1133 IndexView exportLengths(numIndices);
1134 for (
size_t j = 0; j < numIndices; ++j) {
1135 exportStarts[j] = getIndicesTo()[j] * numPackets;
1136 exportLengths[j] = numPackets;
1138 return std::make_pair(exportStarts, exportLengths);
1142DistributorPlan::SubViewLimits DistributorPlan::getExportViewLimits(
const Teuchos::ArrayView<const size_t>& numExportPacketsPerLID)
const {
1143 if (getIndicesTo().is_null()) {
1144 const size_t actualNumSends = getNumSends() + (hasSelfMessage() ? 1 : 0);
1145 IndexView exportStarts(actualNumSends);
1146 IndexView exportLengths(actualNumSends);
1148 for (
size_t pp = 0; pp < actualNumSends; ++pp) {
1149 size_t numPackets = 0;
1150 for (
size_t j = getStartsTo()[pp];
1151 j < getStartsTo()[pp] + getLengthsTo()[pp]; ++j) {
1152 numPackets += numExportPacketsPerLID[j];
1154 exportStarts[pp] = offset;
1155 offset += numPackets;
1156 exportLengths[pp] = numPackets;
1158 return std::make_pair(exportStarts, exportLengths);
1160 const size_t numIndices = getIndicesTo().size();
1161 IndexView exportStarts(numIndices);
1162 IndexView exportLengths(numIndices);
1164 for (
size_t j = 0; j < numIndices; ++j) {
1165 exportStarts[j] = offset;
1166 offset += numExportPacketsPerLID[j];
1167 exportLengths[j] = numExportPacketsPerLID[j];
1169 return std::make_pair(exportStarts, exportLengths);
Declaration of Tpetra::Details::Behavior, a class that describes Tpetra's behavior.
Declaration of Tpetra::Details::Profiling, a scope guard for Kokkos Profiling.
Stand-alone utility functions and macros.
#define TPETRA_EFFICIENCY_WARNING(throw_exception_test, msg)
Print or throw an efficency warning.
#define SHARED_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg, comm)
Test for exception, with reduction over the given communicator.
static bool debug()
Whether Tpetra is in debug mode.
static bool verbose()
Whether Tpetra is in verbose mode.
Nonmember function that computes a residual Computes R = B - A * X.
std::string DistributorSendTypeEnumToString(EDistributorSendType sendType)
Convert an EDistributorSendType enum value to a string.
EDistributorSendType
The type of MPI send that Distributor should use.
Teuchos::Array< EDistributorSendType > distributorSendTypeEnums()
Valid enum values of distributor send types.
Teuchos::Array< std::string > distributorSendTypes()
Valid string values for Distributor's "Send type" parameter.
EDistributorSendType DistributorSendTypeStringToEnum(const std::string_view s)
Convert a string to an EDistributorSendType. Throw on error.
const std::string & validSendTypeOrThrow(const std::string &s)
Valid enum values of distributor send types.
EDistributorHowInitialized
Enum indicating how and whether a Distributor was initialized.
std::string DistributorHowInitializedEnumToString(EDistributorHowInitialized how)
Convert an EDistributorHowInitialized enum value to a string.
Namespace Tpetra contains the class and methods constituting the Tpetra library.
void sort2(const IT1 &first1, const IT1 &last1, const IT2 &first2, const bool stableSort=false)
Sort the first array, and apply the resulting permutation to the second array.