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>::barrier() const
406{
407 TEUCHOS_COMM_TIME_MONITOR(
408 "Teuchos::MpiComm<"<<OrdinalTraits<Ordinal>::name()<<">::barrier()"
409 );
410 const int err = MPI_Barrier (*rawMpiComm_);
411 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
412 "Teuchos::MpiComm::barrier: MPI_Barrier failed with error \""
413 << mpiErrorCodeToString (err) << "\".");
414}
415
416
417template<typename Ordinal>
418void MpiComm<Ordinal>::broadcast(
419 const int rootRank, const Ordinal bytes, char buffer[]
420 ) const
421{
422 TEUCHOS_COMM_TIME_MONITOR(
423 "Teuchos::MpiComm<"<<OrdinalTraits<Ordinal>::name()<<">::broadcast(...)"
424 );
425 const int err = MPI_Bcast (buffer, bytes, MPI_CHAR, rootRank, *rawMpiComm_);
426 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
427 "Teuchos::MpiComm::broadcast: MPI_Bcast failed with error \""
428 << mpiErrorCodeToString (err) << "\".");
429}
430
431
432template<typename Ordinal>
433void MpiComm<Ordinal>::gatherAll(
434 const Ordinal sendBytes, const char sendBuffer[],
435 const Ordinal recvBytes, char recvBuffer[]
436 ) const
437{
438 TEUCHOS_COMM_TIME_MONITOR(
439 "Teuchos::MpiComm<"<<OrdinalTraits<Ordinal>::name()<<">::gatherAll(...)"
440 );
441 TEUCHOS_ASSERT_EQUALITY((sendBytes*size_), recvBytes );
442 const int err =
443 MPI_Allgather (const_cast<char *>(sendBuffer), sendBytes, MPI_CHAR,
444 recvBuffer, sendBytes, MPI_CHAR, *rawMpiComm_);
445 // NOTE: 'sendBytes' is being sent above for the MPI arg recvcount (which is
446 // very confusing in the MPI documentation) for MPI_Allgether(...).
447
448 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
449 "Teuchos::MpiComm::gatherAll: MPI_Allgather failed with error \""
450 << mpiErrorCodeToString (err) << "\".");
451}
452
453
454template<typename Ordinal>
455void
456MpiComm<Ordinal>::gather (const Ordinal sendBytes,
457 const char sendBuffer[],
458 const Ordinal recvBytes,
459 char recvBuffer[],
460 const int root) const
461{
462 (void) recvBytes; // silence compile warning for "unused parameter"
463
464 TEUCHOS_COMM_TIME_MONITOR(
465 "Teuchos::MpiComm<"<<OrdinalTraits<Ordinal>::name()<<">::gather(...)"
466 );
467 const int err =
468 MPI_Gather (const_cast<char *> (sendBuffer), sendBytes, MPI_CHAR,
469 recvBuffer, sendBytes, MPI_CHAR, root, *rawMpiComm_);
470 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
471 "Teuchos::MpiComm::gather: MPI_Gather failed with error \""
472 << mpiErrorCodeToString (err) << "\".");
473}
474
475
476template<typename Ordinal>
477void
478MpiComm<Ordinal>::
479reduceAll (const ValueTypeReductionOp<Ordinal,char> &reductOp,
480 const Ordinal bytes,
481 const char sendBuffer[],
482 char globalReducts[]) const
483{
484 TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::reduceAll(...)" );
485 int err = MPI_SUCCESS;
486
487 if (bytes == 0) return;
488
489 Details::MpiReductionOp<Ordinal> opWrap (reductOp);
490 MPI_Op op = Details::setMpiReductionOp (opWrap);
491
492 // FIXME (mfh 23 Nov 2014) Ross decided to mash every type into
493 // char. This can cause correctness issues if we're actually doing
494 // a reduction over, say, double. Thus, he creates a custom
495 // MPI_Datatype here that represents a contiguous block of char, so
496 // that MPI doesn't split up the reduction type and thus do the sum
497 // wrong. It's a hack but it works.
498
499 MPI_Datatype char_block;
500 err = MPI_Type_contiguous (bytes, MPI_CHAR, &char_block);
502 err != MPI_SUCCESS, std::runtime_error, "Teuchos::reduceAll: "
503 "MPI_Type_contiguous failed with error \"" << mpiErrorCodeToString (err)
504 << "\".");
505 err = MPI_Type_commit (&char_block);
507 err != MPI_SUCCESS, std::runtime_error, "Teuchos::reduceAll: "
508 "MPI_Type_commit failed with error \"" << mpiErrorCodeToString (err)
509 << "\".");
510
511 if (sendBuffer == globalReducts) {
512 // NOTE (mfh 31 May 2017) This is only safe if the communicator is
513 // NOT an intercomm. The usual case is that communicators are
514 // intracomms.
515 err = MPI_Allreduce (MPI_IN_PLACE, globalReducts, 1,
516 char_block, op, *rawMpiComm_);
517 }
518 else {
519 err = MPI_Allreduce (const_cast<char*> (sendBuffer), globalReducts, 1,
520 char_block, op, *rawMpiComm_);
521 }
522 if (err != MPI_SUCCESS) {
523 // Don't throw until we release the type resources we allocated
524 // above. If freeing fails for some reason, let the memory leak
525 // go; we already have more serious problems if MPI_Allreduce
526 // doesn't work.
527 (void) MPI_Type_free (&char_block);
529 true, std::runtime_error, "Teuchos::reduceAll (MPI, custom op): "
530 "MPI_Allreduce failed with error \"" << mpiErrorCodeToString (err)
531 << "\".");
532 }
533 err = MPI_Type_free (&char_block);
535 err != MPI_SUCCESS, std::runtime_error, "Teuchos::reduceAll: "
536 "MPI_Type_free failed with error \"" << mpiErrorCodeToString (err)
537 << "\".");
538}
539
540
541template<typename Ordinal>
542void MpiComm<Ordinal>::scan(
543 const ValueTypeReductionOp<Ordinal,char> &reductOp
544 ,const Ordinal bytes, const char sendBuffer[], char scanReducts[]
545 ) const
546{
547 TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::scan(...)" );
548
549 Details::MpiReductionOp<Ordinal> opWrap (reductOp);
550 MPI_Op op = Details::setMpiReductionOp (opWrap);
551 const int err =
552 MPI_Scan (const_cast<char*> (sendBuffer), scanReducts, bytes, MPI_CHAR,
553 op, *rawMpiComm_);
554 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
555 "Teuchos::MpiComm::scan: MPI_Scan() failed with error \""
556 << mpiErrorCodeToString (err) << "\".");
557}
558
559
560template<typename Ordinal>
561void
562MpiComm<Ordinal>::send (const Ordinal bytes,
563 const char sendBuffer[],
564 const int destRank) const
565{
566 TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::send(...)" );
567
568#ifdef TEUCHOS_MPI_COMM_DUMP
569 if(show_dump) {
570 dumpBuffer<Ordinal,char>(
571 "Teuchos::MpiComm<Ordinal>::send(...)"
572 ,"sendBuffer", bytes, sendBuffer
573 );
574 }
575#endif // TEUCHOS_MPI_COMM_DUMP
576
577 const int err = MPI_Send (const_cast<char*>(sendBuffer), bytes, MPI_CHAR,
578 destRank, tag_, *rawMpiComm_);
579 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
580 "Teuchos::MpiComm::send: MPI_Send() failed with error \""
581 << mpiErrorCodeToString (err) << "\".");
582}
583
584
585template<typename Ordinal>
586void
587MpiComm<Ordinal>::send (const Ordinal bytes,
588 const char sendBuffer[],
589 const int destRank,
590 const int tag) const
591{
592 TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::send(...)" );
593 const int err = MPI_Send (const_cast<char*> (sendBuffer), bytes, MPI_CHAR,
594 destRank, tag, *rawMpiComm_);
595 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
596 "Teuchos::MpiComm::send: MPI_Send() failed with error \""
597 << mpiErrorCodeToString (err) << "\".");
598}
599
600
601template<typename Ordinal>
602void
603MpiComm<Ordinal>::ssend (const Ordinal bytes,
604 const char sendBuffer[],
605 const int destRank) const
606{
607 TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::ssend(...)" );
608
609#ifdef TEUCHOS_MPI_COMM_DUMP
610 if(show_dump) {
611 dumpBuffer<Ordinal,char>(
612 "Teuchos::MpiComm<Ordinal>::send(...)"
613 ,"sendBuffer", bytes, sendBuffer
614 );
615 }
616#endif // TEUCHOS_MPI_COMM_DUMP
617
618 const int err = MPI_Ssend (const_cast<char*>(sendBuffer), bytes, MPI_CHAR,
619 destRank, tag_, *rawMpiComm_);
620 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
621 "Teuchos::MpiComm::send: MPI_Ssend() failed with error \""
622 << mpiErrorCodeToString (err) << "\".");
623}
624
625template<typename Ordinal>
626void
627MpiComm<Ordinal>::ssend (const Ordinal bytes,
628 const char sendBuffer[],
629 const int destRank,
630 const int tag) const
631{
632 TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::ssend(...)" );
633 const int err =
634 MPI_Ssend (const_cast<char*>(sendBuffer), bytes, MPI_CHAR,
635 destRank, tag, *rawMpiComm_);
636 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
637 "Teuchos::MpiComm::send: MPI_Ssend() failed with error \""
638 << mpiErrorCodeToString (err) << "\".");
639}
640
641template<typename Ordinal>
642void MpiComm<Ordinal>::readySend(
643 const ArrayView<const char> &sendBuffer,
644 const int destRank
645 ) const
646{
647 TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::readySend" );
648
649#ifdef TEUCHOS_MPI_COMM_DUMP
650 if(show_dump) {
651 dumpBuffer<Ordinal,char>(
652 "Teuchos::MpiComm<Ordinal>::readySend(...)"
653 ,"sendBuffer", bytes, sendBuffer
654 );
655 }
656#endif // TEUCHOS_MPI_COMM_DUMP
657
658 const int err =
659 MPI_Rsend (const_cast<char*>(sendBuffer.getRawPtr()), static_cast<int>(sendBuffer.size()),
660 MPI_CHAR, destRank, tag_, *rawMpiComm_);
661 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
662 "Teuchos::MpiComm::readySend: MPI_Rsend() failed with error \""
663 << mpiErrorCodeToString (err) << "\".");
664}
665
666
667template<typename Ordinal>
668void MpiComm<Ordinal>::
669readySend (const Ordinal bytes,
670 const char sendBuffer[],
671 const int destRank,
672 const int tag) const
673{
674 TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::readySend" );
675 const int err =
676 MPI_Rsend (const_cast<char*> (sendBuffer), bytes,
677 MPI_CHAR, destRank, tag, *rawMpiComm_);
678 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
679 "Teuchos::MpiComm::readySend: MPI_Rsend() failed with error \""
680 << mpiErrorCodeToString (err) << "\".");
681}
682
683
684template<typename Ordinal>
685int
686MpiComm<Ordinal>::receive (const int sourceRank,
687 const Ordinal bytes,
688 char recvBuffer[]) const
689{
690 TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::receive(...)" );
691
692 // A negative source rank indicates MPI_ANY_SOURCE, namely that we
693 // will take an incoming message from any process, as long as the
694 // tag matches.
695 const int theSrcRank = (sourceRank < 0) ? MPI_ANY_SOURCE : sourceRank;
696
697 MPI_Status status;
698 const int err = MPI_Recv (recvBuffer, bytes, MPI_CHAR, theSrcRank, tag_,
699 *rawMpiComm_, &status);
700 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
701 "Teuchos::MpiComm::receive: MPI_Recv() failed with error \""
702 << mpiErrorCodeToString (err) << "\".");
703
704#ifdef TEUCHOS_MPI_COMM_DUMP
705 if (show_dump) {
706 dumpBuffer<Ordinal,char> ("Teuchos::MpiComm<Ordinal>::receive(...)",
707 "recvBuffer", bytes, recvBuffer);
708 }
709#endif // TEUCHOS_MPI_COMM_DUMP
710
711 // Returning the source rank is useful in the MPI_ANY_SOURCE case.
712 return status.MPI_SOURCE;
713}
714
715
716template<typename Ordinal>
717RCP<CommRequest<Ordinal> >
718MpiComm<Ordinal>::isend (const ArrayView<const char> &sendBuffer,
719 const int destRank) const
720{
721 using Teuchos::as;
722 TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::isend(...)" );
723
724 MPI_Request rawMpiRequest = MPI_REQUEST_NULL;
725 const int err =
726 MPI_Isend (const_cast<char*> (sendBuffer.getRawPtr ()),
727 as<Ordinal> (sendBuffer.size ()), MPI_CHAR,
728 destRank, tag_, *rawMpiComm_, &rawMpiRequest);
729 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
730 "Teuchos::MpiComm::isend: MPI_Isend() failed with error \""
731 << mpiErrorCodeToString (err) << "\".");
732
733 return mpiCommRequest<Ordinal> (rawMpiRequest, sendBuffer.size ());
734}
735
736
737template<typename Ordinal>
738RCP<CommRequest<Ordinal> >
739MpiComm<Ordinal>::
740isend (const ArrayView<const char> &sendBuffer,
741 const int destRank,
742 const int tag) const
743{
744 using Teuchos::as;
745 TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::isend(...)" );
746
747 MPI_Request rawMpiRequest = MPI_REQUEST_NULL;
748 const int err =
749 MPI_Isend (const_cast<char*> (sendBuffer.getRawPtr ()),
750 as<Ordinal> (sendBuffer.size ()), MPI_CHAR,
751 destRank, tag, *rawMpiComm_, &rawMpiRequest);
752 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
753 "Teuchos::MpiComm::isend: MPI_Isend() failed with error \""
754 << mpiErrorCodeToString (err) << "\".");
755
756 return mpiCommRequest<Ordinal> (rawMpiRequest, sendBuffer.size ());
757}
758
759
760template<typename Ordinal>
761RCP<CommRequest<Ordinal> >
762MpiComm<Ordinal>::ireceive (const ArrayView<char> &recvBuffer,
763 const int sourceRank) const
764{
765 TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::ireceive(...)" );
766
767 // A negative source rank indicates MPI_ANY_SOURCE, namely that we
768 // will take an incoming message from any process, as long as the
769 // tag matches.
770 const int theSrcRank = (sourceRank < 0) ? MPI_ANY_SOURCE : sourceRank;
771
772 MPI_Request rawMpiRequest = MPI_REQUEST_NULL;
773 const int err =
774 MPI_Irecv (const_cast<char*>(recvBuffer.getRawPtr()), recvBuffer.size(),
775 MPI_CHAR, theSrcRank, tag_, *rawMpiComm_, &rawMpiRequest);
776 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
777 "Teuchos::MpiComm::ireceive: MPI_Irecv() failed with error \""
778 << mpiErrorCodeToString (err) << "\".");
779
780 return mpiCommRequest<Ordinal> (rawMpiRequest, recvBuffer.size());
781}
782
783template<typename Ordinal>
784RCP<CommRequest<Ordinal> >
785MpiComm<Ordinal>::ireceive (const ArrayView<char> &recvBuffer,
786 const int sourceRank,
787 const int tag) const
788{
789 TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::ireceive(...)" );
790
791 // A negative source rank indicates MPI_ANY_SOURCE, namely that we
792 // will take an incoming message from any process, as long as the
793 // tag matches.
794 const int theSrcRank = (sourceRank < 0) ? MPI_ANY_SOURCE : sourceRank;
795
796 MPI_Request rawMpiRequest = MPI_REQUEST_NULL;
797 const int err =
798 MPI_Irecv (const_cast<char*> (recvBuffer.getRawPtr ()), recvBuffer.size (),
799 MPI_CHAR, theSrcRank, tag, *rawMpiComm_, &rawMpiRequest);
800 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
801 "Teuchos::MpiComm::ireceive: MPI_Irecv() failed with error \""
802 << mpiErrorCodeToString (err) << "\".");
803
804 return mpiCommRequest<Ordinal> (rawMpiRequest, recvBuffer.size ());
805}
806
807namespace {
808 // Called by the two-argument MpiComm::waitAll() variant.
809 template<typename Ordinal>
810 void
811 waitAllImpl (const ArrayView<RCP<CommRequest<Ordinal> > >& requests,
812 const ArrayView<MPI_Status>& rawMpiStatuses)
813 {
814 typedef typename ArrayView<RCP<CommRequest<Ordinal> > >::size_type size_type;
815 const size_type count = requests.size();
816 // waitAllImpl() is not meant to be called by users, so it's a bug
817 // for the two views to have different lengths.
818 TEUCHOS_TEST_FOR_EXCEPTION(rawMpiStatuses.size() != count,
819 std::logic_error, "Teuchos::MpiComm's waitAllImpl: rawMpiStatus.size() = "
820 << rawMpiStatuses.size() << " != requests.size() = " << requests.size()
821 << ". Please report this bug to the Tpetra developers.");
822 if (count == 0) {
823 return; // No requests on which to wait
824 }
825
826 // MpiComm wraps MPI and can't expose any MPI structs or opaque
827 // objects. Thus, we have to unpack requests into a separate array.
828 // If that's too slow, then your code should just call into MPI
829 // directly.
830 //
831 // Pull out the raw MPI requests from the wrapped requests.
832 // MPI_Waitall should not fail if a request is MPI_REQUEST_NULL, but
833 // we keep track just to inform the user.
834 bool someNullRequests = false;
835 Array<MPI_Request> rawMpiRequests (count, MPI_REQUEST_NULL);
836 for (int i = 0; i < count; ++i) {
837 RCP<CommRequest<Ordinal> > request = requests[i];
838 if (! is_null (request)) {
839 RCP<MpiCommRequestBase<Ordinal> > mpiRequest =
840 rcp_dynamic_cast<MpiCommRequestBase<Ordinal> > (request);
841 // releaseRawMpiRequest() sets the MpiCommRequest's raw
842 // MPI_Request to MPI_REQUEST_NULL. This makes waitAll() not
843 // satisfy the strong exception guarantee. That's OK because
844 // MPI_Waitall() doesn't promise that it satisfies the strong
845 // exception guarantee, and we would rather conservatively
846 // invalidate the handles than leave dangling requests around
847 // and risk users trying to wait on the same request twice.
848 rawMpiRequests[i] = mpiRequest->releaseRawMpiRequest();
849 }
850 else { // Null requests map to MPI_REQUEST_NULL
851 rawMpiRequests[i] = MPI_REQUEST_NULL;
852 someNullRequests = true;
853 }
854 }
855
856 // This is the part where we've finally peeled off the wrapper and
857 // we can now interact with MPI directly.
858 //
859 // One option in the one-argument version of waitAll() is to ignore
860 // the statuses completely. MPI lets you pass in the named constant
861 // MPI_STATUSES_IGNORE for the MPI_Status array output argument in
862 // MPI_Waitall(), which would tell MPI not to bother with the
863 // statuses. However, we want the statuses because we can use them
864 // for detailed error diagnostics in case something goes wrong.
865 const int err = MPI_Waitall (count, rawMpiRequests.getRawPtr(),
866 rawMpiStatuses.getRawPtr());
867
868 // In MPI_Waitall(), an error indicates that one or more requests
869 // failed. In that case, there could be requests that completed
870 // (their MPI_Status' error field is MPI_SUCCESS), and other
871 // requests that have not completed yet but have not necessarily
872 // failed (MPI_PENDING). We make no attempt here to wait on the
873 // pending requests. It doesn't make sense for us to do so, because
874 // in general Teuchos::Comm doesn't attempt to provide robust
875 // recovery from failed messages.
876 if (err != MPI_SUCCESS) {
877 if (err == MPI_ERR_IN_STATUS) {
878 //
879 // When MPI_Waitall returns MPI_ERR_IN_STATUS (a standard error
880 // class), it's telling us to check the error codes in the
881 // returned statuses. In that case, we do so and generate a
882 // detailed exception message.
883 //
884 // Figure out which of the requests failed.
885 Array<std::pair<size_type, int> > errorLocationsAndCodes;
886 for (size_type k = 0; k < rawMpiStatuses.size(); ++k) {
887 const int curErr = rawMpiStatuses[k].MPI_ERROR;
888 if (curErr != MPI_SUCCESS) {
889 errorLocationsAndCodes.push_back (std::make_pair (k, curErr));
890 }
891 }
892 const size_type numErrs = errorLocationsAndCodes.size();
893 if (numErrs > 0) {
894 // There was at least one error. Assemble a detailed
895 // exception message reporting which requests failed,
896 // their error codes, and their source
897 std::ostringstream os;
898 os << "Teuchos::MpiComm::waitAll: MPI_Waitall() failed with error \""
899 << mpiErrorCodeToString (err) << "\". Of the " << count
900 << " total request" << (count != 1 ? "s" : "") << ", " << numErrs
901 << " failed. Here are the indices of the failed requests, and the "
902 "error codes extracted from their returned MPI_Status objects:"
903 << std::endl;
904 for (size_type k = 0; k < numErrs; ++k) {
905 const size_type errInd = errorLocationsAndCodes[k].first;
906 os << "Request " << errInd << ": MPI_ERROR = "
907 << mpiErrorCodeToString (rawMpiStatuses[errInd].MPI_ERROR)
908 << std::endl;
909 }
910 if (someNullRequests) {
911 os << " On input to MPI_Waitall, there was at least one MPI_"
912 "Request that was MPI_REQUEST_NULL. MPI_Waitall should not "
913 "normally fail in that case, but we thought we should let you know "
914 "regardless.";
915 }
916 TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, os.str());
917 }
918 // If there were no actual errors in the returned statuses,
919 // well, then I guess everything is OK. Just keep going.
920 }
921 else {
922 std::ostringstream os;
923 os << "Teuchos::MpiComm::waitAll: MPI_Waitall() failed with error \""
924 << mpiErrorCodeToString (err) << "\".";
925 if (someNullRequests) {
926 os << " On input to MPI_Waitall, there was at least one MPI_Request "
927 "that was MPI_REQUEST_NULL. MPI_Waitall should not normally fail in "
928 "that case, but we thought we should let you know regardless.";
929 }
930 TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, os.str());
931 }
932 }
933
934 // Invalidate the input array of requests by setting all entries
935 // to null.
936 std::fill (requests.begin(), requests.end(), null);
937 }
938
939
940
941 // Called by the one-argument MpiComm::waitAll() variant.
942 template<typename Ordinal>
943 void
944 waitAllImpl (const ArrayView<RCP<CommRequest<Ordinal> > >& requests)
945 {
946 typedef typename ArrayView<RCP<CommRequest<Ordinal> > >::size_type size_type;
947 const size_type count = requests.size ();
948 if (count == 0) {
949 return; // No requests on which to wait
950 }
951
952 // MpiComm wraps MPI and can't expose any MPI structs or opaque
953 // objects. Thus, we have to unpack requests into a separate
954 // array. If that's too slow, then your code should just call
955 // into MPI directly.
956 //
957 // Pull out the raw MPI requests from the wrapped requests.
958 // MPI_Waitall should not fail if a request is MPI_REQUEST_NULL,
959 // but we keep track just to inform the user.
960 bool someNullRequests = false;
961 Array<MPI_Request> rawMpiRequests (count, MPI_REQUEST_NULL);
962 for (int i = 0; i < count; ++i) {
963 RCP<CommRequest<Ordinal> > request = requests[i];
964 if (! request.is_null ()) {
965 RCP<MpiCommRequestBase<Ordinal> > mpiRequest =
966 rcp_dynamic_cast<MpiCommRequestBase<Ordinal> > (request);
967 // releaseRawMpiRequest() sets the MpiCommRequest's raw
968 // MPI_Request to MPI_REQUEST_NULL. This makes waitAll() not
969 // satisfy the strong exception guarantee. That's OK because
970 // MPI_Waitall() doesn't promise that it satisfies the strong
971 // exception guarantee, and we would rather conservatively
972 // invalidate the handles than leave dangling requests around
973 // and risk users trying to wait on the same request twice.
974 rawMpiRequests[i] = mpiRequest->releaseRawMpiRequest ();
975 }
976 else { // Null requests map to MPI_REQUEST_NULL
977 rawMpiRequests[i] = MPI_REQUEST_NULL;
978 someNullRequests = true;
979 }
980 }
981
982 // This is the part where we've finally peeled off the wrapper and
983 // we can now interact with MPI directly.
984 //
985 // MPI lets us pass in the named constant MPI_STATUSES_IGNORE for
986 // the MPI_Status array output argument in MPI_Waitall(), which
987 // tells MPI not to bother writing out the statuses.
988 const int err = MPI_Waitall (count, rawMpiRequests.getRawPtr(),
989 MPI_STATUSES_IGNORE);
990
991 // In MPI_Waitall(), an error indicates that one or more requests
992 // failed. In that case, there could be requests that completed
993 // (their MPI_Status' error field is MPI_SUCCESS), and other
994 // requests that have not completed yet but have not necessarily
995 // failed (MPI_PENDING). We make no attempt here to wait on the
996 // pending requests. It doesn't make sense for us to do so,
997 // because in general Teuchos::Comm doesn't attempt to provide
998 // robust recovery from failed messages.
999 if (err != MPI_SUCCESS) {
1000 std::ostringstream os;
1001 os << "Teuchos::MpiComm::waitAll: MPI_Waitall() failed with error \""
1002 << mpiErrorCodeToString (err) << "\".";
1003 if (someNullRequests) {
1004 os << std::endl << "On input to MPI_Waitall, there was at least one "
1005 "MPI_Request that was MPI_REQUEST_NULL. MPI_Waitall should not "
1006 "normally fail in that case, but we thought we should let you know "
1007 "regardless.";
1008 }
1009 TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, os.str());
1010 }
1011
1012 // Invalidate the input array of requests by setting all entries
1013 // to null. We delay this until the end, since some
1014 // implementations of CommRequest might hold the only reference to
1015 // the communication buffer, and we don't want that to go away
1016 // until we've waited on the communication operation.
1017 std::fill (requests.begin(), requests.end(), null);
1018 }
1019
1020} // namespace (anonymous)
1021
1022
1023
1024template<typename Ordinal>
1025void
1026MpiComm<Ordinal>::
1027waitAll (const ArrayView<RCP<CommRequest<Ordinal> > >& requests) const
1028{
1029 TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::waitAll(requests)" );
1030 // Call the one-argument version of waitAllImpl, to avoid overhead
1031 // of handling statuses (which the user didn't want anyway).
1032 waitAllImpl<Ordinal> (requests);
1033}
1034
1035
1036template<typename Ordinal>
1037void
1038MpiComm<Ordinal>::
1039waitAll (const ArrayView<RCP<CommRequest<Ordinal> > >& requests,
1040 const ArrayView<RCP<CommStatus<Ordinal> > >& statuses) const
1041{
1042 TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::waitAll(requests, statuses)" );
1043
1044 typedef typename ArrayView<RCP<CommRequest<Ordinal> > >::size_type size_type;
1045 const size_type count = requests.size();
1046
1047 TEUCHOS_TEST_FOR_EXCEPTION(count != statuses.size(),
1048 std::invalid_argument, "Teuchos::MpiComm::waitAll: requests.size() = "
1049 << count << " != statuses.size() = " << statuses.size() << ".");
1050
1051 Array<MPI_Status> rawMpiStatuses (count);
1052 waitAllImpl<Ordinal> (requests, rawMpiStatuses());
1053
1054 // Repackage the raw MPI_Status structs into the wrappers.
1055 for (size_type i = 0; i < count; ++i) {
1056 statuses[i] = mpiCommStatus<Ordinal> (rawMpiStatuses[i]);
1057 }
1058}
1059
1060
1061template<typename Ordinal>
1062RCP<CommStatus<Ordinal> >
1063MpiComm<Ordinal>::wait (const Ptr<RCP<CommRequest<Ordinal> > >& request) const
1064{
1065 TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::wait(...)" );
1066
1067 if (is_null (*request)) {
1068 return null; // Nothing to wait on ...
1069 }
1070 else {
1071 RCP<CommStatus<Ordinal> > status = (*request)->wait ();
1072 // mfh 22 Oct 2012: The unit tests expect waiting on the
1073 // CommRequest to invalidate it by setting it to null.
1074 *request = null;
1075 return status;
1076 }
1077}
1078
1079template<typename Ordinal>
1080RCP< Comm<Ordinal> >
1081MpiComm<Ordinal>::duplicate() const
1082{
1083 MPI_Comm origRawComm = *rawMpiComm_;
1084 MPI_Comm newRawComm = MPI_COMM_NULL;
1085 const int err = MPI_Comm_dup (origRawComm, &newRawComm);
1086 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error, "Teuchos"
1087 "::MpiComm::duplicate: MPI_Comm_dup failed with the following error: "
1088 << mpiErrorCodeToString (err));
1089
1090 // Wrap the raw communicator, and pass the (const) wrapped
1091 // communicator to MpiComm's constructor. We created the raw comm,
1092 // so we have to supply a function that frees it after use.
1093 RCP<OpaqueWrapper<MPI_Comm> > wrapped =
1094 opaqueWrapper<MPI_Comm> (newRawComm, details::safeCommFree);
1095 // Since newComm's raw MPI_Comm is the result of an MPI_Comm_dup,
1096 // its messages cannot collide with those of any other MpiComm.
1097 // This means we can assign its tag without an MPI_Bcast.
1098 RCP<MpiComm<Ordinal> > newComm =
1099 rcp (new MpiComm<Ordinal> (wrapped.getConst (), minTag_));
1100 return rcp_implicit_cast<Comm<Ordinal> > (newComm);
1101}
1102
1103
1104template<typename Ordinal>
1105RCP< Comm<Ordinal> >
1106MpiComm<Ordinal>::split(const int color, const int key) const
1107{
1108 MPI_Comm newComm;
1109 const int splitReturn =
1110 MPI_Comm_split (*rawMpiComm_,
1111 color < 0 ? MPI_UNDEFINED : color,
1112 key,
1113 &newComm);
1115 splitReturn != MPI_SUCCESS,
1116 std::logic_error,
1117 "Teuchos::MpiComm::split: Failed to create communicator with color "
1118 << color << "and key " << key << ". MPI_Comm_split failed with error \""
1119 << mpiErrorCodeToString (splitReturn) << "\".");
1120 if (newComm == MPI_COMM_NULL) {
1121 return RCP< Comm<Ordinal> >();
1122 } else {
1123 RCP<const OpaqueWrapper<MPI_Comm> > wrapped =
1124 opaqueWrapper<MPI_Comm> (newComm, details::safeCommFree);
1125 // Since newComm's raw MPI_Comm is the result of an
1126 // MPI_Comm_split, its messages cannot collide with those of any
1127 // other MpiComm. This means we can assign its tag without an
1128 // MPI_Bcast.
1129 return rcp (new MpiComm<Ordinal> (wrapped, minTag_));
1130 }
1131}
1132
1133
1134template<typename Ordinal>
1135RCP< Comm<Ordinal> >
1136MpiComm<Ordinal>::createSubcommunicator(const ArrayView<const int> &ranks) const
1137{
1138 int err = MPI_SUCCESS; // For error codes returned by MPI functions
1139
1140 // Get the group that this communicator is in.
1141 MPI_Group thisGroup;
1142 err = MPI_Comm_group (*rawMpiComm_, &thisGroup);
1143 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::logic_error,
1144 "Failed to obtain the current communicator's group. "
1145 "MPI_Comm_group failed with error \""
1146 << mpiErrorCodeToString (err) << "\".");
1147
1148 // Create a new group with the specified members.
1149 MPI_Group newGroup;
1150 // It's rude to cast away const, but MPI functions demand it.
1151 //
1152 // NOTE (mfh 14 Aug 2012) Please don't ask for &ranks[0] unless you
1153 // know that ranks.size() > 0. That's why I'm using getRawPtr().
1154 err = MPI_Group_incl (thisGroup, ranks.size(),
1155 const_cast<int*> (ranks.getRawPtr ()), &newGroup);
1156 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::logic_error,
1157 "Failed to create subgroup. MPI_Group_incl failed with error \""
1158 << mpiErrorCodeToString (err) << "\".");
1159
1160 // Create a new communicator from the new group.
1161 MPI_Comm newComm;
1162 try {
1163 err = MPI_Comm_create (*rawMpiComm_, newGroup, &newComm);
1164 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::logic_error,
1165 "Failed to create subcommunicator. MPI_Comm_create failed with error \""
1166 << mpiErrorCodeToString (err) << "\".");
1167 } catch (...) {
1168 // Attempt to free the new group before rethrowing. If
1169 // successful, this will prevent a memory leak due to the "lost"
1170 // group that was allocated successfully above. Since we're
1171 // throwing std::logic_error anyway, we can only promise
1172 // best-effort recovery; thus, we don't check the error code.
1173 (void) MPI_Group_free (&newGroup);
1174 (void) MPI_Group_free (&thisGroup);
1175 throw;
1176 }
1177
1178 // We don't need the group any more, so free it.
1179 err = MPI_Group_free (&newGroup);
1180 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::logic_error,
1181 "Failed to free subgroup. MPI_Group_free failed with error \""
1182 << mpiErrorCodeToString (err) << "\".");
1183 err = MPI_Group_free (&thisGroup);
1184 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::logic_error,
1185 "Failed to free subgroup. MPI_Group_free failed with error \""
1186 << mpiErrorCodeToString (err) << "\".");
1187
1188 if (newComm == MPI_COMM_NULL) {
1189 return RCP<Comm<Ordinal> > ();
1190 } else {
1191 using Teuchos::details::safeCommFree;
1192 typedef OpaqueWrapper<MPI_Comm> ow_type;
1193 RCP<const ow_type> wrapper =
1194 rcp_implicit_cast<const ow_type> (opaqueWrapper (newComm, safeCommFree));
1195 // Since newComm's raw MPI_Comm is the result of an
1196 // MPI_Comm_create, its messages cannot collide with those of any
1197 // other MpiComm. This means we can assign its tag without an
1198 // MPI_Bcast.
1199 return rcp (new MpiComm<Ordinal> (wrapper, minTag_));
1200 }
1201}
1202
1203
1204// Overridden from Describable
1205
1206
1207template<typename Ordinal>
1208std::string MpiComm<Ordinal>::description() const
1209{
1210 std::ostringstream oss;
1211 oss
1212 << typeName(*this)
1213 << "{"
1214 << "size="<<size_
1215 << ",rank="<<rank_
1216 << ",rawMpiComm="<<static_cast<MPI_Comm>(*rawMpiComm_)
1217 <<"}";
1218 return oss.str();
1219}
1220
1221
1222#ifdef TEUCHOS_MPI_COMM_DUMP
1223template<typename Ordinal>
1224bool MpiComm<Ordinal>::show_dump = false;
1225#endif
1226
1227
1228// private
1229
1230
1231template<typename Ordinal>
1232void MpiComm<Ordinal>::assertRank(const int rank, const std::string &rankName) const
1233{
1235 ! ( 0 <= rank && rank < size_ ), std::logic_error
1236 ,"Error, "<<rankName<<" = " << rank << " is not < 0 or is not"
1237 " in the range [0,"<<size_-1<<"]!"
1238 );
1239}
1240
1241
1242} // namespace Teuchos
1243
1244
1245template<typename Ordinal>
1247Teuchos::createMpiComm(
1248 const RCP<const OpaqueWrapper<MPI_Comm> > &rawMpiComm
1249 )
1250{
1251 if( rawMpiComm.get()!=NULL && *rawMpiComm != MPI_COMM_NULL )
1252 return rcp(new MpiComm<Ordinal>(rawMpiComm));
1253 return Teuchos::null;
1254}
1255
1256
1257template<typename Ordinal>
1259Teuchos::createMpiComm(
1260 const RCP<const OpaqueWrapper<MPI_Comm> > &rawMpiComm,
1261 const int defaultTag
1262 )
1263{
1264 if( rawMpiComm.get()!=NULL && *rawMpiComm != MPI_COMM_NULL )
1265 return rcp(new MpiComm<Ordinal>(rawMpiComm, defaultTag));
1266 return Teuchos::null;
1267}
1268
1269
1270template<typename Ordinal>
1271MPI_Comm
1272Teuchos::getRawMpiComm(const Comm<Ordinal> &comm)
1273{
1274 return *(
1275 dyn_cast<const MpiComm<Ordinal> >(comm).getRawMpiComm()
1276 );
1277}
1278
1279
1280#endif // HAVE_TEUCHOS_MPI
1281#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.