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.
24 namespace {
25 // Default value of the "Debug" parameter.
26 const bool tpetraDistributorDebugDefault = false;
27 } // namespace (anonymous)
28
29 Teuchos::Array<std::string>
31 {
32 Teuchos::Array<std::string> sendTypes;
33 sendTypes.push_back ("Isend");
34 sendTypes.push_back ("Send");
35 sendTypes.push_back ("Alltoall");
36#if defined(HAVE_TPETRACORE_MPI_ADVANCE)
37 sendTypes.push_back ("MpiAdvanceAlltoall");
38 sendTypes.push_back ("MpiAdvanceNbralltoallv");
39#endif
40 return sendTypes;
41 }
42
44 Distributor (const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
45 const Teuchos::RCP<Teuchos::FancyOStream>& /* out */,
46 const Teuchos::RCP<Teuchos::ParameterList>& plist)
47 : plan_(comm)
48 {
49 this->setParameterList(plist);
50 }
51
53 Distributor (const Teuchos::RCP<const Teuchos::Comm<int> >& comm)
54 : Distributor (comm, Teuchos::null, Teuchos::null)
55 {}
56
58 Distributor (const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
59 const Teuchos::RCP<Teuchos::FancyOStream>& out)
60 : Distributor (comm, out, Teuchos::null)
61 {}
62
64 Distributor (const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
65 const Teuchos::RCP<Teuchos::ParameterList>& plist)
66 : Distributor (comm, Teuchos::null, plist)
67 {}
68
70 Distributor (const Distributor& distributor)
71 : plan_(distributor.plan_)
72 , actor_(distributor.actor_)
73 , verbose_ (distributor.verbose_)
74 , reverseDistributor_ (distributor.reverseDistributor_)
75 {
76 using Teuchos::ParameterList;
77 using Teuchos::RCP;
78 using Teuchos::rcp;
79
80 RCP<const ParameterList> rhsList = distributor.getParameterList ();
81 RCP<ParameterList> newList = rhsList.is_null () ? Teuchos::null :
82 Teuchos::parameterList (*rhsList);
83 this->setParameterList (newList);
84 }
85
87 using Teuchos::ParameterList;
88 using Teuchos::parameterList;
89 using Teuchos::RCP;
90
91 std::swap (plan_, rhs.plan_);
92 std::swap (actor_, rhs.actor_);
93 std::swap (verbose_, rhs.verbose_);
94 std::swap (reverseDistributor_, rhs.reverseDistributor_);
95
96 // Swap parameter lists. If they are the same object, make a deep
97 // copy first, so that modifying one won't modify the other one.
98 RCP<ParameterList> lhsList = this->getNonconstParameterList ();
99 RCP<ParameterList> rhsList = rhs.getNonconstParameterList ();
100 if (lhsList.getRawPtr () == rhsList.getRawPtr () && ! rhsList.is_null ()) {
101 rhsList = parameterList (*rhsList);
102 }
103 if (! rhsList.is_null ()) {
104 this->setMyParamList (rhsList);
105 }
106 if (! lhsList.is_null ()) {
107 rhs.setMyParamList (lhsList);
108 }
109
110 // We don't need to swap timers, because all instances of
111 // Distributor use the same timers.
112 }
113
114 bool
115 Distributor::getVerbose()
116 {
117 return Details::Behavior::verbose("Distributor") ||
118 Details::Behavior::verbose("Tpetra::Distributor");
119 }
120
121 std::unique_ptr<std::string>
122 Distributor::
123 createPrefix(const char methodName[]) const
124 {
126 plan_.getComm().getRawPtr(), "Distributor", methodName);
127 }
128
129 void
131 setParameterList (const Teuchos::RCP<Teuchos::ParameterList>& plist)
132 {
134 using Teuchos::FancyOStream;
135 using Teuchos::getIntegralValue;
136 using Teuchos::includesVerbLevel;
137 using Teuchos::ParameterList;
138 using Teuchos::parameterList;
139 using Teuchos::RCP;
140 using std::endl;
141
142 if (! plist.is_null()) {
143 RCP<const ParameterList> validParams = getValidParameters ();
144 plist->validateParametersAndSetDefaults (*validParams);
145
146 // ParameterListAcceptor semantics require pointer identity of the
147 // sublist passed to setParameterList(), so we save the pointer.
148 this->setMyParamList (plist);
149
150 RCP<ParameterList> planParams(plist);
151 planParams->remove("Debug", false);
152 planParams->remove("VerboseObject", false);
153 plan_.setParameterList(planParams);
154 }
155 }
156
157 Teuchos::RCP<const Teuchos::ParameterList>
159 {
160 using Teuchos::Array;
161 using Teuchos::ParameterList;
162 using Teuchos::parameterList;
163 using Teuchos::RCP;
164 using Teuchos::setStringToIntegralParameter;
165
166 const bool debug = tpetraDistributorDebugDefault;
167
168 Array<std::string> sendTypes = distributorSendTypes ();
169 const std::string defaultSendType ("Send");
170 Array<Details::EDistributorSendType> sendTypeEnums;
171 sendTypeEnums.push_back (Details::DISTRIBUTOR_ISEND);
172 sendTypeEnums.push_back (Details::DISTRIBUTOR_SEND);
173 sendTypeEnums.push_back (Details::DISTRIBUTOR_ALLTOALL);
174#if defined(HAVE_TPETRACORE_MPI_ADVANCE)
175 sendTypeEnums.push_back(Details::DISTRIBUTOR_MPIADVANCE_ALLTOALL);
176 sendTypeEnums.push_back(Details::DISTRIBUTOR_MPIADVANCE_NBRALLTOALLV);
177#endif
178
179 RCP<ParameterList> plist = parameterList ("Tpetra::Distributor");
180 setStringToIntegralParameter<Details::EDistributorSendType> ("Send type",
181 defaultSendType, "When using MPI, the variant of send to use in "
182 "do[Reverse]Posts()", sendTypes(), sendTypeEnums(), plist.getRawPtr());
183 plist->set ("Debug", debug, "Whether to print copious debugging output on "
184 "all processes.");
185 plist->set ("Timer Label","","Label for Time Monitor output");
186
187 // mfh 24 Dec 2015: Tpetra no longer inherits from
188 // Teuchos::VerboseObject, so it doesn't need the "VerboseObject"
189 // sublist. However, we retain the "VerboseObject" sublist
190 // anyway, for backwards compatibility (otherwise the above
191 // validation would fail with an invalid parameter name, should
192 // the user still want to provide this list).
193 Teuchos::setupVerboseObjectSublist (&*plist);
194 return Teuchos::rcp_const_cast<const ParameterList> (plist);
195 }
196
197
199 { return plan_.getTotalReceiveLength(); }
200
202 { return plan_.getNumReceives(); }
203
205 { return plan_.hasSelfMessage(); }
206
208 { return plan_.getNumSends(); }
209
211 { return plan_.getMaxSendLength(); }
212
213 Teuchos::ArrayView<const int> Distributor::getProcsFrom() const
214 { return plan_.getProcsFrom(); }
215
216 Teuchos::ArrayView<const size_t> Distributor::getLengthsFrom() const
217 { return plan_.getLengthsFrom(); }
218
219 Teuchos::ArrayView<const int> Distributor::getProcsTo() const
220 { return plan_.getProcsTo(); }
221
222 Teuchos::ArrayView<const size_t> Distributor::getLengthsTo() const
223 { return plan_.getLengthsTo(); }
224
225 Teuchos::RCP<Distributor>
226 Distributor::getReverse(bool create) const {
227 if (reverseDistributor_.is_null () && create) {
228 createReverseDistributor ();
229 }
230 TEUCHOS_TEST_FOR_EXCEPTION
231 (reverseDistributor_.is_null () && create, std::logic_error, "The reverse "
232 "Distributor is null after createReverseDistributor returned. "
233 "Please report this bug to the Tpetra developers.");
234 return reverseDistributor_;
235 }
236
237
238 void
239 Distributor::createReverseDistributor() const
240 {
241 reverseDistributor_ = Teuchos::rcp(new Distributor(plan_.getComm()));
242 reverseDistributor_->plan_ = *plan_.getReversePlan();
243 reverseDistributor_->verbose_ = verbose_;
244
245 // requests_: Allocated on demand.
246 // reverseDistributor_: See note below
247
248 // I am my reverse Distributor's reverse Distributor.
249 // Thus, it would be legit to do the following:
250 //
251 // reverseDistributor_->reverseDistributor_ = Teuchos::rcp (this, false);
252 //
253 // (Note use of a "weak reference" to avoid a circular RCP
254 // dependency.) The only issue is that if users hold on to the
255 // reverse Distributor but let go of the forward one, this
256 // reference won't be valid anymore. However, the reverse
257 // Distributor is really an implementation detail of Distributor
258 // and not meant to be used directly, so we don't need to do this.
259 reverseDistributor_->reverseDistributor_ = Teuchos::null;
260 }
261
262 void
264 {
265 actor_.doWaits(plan_);
266 }
267
269 // call doWaits() on the reverse Distributor, if it exists
270 if (! reverseDistributor_.is_null()) {
271 reverseDistributor_->doWaits();
272 }
273 }
274
275 std::string Distributor::description () const {
276 std::ostringstream out;
277
278 out << "\"Tpetra::Distributor\": {";
279 const std::string label = this->getObjectLabel ();
280 if (label != "") {
281 out << "Label: " << label << ", ";
282 }
283 out << "How initialized: "
284 << Details::DistributorHowInitializedEnumToString (plan_.howInitialized())
285 << ", Parameters: {"
286 << "Send type: "
287 << DistributorSendTypeEnumToString (plan_.getSendType())
288 << ", Debug: " << (verbose_ ? "true" : "false")
289 << "}}";
290 return out.str ();
291 }
292
293 std::string
294 Distributor::
295 localDescribeToString (const Teuchos::EVerbosityLevel vl) const
296 {
297 using Teuchos::toString;
298 using Teuchos::VERB_HIGH;
299 using Teuchos::VERB_EXTREME;
300 using std::endl;
301
302 // This preserves current behavior of Distributor.
303 if (vl <= Teuchos::VERB_LOW || plan_.getComm().is_null ()) {
304 return std::string ();
305 }
306
307 auto outStringP = Teuchos::rcp (new std::ostringstream ());
308 auto outp = Teuchos::getFancyOStream (outStringP); // returns RCP
309 Teuchos::FancyOStream& out = *outp;
310
311 const int myRank = plan_.getComm()->getRank ();
312 const int numProcs = plan_.getComm()->getSize ();
313 out << "Process " << myRank << " of " << numProcs << ":" << endl;
314 Teuchos::OSTab tab1 (out);
315
316 out << "selfMessage: " << hasSelfMessage() << endl;
317 out << "numSends: " << getNumSends() << endl;
318 if (vl == VERB_HIGH || vl == VERB_EXTREME) {
319 out << "procsTo: " << toString (plan_.getProcsTo()) << endl;
320 out << "lengthsTo: " << toString (plan_.getLengthsTo()) << endl;
321 out << "maxSendLength: " << getMaxSendLength() << endl;
322 }
323 if (vl == VERB_EXTREME) {
324 out << "startsTo: " << toString (plan_.getStartsTo()) << endl;
325 out << "indicesTo: " << toString (plan_.getIndicesTo()) << endl;
326 }
327 if (vl == VERB_HIGH || vl == VERB_EXTREME) {
328 out << "numReceives: " << getNumReceives() << endl;
329 out << "totalReceiveLength: " << getTotalReceiveLength() << endl;
330 out << "lengthsFrom: " << toString (plan_.getLengthsFrom()) << endl;
331 out << "procsFrom: " << toString (plan_.getProcsFrom()) << endl;
332 }
333
334 out.flush (); // make sure the ostringstream got everything
335 return outStringP->str ();
336 }
337
338 void
340 describe (Teuchos::FancyOStream& out,
341 const Teuchos::EVerbosityLevel verbLevel) const
342 {
343 using std::endl;
344 using Teuchos::VERB_DEFAULT;
345 using Teuchos::VERB_NONE;
346 using Teuchos::VERB_LOW;
347 using Teuchos::VERB_MEDIUM;
348 using Teuchos::VERB_HIGH;
349 using Teuchos::VERB_EXTREME;
350 const Teuchos::EVerbosityLevel vl =
351 (verbLevel == VERB_DEFAULT) ? VERB_LOW : verbLevel;
352
353 if (vl == VERB_NONE) {
354 return; // don't print anything
355 }
356 // If this Distributor's Comm is null, then the the calling
357 // process does not participate in Distributor-related collective
358 // operations with the other processes. In that case, it is not
359 // even legal to call this method. The reasonable thing to do in
360 // that case is nothing.
361 if (plan_.getComm().is_null ()) {
362 return;
363 }
364 const int myRank = plan_.getComm()->getRank ();
365 const int numProcs = plan_.getComm()->getSize ();
366
367 // Only Process 0 should touch the output stream, but this method
368 // in general may need to do communication. Thus, we may need to
369 // preserve the current tab level across multiple "if (myRank ==
370 // 0) { ... }" inner scopes. This is why we sometimes create
371 // OSTab instances by pointer, instead of by value. We only need
372 // to create them by pointer if the tab level must persist through
373 // multiple inner scopes.
374 Teuchos::RCP<Teuchos::OSTab> tab0, tab1;
375
376 if (myRank == 0) {
377 // At every verbosity level but VERB_NONE, Process 0 prints.
378 // By convention, describe() always begins with a tab before
379 // printing.
380 tab0 = Teuchos::rcp (new Teuchos::OSTab (out));
381 // We quote the class name because it contains colons.
382 // This makes the output valid YAML.
383 out << "\"Tpetra::Distributor\":" << endl;
384 tab1 = Teuchos::rcp (new Teuchos::OSTab (out));
385
386 const std::string label = this->getObjectLabel ();
387 if (label != "") {
388 out << "Label: " << label << endl;
389 }
390 out << "Number of processes: " << numProcs << endl
391 << "How initialized: "
392 << Details::DistributorHowInitializedEnumToString (plan_.howInitialized())
393 << endl;
394 {
395 out << "Parameters: " << endl;
396 Teuchos::OSTab tab2 (out);
397 out << "\"Send type\": "
398 << DistributorSendTypeEnumToString (plan_.getSendType()) << endl
399 << "\"Debug\": " << (verbose_ ? "true" : "false") << endl;
400 }
401 } // if myRank == 0
402
403 // This is collective over the Map's communicator.
404 if (vl > VERB_LOW) {
405 const std::string lclStr = this->localDescribeToString (vl);
406 Tpetra::Details::gathervPrint (out, lclStr, *plan_.getComm());
407 }
408
409 out << "Reverse Distributor:";
410 if (reverseDistributor_.is_null ()) {
411 out << " null" << endl;
412 }
413 else {
414 out << endl;
415 reverseDistributor_->describe (out, vl);
416 }
417 }
418
419 size_t
421 createFromSends(const Teuchos::ArrayView<const int>& exportProcIDs)
422 {
423 return plan_.createFromSends(exportProcIDs);
424 }
425
426 void
428 createFromSendsAndRecvs (const Teuchos::ArrayView<const int>& exportProcIDs,
429 const Teuchos::ArrayView<const int>& remoteProcIDs)
430 {
431 plan_.createFromSendsAndRecvs(exportProcIDs, remoteProcIDs);
432 }
433
434} // 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.
Description of Tpetra's behavior.
static bool verbose()
Whether Tpetra is in verbose mode.
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.
std::unique_ptr< std::string > createPrefix(const int myRank, const char prefix[])
Create string prefix for each line of verbose output.
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.
Teuchos::Array< std::string > distributorSendTypes()
Valid values for Distributor's "Send type" parameter.