Tpetra parallel linear algebra Version of the Day
Loading...
Searching...
No Matches
Tpetra_Distributor.cpp
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#include "Tpetra_Distributor.hpp"
13#include "Tpetra_Util.hpp"
14#include "Tpetra_Details_makeValidVerboseStream.hpp"
15#include "Teuchos_StandardParameterEntryValidators.hpp"
16#include "Teuchos_VerboseObjectParameterListHelpers.hpp"
17#include <numeric>
18
19namespace Tpetra {
20// We set default values of Distributor's Boolean parameters here,
21// in this one place. That way, if we want to change the default
22// value of a parameter, we don't have to search the whole file to
23// ensure a consistent setting.
24namespace {
25// Default value of the "Debug" parameter.
26const bool tpetraDistributorDebugDefault = false;
27} // namespace
28
29#if defined(TPETRA_ENABLE_DEPRECATED_CODE)
30Teuchos::Array<std::string>
33}
34#endif
35
37 Distributor(const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
38 const Teuchos::RCP<Teuchos::FancyOStream>& /* out */,
39 const Teuchos::RCP<Teuchos::ParameterList>& plist)
40 : plan_(comm) {
41 this->setParameterList(plist);
42}
43
45 Distributor(const Teuchos::RCP<const Teuchos::Comm<int> >& comm)
46 : Distributor(comm, Teuchos::null, Teuchos::null) {}
47
49 Distributor(const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
50 const Teuchos::RCP<Teuchos::FancyOStream>& out)
51 : Distributor(comm, out, Teuchos::null) {}
52
54 Distributor(const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
55 const Teuchos::RCP<Teuchos::ParameterList>& plist)
56 : Distributor(comm, Teuchos::null, plist) {}
57
60 : plan_(distributor.plan_)
61 , actor_(distributor.actor_)
62 , verbose_(distributor.verbose_)
63 , reverseDistributor_(distributor.reverseDistributor_) {
64 using Teuchos::ParameterList;
65 using Teuchos::RCP;
66 using Teuchos::rcp;
67
68 RCP<const ParameterList> rhsList = distributor.getParameterList();
69 RCP<ParameterList> newList = rhsList.is_null() ? Teuchos::null : Teuchos::parameterList(*rhsList);
70 this->setParameterList(newList);
71}
72
74 using Teuchos::ParameterList;
75 using Teuchos::parameterList;
76 using Teuchos::RCP;
77
78 std::swap(plan_, rhs.plan_);
79 std::swap(actor_, rhs.actor_);
80 std::swap(verbose_, rhs.verbose_);
81 std::swap(reverseDistributor_, rhs.reverseDistributor_);
82
83 // Swap parameter lists. If they are the same object, make a deep
84 // copy first, so that modifying one won't modify the other one.
86 RCP<ParameterList> rhsList = rhs.getNonconstParameterList();
87 if (lhsList.getRawPtr() == rhsList.getRawPtr() && !rhsList.is_null()) {
89 }
90 if (!rhsList.is_null()) {
92 }
93 if (!lhsList.is_null()) {
94 rhs.setMyParamList(lhsList);
95 }
96
97 // We don't need to swap timers, because all instances of
98 // Distributor use the same timers.
99}
100
101bool Distributor::getVerbose() {
102 return Details::Behavior::verbose("Distributor") ||
103 Details::Behavior::verbose("Tpetra::Distributor");
104}
105
106std::unique_ptr<std::string>
107Distributor::
108 createPrefix(const char methodName[]) const {
110 plan_.getComm().getRawPtr(), "Distributor", methodName);
111}
112
114 setParameterList(const Teuchos::RCP<Teuchos::ParameterList>& plist) {
115 using std::endl;
116 using Teuchos::FancyOStream;
117 using Teuchos::getIntegralValue;
118 using Teuchos::includesVerbLevel;
119 using Teuchos::ParameterList;
120 using Teuchos::parameterList;
121 using Teuchos::RCP;
122 using ::Tpetra::Details::Behavior;
123
124 if (!plist.is_null()) {
126 plist->validateParametersAndSetDefaults(*validParams);
127
128 // ParameterListAcceptor semantics require pointer identity of the
129 // sublist passed to setParameterList(), so we save the pointer.
130 this->setMyParamList(plist);
131
133 planParams->remove("Debug", false);
134 planParams->remove("VerboseObject", false);
135 plan_.setParameterList(planParams);
136 }
137}
138
139Teuchos::RCP<const Teuchos::ParameterList>
141 using Teuchos::Array;
142 using Teuchos::ParameterList;
143 using Teuchos::parameterList;
144 using Teuchos::RCP;
145 using Teuchos::setStringToIntegralParameter;
146
147 const bool debug = tpetraDistributorDebugDefault;
148
152
153 RCP<ParameterList> plist = parameterList("Tpetra::Distributor");
156 "When using MPI, the variant of send to use in "
157 "do[Reverse]Posts()",
158 sendTypes(), sendTypeEnums(), plist.getRawPtr());
159 plist->set("Debug", debug,
160 "Whether to print copious debugging output on "
161 "all processes.");
162 plist->set("Timer Label", "", "Label for Time Monitor output");
163
164 // mfh 24 Dec 2015: Tpetra no longer inherits from
165 // Teuchos::VerboseObject, so it doesn't need the "VerboseObject"
166 // sublist. However, we retain the "VerboseObject" sublist
167 // anyway, for backwards compatibility (otherwise the above
168 // validation would fail with an invalid parameter name, should
169 // the user still want to provide this list).
170 Teuchos::setupVerboseObjectSublist(&*plist);
171 return Teuchos::rcp_const_cast<const ParameterList>(plist);
172}
173
174size_t Distributor::getTotalReceiveLength() const { return plan_.getTotalReceiveLength(); }
175
176size_t Distributor::getNumReceives() const { return plan_.getNumReceives(); }
177
178bool Distributor::hasSelfMessage() const { return plan_.hasSelfMessage(); }
179
180size_t Distributor::getNumSends() const { return plan_.getNumSends(); }
181
182size_t Distributor::getMaxSendLength() const { return plan_.getMaxSendLength(); }
183
184Teuchos::ArrayView<const int> Distributor::getProcsFrom() const { return plan_.getProcsFrom(); }
185
186Teuchos::ArrayView<const size_t> Distributor::getLengthsFrom() const { return plan_.getLengthsFrom(); }
187
188Teuchos::ArrayView<const int> Distributor::getProcsTo() const { return plan_.getProcsTo(); }
189
190Teuchos::ArrayView<const size_t> Distributor::getLengthsTo() const { return plan_.getLengthsTo(); }
191
192Teuchos::RCP<Distributor>
194 if (reverseDistributor_.is_null() && create) {
195 createReverseDistributor();
196 }
197 TEUCHOS_TEST_FOR_EXCEPTION(reverseDistributor_.is_null() && create, std::logic_error,
198 "The reverse "
199 "Distributor is null after createReverseDistributor returned. "
200 "Please report this bug to the Tpetra developers.");
201 return reverseDistributor_;
202}
203
204void Distributor::createReverseDistributor() const {
205 reverseDistributor_ = Teuchos::rcp(new Distributor(plan_.getComm()));
206 reverseDistributor_->plan_ = *plan_.getReversePlan();
207 reverseDistributor_->verbose_ = verbose_;
208
209 // requests_: Allocated on demand.
210 // reverseDistributor_: See note below
211
212 // I am my reverse Distributor's reverse Distributor.
213 // Thus, it would be legit to do the following:
214 //
215 // reverseDistributor_->reverseDistributor_ = Teuchos::rcp (this, false);
216 //
217 // (Note use of a "weak reference" to avoid a circular RCP
218 // dependency.) The only issue is that if users hold on to the
219 // reverse Distributor but let go of the forward one, this
220 // reference won't be valid anymore. However, the reverse
221 // Distributor is really an implementation detail of Distributor
222 // and not meant to be used directly, so we don't need to do this.
223 reverseDistributor_->reverseDistributor_ = Teuchos::null;
224}
225
227 actor_.doWaits(plan_);
228}
229
231 // call doWaits() on the reverse Distributor, if it exists
232 if (!reverseDistributor_.is_null()) {
233 reverseDistributor_->doWaits();
234 }
235}
236
237std::string Distributor::description() const {
238 std::ostringstream out;
239
240 out << "\"Tpetra::Distributor\": {";
241 const std::string label = this->getObjectLabel();
242 if (label != "") {
243 out << "Label: " << label << ", ";
244 }
245 out << "How initialized: "
246 << Details::DistributorHowInitializedEnumToString(plan_.howInitialized())
247 << ", Parameters: {"
248 << "Send type: "
249 << DistributorSendTypeEnumToString(plan_.getSendType())
250 << ", Debug: " << (verbose_ ? "true" : "false")
251 << "}}";
252 return out.str();
253}
254
255std::string
256Distributor::
257 localDescribeToString(const Teuchos::EVerbosityLevel vl) const {
258 using std::endl;
259 using Teuchos::toString;
260 using Teuchos::VERB_EXTREME;
261 using Teuchos::VERB_HIGH;
262
263 // This preserves current behavior of Distributor.
264 if (vl <= Teuchos::VERB_LOW || plan_.getComm().is_null()) {
265 return std::string();
266 }
267
268 auto outStringP = Teuchos::rcp(new std::ostringstream());
269 auto outp = Teuchos::getFancyOStream(outStringP); // returns RCP
270 Teuchos::FancyOStream& out = *outp;
271
272 const int myRank = plan_.getComm()->getRank();
273 const int numProcs = plan_.getComm()->getSize();
274 out << "Process " << myRank << " of " << numProcs << ":" << endl;
275 Teuchos::OSTab tab1(out);
276
277 out << "selfMessage: " << hasSelfMessage() << endl;
278 out << "numSends: " << getNumSends() << endl;
279 if (vl == VERB_HIGH || vl == VERB_EXTREME) {
280 out << "procsTo: " << toString(plan_.getProcsTo()) << endl;
281 out << "lengthsTo: " << toString(plan_.getLengthsTo()) << endl;
282 out << "maxSendLength: " << getMaxSendLength() << endl;
283 }
284 if (vl == VERB_EXTREME) {
285 out << "startsTo: " << toString(plan_.getStartsTo()) << endl;
286 out << "indicesTo: " << toString(plan_.getIndicesTo()) << endl;
287 }
288 if (vl == VERB_HIGH || vl == VERB_EXTREME) {
289 out << "numReceives: " << getNumReceives() << endl;
290 out << "totalReceiveLength: " << getTotalReceiveLength() << endl;
291 out << "lengthsFrom: " << toString(plan_.getLengthsFrom()) << endl;
292 out << "procsFrom: " << toString(plan_.getProcsFrom()) << endl;
293 }
294
295 out.flush(); // make sure the ostringstream got everything
296 return outStringP->str();
297}
298
300 describe(Teuchos::FancyOStream& out,
301 const Teuchos::EVerbosityLevel verbLevel) const {
302 using std::endl;
303 using Teuchos::VERB_DEFAULT;
304 using Teuchos::VERB_EXTREME;
305 using Teuchos::VERB_HIGH;
306 using Teuchos::VERB_LOW;
307 using Teuchos::VERB_MEDIUM;
308 using Teuchos::VERB_NONE;
309 const Teuchos::EVerbosityLevel vl =
311
312 if (vl == VERB_NONE) {
313 return; // don't print anything
314 }
315 // If this Distributor's Comm is null, then the the calling
316 // process does not participate in Distributor-related collective
317 // operations with the other processes. In that case, it is not
318 // even legal to call this method. The reasonable thing to do in
319 // that case is nothing.
320 if (plan_.getComm().is_null()) {
321 return;
322 }
323 const int myRank = plan_.getComm()->getRank();
324 const int numProcs = plan_.getComm()->getSize();
325
326 // Only Process 0 should touch the output stream, but this method
327 // in general may need to do communication. Thus, we may need to
328 // preserve the current tab level across multiple "if (myRank ==
329 // 0) { ... }" inner scopes. This is why we sometimes create
330 // OSTab instances by pointer, instead of by value. We only need
331 // to create them by pointer if the tab level must persist through
332 // multiple inner scopes.
333 Teuchos::RCP<Teuchos::OSTab> tab0, tab1;
334
335 if (myRank == 0) {
336 // At every verbosity level but VERB_NONE, Process 0 prints.
337 // By convention, describe() always begins with a tab before
338 // printing.
339 tab0 = Teuchos::rcp(new Teuchos::OSTab(out));
340 // We quote the class name because it contains colons.
341 // This makes the output valid YAML.
342 out << "\"Tpetra::Distributor\":" << endl;
343 tab1 = Teuchos::rcp(new Teuchos::OSTab(out));
344
345 const std::string label = this->getObjectLabel();
346 if (label != "") {
347 out << "Label: " << label << endl;
348 }
349 out << "Number of processes: " << numProcs << endl
350 << "How initialized: "
351 << Details::DistributorHowInitializedEnumToString(plan_.howInitialized())
352 << endl;
353 {
354 out << "Parameters: " << endl;
355 Teuchos::OSTab tab2(out);
356 out << "\"Send type\": "
357 << DistributorSendTypeEnumToString(plan_.getSendType()) << endl
358 << "\"Debug\": " << (verbose_ ? "true" : "false") << endl;
359 }
360 } // if myRank == 0
361
362 // This is collective over the Map's communicator.
363 if (vl > VERB_LOW) {
364 const std::string lclStr = this->localDescribeToString(vl);
365 Tpetra::Details::gathervPrint(out, lclStr, *plan_.getComm());
366 }
367
368 out << "Reverse Distributor:";
369 if (reverseDistributor_.is_null()) {
370 out << " null" << endl;
371 } else {
372 out << endl;
373 reverseDistributor_->describe(out, vl);
374 }
375}
376
377size_t
379 createFromSends(const Teuchos::ArrayView<const int>& exportProcIDs) {
380 return plan_.createFromSends(exportProcIDs);
381}
382
384 createFromSendsAndRecvs(const Teuchos::ArrayView<const int>& exportProcIDs,
385 const Teuchos::ArrayView<const int>& remoteProcIDs) {
386 plan_.createFromSendsAndRecvs(exportProcIDs, remoteProcIDs);
387}
388
389} // namespace Tpetra
Declaration of Tpetra::Details::Behavior, a class that describes Tpetra's behavior.
Declaration of a function that prints strings from each process.
Stand-alone utility functions and macros.
Struct that holds views of the contents of a CrsMatrix.
static bool verbose()
Whether Tpetra is in verbose mode.
static std::string defaultSendType()
Default send type.
Sets up and executes a communication plan for a Tpetra DistObject.
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.
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.
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.
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.
Distributor(const Teuchos::RCP< const Teuchos::Comm< int > > &comm)
Construct using the specified communicator and default parameters.
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.
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.
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.
std::unique_ptr< std::string > createPrefix(const int myRank, const char prefix[])
Create string prefix for each line of verbose output.
const std::string & validSendTypeOrThrow(const std::string &s)
Valid enum values of distributor send types.
std::string DistributorHowInitializedEnumToString(EDistributorHowInitialized how)
Convert an EDistributorHowInitialized enum value to a string.
void gathervPrint(std::ostream &out, const std::string &s, const Teuchos::Comm< int > &comm)
On Process 0 in the given communicator, print strings from each process in that communicator,...
Namespace Tpetra contains the class and methods constituting the Tpetra library.