Tpetra parallel linear algebra Version of the Day
Loading...
Searching...
No Matches
Tpetra_Distributor.hpp
1// @HEADER
2// *****************************************************************************
3// Tpetra: Templated Linear Algebra Services Package
4//
5// Copyright 2008 NTESS and the Tpetra contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9
10#ifndef TPETRA_DISTRIBUTOR_HPP
11#define TPETRA_DISTRIBUTOR_HPP
12
13#include "Tpetra_Details_DistributorActor.hpp"
15
16#include "Tpetra_Util.hpp"
17#include "Teuchos_as.hpp"
18#include "Teuchos_Describable.hpp"
19#include "Teuchos_ParameterListAcceptorDefaultBase.hpp"
20#include "Teuchos_VerboseObject.hpp"
22
23#include "KokkosCompat_View.hpp"
24#include "Kokkos_Core.hpp"
25#include "Kokkos_TeuchosCommAdapters.hpp"
26#include <memory>
27#include <sstream>
28#include <type_traits>
29
30namespace Tpetra {
31
94class Distributor : public Teuchos::Describable,
95 public Teuchos::ParameterListAcceptorDefaultBase {
96 public:
98
99
108 explicit Distributor(const Teuchos::RCP<const Teuchos::Comm<int> >& comm);
109
121 Distributor(const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
122 const Teuchos::RCP<Teuchos::FancyOStream>& out);
123
137 Distributor(const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
138 const Teuchos::RCP<Teuchos::ParameterList>& plist);
139
156 Distributor(const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
157 const Teuchos::RCP<Teuchos::FancyOStream>& out,
158 const Teuchos::RCP<Teuchos::ParameterList>& plist);
159
162
167 virtual ~Distributor() = default;
168
174 void swap(Distributor& rhs);
175
177
179
184 void setParameterList(const Teuchos::RCP<Teuchos::ParameterList>& plist);
185
190 Teuchos::RCP<const Teuchos::ParameterList> getValidParameters() const;
191
193
195
215 size_t createFromSends(const Teuchos::ArrayView<const int>& exportProcIDs);
216
250 template <class Ordinal>
251 void
252 createFromRecvs(const Teuchos::ArrayView<const Ordinal>& remoteIDs,
253 const Teuchos::ArrayView<const int>& remoteProcIDs,
254 Teuchos::Array<Ordinal>& exportIDs,
255 Teuchos::Array<int>& exportProcIDs);
256
264 void
265 createFromSendsAndRecvs(const Teuchos::ArrayView<const int>& exportProcIDs,
266 const Teuchos::ArrayView<const int>& remoteProcIDs);
267
269
271
275 size_t getNumReceives() const;
276
280 size_t getNumSends() const;
281
283 bool hasSelfMessage() const;
284
286 size_t getMaxSendLength() const;
287
289 size_t getTotalReceiveLength() const;
290
295 Teuchos::ArrayView<const int> getProcsFrom() const;
296
301 Teuchos::ArrayView<const int> getProcsTo() const;
302
310 Teuchos::ArrayView<const size_t> getLengthsFrom() const;
311
319 Teuchos::ArrayView<const size_t> getLengthsTo() const;
320
326 return plan_->howInitialized();
327 }
328
330
332
343 Teuchos::RCP<Distributor> getReverse(bool create = true) const;
344
346
348
355 void doWaits();
356
363 void doReverseWaits();
364
385 template <class ExpView, class ImpView>
386 typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
388 const ExpView& exports,
389 size_t numPackets,
390 const ImpView& imports);
391
413 template <class ExpView, class ImpView>
414 typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
415 doPostsAndWaits(const ExpView& exports,
416 const Teuchos::ArrayView<const size_t>& numExportPacketsPerLID,
417 const ImpView& imports,
418 const Teuchos::ArrayView<const size_t>& numImportPacketsPerLID);
419
444 template <class ExpView, class ImpView>
445 typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
446 doPosts(const ExpView& exports,
447 size_t numPackets,
448 const ImpView& imports);
449
468 template <class ExpView, class ImpView>
469 typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
470 doPosts(const ExpView& exports,
471 const Teuchos::ArrayView<const size_t>& numExportPacketsPerLID,
472 const ImpView& imports,
473 const Teuchos::ArrayView<const size_t>& numImportPacketsPerLID);
474
479 template <class ExpView, class ImpView>
480 typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
481 doReversePostsAndWaits(const ExpView& exports,
482 size_t numPackets,
483 const ImpView& imports);
484
489 template <class ExpView, class ImpView>
490 typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
491 doReversePostsAndWaits(const ExpView& exports,
492 const Teuchos::ArrayView<const size_t>& numExportPacketsPerLID,
493 const ImpView& imports,
494 const Teuchos::ArrayView<const size_t>& numImportPacketsPerLID);
495
500 template <class ExpView, class ImpView>
501 typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
502 doReversePosts(const ExpView& exports,
503 size_t numPackets,
504 const ImpView& imports);
505
510 template <class ExpView, class ImpView>
511 typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
512 doReversePosts(const ExpView& exports,
513 const Teuchos::ArrayView<const size_t>& numExportPacketsPerLID,
514 const ImpView& imports,
515 const Teuchos::ArrayView<const size_t>& numImportPacketsPerLID);
516
518
520
522 std::string description() const;
523
545 void
546 describe(Teuchos::FancyOStream& out,
547 const Teuchos::EVerbosityLevel verbLevel =
548 Teuchos::Describable::verbLevel_default) const;
550
555 const Details::DistributorPlan& getPlan() const { return *plan_; }
556
557 private:
558 Teuchos::RCP<Details::DistributorPlan> plan_;
559 Details::DistributorActor actor_;
560
562
563
565 static bool getVerbose();
566
571 std::unique_ptr<std::string>
572 createPrefix(const char methodName[]) const;
573
575 bool verbose_ = getVerbose();
577
582 mutable Teuchos::RCP<Distributor> reverseDistributor_;
583
596 template <class Ordinal>
597 void computeSends(const Teuchos::ArrayView<const Ordinal>& remoteGIDs,
598 const Teuchos::ArrayView<const int>& remoteProcIDs,
599 Teuchos::Array<Ordinal>& exportGIDs,
600 Teuchos::Array<int>& exportProcIDs);
601
603 void createReverseDistributor() const;
604
609 std::string
610 localDescribeToString(const Teuchos::EVerbosityLevel vl) const;
611}; // class Distributor
612
613template <class ExpView, class ImpView>
614typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
616 doPostsAndWaits(const ExpView& exports,
618 const ImpView& imports) {
619 actor_.doPostsAndWaits(*plan_, exports, numPackets, imports);
620}
621
622template <class ExpView, class ImpView>
623typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
625 doPostsAndWaits(const ExpView& exports,
627 const ImpView& imports,
629 actor_.doPostsAndWaits(*plan_, exports, numExportPacketsPerLID, imports, numImportPacketsPerLID);
630}
631
632template <class ExpView, class ImpView>
633typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
635 doPosts(const ExpView& exports,
637 const ImpView& imports) {
638 actor_.doPosts(*plan_, exports, numPackets, imports);
639}
640
641template <class ExpView, class ImpView>
642typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
644 doPosts(const ExpView& exports,
646 const ImpView& imports,
648 actor_.doPosts(*plan_, exports, numExportPacketsPerLID, imports, numImportPacketsPerLID);
649}
650
651template <class ExpView, class ImpView>
652typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
654 doReversePostsAndWaits(const ExpView& exports,
656 const ImpView& imports) {
657 doReversePosts(exports, numPackets, imports);
658 doReverseWaits();
659}
660
661template <class ExpView, class ImpView>
662typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
664 doReversePostsAndWaits(const ExpView& exports,
666 const ImpView& imports,
668 doReversePosts(exports, numExportPacketsPerLID, imports,
670 doReverseWaits();
671}
672
673template <class ExpView, class ImpView>
674typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
676 doReversePosts(const ExpView& exports,
678 const ImpView& imports) {
679 // FIXME (mfh 29 Mar 2012) WHY?
681 !plan_->getIndicesTo().is_null(), std::runtime_error,
682 "Tpetra::Distributor::doReversePosts(3 args): Can only do "
683 "reverse communication when original data are blocked by process.");
684 if (reverseDistributor_.is_null()) {
685 createReverseDistributor();
686 }
687 reverseDistributor_->doPosts(exports, numPackets, imports);
688}
689
690template <class ExpView, class ImpView>
691typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
693 doReversePosts(const ExpView& exports,
695 const ImpView& imports,
697 // FIXME (mfh 29 Mar 2012) WHY?
699 !plan_->getIndicesTo().is_null(), std::runtime_error,
700 "Tpetra::Distributor::doReversePosts(3 args): Can only do "
701 "reverse communication when original data are blocked by process.");
702 if (reverseDistributor_.is_null()) {
703 createReverseDistributor();
704 }
705 reverseDistributor_->doPosts(exports, numExportPacketsPerLID,
706 imports, numImportPacketsPerLID);
707}
708
709template <class OrdinalType>
710void Distributor::
711 computeSends(const Teuchos::ArrayView<const OrdinalType>& importGIDs,
712 const Teuchos::ArrayView<const int>& importProcIDs,
713 Teuchos::Array<OrdinalType>& exportGIDs,
714 Teuchos::Array<int>& exportProcIDs) {
715 // NOTE (mfh 19 Apr 2012): There was a note on this code saying:
716 // "assumes that size_t >= Ordinal". The code certainly does
717 // assume that sizeof(size_t) >= sizeof(OrdinalType) as well as
718 // sizeof(size_t) >= sizeof(int). This is because it casts the
719 // OrdinalType elements of importGIDs (along with their
720 // corresponding process IDs, as int) to size_t, and does a
721 // doPostsAndWaits<size_t>() to send the packed data.
722 using std::endl;
723 using Teuchos::ArrayView;
724 using size_type = typename ArrayView<const OrdinalType>::size_type;
725 const char errPrefix[] = "Tpetra::Distributor::computeSends: ";
726 const char suffix[] =
727 " Please report this bug to the Tpetra developers.";
728 Tpetra::Details::ProfilingRegion pr("Tpetra::Distributor::computeSends");
729
730 const int myRank = plan_->getComm()->getRank();
731
733 std::invalid_argument, errPrefix << "On Process " << myRank << ": importProcIDs.size()=" << importProcIDs.size() << " != importGIDs.size()=" << importGIDs.size() << ".");
734
735 const size_type numImports = importProcIDs.size();
736 Kokkos::View<size_t*, Kokkos::HostSpace> importObjs("importObjs", 2 * numImports);
737 // Pack pairs (importGIDs[i], my process ID) to send into importObjs.
738 for (size_type i = 0; i < numImports; ++i) {
739 importObjs[2 * i] = static_cast<size_t>(importGIDs[i]);
740 importObjs[2 * i + 1] = static_cast<size_t>(myRank);
741 }
742 //
743 // Use a temporary Distributor to send the (importGIDs[i], myRank)
744 // pairs to importProcIDs[i].
745 //
746 Distributor tempPlan(plan_->getComm());
747 // mfh 20 Mar 2014: An extra-cautious cast from unsigned to
748 // signed, in order to forestall any possible causes for Bug 6069.
749 const size_t numExportsAsSizeT =
750 tempPlan.createFromSends(importProcIDs);
751 const size_type numExports =
752 static_cast<size_type>(numExportsAsSizeT);
753 TEUCHOS_TEST_FOR_EXCEPTION(numExports < 0, std::logic_error, errPrefix << "tempPlan.createFromSends() returned numExports=" << numExportsAsSizeT << " as a size_t, which overflows to " << numExports << " when cast to " << Teuchos::TypeNameTraits<size_type>::name() << "." << suffix);
754 TEUCHOS_TEST_FOR_EXCEPTION(size_type(tempPlan.getTotalReceiveLength()) != numExports,
755 std::logic_error, errPrefix << "tempPlan.getTotalReceiveLength()=" << tempPlan.getTotalReceiveLength() << " != numExports=" << numExports << "." << suffix);
756
757 if (numExports > 0) {
758 exportGIDs.resize(numExports);
759 exportProcIDs.resize(numExports);
760 }
761
762 // exportObjs: Packed receive buffer. (exportObjs[2*i],
763 // exportObjs[2*i+1]) will give the (GID, PID) pair for export i,
764 // after tempPlan.doPostsAndWaits(...) finishes below.
765 //
766 // FIXME (mfh 19 Mar 2014) This only works if OrdinalType fits in
767 // size_t. This issue might come up, for example, on a 32-bit
768 // machine using 64-bit global indices. I will add a check here
769 // for that case.
770 static_assert(sizeof(size_t) >= sizeof(OrdinalType),
771 "Tpetra::Distributor::computeSends: "
772 "sizeof(size_t) < sizeof(OrdinalType).");
773
774 TEUCHOS_TEST_FOR_EXCEPTION(tempPlan.getTotalReceiveLength() < size_t(numExports),
775 std::logic_error,
776 errPrefix << "tempPlan.getTotalReceiveLength()="
777 << tempPlan.getTotalReceiveLength() << " < numExports="
778 << numExports << "." << suffix);
779
780 Kokkos::View<size_t*, Kokkos::HostSpace> exportObjs("exportObjs", tempPlan.getTotalReceiveLength() * 2);
781 tempPlan.doPostsAndWaits(importObjs, 2, exportObjs);
782
783 // Unpack received (GID, PID) pairs into exportIDs resp. exportProcIDs.
784 for (size_type i = 0; i < numExports; ++i) {
785 exportGIDs[i] = static_cast<OrdinalType>(exportObjs[2 * i]);
786 exportProcIDs[i] = static_cast<int>(exportObjs[2 * i + 1]);
787 }
788
789 // Store tempPlan instead of recreating it later
790 plan_ = tempPlan.plan_;
791}
792
793template <class OrdinalType>
794void Distributor::
795 createFromRecvs(const Teuchos::ArrayView<const OrdinalType>& remoteGIDs,
796 const Teuchos::ArrayView<const int>& remoteProcIDs,
797 Teuchos::Array<OrdinalType>& exportGIDs,
798 Teuchos::Array<int>& exportProcIDs) {
799 using std::endl;
800 const char errPrefix[] = "Tpetra::Distributor::createFromRecvs: ";
801 const int myRank = plan_->getComm()->getRank();
802
803 std::unique_ptr<std::string> prefix;
804 if (verbose_) {
805 prefix = createPrefix("createFromRecvs");
806 std::ostringstream os;
807 os << *prefix << "Start" << endl;
808 std::cerr << os.str();
809 }
810
811 const bool debug = Details::Behavior::debug("Distributor");
812 if (debug) {
813 using Teuchos::outArg;
814 using Teuchos::REDUCE_MAX;
815 using Teuchos::reduceAll;
816 // In debug mode, first test locally, then do an all-reduce to
817 // make sure that all processes passed.
818 const int errProc =
819 (remoteGIDs.size() != remoteProcIDs.size()) ? myRank : -1;
820 int maxErrProc = -1;
821 reduceAll(*plan_->getComm(), REDUCE_MAX, errProc, outArg(maxErrProc));
822 TEUCHOS_TEST_FOR_EXCEPTION(maxErrProc != -1, std::runtime_error, errPrefix << "Lists "
823 "of remote IDs and remote process IDs must have the same "
824 "size on all participating processes. Maximum process ID "
825 "with error: "
826 << maxErrProc << ".");
827 } else { // in non-debug mode, just test locally
828 // NOTE (mfh 13 Feb 2020) This needs to throw std::runtime_error
829 // in order to make an existing Distributor unit test pass.
830 TEUCHOS_TEST_FOR_EXCEPTION(remoteGIDs.size() != remoteProcIDs.size(), std::runtime_error,
831 errPrefix << "On Process " << myRank << ": "
832 "remoteGIDs.size()="
833 << remoteGIDs.size() << " != remoteProcIDs.size()=" << remoteProcIDs.size() << ".");
834 }
835
836 computeSends(remoteGIDs, remoteProcIDs, exportGIDs, exportProcIDs);
837
838 plan_->createFromRecvs(remoteProcIDs);
839
840 if (verbose_) {
841 std::ostringstream os;
842 os << *prefix << "Done" << endl;
843 std::cerr << os.str();
844 }
845}
846
847} // namespace Tpetra
848
849#endif // TPETRA_DISTRIBUTOR_HPP
Declaration of Tpetra::Details::Behavior, a class that describes Tpetra's behavior.
Stand-alone utility functions and macros.
Struct that holds views of the contents of a CrsMatrix.
static bool debug()
Whether Tpetra is in debug mode.
Sets up and executes a communication plan for a Tpetra DistObject.
std::enable_if<(Kokkos::is_view< ExpView >::value &&Kokkos::is_view< ImpView >::value)>::type doPosts(const ExpView &exports, size_t numPackets, const ImpView &imports)
Post the data for a forward plan, but do not execute the waits yet.
std::enable_if<(Kokkos::is_view< ExpView >::value &&Kokkos::is_view< ImpView >::value)>::type doPostsAndWaits(const ExpView &exports, size_t numPackets, const ImpView &imports)
Execute the (forward) communication plan.
const Details::DistributorPlan & getPlan() const
Get this Distributor's DistributorPlan.
size_t getMaxSendLength() const
Maximum number of values this process will send to another single process.
Teuchos::RCP< Distributor > getReverse(bool create=true) const
A reverse communication plan Distributor.
void createFromRecvs(const Teuchos::ArrayView< const Ordinal > &remoteIDs, const Teuchos::ArrayView< const int > &remoteProcIDs, Teuchos::Array< Ordinal > &exportIDs, Teuchos::Array< int > &exportProcIDs)
Set up Distributor using list of process ranks from which to receive.
Teuchos::ArrayView< const int > getProcsTo() const
Ranks of the processes to which this process will send values.
size_t getNumReceives() const
The number of processes from which we will receive data.
std::enable_if<(Kokkos::is_view< ExpView >::value &&Kokkos::is_view< ImpView >::value)>::type doReversePostsAndWaits(const ExpView &exports, size_t numPackets, const ImpView &imports)
Execute the reverse communication plan.
void setParameterList(const Teuchos::RCP< Teuchos::ParameterList > &plist)
Set Distributor parameters.
size_t getTotalReceiveLength() const
Total number of values this process will receive from other processes.
virtual ~Distributor()=default
Destructor (virtual for memory safety).
bool hasSelfMessage() const
Whether the calling process will send or receive messages to itself.
void swap(Distributor &rhs)
Swap the contents of rhs with those of *this.
Teuchos::ArrayView< const size_t > getLengthsTo() const
Number of values this process will send to each process.
Teuchos::ArrayView< const int > getProcsFrom() const
Ranks of the processes sending values to this process.
std::string description() const
Return a one-line description of this object.
size_t createFromSends(const Teuchos::ArrayView< const int > &exportProcIDs)
Set up Distributor using list of process ranks to which this process will send.
void createFromSendsAndRecvs(const Teuchos::ArrayView< const int > &exportProcIDs, const Teuchos::ArrayView< const int > &remoteProcIDs)
Set up Distributor using list of process ranks to which to send, and list of process ranks from which...
Teuchos::RCP< const Teuchos::ParameterList > getValidParameters() const
List of valid Distributor parameters.
Teuchos::ArrayView< const size_t > getLengthsFrom() const
Number of values this process will receive from each process.
std::enable_if<(Kokkos::is_view< ExpView >::value &&Kokkos::is_view< ImpView >::value)>::type doReversePosts(const ExpView &exports, size_t numPackets, const ImpView &imports)
Post the data for a reverse plan, but do not execute the waits yet.
Details::EDistributorHowInitialized howInitialized() const
Return an enum indicating whether and how a Distributor was initialized.
size_t getNumSends() const
The number of processes to which we will send data.
void describe(Teuchos::FancyOStream &out, const Teuchos::EVerbosityLevel verbLevel=Teuchos::Describable::verbLevel_default) const
Describe this object in a human-readable way to the given output stream.
EDistributorHowInitialized
Enum indicating how and whether a Distributor was initialized.
Namespace Tpetra contains the class and methods constituting the Tpetra library.