Teuchos - Trilinos Tools Package  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Teuchos_DefaultMpiComm.hpp
Go to the documentation of this file.
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_HPP
11 #define TEUCHOS_MPI_COMM_HPP
12 
17 
18 #include <Teuchos_ConfigDefs.hpp>
19 
20 // If MPI is not enabled, disable the contents of this file.
21 #ifdef HAVE_TEUCHOS_MPI
22 
23 #include "Teuchos_Comm.hpp"
24 #include "Teuchos_CommUtilities.hpp"
26 #include "Teuchos_OpaqueWrapper.hpp"
28 #include "Teuchos_SerializationTraitsHelpers.hpp"
29 #include "Teuchos_Workspace.hpp"
31 #include "Teuchos_as.hpp"
32 #include "Teuchos_Assert.hpp"
33 #include <mpi.h>
34 #include <iterator>
35 
36 // This must be defined globally for the whole program!
37 //#define TEUCHOS_MPI_COMM_DUMP
38 
39 #ifdef TEUCHOS_MPI_COMM_DUMP
40 # include "Teuchos_VerboseObject.hpp"
41 #endif
42 
43 namespace Teuchos {
44 
46 TEUCHOSCOMM_LIB_DLL_EXPORT std::string
47 mpiErrorCodeToString (const int err);
48 
49 namespace details {
63  TEUCHOSCOMM_LIB_DLL_EXPORT void safeCommFree (MPI_Comm* comm);
64 
69  TEUCHOSCOMM_LIB_DLL_EXPORT int setCommErrhandler (MPI_Comm comm, MPI_Errhandler handler);
70 
71 } // namespace details
72 
73 #ifdef TEUCHOS_MPI_COMM_DUMP
74 template<typename Ordinal, typename T>
75 void dumpBuffer(
76  const std::string &funcName, const std::string &buffName
77  ,const Ordinal bytes, const T buff[]
78  )
79 {
82  Teuchos::OSTab tab(out);
83  *out
84  << "\n" << funcName << "::" << buffName << ":\n";
85  tab.incrTab();
86  for( Ordinal i = 0; i < bytes; ++i ) {
87  *out << buffName << "[" << i << "] = '" << buff[i] << "'\n";
88  }
89  *out << "\n";
90 }
91 #endif // TEUCHOS_MPI_COMM_DUMP
92 
104 template<class OrdinalType>
105 class MpiCommStatus : public CommStatus<OrdinalType> {
106 public:
107  MpiCommStatus (MPI_Status status) : status_ (status) {}
108 
110  virtual ~MpiCommStatus() {}
111 
113  OrdinalType getSourceRank () { return status_.MPI_SOURCE; }
114 
116  OrdinalType getTag () { return status_.MPI_TAG; }
117 
119  OrdinalType getError () { return status_.MPI_ERROR; }
120 
121 private:
123  MpiCommStatus ();
124 
126  MPI_Status status_;
127 };
128 
132 template<class OrdinalType>
133 inline RCP<MpiCommStatus<OrdinalType> >
134 mpiCommStatus (MPI_Status rawMpiStatus)
135 {
136  return rcp (new MpiCommStatus<OrdinalType> (rawMpiStatus));
137 }
138 
154 template<class OrdinalType>
155 class MpiCommRequestBase : public CommRequest<OrdinalType> {
156 public:
158  MpiCommRequestBase () :
159  rawMpiRequest_ (MPI_REQUEST_NULL)
160  {}
161 
163  MpiCommRequestBase (MPI_Request rawMpiRequest) :
164  rawMpiRequest_ (rawMpiRequest)
165  {}
166 
174  MPI_Request releaseRawMpiRequest()
175  {
176  MPI_Request tmp_rawMpiRequest = rawMpiRequest_;
177  rawMpiRequest_ = MPI_REQUEST_NULL;
178  return tmp_rawMpiRequest;
179  }
180 
182  bool isNull() const {
183  return rawMpiRequest_ == MPI_REQUEST_NULL;
184  }
185 
186  bool isReady() {
187  MPI_Status rawMpiStatus;
188  int flag = 0;
189 
190  MPI_Test(&rawMpiRequest_, &flag, &rawMpiStatus);
191 
192  return (flag != 0);
193  }
194 
200  RCP<CommStatus<OrdinalType> > wait () {
201  MPI_Status rawMpiStatus;
202  // Whether this function satisfies the strong exception guarantee
203  // depends on whether MPI_Wait modifies its input request on error.
204  const int err = MPI_Wait (&rawMpiRequest_, &rawMpiStatus);
206  err != MPI_SUCCESS, std::runtime_error,
207  "Teuchos: MPI_Wait() failed with error \""
208  << mpiErrorCodeToString (err));
209  // MPI_Wait sets the MPI_Request to MPI_REQUEST_NULL on success.
210  return mpiCommStatus<OrdinalType> (rawMpiStatus);
211  }
212 
217  RCP<CommStatus<OrdinalType> > cancel () {
218  if (rawMpiRequest_ == MPI_REQUEST_NULL) {
219  return null;
220  }
221  else {
222  int err = MPI_Cancel (&rawMpiRequest_);
224  err != MPI_SUCCESS, std::runtime_error,
225  "Teuchos: MPI_Cancel failed with the following error: "
226  << mpiErrorCodeToString (err));
227 
228  // Wait on the request. If successful, MPI_Wait will set the
229  // MPI_Request to MPI_REQUEST_NULL. The returned status may
230  // still be useful; for example, one may call MPI_Test_cancelled
231  // to test an MPI_Status from a nonblocking send.
232  MPI_Status status;
233  err = MPI_Wait (&rawMpiRequest_, &status);
234  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
235  "Teuchos::MpiCommStatus::cancel: MPI_Wait failed with the following "
236  "error: " << mpiErrorCodeToString (err));
237  return mpiCommStatus<OrdinalType> (status);
238  }
239  }
240 
242  virtual ~MpiCommRequestBase () {
243  if (rawMpiRequest_ != MPI_REQUEST_NULL) {
244  // We're in a destructor, so don't throw errors. However, if
245  // MPI_Cancel fails, it's probably a bad idea to call MPI_Wait.
246  const int err = MPI_Cancel (&rawMpiRequest_);
247  if (err == MPI_SUCCESS) {
248  // The MPI_Cancel succeeded. Now wait on the request. Ignore
249  // any reported error, since we can't do anything about those
250  // in the destructor (other than kill the program). If
251  // successful, MPI_Wait will set the MPI_Request to
252  // MPI_REQUEST_NULL. We ignore the returned MPI_Status, since
253  // if the user let the request fall out of scope, she must not
254  // care about the status.
255  //
256  // mfh 21 Oct 2012: The MPI standard requires completing a
257  // canceled request by calling a function like MPI_Wait,
258  // MPI_Test, or MPI_Request_free. MPI_Wait on a canceled
259  // request behaves like a local operation (it does not
260  // communicate or block waiting for communication). One could
261  // also call MPI_Request_free instead of MPI_Wait, but
262  // MPI_Request_free is intended more for persistent requests
263  // (created with functions like MPI_Recv_init).
264  (void) MPI_Wait (&rawMpiRequest_, MPI_STATUS_IGNORE);
265  }
266  }
267  }
268 
269 private:
271  MPI_Request rawMpiRequest_;
272 };
273 
289 template<class OrdinalType>
290 class MpiCommRequest : public MpiCommRequestBase<OrdinalType> {
291 public:
293  MpiCommRequest () :
294  MpiCommRequestBase<OrdinalType> (MPI_REQUEST_NULL),
295  numBytes_ (0)
296  {}
297 
299  MpiCommRequest (MPI_Request rawMpiRequest,
300  const ArrayView<char>::size_type numBytesInMessage) :
301  MpiCommRequestBase<OrdinalType> (rawMpiRequest),
302  numBytes_ (numBytesInMessage)
303  {}
304 
310  ArrayView<char>::size_type numBytes () const {
311  return numBytes_;
312  }
313 
315  virtual ~MpiCommRequest () {}
316 
317 private:
319  ArrayView<char>::size_type numBytes_;
320 };
321 
330 template<class OrdinalType>
331 inline RCP<MpiCommRequest<OrdinalType> >
332 mpiCommRequest (MPI_Request rawMpiRequest,
333  const ArrayView<char>::size_type numBytes)
334 {
335  return rcp (new MpiCommRequest<OrdinalType> (rawMpiRequest, numBytes));
336 }
337 
353 template<typename Ordinal>
354 class MpiComm : public Comm<Ordinal> {
355 public:
357 
358 
379  explicit MpiComm (MPI_Comm rawMpiComm);
380 
395  MpiComm (const RCP<const OpaqueWrapper<MPI_Comm> >& rawMpiComm);
396 
414  MpiComm (const RCP<const OpaqueWrapper<MPI_Comm> >& rawMpiComm,
415  const int defaultTag);
416 
433  MpiComm (const MpiComm<Ordinal>& other);
434 
436  RCP<const OpaqueWrapper<MPI_Comm> > getRawMpiComm () const {
437  return rawMpiComm_;
438  }
439 
504  void setErrorHandler (const RCP<const OpaqueWrapper<MPI_Errhandler> >& errHandler);
505 
507 
509 
511  virtual int getRank() const;
512 
514  virtual int getSize() const;
515 
517  virtual void barrier() const;
518 
520  virtual void broadcast(
521  const int rootRank, const Ordinal bytes, char buffer[]
522  ) const;
523 
525  virtual void
526  gather (const Ordinal sendBytes, const char sendBuffer[],
527  const Ordinal recvBytes, char recvBuffer[],
528  const int root) const;
530  virtual void gatherAll(
531  const Ordinal sendBytes, const char sendBuffer[]
532  ,const Ordinal recvBytes, char recvBuffer[]
533  ) const;
535  virtual void reduceAll(
536  const ValueTypeReductionOp<Ordinal,char> &reductOp
537  ,const Ordinal bytes, const char sendBuffer[], char globalReducts[]
538  ) const;
540  virtual void scan(
541  const ValueTypeReductionOp<Ordinal,char> &reductOp
542  ,const Ordinal bytes, const char sendBuffer[], char scanReducts[]
543  ) const;
545  virtual void send(
546  const Ordinal bytes, const char sendBuffer[], const int destRank
547  ) const;
549  virtual void
550  send (const Ordinal bytes,
551  const char sendBuffer[],
552  const int destRank,
553  const int tag) const;
555  virtual void ssend(
556  const Ordinal bytes, const char sendBuffer[], const int destRank
557  ) const;
559  virtual void
560  ssend (const Ordinal bytes,
561  const char sendBuffer[],
562  const int destRank,
563  const int tag) const;
565  virtual int receive(
566  const int sourceRank, const Ordinal bytes, char recvBuffer[]
567  ) const;
569  virtual void readySend(
570  const ArrayView<const char> &sendBuffer,
571  const int destRank
572  ) const;
574  virtual void
575  readySend (const Ordinal bytes,
576  const char sendBuffer[],
577  const int destRank,
578  const int tag) const;
580  virtual RCP<CommRequest<Ordinal> > isend(
581  const ArrayView<const char> &sendBuffer,
582  const int destRank
583  ) const;
585  virtual RCP<CommRequest<Ordinal> >
586  isend (const ArrayView<const char> &sendBuffer,
587  const int destRank,
588  const int tag) const;
590  virtual RCP<CommRequest<Ordinal> > ireceive(
591  const ArrayView<char> &Buffer,
592  const int sourceRank
593  ) const;
595  virtual RCP<CommRequest<Ordinal> >
596  ireceive (const ArrayView<char> &Buffer,
597  const int sourceRank,
598  const int tag) const;
600  virtual void waitAll(
601  const ArrayView<RCP<CommRequest<Ordinal> > > &requests
602  ) const;
604  virtual void
605  waitAll (const ArrayView<RCP<CommRequest<Ordinal> > >& requests,
606  const ArrayView<RCP<CommStatus<Ordinal> > >& statuses) const;
608  virtual RCP<CommStatus<Ordinal> >
609  wait (const Ptr<RCP<CommRequest<Ordinal> > >& request) const;
611  virtual RCP< Comm<Ordinal> > duplicate() const;
613  virtual RCP< Comm<Ordinal> > split(const int color, const int key) const;
615  virtual RCP< Comm<Ordinal> > createSubcommunicator(
616  const ArrayView<const int>& ranks) const;
617 
619 
621 
623  std::string description() const;
624 
626 
627  // These should be private but the PGI compiler requires them be public
628 
629  static int const minTag_ = 26000; // These came from Teuchos::MpiComm???
630  static int const maxTag_ = 26099; // ""
631 
637  int getTag () const { return tag_; }
638 
639  int incrementTag() {
640  ++tag_;
641  if (tag_ == std::numeric_limits<int>::max())
642  tag_ = 0;
643  return tag_;
644  }
645 
646 private:
647 
651  void setupMembersFromComm();
652  static int tagCounter_;
653 
661  RCP<const OpaqueWrapper<MPI_Comm> > rawMpiComm_;
662 
664  int rank_;
665 
667  int size_;
668 
676  int tag_;
677 
679  RCP<const OpaqueWrapper<MPI_Errhandler> > customErrorHandler_;
680 
681  void assertRank(const int rank, const std::string &rankName) const;
682 
683  // Not defined and not to be called!
684  MpiComm();
685 
686 #ifdef TEUCHOS_MPI_COMM_DUMP
687 public:
688  static bool show_dump;
689 #endif // TEUCHOS_MPI_COMM_DUMP
690 
691 };
692 
693 
707 template<typename Ordinal>
708 RCP<MpiComm<Ordinal> >
709 createMpiComm(
710  const RCP<const OpaqueWrapper<MPI_Comm> > &rawMpiComm
711  );
712 
713 
727 template<typename Ordinal>
728 RCP<MpiComm<Ordinal> >
729 createMpiComm(
730  const RCP<const OpaqueWrapper<MPI_Comm> > &rawMpiComm,
731  const int defaultTag
732  );
733 
734 
762 template<typename Ordinal>
763 MPI_Comm
764 getRawMpiComm(const Comm<Ordinal> &comm);
765 
766 
767 // ////////////////////////
768 // Implementations
769 
770 
771 // Static members
772 
773 
774 template<typename Ordinal>
775 int MpiComm<Ordinal>::tagCounter_ = MpiComm<Ordinal>::minTag_;
776 
777 
778 // Constructors
779 
780 
781 template<typename Ordinal>
782 MpiComm<Ordinal>::
783 MpiComm (const RCP<const OpaqueWrapper<MPI_Comm> >& rawMpiComm)
784 {
786  rawMpiComm.get () == NULL, std::invalid_argument,
787  "Teuchos::MpiComm constructor: The input RCP is null.");
789  *rawMpiComm == MPI_COMM_NULL, std::invalid_argument,
790  "Teuchos::MpiComm constructor: The given MPI_Comm is MPI_COMM_NULL.");
791 
792  rawMpiComm_ = rawMpiComm;
793 
794  // mfh 09 Jul 2013: Please resist the temptation to modify the given
795  // MPI communicator's error handler here. See Bug 5943. Note that
796  // an MPI communicator's default error handler is
797  // MPI_ERRORS_ARE_FATAL, which immediately aborts on error (without
798  // returning an error code from the MPI function). Users who want
799  // MPI functions instead to return an error code if they encounter
800  // an error, should set the error handler to MPI_ERRORS_RETURN. DO
801  // NOT SET THE ERROR HANDLER HERE!!! Teuchos' MPI wrappers should
802  // always check the error code returned by an MPI function,
803  // regardless of the error handler. Users who want to set the error
804  // handler on an MpiComm may call its setErrorHandler method.
805 
806  setupMembersFromComm ();
807 }
808 
809 
810 template<typename Ordinal>
811 MpiComm<Ordinal>::
812 MpiComm (const RCP<const OpaqueWrapper<MPI_Comm> >& rawMpiComm,
813  const int defaultTag)
814 {
816  rawMpiComm.get () == NULL, std::invalid_argument,
817  "Teuchos::MpiComm constructor: The input RCP is null.");
819  *rawMpiComm == MPI_COMM_NULL, std::invalid_argument,
820  "Teuchos::MpiComm constructor: The given MPI_Comm is MPI_COMM_NULL.");
821 
822  rawMpiComm_ = rawMpiComm;
823  // Set size_ (the number of processes in the communicator).
824  int err = MPI_Comm_size (*rawMpiComm_, &size_);
825  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
826  "Teuchos::MpiComm constructor: MPI_Comm_size failed with "
827  "error \"" << mpiErrorCodeToString (err) << "\".");
828  // Set rank_ (the calling process' rank).
829  err = MPI_Comm_rank (*rawMpiComm_, &rank_);
830  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
831  "Teuchos::MpiComm constructor: MPI_Comm_rank failed with "
832  "error \"" << mpiErrorCodeToString (err) << "\".");
833  tag_ = defaultTag; // set the default message tag
834 }
835 
836 
837 template<typename Ordinal>
838 MpiComm<Ordinal>::MpiComm (MPI_Comm rawMpiComm)
839 {
840  TEUCHOS_TEST_FOR_EXCEPTION(rawMpiComm == MPI_COMM_NULL,
841  std::invalid_argument, "Teuchos::MpiComm constructor: The given MPI_Comm "
842  "is MPI_COMM_NULL.");
843  // We don't supply a "free" function here, since this version of the
844  // constructor makes the caller responsible for freeing rawMpiComm
845  // after use if necessary.
846  rawMpiComm_ = opaqueWrapper<MPI_Comm> (rawMpiComm);
847 
848  // mfh 09 Jul 2013: Please resist the temptation to modify the given
849  // MPI communicator's error handler here. See Bug 5943. Note that
850  // an MPI communicator's default error handler is
851  // MPI_ERRORS_ARE_FATAL, which immediately aborts on error (without
852  // returning an error code from the MPI function). Users who want
853  // MPI functions instead to return an error code if they encounter
854  // an error, should set the error handler to MPI_ERRORS_RETURN. DO
855  // NOT SET THE ERROR HANDLER HERE!!! Teuchos' MPI wrappers should
856  // always check the error code returned by an MPI function,
857  // regardless of the error handler. Users who want to set the error
858  // handler on an MpiComm may call its setErrorHandler method.
859 
860  setupMembersFromComm ();
861 }
862 
863 
864 template<typename Ordinal>
865 MpiComm<Ordinal>::MpiComm (const MpiComm<Ordinal>& other) :
866  rawMpiComm_ (opaqueWrapper<MPI_Comm> (MPI_COMM_NULL)) // <- This will be set below
867 {
868  // These are logic errors, since they violate MpiComm's invariants.
869  RCP<const OpaqueWrapper<MPI_Comm> > origCommPtr = other.getRawMpiComm ();
870  TEUCHOS_TEST_FOR_EXCEPTION(origCommPtr == null, std::logic_error,
871  "Teuchos::MpiComm copy constructor: "
872  "The input's getRawMpiComm() method returns null.");
873  MPI_Comm origComm = *origCommPtr;
874  TEUCHOS_TEST_FOR_EXCEPTION(origComm == MPI_COMM_NULL, std::logic_error,
875  "Teuchos::MpiComm copy constructor: "
876  "The input's raw MPI_Comm is MPI_COMM_NULL.");
877 
878  // mfh 19 Oct 2012: Don't change the behavior of MpiComm's copy
879  // constructor for now. Later, we'll switch to the version that
880  // calls MPI_Comm_dup. For now, we just copy other's handle over.
881  // Note that the new MpiComm's tag is still different than the input
882  // MpiComm's tag. See Bug 5740.
883  if (true) {
884  rawMpiComm_ = origCommPtr;
885  }
886  else { // false (not run)
887  MPI_Comm newComm;
888  const int err = MPI_Comm_dup (origComm, &newComm);
889  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
890  "Teuchos::MpiComm copy constructor: MPI_Comm_dup failed with "
891  "the following error: " << mpiErrorCodeToString (err));
892  // No side effects until after everything has succeeded.
893  rawMpiComm_ = opaqueWrapper (newComm, details::safeCommFree);
894  }
895 
896  setupMembersFromComm ();
897 }
898 
899 
900 template<typename Ordinal>
901 void MpiComm<Ordinal>::setupMembersFromComm ()
902 {
903  int err = MPI_Comm_size (*rawMpiComm_, &size_);
904  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
905  "Teuchos::MpiComm constructor: MPI_Comm_size failed with "
906  "error \"" << mpiErrorCodeToString (err) << "\".");
907  err = MPI_Comm_rank (*rawMpiComm_, &rank_);
908  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
909  "Teuchos::MpiComm constructor: MPI_Comm_rank failed with "
910  "error \"" << mpiErrorCodeToString (err) << "\".");
911 
912  // Set the default tag to make unique across all communicators
913  if (tagCounter_ > maxTag_) {
914  tagCounter_ = minTag_;
915  }
916  tag_ = tagCounter_++;
917  // Ensure that the same tag is used on all processes.
918  //
919  // FIXME (mfh 09 Jul 2013) This would not be necessary if MpiComm
920  // were just to call MPI_Comm_dup (as every library should) when
921  // given its communicator. Of course, MPI_Comm_dup may also be
922  // implemented as a collective, and may even be more expensive than
923  // a broadcast. If we do decide to use MPI_Comm_dup, we can get rid
924  // of the broadcast below, and also get rid of tag_, tagCounter_,
925  // minTag_, and maxTag_.
926  MPI_Bcast (&tag_, 1, MPI_INT, 0, *rawMpiComm_);
927 }
928 
929 
930 template<typename Ordinal>
931 void
932 MpiComm<Ordinal>::
933 setErrorHandler (const RCP<const OpaqueWrapper<MPI_Errhandler> >& errHandler)
934 {
935  if (! is_null (errHandler)) {
936  const int err = details::setCommErrhandler (*getRawMpiComm (), *errHandler);
937  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
938  "Teuchos::MpiComm: Setting the MPI_Comm's error handler failed with "
939  "error \"" << mpiErrorCodeToString (err) << "\".");
940  }
941  // Wait to set this until the end, in case setting the error handler
942  // doesn't succeed.
943  customErrorHandler_ = errHandler;
944 }
945 
946 //
947 // Overridden from Comm
948 //
949 
950 template<typename Ordinal>
951 int MpiComm<Ordinal>::getRank() const
952 {
953  return rank_;
954 }
955 
956 
957 template<typename Ordinal>
958 int MpiComm<Ordinal>::getSize() const
959 {
960  return size_;
961 }
962 
963 
964 template<typename Ordinal>
965 void MpiComm<Ordinal>::barrier() const
966 {
967  TEUCHOS_COMM_TIME_MONITOR(
968  "Teuchos::MpiComm<"<<OrdinalTraits<Ordinal>::name()<<">::barrier()"
969  );
970  const int err = MPI_Barrier (*rawMpiComm_);
971  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
972  "Teuchos::MpiComm::barrier: MPI_Barrier failed with error \""
973  << mpiErrorCodeToString (err) << "\".");
974 }
975 
976 
977 template<typename Ordinal>
978 void MpiComm<Ordinal>::broadcast(
979  const int rootRank, const Ordinal bytes, char buffer[]
980  ) const
981 {
982  TEUCHOS_COMM_TIME_MONITOR(
983  "Teuchos::MpiComm<"<<OrdinalTraits<Ordinal>::name()<<">::broadcast(...)"
984  );
985  const int err = MPI_Bcast (buffer, bytes, MPI_CHAR, rootRank, *rawMpiComm_);
986  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
987  "Teuchos::MpiComm::broadcast: MPI_Bcast failed with error \""
988  << mpiErrorCodeToString (err) << "\".");
989 }
990 
991 
992 template<typename Ordinal>
993 void MpiComm<Ordinal>::gatherAll(
994  const Ordinal sendBytes, const char sendBuffer[],
995  const Ordinal recvBytes, char recvBuffer[]
996  ) const
997 {
998  TEUCHOS_COMM_TIME_MONITOR(
999  "Teuchos::MpiComm<"<<OrdinalTraits<Ordinal>::name()<<">::gatherAll(...)"
1000  );
1001  TEUCHOS_ASSERT_EQUALITY((sendBytes*size_), recvBytes );
1002  const int err =
1003  MPI_Allgather (const_cast<char *>(sendBuffer), sendBytes, MPI_CHAR,
1004  recvBuffer, sendBytes, MPI_CHAR, *rawMpiComm_);
1005  // NOTE: 'sendBytes' is being sent above for the MPI arg recvcount (which is
1006  // very confusing in the MPI documentation) for MPI_Allgether(...).
1007 
1008  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1009  "Teuchos::MpiComm::gatherAll: MPI_Allgather failed with error \""
1010  << mpiErrorCodeToString (err) << "\".");
1011 }
1012 
1013 
1014 template<typename Ordinal>
1015 void
1016 MpiComm<Ordinal>::gather (const Ordinal sendBytes,
1017  const char sendBuffer[],
1018  const Ordinal recvBytes,
1019  char recvBuffer[],
1020  const int root) const
1021 {
1022  (void) recvBytes; // silence compile warning for "unused parameter"
1023 
1024  TEUCHOS_COMM_TIME_MONITOR(
1025  "Teuchos::MpiComm<"<<OrdinalTraits<Ordinal>::name()<<">::gather(...)"
1026  );
1027  const int err =
1028  MPI_Gather (const_cast<char *> (sendBuffer), sendBytes, MPI_CHAR,
1029  recvBuffer, sendBytes, MPI_CHAR, root, *rawMpiComm_);
1030  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1031  "Teuchos::MpiComm::gather: MPI_Gather failed with error \""
1032  << mpiErrorCodeToString (err) << "\".");
1033 }
1034 
1035 
1036 template<typename Ordinal>
1037 void
1038 MpiComm<Ordinal>::
1039 reduceAll (const ValueTypeReductionOp<Ordinal,char> &reductOp,
1040  const Ordinal bytes,
1041  const char sendBuffer[],
1042  char globalReducts[]) const
1043 {
1044  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::reduceAll(...)" );
1045  int err = MPI_SUCCESS;
1046 
1047  if (bytes == 0) return;
1048 
1049  Details::MpiReductionOp<Ordinal> opWrap (reductOp);
1050  MPI_Op op = Details::setMpiReductionOp (opWrap);
1051 
1052  // FIXME (mfh 23 Nov 2014) Ross decided to mash every type into
1053  // char. This can cause correctness issues if we're actually doing
1054  // a reduction over, say, double. Thus, he creates a custom
1055  // MPI_Datatype here that represents a contiguous block of char, so
1056  // that MPI doesn't split up the reduction type and thus do the sum
1057  // wrong. It's a hack but it works.
1058 
1059  MPI_Datatype char_block;
1060  err = MPI_Type_contiguous (bytes, MPI_CHAR, &char_block);
1062  err != MPI_SUCCESS, std::runtime_error, "Teuchos::reduceAll: "
1063  "MPI_Type_contiguous failed with error \"" << mpiErrorCodeToString (err)
1064  << "\".");
1065  err = MPI_Type_commit (&char_block);
1067  err != MPI_SUCCESS, std::runtime_error, "Teuchos::reduceAll: "
1068  "MPI_Type_commit failed with error \"" << mpiErrorCodeToString (err)
1069  << "\".");
1070 
1071  if (sendBuffer == globalReducts) {
1072  // NOTE (mfh 31 May 2017) This is only safe if the communicator is
1073  // NOT an intercomm. The usual case is that communicators are
1074  // intracomms.
1075  err = MPI_Allreduce (MPI_IN_PLACE, globalReducts, 1,
1076  char_block, op, *rawMpiComm_);
1077  }
1078  else {
1079  err = MPI_Allreduce (const_cast<char*> (sendBuffer), globalReducts, 1,
1080  char_block, op, *rawMpiComm_);
1081  }
1082  if (err != MPI_SUCCESS) {
1083  // Don't throw until we release the type resources we allocated
1084  // above. If freeing fails for some reason, let the memory leak
1085  // go; we already have more serious problems if MPI_Allreduce
1086  // doesn't work.
1087  (void) MPI_Type_free (&char_block);
1089  true, std::runtime_error, "Teuchos::reduceAll (MPI, custom op): "
1090  "MPI_Allreduce failed with error \"" << mpiErrorCodeToString (err)
1091  << "\".");
1092  }
1093  err = MPI_Type_free (&char_block);
1095  err != MPI_SUCCESS, std::runtime_error, "Teuchos::reduceAll: "
1096  "MPI_Type_free failed with error \"" << mpiErrorCodeToString (err)
1097  << "\".");
1098 }
1099 
1100 
1101 template<typename Ordinal>
1102 void MpiComm<Ordinal>::scan(
1103  const ValueTypeReductionOp<Ordinal,char> &reductOp
1104  ,const Ordinal bytes, const char sendBuffer[], char scanReducts[]
1105  ) const
1106 {
1107  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::scan(...)" );
1108 
1109  Details::MpiReductionOp<Ordinal> opWrap (reductOp);
1110  MPI_Op op = Details::setMpiReductionOp (opWrap);
1111  const int err =
1112  MPI_Scan (const_cast<char*> (sendBuffer), scanReducts, bytes, MPI_CHAR,
1113  op, *rawMpiComm_);
1114  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1115  "Teuchos::MpiComm::scan: MPI_Scan() failed with error \""
1116  << mpiErrorCodeToString (err) << "\".");
1117 }
1118 
1119 
1120 template<typename Ordinal>
1121 void
1122 MpiComm<Ordinal>::send (const Ordinal bytes,
1123  const char sendBuffer[],
1124  const int destRank) const
1125 {
1126  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::send(...)" );
1127 
1128 #ifdef TEUCHOS_MPI_COMM_DUMP
1129  if(show_dump) {
1130  dumpBuffer<Ordinal,char>(
1131  "Teuchos::MpiComm<Ordinal>::send(...)"
1132  ,"sendBuffer", bytes, sendBuffer
1133  );
1134  }
1135 #endif // TEUCHOS_MPI_COMM_DUMP
1136 
1137  const int err = MPI_Send (const_cast<char*>(sendBuffer), bytes, MPI_CHAR,
1138  destRank, tag_, *rawMpiComm_);
1139  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1140  "Teuchos::MpiComm::send: MPI_Send() failed with error \""
1141  << mpiErrorCodeToString (err) << "\".");
1142 }
1143 
1144 
1145 template<typename Ordinal>
1146 void
1147 MpiComm<Ordinal>::send (const Ordinal bytes,
1148  const char sendBuffer[],
1149  const int destRank,
1150  const int tag) const
1151 {
1152  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::send(...)" );
1153  const int err = MPI_Send (const_cast<char*> (sendBuffer), bytes, MPI_CHAR,
1154  destRank, tag, *rawMpiComm_);
1155  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1156  "Teuchos::MpiComm::send: MPI_Send() failed with error \""
1157  << mpiErrorCodeToString (err) << "\".");
1158 }
1159 
1160 
1161 template<typename Ordinal>
1162 void
1163 MpiComm<Ordinal>::ssend (const Ordinal bytes,
1164  const char sendBuffer[],
1165  const int destRank) const
1166 {
1167  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::ssend(...)" );
1168 
1169 #ifdef TEUCHOS_MPI_COMM_DUMP
1170  if(show_dump) {
1171  dumpBuffer<Ordinal,char>(
1172  "Teuchos::MpiComm<Ordinal>::send(...)"
1173  ,"sendBuffer", bytes, sendBuffer
1174  );
1175  }
1176 #endif // TEUCHOS_MPI_COMM_DUMP
1177 
1178  const int err = MPI_Ssend (const_cast<char*>(sendBuffer), bytes, MPI_CHAR,
1179  destRank, tag_, *rawMpiComm_);
1180  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1181  "Teuchos::MpiComm::send: MPI_Ssend() failed with error \""
1182  << mpiErrorCodeToString (err) << "\".");
1183 }
1184 
1185 template<typename Ordinal>
1186 void
1187 MpiComm<Ordinal>::ssend (const Ordinal bytes,
1188  const char sendBuffer[],
1189  const int destRank,
1190  const int tag) const
1191 {
1192  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::ssend(...)" );
1193  const int err =
1194  MPI_Ssend (const_cast<char*>(sendBuffer), bytes, MPI_CHAR,
1195  destRank, tag, *rawMpiComm_);
1196  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1197  "Teuchos::MpiComm::send: MPI_Ssend() failed with error \""
1198  << mpiErrorCodeToString (err) << "\".");
1199 }
1200 
1201 template<typename Ordinal>
1202 void MpiComm<Ordinal>::readySend(
1203  const ArrayView<const char> &sendBuffer,
1204  const int destRank
1205  ) const
1206 {
1207  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::readySend" );
1208 
1209 #ifdef TEUCHOS_MPI_COMM_DUMP
1210  if(show_dump) {
1211  dumpBuffer<Ordinal,char>(
1212  "Teuchos::MpiComm<Ordinal>::readySend(...)"
1213  ,"sendBuffer", bytes, sendBuffer
1214  );
1215  }
1216 #endif // TEUCHOS_MPI_COMM_DUMP
1217 
1218  const int err =
1219  MPI_Rsend (const_cast<char*>(sendBuffer.getRawPtr()), static_cast<int>(sendBuffer.size()),
1220  MPI_CHAR, destRank, tag_, *rawMpiComm_);
1221  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1222  "Teuchos::MpiComm::readySend: MPI_Rsend() failed with error \""
1223  << mpiErrorCodeToString (err) << "\".");
1224 }
1225 
1226 
1227 template<typename Ordinal>
1228 void MpiComm<Ordinal>::
1229 readySend (const Ordinal bytes,
1230  const char sendBuffer[],
1231  const int destRank,
1232  const int tag) const
1233 {
1234  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::readySend" );
1235  const int err =
1236  MPI_Rsend (const_cast<char*> (sendBuffer), bytes,
1237  MPI_CHAR, destRank, tag, *rawMpiComm_);
1238  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1239  "Teuchos::MpiComm::readySend: MPI_Rsend() failed with error \""
1240  << mpiErrorCodeToString (err) << "\".");
1241 }
1242 
1243 
1244 template<typename Ordinal>
1245 int
1246 MpiComm<Ordinal>::receive (const int sourceRank,
1247  const Ordinal bytes,
1248  char recvBuffer[]) const
1249 {
1250  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::receive(...)" );
1251 
1252  // A negative source rank indicates MPI_ANY_SOURCE, namely that we
1253  // will take an incoming message from any process, as long as the
1254  // tag matches.
1255  const int theSrcRank = (sourceRank < 0) ? MPI_ANY_SOURCE : sourceRank;
1256 
1257  MPI_Status status;
1258  const int err = MPI_Recv (recvBuffer, bytes, MPI_CHAR, theSrcRank, tag_,
1259  *rawMpiComm_, &status);
1260  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1261  "Teuchos::MpiComm::receive: MPI_Recv() failed with error \""
1262  << mpiErrorCodeToString (err) << "\".");
1263 
1264 #ifdef TEUCHOS_MPI_COMM_DUMP
1265  if (show_dump) {
1266  dumpBuffer<Ordinal,char> ("Teuchos::MpiComm<Ordinal>::receive(...)",
1267  "recvBuffer", bytes, recvBuffer);
1268  }
1269 #endif // TEUCHOS_MPI_COMM_DUMP
1270 
1271  // Returning the source rank is useful in the MPI_ANY_SOURCE case.
1272  return status.MPI_SOURCE;
1273 }
1274 
1275 
1276 template<typename Ordinal>
1277 RCP<CommRequest<Ordinal> >
1278 MpiComm<Ordinal>::isend (const ArrayView<const char> &sendBuffer,
1279  const int destRank) const
1280 {
1281  using Teuchos::as;
1282  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::isend(...)" );
1283 
1284  MPI_Request rawMpiRequest = MPI_REQUEST_NULL;
1285  const int err =
1286  MPI_Isend (const_cast<char*> (sendBuffer.getRawPtr ()),
1287  as<Ordinal> (sendBuffer.size ()), MPI_CHAR,
1288  destRank, tag_, *rawMpiComm_, &rawMpiRequest);
1289  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1290  "Teuchos::MpiComm::isend: MPI_Isend() failed with error \""
1291  << mpiErrorCodeToString (err) << "\".");
1292 
1293  return mpiCommRequest<Ordinal> (rawMpiRequest, sendBuffer.size ());
1294 }
1295 
1296 
1297 template<typename Ordinal>
1298 RCP<CommRequest<Ordinal> >
1299 MpiComm<Ordinal>::
1300 isend (const ArrayView<const char> &sendBuffer,
1301  const int destRank,
1302  const int tag) const
1303 {
1304  using Teuchos::as;
1305  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::isend(...)" );
1306 
1307  MPI_Request rawMpiRequest = MPI_REQUEST_NULL;
1308  const int err =
1309  MPI_Isend (const_cast<char*> (sendBuffer.getRawPtr ()),
1310  as<Ordinal> (sendBuffer.size ()), MPI_CHAR,
1311  destRank, tag, *rawMpiComm_, &rawMpiRequest);
1312  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1313  "Teuchos::MpiComm::isend: MPI_Isend() failed with error \""
1314  << mpiErrorCodeToString (err) << "\".");
1315 
1316  return mpiCommRequest<Ordinal> (rawMpiRequest, sendBuffer.size ());
1317 }
1318 
1319 
1320 template<typename Ordinal>
1321 RCP<CommRequest<Ordinal> >
1322 MpiComm<Ordinal>::ireceive (const ArrayView<char> &recvBuffer,
1323  const int sourceRank) const
1324 {
1325  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::ireceive(...)" );
1326 
1327  // A negative source rank indicates MPI_ANY_SOURCE, namely that we
1328  // will take an incoming message from any process, as long as the
1329  // tag matches.
1330  const int theSrcRank = (sourceRank < 0) ? MPI_ANY_SOURCE : sourceRank;
1331 
1332  MPI_Request rawMpiRequest = MPI_REQUEST_NULL;
1333  const int err =
1334  MPI_Irecv (const_cast<char*>(recvBuffer.getRawPtr()), recvBuffer.size(),
1335  MPI_CHAR, theSrcRank, tag_, *rawMpiComm_, &rawMpiRequest);
1336  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1337  "Teuchos::MpiComm::ireceive: MPI_Irecv() failed with error \""
1338  << mpiErrorCodeToString (err) << "\".");
1339 
1340  return mpiCommRequest<Ordinal> (rawMpiRequest, recvBuffer.size());
1341 }
1342 
1343 template<typename Ordinal>
1344 RCP<CommRequest<Ordinal> >
1345 MpiComm<Ordinal>::ireceive (const ArrayView<char> &recvBuffer,
1346  const int sourceRank,
1347  const int tag) const
1348 {
1349  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::ireceive(...)" );
1350 
1351  // A negative source rank indicates MPI_ANY_SOURCE, namely that we
1352  // will take an incoming message from any process, as long as the
1353  // tag matches.
1354  const int theSrcRank = (sourceRank < 0) ? MPI_ANY_SOURCE : sourceRank;
1355 
1356  MPI_Request rawMpiRequest = MPI_REQUEST_NULL;
1357  const int err =
1358  MPI_Irecv (const_cast<char*> (recvBuffer.getRawPtr ()), recvBuffer.size (),
1359  MPI_CHAR, theSrcRank, tag, *rawMpiComm_, &rawMpiRequest);
1360  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1361  "Teuchos::MpiComm::ireceive: MPI_Irecv() failed with error \""
1362  << mpiErrorCodeToString (err) << "\".");
1363 
1364  return mpiCommRequest<Ordinal> (rawMpiRequest, recvBuffer.size ());
1365 }
1366 
1367 namespace {
1368  // Called by the two-argument MpiComm::waitAll() variant.
1369  template<typename Ordinal>
1370  void
1371  waitAllImpl (const ArrayView<RCP<CommRequest<Ordinal> > >& requests,
1372  const ArrayView<MPI_Status>& rawMpiStatuses)
1373  {
1374  typedef typename ArrayView<RCP<CommRequest<Ordinal> > >::size_type size_type;
1375  const size_type count = requests.size();
1376  // waitAllImpl() is not meant to be called by users, so it's a bug
1377  // for the two views to have different lengths.
1378  TEUCHOS_TEST_FOR_EXCEPTION(rawMpiStatuses.size() != count,
1379  std::logic_error, "Teuchos::MpiComm's waitAllImpl: rawMpiStatus.size() = "
1380  << rawMpiStatuses.size() << " != requests.size() = " << requests.size()
1381  << ". Please report this bug to the Tpetra developers.");
1382  if (count == 0) {
1383  return; // No requests on which to wait
1384  }
1385 
1386  // MpiComm wraps MPI and can't expose any MPI structs or opaque
1387  // objects. Thus, we have to unpack requests into a separate array.
1388  // If that's too slow, then your code should just call into MPI
1389  // directly.
1390  //
1391  // Pull out the raw MPI requests from the wrapped requests.
1392  // MPI_Waitall should not fail if a request is MPI_REQUEST_NULL, but
1393  // we keep track just to inform the user.
1394  bool someNullRequests = false;
1395  Array<MPI_Request> rawMpiRequests (count, MPI_REQUEST_NULL);
1396  for (int i = 0; i < count; ++i) {
1397  RCP<CommRequest<Ordinal> > request = requests[i];
1398  if (! is_null (request)) {
1399  RCP<MpiCommRequestBase<Ordinal> > mpiRequest =
1400  rcp_dynamic_cast<MpiCommRequestBase<Ordinal> > (request);
1401  // releaseRawMpiRequest() sets the MpiCommRequest's raw
1402  // MPI_Request to MPI_REQUEST_NULL. This makes waitAll() not
1403  // satisfy the strong exception guarantee. That's OK because
1404  // MPI_Waitall() doesn't promise that it satisfies the strong
1405  // exception guarantee, and we would rather conservatively
1406  // invalidate the handles than leave dangling requests around
1407  // and risk users trying to wait on the same request twice.
1408  rawMpiRequests[i] = mpiRequest->releaseRawMpiRequest();
1409  }
1410  else { // Null requests map to MPI_REQUEST_NULL
1411  rawMpiRequests[i] = MPI_REQUEST_NULL;
1412  someNullRequests = true;
1413  }
1414  }
1415 
1416  // This is the part where we've finally peeled off the wrapper and
1417  // we can now interact with MPI directly.
1418  //
1419  // One option in the one-argument version of waitAll() is to ignore
1420  // the statuses completely. MPI lets you pass in the named constant
1421  // MPI_STATUSES_IGNORE for the MPI_Status array output argument in
1422  // MPI_Waitall(), which would tell MPI not to bother with the
1423  // statuses. However, we want the statuses because we can use them
1424  // for detailed error diagnostics in case something goes wrong.
1425  const int err = MPI_Waitall (count, rawMpiRequests.getRawPtr(),
1426  rawMpiStatuses.getRawPtr());
1427 
1428  // In MPI_Waitall(), an error indicates that one or more requests
1429  // failed. In that case, there could be requests that completed
1430  // (their MPI_Status' error field is MPI_SUCCESS), and other
1431  // requests that have not completed yet but have not necessarily
1432  // failed (MPI_PENDING). We make no attempt here to wait on the
1433  // pending requests. It doesn't make sense for us to do so, because
1434  // in general Teuchos::Comm doesn't attempt to provide robust
1435  // recovery from failed messages.
1436  if (err != MPI_SUCCESS) {
1437  if (err == MPI_ERR_IN_STATUS) {
1438  //
1439  // When MPI_Waitall returns MPI_ERR_IN_STATUS (a standard error
1440  // class), it's telling us to check the error codes in the
1441  // returned statuses. In that case, we do so and generate a
1442  // detailed exception message.
1443  //
1444  // Figure out which of the requests failed.
1445  Array<std::pair<size_type, int> > errorLocationsAndCodes;
1446  for (size_type k = 0; k < rawMpiStatuses.size(); ++k) {
1447  const int curErr = rawMpiStatuses[k].MPI_ERROR;
1448  if (curErr != MPI_SUCCESS) {
1449  errorLocationsAndCodes.push_back (std::make_pair (k, curErr));
1450  }
1451  }
1452  const size_type numErrs = errorLocationsAndCodes.size();
1453  if (numErrs > 0) {
1454  // There was at least one error. Assemble a detailed
1455  // exception message reporting which requests failed,
1456  // their error codes, and their source
1457  std::ostringstream os;
1458  os << "Teuchos::MpiComm::waitAll: MPI_Waitall() failed with error \""
1459  << mpiErrorCodeToString (err) << "\". Of the " << count
1460  << " total request" << (count != 1 ? "s" : "") << ", " << numErrs
1461  << " failed. Here are the indices of the failed requests, and the "
1462  "error codes extracted from their returned MPI_Status objects:"
1463  << std::endl;
1464  for (size_type k = 0; k < numErrs; ++k) {
1465  const size_type errInd = errorLocationsAndCodes[k].first;
1466  os << "Request " << errInd << ": MPI_ERROR = "
1467  << mpiErrorCodeToString (rawMpiStatuses[errInd].MPI_ERROR)
1468  << std::endl;
1469  }
1470  if (someNullRequests) {
1471  os << " On input to MPI_Waitall, there was at least one MPI_"
1472  "Request that was MPI_REQUEST_NULL. MPI_Waitall should not "
1473  "normally fail in that case, but we thought we should let you know "
1474  "regardless.";
1475  }
1476  TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, os.str());
1477  }
1478  // If there were no actual errors in the returned statuses,
1479  // well, then I guess everything is OK. Just keep going.
1480  }
1481  else {
1482  std::ostringstream os;
1483  os << "Teuchos::MpiComm::waitAll: MPI_Waitall() failed with error \""
1484  << mpiErrorCodeToString (err) << "\".";
1485  if (someNullRequests) {
1486  os << " On input to MPI_Waitall, there was at least one MPI_Request "
1487  "that was MPI_REQUEST_NULL. MPI_Waitall should not normally fail in "
1488  "that case, but we thought we should let you know regardless.";
1489  }
1490  TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, os.str());
1491  }
1492  }
1493 
1494  // Invalidate the input array of requests by setting all entries
1495  // to null.
1496  std::fill (requests.begin(), requests.end(), null);
1497  }
1498 
1499 
1500 
1501  // Called by the one-argument MpiComm::waitAll() variant.
1502  template<typename Ordinal>
1503  void
1504  waitAllImpl (const ArrayView<RCP<CommRequest<Ordinal> > >& requests)
1505  {
1506  typedef typename ArrayView<RCP<CommRequest<Ordinal> > >::size_type size_type;
1507  const size_type count = requests.size ();
1508  if (count == 0) {
1509  return; // No requests on which to wait
1510  }
1511 
1512  // MpiComm wraps MPI and can't expose any MPI structs or opaque
1513  // objects. Thus, we have to unpack requests into a separate
1514  // array. If that's too slow, then your code should just call
1515  // into MPI directly.
1516  //
1517  // Pull out the raw MPI requests from the wrapped requests.
1518  // MPI_Waitall should not fail if a request is MPI_REQUEST_NULL,
1519  // but we keep track just to inform the user.
1520  bool someNullRequests = false;
1521  Array<MPI_Request> rawMpiRequests (count, MPI_REQUEST_NULL);
1522  for (int i = 0; i < count; ++i) {
1523  RCP<CommRequest<Ordinal> > request = requests[i];
1524  if (! request.is_null ()) {
1525  RCP<MpiCommRequestBase<Ordinal> > mpiRequest =
1526  rcp_dynamic_cast<MpiCommRequestBase<Ordinal> > (request);
1527  // releaseRawMpiRequest() sets the MpiCommRequest's raw
1528  // MPI_Request to MPI_REQUEST_NULL. This makes waitAll() not
1529  // satisfy the strong exception guarantee. That's OK because
1530  // MPI_Waitall() doesn't promise that it satisfies the strong
1531  // exception guarantee, and we would rather conservatively
1532  // invalidate the handles than leave dangling requests around
1533  // and risk users trying to wait on the same request twice.
1534  rawMpiRequests[i] = mpiRequest->releaseRawMpiRequest ();
1535  }
1536  else { // Null requests map to MPI_REQUEST_NULL
1537  rawMpiRequests[i] = MPI_REQUEST_NULL;
1538  someNullRequests = true;
1539  }
1540  }
1541 
1542  // This is the part where we've finally peeled off the wrapper and
1543  // we can now interact with MPI directly.
1544  //
1545  // MPI lets us pass in the named constant MPI_STATUSES_IGNORE for
1546  // the MPI_Status array output argument in MPI_Waitall(), which
1547  // tells MPI not to bother writing out the statuses.
1548  const int err = MPI_Waitall (count, rawMpiRequests.getRawPtr(),
1549  MPI_STATUSES_IGNORE);
1550 
1551  // In MPI_Waitall(), an error indicates that one or more requests
1552  // failed. In that case, there could be requests that completed
1553  // (their MPI_Status' error field is MPI_SUCCESS), and other
1554  // requests that have not completed yet but have not necessarily
1555  // failed (MPI_PENDING). We make no attempt here to wait on the
1556  // pending requests. It doesn't make sense for us to do so,
1557  // because in general Teuchos::Comm doesn't attempt to provide
1558  // robust recovery from failed messages.
1559  if (err != MPI_SUCCESS) {
1560  std::ostringstream os;
1561  os << "Teuchos::MpiComm::waitAll: MPI_Waitall() failed with error \""
1562  << mpiErrorCodeToString (err) << "\".";
1563  if (someNullRequests) {
1564  os << std::endl << "On input to MPI_Waitall, there was at least one "
1565  "MPI_Request that was MPI_REQUEST_NULL. MPI_Waitall should not "
1566  "normally fail in that case, but we thought we should let you know "
1567  "regardless.";
1568  }
1569  TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, os.str());
1570  }
1571 
1572  // Invalidate the input array of requests by setting all entries
1573  // to null. We delay this until the end, since some
1574  // implementations of CommRequest might hold the only reference to
1575  // the communication buffer, and we don't want that to go away
1576  // until we've waited on the communication operation.
1577  std::fill (requests.begin(), requests.end(), null);
1578  }
1579 
1580 } // namespace (anonymous)
1581 
1582 
1583 
1584 template<typename Ordinal>
1585 void
1586 MpiComm<Ordinal>::
1587 waitAll (const ArrayView<RCP<CommRequest<Ordinal> > >& requests) const
1588 {
1589  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::waitAll(requests)" );
1590  // Call the one-argument version of waitAllImpl, to avoid overhead
1591  // of handling statuses (which the user didn't want anyway).
1592  waitAllImpl<Ordinal> (requests);
1593 }
1594 
1595 
1596 template<typename Ordinal>
1597 void
1598 MpiComm<Ordinal>::
1599 waitAll (const ArrayView<RCP<CommRequest<Ordinal> > >& requests,
1600  const ArrayView<RCP<CommStatus<Ordinal> > >& statuses) const
1601 {
1602  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::waitAll(requests, statuses)" );
1603 
1604  typedef typename ArrayView<RCP<CommRequest<Ordinal> > >::size_type size_type;
1605  const size_type count = requests.size();
1606 
1607  TEUCHOS_TEST_FOR_EXCEPTION(count != statuses.size(),
1608  std::invalid_argument, "Teuchos::MpiComm::waitAll: requests.size() = "
1609  << count << " != statuses.size() = " << statuses.size() << ".");
1610 
1611  Array<MPI_Status> rawMpiStatuses (count);
1612  waitAllImpl<Ordinal> (requests, rawMpiStatuses());
1613 
1614  // Repackage the raw MPI_Status structs into the wrappers.
1615  for (size_type i = 0; i < count; ++i) {
1616  statuses[i] = mpiCommStatus<Ordinal> (rawMpiStatuses[i]);
1617  }
1618 }
1619 
1620 
1621 template<typename Ordinal>
1622 RCP<CommStatus<Ordinal> >
1623 MpiComm<Ordinal>::wait (const Ptr<RCP<CommRequest<Ordinal> > >& request) const
1624 {
1625  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::wait(...)" );
1626 
1627  if (is_null (*request)) {
1628  return null; // Nothing to wait on ...
1629  }
1630  else {
1631  RCP<CommStatus<Ordinal> > status = (*request)->wait ();
1632  // mfh 22 Oct 2012: The unit tests expect waiting on the
1633  // CommRequest to invalidate it by setting it to null.
1634  *request = null;
1635  return status;
1636  }
1637 }
1638 
1639 template<typename Ordinal>
1640 RCP< Comm<Ordinal> >
1641 MpiComm<Ordinal>::duplicate() const
1642 {
1643  MPI_Comm origRawComm = *rawMpiComm_;
1644  MPI_Comm newRawComm = MPI_COMM_NULL;
1645  const int err = MPI_Comm_dup (origRawComm, &newRawComm);
1646  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error, "Teuchos"
1647  "::MpiComm::duplicate: MPI_Comm_dup failed with the following error: "
1648  << mpiErrorCodeToString (err));
1649 
1650  // Wrap the raw communicator, and pass the (const) wrapped
1651  // communicator to MpiComm's constructor. We created the raw comm,
1652  // so we have to supply a function that frees it after use.
1653  RCP<OpaqueWrapper<MPI_Comm> > wrapped =
1654  opaqueWrapper<MPI_Comm> (newRawComm, details::safeCommFree);
1655  // Since newComm's raw MPI_Comm is the result of an MPI_Comm_dup,
1656  // its messages cannot collide with those of any other MpiComm.
1657  // This means we can assign its tag without an MPI_Bcast.
1658  RCP<MpiComm<Ordinal> > newComm =
1659  rcp (new MpiComm<Ordinal> (wrapped.getConst (), minTag_));
1660  return rcp_implicit_cast<Comm<Ordinal> > (newComm);
1661 }
1662 
1663 
1664 template<typename Ordinal>
1665 RCP< Comm<Ordinal> >
1666 MpiComm<Ordinal>::split(const int color, const int key) const
1667 {
1668  MPI_Comm newComm;
1669  const int splitReturn =
1670  MPI_Comm_split (*rawMpiComm_,
1671  color < 0 ? MPI_UNDEFINED : color,
1672  key,
1673  &newComm);
1675  splitReturn != MPI_SUCCESS,
1676  std::logic_error,
1677  "Teuchos::MpiComm::split: Failed to create communicator with color "
1678  << color << "and key " << key << ". MPI_Comm_split failed with error \""
1679  << mpiErrorCodeToString (splitReturn) << "\".");
1680  if (newComm == MPI_COMM_NULL) {
1681  return RCP< Comm<Ordinal> >();
1682  } else {
1683  RCP<const OpaqueWrapper<MPI_Comm> > wrapped =
1684  opaqueWrapper<MPI_Comm> (newComm, details::safeCommFree);
1685  // Since newComm's raw MPI_Comm is the result of an
1686  // MPI_Comm_split, its messages cannot collide with those of any
1687  // other MpiComm. This means we can assign its tag without an
1688  // MPI_Bcast.
1689  return rcp (new MpiComm<Ordinal> (wrapped, minTag_));
1690  }
1691 }
1692 
1693 
1694 template<typename Ordinal>
1695 RCP< Comm<Ordinal> >
1696 MpiComm<Ordinal>::createSubcommunicator(const ArrayView<const int> &ranks) const
1697 {
1698  int err = MPI_SUCCESS; // For error codes returned by MPI functions
1699 
1700  // Get the group that this communicator is in.
1701  MPI_Group thisGroup;
1702  err = MPI_Comm_group (*rawMpiComm_, &thisGroup);
1703  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::logic_error,
1704  "Failed to obtain the current communicator's group. "
1705  "MPI_Comm_group failed with error \""
1706  << mpiErrorCodeToString (err) << "\".");
1707 
1708  // Create a new group with the specified members.
1709  MPI_Group newGroup;
1710  // It's rude to cast away const, but MPI functions demand it.
1711  //
1712  // NOTE (mfh 14 Aug 2012) Please don't ask for &ranks[0] unless you
1713  // know that ranks.size() > 0. That's why I'm using getRawPtr().
1714  err = MPI_Group_incl (thisGroup, ranks.size(),
1715  const_cast<int*> (ranks.getRawPtr ()), &newGroup);
1716  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::logic_error,
1717  "Failed to create subgroup. MPI_Group_incl failed with error \""
1718  << mpiErrorCodeToString (err) << "\".");
1719 
1720  // Create a new communicator from the new group.
1721  MPI_Comm newComm;
1722  try {
1723  err = MPI_Comm_create (*rawMpiComm_, newGroup, &newComm);
1724  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::logic_error,
1725  "Failed to create subcommunicator. MPI_Comm_create failed with error \""
1726  << mpiErrorCodeToString (err) << "\".");
1727  } catch (...) {
1728  // Attempt to free the new group before rethrowing. If
1729  // successful, this will prevent a memory leak due to the "lost"
1730  // group that was allocated successfully above. Since we're
1731  // throwing std::logic_error anyway, we can only promise
1732  // best-effort recovery; thus, we don't check the error code.
1733  (void) MPI_Group_free (&newGroup);
1734  (void) MPI_Group_free (&thisGroup);
1735  throw;
1736  }
1737 
1738  // We don't need the group any more, so free it.
1739  err = MPI_Group_free (&newGroup);
1740  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::logic_error,
1741  "Failed to free subgroup. MPI_Group_free failed with error \""
1742  << mpiErrorCodeToString (err) << "\".");
1743  err = MPI_Group_free (&thisGroup);
1744  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::logic_error,
1745  "Failed to free subgroup. MPI_Group_free failed with error \""
1746  << mpiErrorCodeToString (err) << "\".");
1747 
1748  if (newComm == MPI_COMM_NULL) {
1749  return RCP<Comm<Ordinal> > ();
1750  } else {
1751  using Teuchos::details::safeCommFree;
1752  typedef OpaqueWrapper<MPI_Comm> ow_type;
1753  RCP<const ow_type> wrapper =
1754  rcp_implicit_cast<const ow_type> (opaqueWrapper (newComm, safeCommFree));
1755  // Since newComm's raw MPI_Comm is the result of an
1756  // MPI_Comm_create, its messages cannot collide with those of any
1757  // other MpiComm. This means we can assign its tag without an
1758  // MPI_Bcast.
1759  return rcp (new MpiComm<Ordinal> (wrapper, minTag_));
1760  }
1761 }
1762 
1763 
1764 // Overridden from Describable
1765 
1766 
1767 template<typename Ordinal>
1768 std::string MpiComm<Ordinal>::description() const
1769 {
1770  std::ostringstream oss;
1771  oss
1772  << typeName(*this)
1773  << "{"
1774  << "size="<<size_
1775  << ",rank="<<rank_
1776  << ",rawMpiComm="<<static_cast<MPI_Comm>(*rawMpiComm_)
1777  <<"}";
1778  return oss.str();
1779 }
1780 
1781 
1782 #ifdef TEUCHOS_MPI_COMM_DUMP
1783 template<typename Ordinal>
1784 bool MpiComm<Ordinal>::show_dump = false;
1785 #endif
1786 
1787 
1788 // private
1789 
1790 
1791 template<typename Ordinal>
1792 void MpiComm<Ordinal>::assertRank(const int rank, const std::string &rankName) const
1793 {
1795  ! ( 0 <= rank && rank < size_ ), std::logic_error
1796  ,"Error, "<<rankName<<" = " << rank << " is not < 0 or is not"
1797  " in the range [0,"<<size_-1<<"]!"
1798  );
1799 }
1800 
1801 
1802 } // namespace Teuchos
1803 
1804 
1805 template<typename Ordinal>
1807 Teuchos::createMpiComm(
1808  const RCP<const OpaqueWrapper<MPI_Comm> > &rawMpiComm
1809  )
1810 {
1811  if( rawMpiComm.get()!=NULL && *rawMpiComm != MPI_COMM_NULL )
1812  return rcp(new MpiComm<Ordinal>(rawMpiComm));
1813  return Teuchos::null;
1814 }
1815 
1816 
1817 template<typename Ordinal>
1819 Teuchos::createMpiComm(
1820  const RCP<const OpaqueWrapper<MPI_Comm> > &rawMpiComm,
1821  const int defaultTag
1822  )
1823 {
1824  if( rawMpiComm.get()!=NULL && *rawMpiComm != MPI_COMM_NULL )
1825  return rcp(new MpiComm<Ordinal>(rawMpiComm, defaultTag));
1826  return Teuchos::null;
1827 }
1828 
1829 
1830 template<typename Ordinal>
1831 MPI_Comm
1832 Teuchos::getRawMpiComm(const Comm<Ordinal> &comm)
1833 {
1834  return *(
1835  dyn_cast<const MpiComm<Ordinal> >(comm).getRawMpiComm()
1836  );
1837 }
1838 
1839 
1840 #endif // HAVE_TEUCHOS_MPI
1841 #endif // TEUCHOS_MPI_COMM_HPP
1842 
RCP< T > rcp(const boost::shared_ptr< T > &sptr)
Conversion function that takes in a boost::shared_ptr object and spits out a Teuchos::RCP object...
bool is_null(const std::shared_ptr< T > &p)
Returns true if p.get()==NULL.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Macro for throwing an exception with breakpointing to ease debugging.
T_To & dyn_cast(T_From &from)
Dynamic casting utility function meant to replace dynamic_cast&lt;T&amp;&gt; by throwing a better documented er...
Teuchos header file which uses auto-configuration information to include necessary C++ headers...
Tabbing class for helping to create formated, indented output for a basic_FancyOStream object...
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Deprecated.
static RCP< FancyOStream > getDefaultOStream()
Get the default output stream object.
void send(const Packet sendBuffer[], const Ordinal count, const int destRank, const int tag, const Comm< Ordinal > &comm)
Variant of send() that takes a tag (and restores the correct order of arguments). ...
RCP< CommRequest< Ordinal > > ireceive(const ArrayRCP< Packet > &recvBuffer, const int sourceRank, const int tag, const Comm< Ordinal > &comm)
Variant of ireceive that takes a tag argument (and restores the correct order of arguments).
Defines basic traits for the ordinal field type.
TypeTo as(const TypeFrom &t)
Convert from one value type to another.
void ssend(const Packet sendBuffer[], const Ordinal count, const int destRank, const int tag, const Comm< Ordinal > &comm)
Variant of ssend() that takes a tag (and restores the correct order of arguments).
Smart reference counting pointer class for automatic garbage collection.
Implementation detail of Teuchos&#39; MPI wrapper.
#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 ...
Defines basic traits returning the name of a type in a portable and readable way. ...
Definition of Teuchos::as, for conversions between types.
void readySend(const Packet sendBuffer[], const Ordinal count, const int destRank, const int tag, const Comm< Ordinal > &comm)
Variant of readySend() that accepts a message tag.
std::string typeName(const T &t)
Template function for returning the concrete type name of a passed-in object.