Teuchos - Trilinos Tools Package Version of the Day
Loading...
Searching...
No Matches
Teuchos_DefaultMpiComm_def.hpp
1// @HEADER
2// *****************************************************************************
3// Teuchos: Common Tools Package
4//
5// Copyright 2004 NTESS and the Teuchos contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9
10#ifndef TEUCHOS_MPI_COMM_DEF_HPP
11#define TEUCHOS_MPI_COMM_DEF_HPP
12
13
15
16// If MPI is not enabled, disable the contents of this file.
17#ifdef HAVE_TEUCHOS_MPI
18
20
21namespace Teuchos {
22
23template <class OrdinalType>
24MpiCommStatus<OrdinalType>::MpiCommStatus(MPI_Status status)
25 : status_(status) {}
26
27template <class OrdinalType> MpiCommStatus<OrdinalType>::~MpiCommStatus() {}
28
29template <class OrdinalType>
30OrdinalType MpiCommStatus<OrdinalType>::getSourceRank() {
31 return status_.MPI_SOURCE;
32}
33
34template <class OrdinalType> OrdinalType MpiCommStatus<OrdinalType>::getTag() {
35 return status_.MPI_TAG;
36}
37
38template <class OrdinalType>
39OrdinalType MpiCommStatus<OrdinalType>::getError() {
40 return status_.MPI_ERROR;
41}
42
43template<class OrdinalType>
44RCP<MpiCommStatus<OrdinalType> >
45mpiCommStatus (MPI_Status rawMpiStatus)
46{
47 return rcp (new MpiCommStatus<OrdinalType> (rawMpiStatus));
48}
49
50
51template<class OrdinalType>
52MpiCommRequestBase<OrdinalType>::MpiCommRequestBase () :
53 rawMpiRequest_ (MPI_REQUEST_NULL)
54 {}
55
56
57template<class OrdinalType>
58MpiCommRequestBase<OrdinalType>::MpiCommRequestBase (MPI_Request rawMpiRequest) :
59 rawMpiRequest_ (rawMpiRequest)
60 {}
61
62template<class OrdinalType>
63MPI_Request MpiCommRequestBase<OrdinalType>::releaseRawMpiRequest()
64{
65 MPI_Request tmp_rawMpiRequest = rawMpiRequest_;
66 rawMpiRequest_ = MPI_REQUEST_NULL;
67 return tmp_rawMpiRequest;
68}
69
70template<class OrdinalType>
71bool MpiCommRequestBase<OrdinalType>::isNull() const {
72 return rawMpiRequest_ == MPI_REQUEST_NULL;
73}
74
75template<class OrdinalType>
76bool MpiCommRequestBase<OrdinalType>::isReady() {
77 MPI_Status rawMpiStatus;
78 int flag = 0;
79
80 MPI_Test(&rawMpiRequest_, &flag, &rawMpiStatus);
81
82 return (flag != 0);
83}
84
85
86template<class OrdinalType>
87RCP<CommStatus<OrdinalType> >
88MpiCommRequestBase<OrdinalType>::wait () {
89 MPI_Status rawMpiStatus;
90 // Whether this function satisfies the strong exception guarantee
91 // depends on whether MPI_Wait modifies its input request on error.
92 const int err = MPI_Wait (&rawMpiRequest_, &rawMpiStatus);
94 err != MPI_SUCCESS, std::runtime_error,
95 "Teuchos: MPI_Wait() failed with error \""
96 << mpiErrorCodeToString (err));
97 // MPI_Wait sets the MPI_Request to MPI_REQUEST_NULL on success.
98 return mpiCommStatus<OrdinalType> (rawMpiStatus);
99}
100
101
102template<class OrdinalType>
103RCP<CommStatus<OrdinalType> > MpiCommRequestBase<OrdinalType>::cancel () {
104 if (rawMpiRequest_ == MPI_REQUEST_NULL) {
105 return null;
106 }
107 else {
108 int err = MPI_Cancel (&rawMpiRequest_);
110 err != MPI_SUCCESS, std::runtime_error,
111 "Teuchos: MPI_Cancel failed with the following error: "
112 << mpiErrorCodeToString (err));
113
114 // Wait on the request. If successful, MPI_Wait will set the
115 // MPI_Request to MPI_REQUEST_NULL. The returned status may
116 // still be useful; for example, one may call MPI_Test_cancelled
117 // to test an MPI_Status from a nonblocking send.
118 MPI_Status status;
119 err = MPI_Wait (&rawMpiRequest_, &status);
120 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
121 "Teuchos::MpiCommStatus::cancel: MPI_Wait failed with the following "
122 "error: " << mpiErrorCodeToString (err));
123 return mpiCommStatus<OrdinalType> (status);
124 }
125}
126
127template<class OrdinalType>
128MpiCommRequestBase<OrdinalType>::~MpiCommRequestBase () {
129 if (rawMpiRequest_ != MPI_REQUEST_NULL) {
130 // We're in a destructor, so don't throw errors. However, if
131 // MPI_Cancel fails, it's probably a bad idea to call MPI_Wait.
132 const int err = MPI_Cancel (&rawMpiRequest_);
133 if (err == MPI_SUCCESS) {
134 // The MPI_Cancel succeeded. Now wait on the request. Ignore
135 // any reported error, since we can't do anything about those
136 // in the destructor (other than kill the program). If
137 // successful, MPI_Wait will set the MPI_Request to
138 // MPI_REQUEST_NULL. We ignore the returned MPI_Status, since
139 // if the user let the request fall out of scope, she must not
140 // care about the status.
141 //
142 // mfh 21 Oct 2012: The MPI standard requires completing a
143 // canceled request by calling a function like MPI_Wait,
144 // MPI_Test, or MPI_Request_free. MPI_Wait on a canceled
145 // request behaves like a local operation (it does not
146 // communicate or block waiting for communication). One could
147 // also call MPI_Request_free instead of MPI_Wait, but
148 // MPI_Request_free is intended more for persistent requests
149 // (created with functions like MPI_Recv_init).
150 (void) MPI_Wait (&rawMpiRequest_, MPI_STATUS_IGNORE);
151 }
152 }
153}
154
155
156template<class OrdinalType>
157MpiCommRequest<OrdinalType>::MpiCommRequest () :
158 MpiCommRequestBase<OrdinalType> (MPI_REQUEST_NULL),
159 numBytes_ (0)
160{}
161
162template<class OrdinalType>
163MpiCommRequest<OrdinalType>::MpiCommRequest (MPI_Request rawMpiRequest,
164 const ArrayView<char>::size_type numBytesInMessage) :
165 MpiCommRequestBase<OrdinalType> (rawMpiRequest),
166 numBytes_ (numBytesInMessage)
167{}
168
169template<class OrdinalType>
170ArrayView<char>::size_type MpiCommRequest<OrdinalType>::numBytes () const {
171 return numBytes_;
172}
173
174template<class OrdinalType>
175MpiCommRequest<OrdinalType>::~MpiCommRequest () = default;
176
177
178template<class OrdinalType>
179RCP<MpiCommRequest<OrdinalType> >
180mpiCommRequest (MPI_Request rawMpiRequest,
181 const ArrayView<char>::size_type numBytes)
182{
183 return rcp (new MpiCommRequest<OrdinalType> (rawMpiRequest, numBytes));
184}
185
186// ////////////////////////
187// Implementations
188
189
190// Static members
191
192
193template<typename Ordinal>
194int MpiComm<Ordinal>::tagCounter_ = MpiComm<Ordinal>::minTag_;
195
196
197// Constructors
198
199
200template<typename Ordinal>
201MpiComm<Ordinal>::
202MpiComm (const RCP<const OpaqueWrapper<MPI_Comm> >& rawMpiComm)
203{
205 rawMpiComm.get () == NULL, std::invalid_argument,
206 "Teuchos::MpiComm constructor: The input RCP is null.");
208 *rawMpiComm == MPI_COMM_NULL, std::invalid_argument,
209 "Teuchos::MpiComm constructor: The given MPI_Comm is MPI_COMM_NULL.");
210
211 rawMpiComm_ = rawMpiComm;
212
213 // mfh 09 Jul 2013: Please resist the temptation to modify the given
214 // MPI communicator's error handler here. See Bug 5943. Note that
215 // an MPI communicator's default error handler is
216 // MPI_ERRORS_ARE_FATAL, which immediately aborts on error (without
217 // returning an error code from the MPI function). Users who want
218 // MPI functions instead to return an error code if they encounter
219 // an error, should set the error handler to MPI_ERRORS_RETURN. DO
220 // NOT SET THE ERROR HANDLER HERE!!! Teuchos' MPI wrappers should
221 // always check the error code returned by an MPI function,
222 // regardless of the error handler. Users who want to set the error
223 // handler on an MpiComm may call its setErrorHandler method.
224
225 setupMembersFromComm ();
226}
227
228
229template<typename Ordinal>
230MpiComm<Ordinal>::
231MpiComm (const RCP<const OpaqueWrapper<MPI_Comm> >& rawMpiComm,
232 const int defaultTag)
233{
235 rawMpiComm.get () == NULL, std::invalid_argument,
236 "Teuchos::MpiComm constructor: The input RCP is null.");
238 *rawMpiComm == MPI_COMM_NULL, std::invalid_argument,
239 "Teuchos::MpiComm constructor: The given MPI_Comm is MPI_COMM_NULL.");
240
241 rawMpiComm_ = rawMpiComm;
242 // Set size_ (the number of processes in the communicator).
243 int err = MPI_Comm_size (*rawMpiComm_, &size_);
244 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
245 "Teuchos::MpiComm constructor: MPI_Comm_size failed with "
246 "error \"" << mpiErrorCodeToString (err) << "\".");
247 // Set rank_ (the calling process' rank).
248 err = MPI_Comm_rank (*rawMpiComm_, &rank_);
249 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
250 "Teuchos::MpiComm constructor: MPI_Comm_rank failed with "
251 "error \"" << mpiErrorCodeToString (err) << "\".");
252 tag_ = defaultTag; // set the default message tag
253 // Cache MPI_TAG_UB so incrementTag wraps within the valid tag range
254 // (see setupMembersFromComm and incrementTag).
255 {
256 int* tag_ub_val = nullptr;
257 int found = 0;
258 int const aerr = MPI_Comm_get_attr (*rawMpiComm_, MPI_TAG_UB, &tag_ub_val, &found);
259 tagUb_ = (aerr == MPI_SUCCESS && found && tag_ub_val != nullptr && *tag_ub_val > minTag_) ? *tag_ub_val : 32767;
260 }
261}
262
263
264template<typename Ordinal>
265MpiComm<Ordinal>::MpiComm (MPI_Comm rawMpiComm)
266{
267 TEUCHOS_TEST_FOR_EXCEPTION(rawMpiComm == MPI_COMM_NULL,
268 std::invalid_argument, "Teuchos::MpiComm constructor: The given MPI_Comm "
269 "is MPI_COMM_NULL.");
270 // We don't supply a "free" function here, since this version of the
271 // constructor makes the caller responsible for freeing rawMpiComm
272 // after use if necessary.
273 rawMpiComm_ = opaqueWrapper<MPI_Comm> (rawMpiComm);
274
275 // mfh 09 Jul 2013: Please resist the temptation to modify the given
276 // MPI communicator's error handler here. See Bug 5943. Note that
277 // an MPI communicator's default error handler is
278 // MPI_ERRORS_ARE_FATAL, which immediately aborts on error (without
279 // returning an error code from the MPI function). Users who want
280 // MPI functions instead to return an error code if they encounter
281 // an error, should set the error handler to MPI_ERRORS_RETURN. DO
282 // NOT SET THE ERROR HANDLER HERE!!! Teuchos' MPI wrappers should
283 // always check the error code returned by an MPI function,
284 // regardless of the error handler. Users who want to set the error
285 // handler on an MpiComm may call its setErrorHandler method.
286
287 setupMembersFromComm ();
288}
289
290
291template<typename Ordinal>
292MpiComm<Ordinal>::MpiComm (const MpiComm<Ordinal>& other) :
293 rawMpiComm_ (opaqueWrapper<MPI_Comm> (MPI_COMM_NULL)) // <- This will be set below
294{
295 // These are logic errors, since they violate MpiComm's invariants.
296 RCP<const OpaqueWrapper<MPI_Comm> > origCommPtr = other.getRawMpiComm ();
297 TEUCHOS_TEST_FOR_EXCEPTION(origCommPtr == null, std::logic_error,
298 "Teuchos::MpiComm copy constructor: "
299 "The input's getRawMpiComm() method returns null.");
300 MPI_Comm origComm = *origCommPtr;
301 TEUCHOS_TEST_FOR_EXCEPTION(origComm == MPI_COMM_NULL, std::logic_error,
302 "Teuchos::MpiComm copy constructor: "
303 "The input's raw MPI_Comm is MPI_COMM_NULL.");
304
305 // mfh 19 Oct 2012: Don't change the behavior of MpiComm's copy
306 // constructor for now. Later, we'll switch to the version that
307 // calls MPI_Comm_dup. For now, we just copy other's handle over.
308 // Note that the new MpiComm's tag is still different than the input
309 // MpiComm's tag. See Bug 5740.
310 if (true) {
311 rawMpiComm_ = origCommPtr;
312 }
313 else { // false (not run)
314 MPI_Comm newComm;
315 const int err = MPI_Comm_dup (origComm, &newComm);
316 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
317 "Teuchos::MpiComm copy constructor: MPI_Comm_dup failed with "
318 "the following error: " << mpiErrorCodeToString (err));
319 // No side effects until after everything has succeeded.
320 rawMpiComm_ = opaqueWrapper (newComm, details::safeCommFree);
321 }
322
323 setupMembersFromComm ();
324}
325
326
327template<typename Ordinal>
328void MpiComm<Ordinal>::setupMembersFromComm ()
329{
330 int err = MPI_Comm_size (*rawMpiComm_, &size_);
331 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
332 "Teuchos::MpiComm constructor: MPI_Comm_size failed with "
333 "error \"" << mpiErrorCodeToString (err) << "\".");
334 err = MPI_Comm_rank (*rawMpiComm_, &rank_);
335 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
336 "Teuchos::MpiComm constructor: MPI_Comm_rank failed with "
337 "error \"" << mpiErrorCodeToString (err) << "\".");
338
339 // Query the largest tag MPI will accept on this communicator. Tags
340 // above MPI_TAG_UB are rejected with MPI_ERR_TAG, and on real MPI
341 // implementations MPI_TAG_UB is far below INT_MAX (e.g. 2^23-1 on
342 // OpenMPI). incrementTag uses this to wrap the tag before it leaves the
343 // valid range. Fall back to the MPI-standard guaranteed minimum (32767)
344 // if the attribute is somehow unavailable.
345 {
346 int* tag_ub_val = nullptr;
347 int found = 0;
348 int const aerr = MPI_Comm_get_attr (*rawMpiComm_, MPI_TAG_UB, &tag_ub_val, &found);
349 tagUb_ = (aerr == MPI_SUCCESS && found && tag_ub_val != nullptr && *tag_ub_val > minTag_) ? *tag_ub_val : 32767;
350 }
351
352 // Set the default tag to make unique across all communicators
353 if (tagCounter_ > maxTag_) {
354 tagCounter_ = minTag_;
355 }
356 tag_ = tagCounter_++;
357 // Ensure that the same tag is used on all processes.
358 //
359 // FIXME (mfh 09 Jul 2013) This would not be necessary if MpiComm
360 // were just to call MPI_Comm_dup (as every library should) when
361 // given its communicator. Of course, MPI_Comm_dup may also be
362 // implemented as a collective, and may even be more expensive than
363 // a broadcast. If we do decide to use MPI_Comm_dup, we can get rid
364 // of the broadcast below, and also get rid of tag_, tagCounter_,
365 // minTag_, and maxTag_.
366 MPI_Bcast (&tag_, 1, MPI_INT, 0, *rawMpiComm_);
367}
368
369
370template<typename Ordinal>
371void
372MpiComm<Ordinal>::
373setErrorHandler (const RCP<const OpaqueWrapper<MPI_Errhandler> >& errHandler)
374{
375 if (! is_null (errHandler)) {
376 const int err = details::setCommErrhandler (*getRawMpiComm (), *errHandler);
377 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
378 "Teuchos::MpiComm: Setting the MPI_Comm's error handler failed with "
379 "error \"" << mpiErrorCodeToString (err) << "\".");
380 }
381 // Wait to set this until the end, in case setting the error handler
382 // doesn't succeed.
383 customErrorHandler_ = errHandler;
384}
385
386//
387// Overridden from Comm
388//
389
390template<typename Ordinal>
391int MpiComm<Ordinal>::getRank() const
392{
393 return rank_;
394}
395
396
397template<typename Ordinal>
398int MpiComm<Ordinal>::getSize() const
399{
400 return size_;
401}
402
403
404template<typename Ordinal>
405void MpiComm<Ordinal>::alltoAll(
406 const Ordinal sendBytes, const char sendBuffer[],
407 const Ordinal recvBytes, char recvBuffer[]) const
408{
409 TEUCHOS_COMM_TIME_MONITOR(
410 "Teuchos::MpiComm<"<<OrdinalTraits<Ordinal>::name()<<">::alltoAll(...)"
411 );
412 const int err = MPI_Alltoall (sendBuffer, sendBytes, MPI_CHAR, recvBuffer, recvBytes, MPI_CHAR, *rawMpiComm_);
413 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
414 "Teuchos::MpiComm::alltoAll: MPI_Alltoall failed with error \""
415 << mpiErrorCodeToString (err) << "\".");
416}
417
418
419template<typename Ordinal>
420void MpiComm<Ordinal>::barrier() const
421{
422 TEUCHOS_COMM_TIME_MONITOR(
423 "Teuchos::MpiComm<"<<OrdinalTraits<Ordinal>::name()<<">::barrier()"
424 );
425 const int err = MPI_Barrier (*rawMpiComm_);
426 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
427 "Teuchos::MpiComm::barrier: MPI_Barrier failed with error \""
428 << mpiErrorCodeToString (err) << "\".");
429}
430
431
432template<typename Ordinal>
433void MpiComm<Ordinal>::broadcast(
434 const int rootRank, const Ordinal bytes, char buffer[]
435 ) const
436{
437 TEUCHOS_COMM_TIME_MONITOR(
438 "Teuchos::MpiComm<"<<OrdinalTraits<Ordinal>::name()<<">::broadcast(...)"
439 );
440 const int err = MPI_Bcast (buffer, bytes, MPI_CHAR, rootRank, *rawMpiComm_);
441 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
442 "Teuchos::MpiComm::broadcast: MPI_Bcast failed with error \""
443 << mpiErrorCodeToString (err) << "\".");
444}
445
446
447template<typename Ordinal>
448void MpiComm<Ordinal>::gatherAll(
449 const Ordinal sendBytes, const char sendBuffer[],
450 const Ordinal recvBytes, char recvBuffer[]
451 ) const
452{
453 TEUCHOS_COMM_TIME_MONITOR(
454 "Teuchos::MpiComm<"<<OrdinalTraits<Ordinal>::name()<<">::gatherAll(...)"
455 );
456 TEUCHOS_ASSERT_EQUALITY((sendBytes*size_), recvBytes );
457 const int err =
458 MPI_Allgather (const_cast<char *>(sendBuffer), sendBytes, MPI_CHAR,
459 recvBuffer, sendBytes, MPI_CHAR, *rawMpiComm_);
460 // NOTE: 'sendBytes' is being sent above for the MPI arg recvcount (which is
461 // very confusing in the MPI documentation) for MPI_Allgether(...).
462
463 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
464 "Teuchos::MpiComm::gatherAll: MPI_Allgather failed with error \""
465 << mpiErrorCodeToString (err) << "\".");
466}
467
468
469template<typename Ordinal>
470void
471MpiComm<Ordinal>::gather (const Ordinal sendBytes,
472 const char sendBuffer[],
473 const Ordinal recvBytes,
474 char recvBuffer[],
475 const int root) const
476{
477 (void) recvBytes; // silence compile warning for "unused parameter"
478
479 TEUCHOS_COMM_TIME_MONITOR(
480 "Teuchos::MpiComm<"<<OrdinalTraits<Ordinal>::name()<<">::gather(...)"
481 );
482 const int err =
483 MPI_Gather (const_cast<char *> (sendBuffer), sendBytes, MPI_CHAR,
484 recvBuffer, sendBytes, MPI_CHAR, root, *rawMpiComm_);
485 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
486 "Teuchos::MpiComm::gather: MPI_Gather failed with error \""
487 << mpiErrorCodeToString (err) << "\".");
488}
489
490
491template<typename Ordinal>
492void
493MpiComm<Ordinal>::
494reduceAll (const ValueTypeReductionOp<Ordinal,char> &reductOp,
495 const Ordinal bytes,
496 const char sendBuffer[],
497 char globalReducts[]) const
498{
499 TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::reduceAll(...)" );
500 int err = MPI_SUCCESS;
501
502 if (bytes == 0) return;
503
504 Details::MpiReductionOp<Ordinal> opWrap (reductOp);
505 MPI_Op op = Details::setMpiReductionOp (opWrap);
506
507 // FIXME (mfh 23 Nov 2014) Ross decided to mash every type into
508 // char. This can cause correctness issues if we're actually doing
509 // a reduction over, say, double. Thus, he creates a custom
510 // MPI_Datatype here that represents a contiguous block of char, so
511 // that MPI doesn't split up the reduction type and thus do the sum
512 // wrong. It's a hack but it works.
513
514 MPI_Datatype char_block;
515 err = MPI_Type_contiguous (bytes, MPI_CHAR, &char_block);
517 err != MPI_SUCCESS, std::runtime_error, "Teuchos::reduceAll: "
518 "MPI_Type_contiguous failed with error \"" << mpiErrorCodeToString (err)
519 << "\".");
520 err = MPI_Type_commit (&char_block);
522 err != MPI_SUCCESS, std::runtime_error, "Teuchos::reduceAll: "
523 "MPI_Type_commit failed with error \"" << mpiErrorCodeToString (err)
524 << "\".");
525
526 if (sendBuffer == globalReducts) {
527 // NOTE (mfh 31 May 2017) This is only safe if the communicator is
528 // NOT an intercomm. The usual case is that communicators are
529 // intracomms.
530 err = MPI_Allreduce (MPI_IN_PLACE, globalReducts, 1,
531 char_block, op, *rawMpiComm_);
532 }
533 else {
534 err = MPI_Allreduce (const_cast<char*> (sendBuffer), globalReducts, 1,
535 char_block, op, *rawMpiComm_);
536 }
537 if (err != MPI_SUCCESS) {
538 // Don't throw until we release the type resources we allocated
539 // above. If freeing fails for some reason, let the memory leak
540 // go; we already have more serious problems if MPI_Allreduce
541 // doesn't work.
542 (void) MPI_Type_free (&char_block);
544 true, std::runtime_error, "Teuchos::reduceAll (MPI, custom op): "
545 "MPI_Allreduce failed with error \"" << mpiErrorCodeToString (err)
546 << "\".");
547 }
548 err = MPI_Type_free (&char_block);
550 err != MPI_SUCCESS, std::runtime_error, "Teuchos::reduceAll: "
551 "MPI_Type_free failed with error \"" << mpiErrorCodeToString (err)
552 << "\".");
553}
554
555
556template<typename Ordinal>
557void MpiComm<Ordinal>::scan(
558 const ValueTypeReductionOp<Ordinal,char> &reductOp
559 ,const Ordinal bytes, const char sendBuffer[], char scanReducts[]
560 ) const
561{
562 TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::scan(...)" );
563
564 Details::MpiReductionOp<Ordinal> opWrap (reductOp);
565 MPI_Op op = Details::setMpiReductionOp (opWrap);
566 const int err =
567 MPI_Scan (const_cast<char*> (sendBuffer), scanReducts, bytes, MPI_CHAR,
568 op, *rawMpiComm_);
569 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
570 "Teuchos::MpiComm::scan: MPI_Scan() failed with error \""
571 << mpiErrorCodeToString (err) << "\".");
572}
573
574
575template<typename Ordinal>
576void
577MpiComm<Ordinal>::send (const Ordinal bytes,
578 const char sendBuffer[],
579 const int destRank) const
580{
581 TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::send(...)" );
582
583#ifdef TEUCHOS_MPI_COMM_DUMP
584 if(show_dump) {
585 dumpBuffer<Ordinal,char>(
586 "Teuchos::MpiComm<Ordinal>::send(...)"
587 ,"sendBuffer", bytes, sendBuffer
588 );
589 }
590#endif // TEUCHOS_MPI_COMM_DUMP
591
592 const int err = MPI_Send (const_cast<char*>(sendBuffer), bytes, MPI_CHAR,
593 destRank, tag_, *rawMpiComm_);
594 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
595 "Teuchos::MpiComm::send: MPI_Send() failed with error \""
596 << mpiErrorCodeToString (err) << "\".");
597}
598
599
600template<typename Ordinal>
601void
602MpiComm<Ordinal>::send (const Ordinal bytes,
603 const char sendBuffer[],
604 const int destRank,
605 const int tag) const
606{
607 TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::send(...)" );
608 const int err = MPI_Send (const_cast<char*> (sendBuffer), bytes, MPI_CHAR,
609 destRank, tag, *rawMpiComm_);
610 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
611 "Teuchos::MpiComm::send: MPI_Send() failed with error \""
612 << mpiErrorCodeToString (err) << "\".");
613}
614
615
616template<typename Ordinal>
617void
618MpiComm<Ordinal>::ssend (const Ordinal bytes,
619 const char sendBuffer[],
620 const int destRank) const
621{
622 TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::ssend(...)" );
623
624#ifdef TEUCHOS_MPI_COMM_DUMP
625 if(show_dump) {
626 dumpBuffer<Ordinal,char>(
627 "Teuchos::MpiComm<Ordinal>::send(...)"
628 ,"sendBuffer", bytes, sendBuffer
629 );
630 }
631#endif // TEUCHOS_MPI_COMM_DUMP
632
633 const int err = MPI_Ssend (const_cast<char*>(sendBuffer), bytes, MPI_CHAR,
634 destRank, tag_, *rawMpiComm_);
635 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
636 "Teuchos::MpiComm::send: MPI_Ssend() failed with error \""
637 << mpiErrorCodeToString (err) << "\".");
638}
639
640template<typename Ordinal>
641void
642MpiComm<Ordinal>::ssend (const Ordinal bytes,
643 const char sendBuffer[],
644 const int destRank,
645 const int tag) const
646{
647 TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::ssend(...)" );
648 const int err =
649 MPI_Ssend (const_cast<char*>(sendBuffer), bytes, MPI_CHAR,
650 destRank, tag, *rawMpiComm_);
651 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
652 "Teuchos::MpiComm::send: MPI_Ssend() failed with error \""
653 << mpiErrorCodeToString (err) << "\".");
654}
655
656template<typename Ordinal>
657void MpiComm<Ordinal>::readySend(
658 const ArrayView<const char> &sendBuffer,
659 const int destRank
660 ) const
661{
662 TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::readySend" );
663
664#ifdef TEUCHOS_MPI_COMM_DUMP
665 if(show_dump) {
666 dumpBuffer<Ordinal,char>(
667 "Teuchos::MpiComm<Ordinal>::readySend(...)"
668 ,"sendBuffer", bytes, sendBuffer
669 );
670 }
671#endif // TEUCHOS_MPI_COMM_DUMP
672
673 const int err =
674 MPI_Rsend (const_cast<char*>(sendBuffer.getRawPtr()), static_cast<int>(sendBuffer.size()),
675 MPI_CHAR, destRank, tag_, *rawMpiComm_);
676 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
677 "Teuchos::MpiComm::readySend: MPI_Rsend() failed with error \""
678 << mpiErrorCodeToString (err) << "\".");
679}
680
681
682template<typename Ordinal>
683void MpiComm<Ordinal>::
684readySend (const Ordinal bytes,
685 const char sendBuffer[],
686 const int destRank,
687 const int tag) const
688{
689 TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::readySend" );
690 const int err =
691 MPI_Rsend (const_cast<char*> (sendBuffer), bytes,
692 MPI_CHAR, destRank, tag, *rawMpiComm_);
693 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
694 "Teuchos::MpiComm::readySend: MPI_Rsend() failed with error \""
695 << mpiErrorCodeToString (err) << "\".");
696}
697
698
699template<typename Ordinal>
700int
701MpiComm<Ordinal>::receive (const int sourceRank,
702 const Ordinal bytes,
703 char recvBuffer[]) const
704{
705 TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::receive(...)" );
706
707 // A negative source rank indicates MPI_ANY_SOURCE, namely that we
708 // will take an incoming message from any process, as long as the
709 // tag matches.
710 const int theSrcRank = (sourceRank < 0) ? MPI_ANY_SOURCE : sourceRank;
711
712 MPI_Status status;
713 const int err = MPI_Recv (recvBuffer, bytes, MPI_CHAR, theSrcRank, tag_,
714 *rawMpiComm_, &status);
715 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
716 "Teuchos::MpiComm::receive: MPI_Recv() failed with error \""
717 << mpiErrorCodeToString (err) << "\".");
718
719#ifdef TEUCHOS_MPI_COMM_DUMP
720 if (show_dump) {
721 dumpBuffer<Ordinal,char> ("Teuchos::MpiComm<Ordinal>::receive(...)",
722 "recvBuffer", bytes, recvBuffer);
723 }
724#endif // TEUCHOS_MPI_COMM_DUMP
725
726 // Returning the source rank is useful in the MPI_ANY_SOURCE case.
727 return status.MPI_SOURCE;
728}
729
730
731template<typename Ordinal>
732RCP<CommRequest<Ordinal> >
733MpiComm<Ordinal>::isend (const ArrayView<const char> &sendBuffer,
734 const int destRank) const
735{
736 using Teuchos::as;
737 TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::isend(...)" );
738
739 MPI_Request rawMpiRequest = MPI_REQUEST_NULL;
740 const int err =
741 MPI_Isend (const_cast<char*> (sendBuffer.getRawPtr ()),
742 as<Ordinal> (sendBuffer.size ()), MPI_CHAR,
743 destRank, tag_, *rawMpiComm_, &rawMpiRequest);
744 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
745 "Teuchos::MpiComm::isend: MPI_Isend() failed with error \""
746 << mpiErrorCodeToString (err) << "\".");
747
748 return mpiCommRequest<Ordinal> (rawMpiRequest, sendBuffer.size ());
749}
750
751
752template<typename Ordinal>
753RCP<CommRequest<Ordinal> >
754MpiComm<Ordinal>::
755isend (const ArrayView<const char> &sendBuffer,
756 const int destRank,
757 const int tag) const
758{
759 using Teuchos::as;
760 TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::isend(...)" );
761
762 MPI_Request rawMpiRequest = MPI_REQUEST_NULL;
763 const int err =
764 MPI_Isend (const_cast<char*> (sendBuffer.getRawPtr ()),
765 as<Ordinal> (sendBuffer.size ()), MPI_CHAR,
766 destRank, tag, *rawMpiComm_, &rawMpiRequest);
767 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
768 "Teuchos::MpiComm::isend: MPI_Isend() failed with error \""
769 << mpiErrorCodeToString (err) << "\".");
770
771 return mpiCommRequest<Ordinal> (rawMpiRequest, sendBuffer.size ());
772}
773
774
775template<typename Ordinal>
776RCP<CommRequest<Ordinal> >
777MpiComm<Ordinal>::ireceive (const ArrayView<char> &recvBuffer,
778 const int sourceRank) const
779{
780 TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::ireceive(...)" );
781
782 // A negative source rank indicates MPI_ANY_SOURCE, namely that we
783 // will take an incoming message from any process, as long as the
784 // tag matches.
785 const int theSrcRank = (sourceRank < 0) ? MPI_ANY_SOURCE : sourceRank;
786
787 MPI_Request rawMpiRequest = MPI_REQUEST_NULL;
788 const int err =
789 MPI_Irecv (const_cast<char*>(recvBuffer.getRawPtr()), recvBuffer.size(),
790 MPI_CHAR, theSrcRank, tag_, *rawMpiComm_, &rawMpiRequest);
791 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
792 "Teuchos::MpiComm::ireceive: MPI_Irecv() failed with error \""
793 << mpiErrorCodeToString (err) << "\".");
794
795 return mpiCommRequest<Ordinal> (rawMpiRequest, recvBuffer.size());
796}
797
798template<typename Ordinal>
799RCP<CommRequest<Ordinal> >
800MpiComm<Ordinal>::ireceive (const ArrayView<char> &recvBuffer,
801 const int sourceRank,
802 const int tag) const
803{
804 TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::ireceive(...)" );
805
806 // A negative source rank indicates MPI_ANY_SOURCE, namely that we
807 // will take an incoming message from any process, as long as the
808 // tag matches.
809 const int theSrcRank = (sourceRank < 0) ? MPI_ANY_SOURCE : sourceRank;
810
811 MPI_Request rawMpiRequest = MPI_REQUEST_NULL;
812 const int err =
813 MPI_Irecv (const_cast<char*> (recvBuffer.getRawPtr ()), recvBuffer.size (),
814 MPI_CHAR, theSrcRank, tag, *rawMpiComm_, &rawMpiRequest);
815 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
816 "Teuchos::MpiComm::ireceive: MPI_Irecv() failed with error \""
817 << mpiErrorCodeToString (err) << "\".");
818
819 return mpiCommRequest<Ordinal> (rawMpiRequest, recvBuffer.size ());
820}
821
822namespace {
823 // Called by the two-argument MpiComm::waitAll() variant.
824 template<typename Ordinal>
825 void
826 waitAllImpl (const ArrayView<RCP<CommRequest<Ordinal> > >& requests,
827 const ArrayView<MPI_Status>& rawMpiStatuses)
828 {
829 typedef typename ArrayView<RCP<CommRequest<Ordinal> > >::size_type size_type;
830 const size_type count = requests.size();
831 // waitAllImpl() is not meant to be called by users, so it's a bug
832 // for the two views to have different lengths.
833 TEUCHOS_TEST_FOR_EXCEPTION(rawMpiStatuses.size() != count,
834 std::logic_error, "Teuchos::MpiComm's waitAllImpl: rawMpiStatus.size() = "
835 << rawMpiStatuses.size() << " != requests.size() = " << requests.size()
836 << ". Please report this bug to the Tpetra developers.");
837 if (count == 0) {
838 return; // No requests on which to wait
839 }
840
841 // MpiComm wraps MPI and can't expose any MPI structs or opaque
842 // objects. Thus, we have to unpack requests into a separate array.
843 // If that's too slow, then your code should just call into MPI
844 // directly.
845 //
846 // Pull out the raw MPI requests from the wrapped requests.
847 // MPI_Waitall should not fail if a request is MPI_REQUEST_NULL, but
848 // we keep track just to inform the user.
849 bool someNullRequests = false;
850 Array<MPI_Request> rawMpiRequests (count, MPI_REQUEST_NULL);
851 for (int i = 0; i < count; ++i) {
852 RCP<CommRequest<Ordinal> > request = requests[i];
853 if (! is_null (request)) {
854 RCP<MpiCommRequestBase<Ordinal> > mpiRequest =
855 rcp_dynamic_cast<MpiCommRequestBase<Ordinal> > (request);
856 // releaseRawMpiRequest() sets the MpiCommRequest's raw
857 // MPI_Request to MPI_REQUEST_NULL. This makes waitAll() not
858 // satisfy the strong exception guarantee. That's OK because
859 // MPI_Waitall() doesn't promise that it satisfies the strong
860 // exception guarantee, and we would rather conservatively
861 // invalidate the handles than leave dangling requests around
862 // and risk users trying to wait on the same request twice.
863 rawMpiRequests[i] = mpiRequest->releaseRawMpiRequest();
864 }
865 else { // Null requests map to MPI_REQUEST_NULL
866 rawMpiRequests[i] = MPI_REQUEST_NULL;
867 someNullRequests = true;
868 }
869 }
870
871 // This is the part where we've finally peeled off the wrapper and
872 // we can now interact with MPI directly.
873 //
874 // One option in the one-argument version of waitAll() is to ignore
875 // the statuses completely. MPI lets you pass in the named constant
876 // MPI_STATUSES_IGNORE for the MPI_Status array output argument in
877 // MPI_Waitall(), which would tell MPI not to bother with the
878 // statuses. However, we want the statuses because we can use them
879 // for detailed error diagnostics in case something goes wrong.
880 const int err = MPI_Waitall (count, rawMpiRequests.getRawPtr(),
881 rawMpiStatuses.getRawPtr());
882
883 // In MPI_Waitall(), an error indicates that one or more requests
884 // failed. In that case, there could be requests that completed
885 // (their MPI_Status' error field is MPI_SUCCESS), and other
886 // requests that have not completed yet but have not necessarily
887 // failed (MPI_PENDING). We make no attempt here to wait on the
888 // pending requests. It doesn't make sense for us to do so, because
889 // in general Teuchos::Comm doesn't attempt to provide robust
890 // recovery from failed messages.
891 if (err != MPI_SUCCESS) {
892 if (err == MPI_ERR_IN_STATUS) {
893 //
894 // When MPI_Waitall returns MPI_ERR_IN_STATUS (a standard error
895 // class), it's telling us to check the error codes in the
896 // returned statuses. In that case, we do so and generate a
897 // detailed exception message.
898 //
899 // Figure out which of the requests failed.
900 Array<std::pair<size_type, int> > errorLocationsAndCodes;
901 for (size_type k = 0; k < rawMpiStatuses.size(); ++k) {
902 const int curErr = rawMpiStatuses[k].MPI_ERROR;
903 if (curErr != MPI_SUCCESS) {
904 errorLocationsAndCodes.push_back (std::make_pair (k, curErr));
905 }
906 }
907 const size_type numErrs = errorLocationsAndCodes.size();
908 if (numErrs > 0) {
909 // There was at least one error. Assemble a detailed
910 // exception message reporting which requests failed,
911 // their error codes, and their source
912 std::ostringstream os;
913 os << "Teuchos::MpiComm::waitAll: MPI_Waitall() failed with error \""
914 << mpiErrorCodeToString (err) << "\". Of the " << count
915 << " total request" << (count != 1 ? "s" : "") << ", " << numErrs
916 << " failed. Here are the indices of the failed requests, and the "
917 "error codes extracted from their returned MPI_Status objects:"
918 << std::endl;
919 for (size_type k = 0; k < numErrs; ++k) {
920 const size_type errInd = errorLocationsAndCodes[k].first;
921 os << "Request " << errInd << ": MPI_ERROR = "
922 << mpiErrorCodeToString (rawMpiStatuses[errInd].MPI_ERROR)
923 << std::endl;
924 }
925 if (someNullRequests) {
926 os << " On input to MPI_Waitall, there was at least one MPI_"
927 "Request that was MPI_REQUEST_NULL. MPI_Waitall should not "
928 "normally fail in that case, but we thought we should let you know "
929 "regardless.";
930 }
931 TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, os.str());
932 }
933 // If there were no actual errors in the returned statuses,
934 // well, then I guess everything is OK. Just keep going.
935 }
936 else {
937 std::ostringstream os;
938 os << "Teuchos::MpiComm::waitAll: MPI_Waitall() failed with error \""
939 << mpiErrorCodeToString (err) << "\".";
940 if (someNullRequests) {
941 os << " On input to MPI_Waitall, there was at least one MPI_Request "
942 "that was MPI_REQUEST_NULL. MPI_Waitall should not normally fail in "
943 "that case, but we thought we should let you know regardless.";
944 }
945 TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, os.str());
946 }
947 }
948
949 // Invalidate the input array of requests by setting all entries
950 // to null.
951 std::fill (requests.begin(), requests.end(), null);
952 }
953
954
955
956 // Called by the one-argument MpiComm::waitAll() variant.
957 template<typename Ordinal>
958 void
959 waitAllImpl (const ArrayView<RCP<CommRequest<Ordinal> > >& requests)
960 {
961 typedef typename ArrayView<RCP<CommRequest<Ordinal> > >::size_type size_type;
962 const size_type count = requests.size ();
963 if (count == 0) {
964 return; // No requests on which to wait
965 }
966
967 // MpiComm wraps MPI and can't expose any MPI structs or opaque
968 // objects. Thus, we have to unpack requests into a separate
969 // array. If that's too slow, then your code should just call
970 // into MPI directly.
971 //
972 // Pull out the raw MPI requests from the wrapped requests.
973 // MPI_Waitall should not fail if a request is MPI_REQUEST_NULL,
974 // but we keep track just to inform the user.
975 bool someNullRequests = false;
976 Array<MPI_Request> rawMpiRequests (count, MPI_REQUEST_NULL);
977 for (int i = 0; i < count; ++i) {
978 RCP<CommRequest<Ordinal> > request = requests[i];
979 if (! request.is_null ()) {
980 RCP<MpiCommRequestBase<Ordinal> > mpiRequest =
981 rcp_dynamic_cast<MpiCommRequestBase<Ordinal> > (request);
982 // releaseRawMpiRequest() sets the MpiCommRequest's raw
983 // MPI_Request to MPI_REQUEST_NULL. This makes waitAll() not
984 // satisfy the strong exception guarantee. That's OK because
985 // MPI_Waitall() doesn't promise that it satisfies the strong
986 // exception guarantee, and we would rather conservatively
987 // invalidate the handles than leave dangling requests around
988 // and risk users trying to wait on the same request twice.
989 rawMpiRequests[i] = mpiRequest->releaseRawMpiRequest ();
990 }
991 else { // Null requests map to MPI_REQUEST_NULL
992 rawMpiRequests[i] = MPI_REQUEST_NULL;
993 someNullRequests = true;
994 }
995 }
996
997 // This is the part where we've finally peeled off the wrapper and
998 // we can now interact with MPI directly.
999 //
1000 // MPI lets us pass in the named constant MPI_STATUSES_IGNORE for
1001 // the MPI_Status array output argument in MPI_Waitall(), which
1002 // tells MPI not to bother writing out the statuses.
1003 const int err = MPI_Waitall (count, rawMpiRequests.getRawPtr(),
1004 MPI_STATUSES_IGNORE);
1005
1006 // In MPI_Waitall(), an error indicates that one or more requests
1007 // failed. In that case, there could be requests that completed
1008 // (their MPI_Status' error field is MPI_SUCCESS), and other
1009 // requests that have not completed yet but have not necessarily
1010 // failed (MPI_PENDING). We make no attempt here to wait on the
1011 // pending requests. It doesn't make sense for us to do so,
1012 // because in general Teuchos::Comm doesn't attempt to provide
1013 // robust recovery from failed messages.
1014 if (err != MPI_SUCCESS) {
1015 std::ostringstream os;
1016 os << "Teuchos::MpiComm::waitAll: MPI_Waitall() failed with error \""
1017 << mpiErrorCodeToString (err) << "\".";
1018 if (someNullRequests) {
1019 os << std::endl << "On input to MPI_Waitall, there was at least one "
1020 "MPI_Request that was MPI_REQUEST_NULL. MPI_Waitall should not "
1021 "normally fail in that case, but we thought we should let you know "
1022 "regardless.";
1023 }
1024 TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, os.str());
1025 }
1026
1027 // Invalidate the input array of requests by setting all entries
1028 // to null. We delay this until the end, since some
1029 // implementations of CommRequest might hold the only reference to
1030 // the communication buffer, and we don't want that to go away
1031 // until we've waited on the communication operation.
1032 std::fill (requests.begin(), requests.end(), null);
1033 }
1034
1035} // namespace (anonymous)
1036
1037
1038
1039template<typename Ordinal>
1040void
1041MpiComm<Ordinal>::
1042waitAll (const ArrayView<RCP<CommRequest<Ordinal> > >& requests) const
1043{
1044 TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::waitAll(requests)" );
1045 // Call the one-argument version of waitAllImpl, to avoid overhead
1046 // of handling statuses (which the user didn't want anyway).
1047 waitAllImpl<Ordinal> (requests);
1048}
1049
1050
1051template<typename Ordinal>
1052void
1053MpiComm<Ordinal>::
1054waitAll (const ArrayView<RCP<CommRequest<Ordinal> > >& requests,
1055 const ArrayView<RCP<CommStatus<Ordinal> > >& statuses) const
1056{
1057 TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::waitAll(requests, statuses)" );
1058
1059 typedef typename ArrayView<RCP<CommRequest<Ordinal> > >::size_type size_type;
1060 const size_type count = requests.size();
1061
1062 TEUCHOS_TEST_FOR_EXCEPTION(count != statuses.size(),
1063 std::invalid_argument, "Teuchos::MpiComm::waitAll: requests.size() = "
1064 << count << " != statuses.size() = " << statuses.size() << ".");
1065
1066 Array<MPI_Status> rawMpiStatuses (count);
1067 waitAllImpl<Ordinal> (requests, rawMpiStatuses());
1068
1069 // Repackage the raw MPI_Status structs into the wrappers.
1070 for (size_type i = 0; i < count; ++i) {
1071 statuses[i] = mpiCommStatus<Ordinal> (rawMpiStatuses[i]);
1072 }
1073}
1074
1075
1076template<typename Ordinal>
1077RCP<CommStatus<Ordinal> >
1078MpiComm<Ordinal>::wait (const Ptr<RCP<CommRequest<Ordinal> > >& request) const
1079{
1080 TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::wait(...)" );
1081
1082 if (is_null (*request)) {
1083 return null; // Nothing to wait on ...
1084 }
1085 else {
1086 RCP<CommStatus<Ordinal> > status = (*request)->wait ();
1087 // mfh 22 Oct 2012: The unit tests expect waiting on the
1088 // CommRequest to invalidate it by setting it to null.
1089 *request = null;
1090 return status;
1091 }
1092}
1093
1094template<typename Ordinal>
1095RCP< Comm<Ordinal> >
1096MpiComm<Ordinal>::duplicate() const
1097{
1098 MPI_Comm origRawComm = *rawMpiComm_;
1099 MPI_Comm newRawComm = MPI_COMM_NULL;
1100 const int err = MPI_Comm_dup (origRawComm, &newRawComm);
1101 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error, "Teuchos"
1102 "::MpiComm::duplicate: MPI_Comm_dup failed with the following error: "
1103 << mpiErrorCodeToString (err));
1104
1105 // Wrap the raw communicator, and pass the (const) wrapped
1106 // communicator to MpiComm's constructor. We created the raw comm,
1107 // so we have to supply a function that frees it after use.
1108 RCP<OpaqueWrapper<MPI_Comm> > wrapped =
1109 opaqueWrapper<MPI_Comm> (newRawComm, details::safeCommFree);
1110 // Since newComm's raw MPI_Comm is the result of an MPI_Comm_dup,
1111 // its messages cannot collide with those of any other MpiComm.
1112 // This means we can assign its tag without an MPI_Bcast.
1113 RCP<MpiComm<Ordinal> > newComm =
1114 rcp (new MpiComm<Ordinal> (wrapped.getConst (), minTag_));
1115 return rcp_implicit_cast<Comm<Ordinal> > (newComm);
1116}
1117
1118
1119template<typename Ordinal>
1120RCP< Comm<Ordinal> >
1121MpiComm<Ordinal>::split(const int color, const int key) const
1122{
1123 MPI_Comm newComm;
1124 const int splitReturn =
1125 MPI_Comm_split (*rawMpiComm_,
1126 color < 0 ? MPI_UNDEFINED : color,
1127 key,
1128 &newComm);
1130 splitReturn != MPI_SUCCESS,
1131 std::logic_error,
1132 "Teuchos::MpiComm::split: Failed to create communicator with color "
1133 << color << "and key " << key << ". MPI_Comm_split failed with error \""
1134 << mpiErrorCodeToString (splitReturn) << "\".");
1135 if (newComm == MPI_COMM_NULL) {
1136 return RCP< Comm<Ordinal> >();
1137 } else {
1138 RCP<const OpaqueWrapper<MPI_Comm> > wrapped =
1139 opaqueWrapper<MPI_Comm> (newComm, details::safeCommFree);
1140 // Since newComm's raw MPI_Comm is the result of an
1141 // MPI_Comm_split, its messages cannot collide with those of any
1142 // other MpiComm. This means we can assign its tag without an
1143 // MPI_Bcast.
1144 return rcp (new MpiComm<Ordinal> (wrapped, minTag_));
1145 }
1146}
1147
1148
1149template<typename Ordinal>
1150RCP< Comm<Ordinal> >
1151MpiComm<Ordinal>::createSubcommunicator(const ArrayView<const int> &ranks) const
1152{
1153 int err = MPI_SUCCESS; // For error codes returned by MPI functions
1154
1155 // Get the group that this communicator is in.
1156 MPI_Group thisGroup;
1157 err = MPI_Comm_group (*rawMpiComm_, &thisGroup);
1158 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::logic_error,
1159 "Failed to obtain the current communicator's group. "
1160 "MPI_Comm_group failed with error \""
1161 << mpiErrorCodeToString (err) << "\".");
1162
1163 // Create a new group with the specified members.
1164 MPI_Group newGroup;
1165 // It's rude to cast away const, but MPI functions demand it.
1166 //
1167 // NOTE (mfh 14 Aug 2012) Please don't ask for &ranks[0] unless you
1168 // know that ranks.size() > 0. That's why I'm using getRawPtr().
1169 err = MPI_Group_incl (thisGroup, ranks.size(),
1170 const_cast<int*> (ranks.getRawPtr ()), &newGroup);
1171 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::logic_error,
1172 "Failed to create subgroup. MPI_Group_incl failed with error \""
1173 << mpiErrorCodeToString (err) << "\".");
1174
1175 // Create a new communicator from the new group.
1176 MPI_Comm newComm;
1177 try {
1178 err = MPI_Comm_create (*rawMpiComm_, newGroup, &newComm);
1179 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::logic_error,
1180 "Failed to create subcommunicator. MPI_Comm_create failed with error \""
1181 << mpiErrorCodeToString (err) << "\".");
1182 } catch (...) {
1183 // Attempt to free the new group before rethrowing. If
1184 // successful, this will prevent a memory leak due to the "lost"
1185 // group that was allocated successfully above. Since we're
1186 // throwing std::logic_error anyway, we can only promise
1187 // best-effort recovery; thus, we don't check the error code.
1188 (void) MPI_Group_free (&newGroup);
1189 (void) MPI_Group_free (&thisGroup);
1190 throw;
1191 }
1192
1193 // We don't need the group any more, so free it.
1194 err = MPI_Group_free (&newGroup);
1195 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::logic_error,
1196 "Failed to free subgroup. MPI_Group_free failed with error \""
1197 << mpiErrorCodeToString (err) << "\".");
1198 err = MPI_Group_free (&thisGroup);
1199 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::logic_error,
1200 "Failed to free subgroup. MPI_Group_free failed with error \""
1201 << mpiErrorCodeToString (err) << "\".");
1202
1203 if (newComm == MPI_COMM_NULL) {
1204 return RCP<Comm<Ordinal> > ();
1205 } else {
1206 using Teuchos::details::safeCommFree;
1207 typedef OpaqueWrapper<MPI_Comm> ow_type;
1208 RCP<const ow_type> wrapper =
1209 rcp_implicit_cast<const ow_type> (opaqueWrapper (newComm, safeCommFree));
1210 // Since newComm's raw MPI_Comm is the result of an
1211 // MPI_Comm_create, its messages cannot collide with those of any
1212 // other MpiComm. This means we can assign its tag without an
1213 // MPI_Bcast.
1214 return rcp (new MpiComm<Ordinal> (wrapper, minTag_));
1215 }
1216}
1217
1218
1219// Overridden from Describable
1220
1221
1222template<typename Ordinal>
1223std::string MpiComm<Ordinal>::description() const
1224{
1225 std::ostringstream oss;
1226 oss
1227 << typeName(*this)
1228 << "{"
1229 << "size="<<size_
1230 << ",rank="<<rank_
1231 << ",rawMpiComm="<<static_cast<MPI_Comm>(*rawMpiComm_)
1232 <<"}";
1233 return oss.str();
1234}
1235
1236
1237#ifdef TEUCHOS_MPI_COMM_DUMP
1238template<typename Ordinal>
1239bool MpiComm<Ordinal>::show_dump = false;
1240#endif
1241
1242
1243// private
1244
1245
1246template<typename Ordinal>
1247void MpiComm<Ordinal>::assertRank(const int rank, const std::string &rankName) const
1248{
1250 ! ( 0 <= rank && rank < size_ ), std::logic_error
1251 ,"Error, "<<rankName<<" = " << rank << " is not < 0 or is not"
1252 " in the range [0,"<<size_-1<<"]!"
1253 );
1254}
1255
1256
1257} // namespace Teuchos
1258
1259
1260template<typename Ordinal>
1262Teuchos::createMpiComm(
1263 const RCP<const OpaqueWrapper<MPI_Comm> > &rawMpiComm
1264 )
1265{
1266 if( rawMpiComm.get()!=NULL && *rawMpiComm != MPI_COMM_NULL )
1267 return rcp(new MpiComm<Ordinal>(rawMpiComm));
1268 return Teuchos::null;
1269}
1270
1271
1272template<typename Ordinal>
1274Teuchos::createMpiComm(
1275 const RCP<const OpaqueWrapper<MPI_Comm> > &rawMpiComm,
1276 const int defaultTag
1277 )
1278{
1279 if( rawMpiComm.get()!=NULL && *rawMpiComm != MPI_COMM_NULL )
1280 return rcp(new MpiComm<Ordinal>(rawMpiComm, defaultTag));
1281 return Teuchos::null;
1282}
1283
1284
1285template<typename Ordinal>
1286MPI_Comm
1287Teuchos::getRawMpiComm(const Comm<Ordinal> &comm)
1288{
1289 return *(
1290 dyn_cast<const MpiComm<Ordinal> >(comm).getRawMpiComm()
1291 );
1292}
1293
1294
1295#endif // HAVE_TEUCHOS_MPI
1296#endif // TEUCHOS_MPI_COMM_DEF_HPP
Teuchos header file which uses auto-configuration information to include necessary C++ headers.
Implementation of Teuchos wrappers for MPI.
Smart reference counting pointer class for automatic garbage collection.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Macro for throwing an exception with breakpointing to ease debugging.
#define TEUCHOS_ASSERT_EQUALITY(val1, val2)
This macro is checks that to numbers are equal and if not then throws an exception with a good error ...
TypeTo as(const TypeFrom &t)
Convert from one value type to another.
std::string typeName(const T &t)
Template function for returning the concrete type name of a passed-in object.
The Teuchos namespace contains all of the classes, structs and enums used by Teuchos,...
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Deprecated.