Teuchos Package Browser (Single Doxygen Collection)  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 //
4 // Teuchos: Common Tools Package
5 // Copyright (2004) Sandia Corporation
6 //
7 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
8 // license for use of this work by or on behalf of the U.S. Government.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are
12 // met:
13 //
14 // 1. Redistributions of source code must retain the above copyright
15 // notice, this list of conditions and the following disclaimer.
16 //
17 // 2. Redistributions in binary form must reproduce the above copyright
18 // notice, this list of conditions and the following disclaimer in the
19 // documentation and/or other materials provided with the distribution.
20 //
21 // 3. Neither the name of the Corporation nor the names of the
22 // contributors may be used to endorse or promote products derived from
23 // this software without specific prior written permission.
24 //
25 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 //
37 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
38 //
39 // ***********************************************************************
40 // @HEADER
41 
42 #ifndef TEUCHOS_MPI_COMM_HPP
43 #define TEUCHOS_MPI_COMM_HPP
44 
49 
50 #include <Teuchos_ConfigDefs.hpp>
51 
52 // If MPI is not enabled, disable the contents of this file.
53 #ifdef HAVE_TEUCHOS_MPI
54 
55 #include "Teuchos_Comm.hpp"
61 #include "Teuchos_Workspace.hpp"
63 #include "Teuchos_as.hpp"
64 #include "Teuchos_Assert.hpp"
65 #include <mpi.h>
66 #include <iterator>
67 
68 // This must be defined globally for the whole program!
69 //#define TEUCHOS_MPI_COMM_DUMP
70 
71 #ifdef TEUCHOS_MPI_COMM_DUMP
72 # include "Teuchos_VerboseObject.hpp"
73 #endif
74 
75 namespace Teuchos {
76 
78 std::string
79 mpiErrorCodeToString (const int err);
80 
81 namespace details {
95  void safeCommFree (MPI_Comm* comm);
96 
101  int setCommErrhandler (MPI_Comm comm, MPI_Errhandler handler);
102 
103 } // namespace details
104 
105 #ifdef TEUCHOS_MPI_COMM_DUMP
106 template<typename Ordinal, typename T>
107 void dumpBuffer(
108  const std::string &funcName, const std::string &buffName
109  ,const Ordinal bytes, const T buff[]
110  )
111 {
114  Teuchos::OSTab tab(out);
115  *out
116  << "\n" << funcName << "::" << buffName << ":\n";
117  tab.incrTab();
118  for( Ordinal i = 0; i < bytes; ++i ) {
119  *out << buffName << "[" << i << "] = '" << buff[i] << "'\n";
120  }
121  *out << "\n";
122 }
123 #endif // TEUCHOS_MPI_COMM_DUMP
124 
136 template<class OrdinalType>
137 class MpiCommStatus : public CommStatus<OrdinalType> {
138 public:
139  MpiCommStatus (MPI_Status status) : status_ (status) {}
140 
142  virtual ~MpiCommStatus() {}
143 
145  OrdinalType getSourceRank () { return status_.MPI_SOURCE; }
146 
148  OrdinalType getTag () { return status_.MPI_TAG; }
149 
151  OrdinalType getError () { return status_.MPI_ERROR; }
152 
153 private:
155  MpiCommStatus ();
156 
158  MPI_Status status_;
159 };
160 
164 template<class OrdinalType>
165 inline RCP<MpiCommStatus<OrdinalType> >
166 mpiCommStatus (MPI_Status rawMpiStatus)
167 {
168  return rcp (new MpiCommStatus<OrdinalType> (rawMpiStatus));
169 }
170 
186 template<class OrdinalType>
187 class MpiCommRequestBase : public CommRequest<OrdinalType> {
188 public:
190  MpiCommRequestBase () :
191  rawMpiRequest_ (MPI_REQUEST_NULL)
192  {}
193 
195  MpiCommRequestBase (MPI_Request rawMpiRequest) :
196  rawMpiRequest_ (rawMpiRequest)
197  {}
198 
206  MPI_Request releaseRawMpiRequest()
207  {
208  MPI_Request tmp_rawMpiRequest = rawMpiRequest_;
209  rawMpiRequest_ = MPI_REQUEST_NULL;
210  return tmp_rawMpiRequest;
211  }
212 
214  bool isNull() const {
215  return rawMpiRequest_ == MPI_REQUEST_NULL;
216  }
217 
223  RCP<CommStatus<OrdinalType> > wait () {
224  MPI_Status rawMpiStatus;
225  // Whether this function satisfies the strong exception guarantee
226  // depends on whether MPI_Wait modifies its input request on error.
227  const int err = MPI_Wait (&rawMpiRequest_, &rawMpiStatus);
229  err != MPI_SUCCESS, std::runtime_error,
230  "Teuchos: MPI_Wait() failed with error \""
231  << mpiErrorCodeToString (err));
232  // MPI_Wait sets the MPI_Request to MPI_REQUEST_NULL on success.
233  return mpiCommStatus<OrdinalType> (rawMpiStatus);
234  }
235 
240  RCP<CommStatus<OrdinalType> > cancel () {
241  if (rawMpiRequest_ == MPI_REQUEST_NULL) {
242  return null;
243  }
244  else {
245  int err = MPI_Cancel (&rawMpiRequest_);
247  err != MPI_SUCCESS, std::runtime_error,
248  "Teuchos: MPI_Cancel failed with the following error: "
249  << mpiErrorCodeToString (err));
250 
251  // Wait on the request. If successful, MPI_Wait will set the
252  // MPI_Request to MPI_REQUEST_NULL. The returned status may
253  // still be useful; for example, one may call MPI_Test_cancelled
254  // to test an MPI_Status from a nonblocking send.
255  MPI_Status status;
256  err = MPI_Wait (&rawMpiRequest_, &status);
257  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
258  "Teuchos::MpiCommStatus::cancel: MPI_Wait failed with the following "
259  "error: " << mpiErrorCodeToString (err));
260  return mpiCommStatus<OrdinalType> (status);
261  }
262  }
263 
265  virtual ~MpiCommRequestBase () {
266  if (rawMpiRequest_ != MPI_REQUEST_NULL) {
267  // We're in a destructor, so don't throw errors. However, if
268  // MPI_Cancel fails, it's probably a bad idea to call MPI_Wait.
269  const int err = MPI_Cancel (&rawMpiRequest_);
270  if (err == MPI_SUCCESS) {
271  // The MPI_Cancel succeeded. Now wait on the request. Ignore
272  // any reported error, since we can't do anything about those
273  // in the destructor (other than kill the program). If
274  // successful, MPI_Wait will set the MPI_Request to
275  // MPI_REQUEST_NULL. We ignore the returned MPI_Status, since
276  // if the user let the request fall out of scope, she must not
277  // care about the status.
278  //
279  // mfh 21 Oct 2012: The MPI standard requires completing a
280  // canceled request by calling a function like MPI_Wait,
281  // MPI_Test, or MPI_Request_free. MPI_Wait on a canceled
282  // request behaves like a local operation (it does not
283  // communicate or block waiting for communication). One could
284  // also call MPI_Request_free instead of MPI_Wait, but
285  // MPI_Request_free is intended more for persistent requests
286  // (created with functions like MPI_Recv_init).
287  (void) MPI_Wait (&rawMpiRequest_, MPI_STATUS_IGNORE);
288  }
289  }
290  }
291 
292 private:
294  MPI_Request rawMpiRequest_;
295 };
296 
312 template<class OrdinalType>
313 class MpiCommRequest : public MpiCommRequestBase<OrdinalType> {
314 public:
316  MpiCommRequest () :
317  MpiCommRequestBase<OrdinalType> (MPI_REQUEST_NULL),
318  numBytes_ (0)
319  {}
320 
322  MpiCommRequest (MPI_Request rawMpiRequest,
323  const ArrayView<char>::size_type numBytesInMessage) :
324  MpiCommRequestBase<OrdinalType> (rawMpiRequest),
325  numBytes_ (numBytesInMessage)
326  {}
327 
333  ArrayView<char>::size_type numBytes () const {
334  return numBytes_;
335  }
336 
338  virtual ~MpiCommRequest () {}
339 
340 private:
342  ArrayView<char>::size_type numBytes_;
343 };
344 
353 template<class OrdinalType>
354 inline RCP<MpiCommRequest<OrdinalType> >
355 mpiCommRequest (MPI_Request rawMpiRequest,
356  const ArrayView<char>::size_type numBytes)
357 {
358  return rcp (new MpiCommRequest<OrdinalType> (rawMpiRequest, numBytes));
359 }
360 
376 template<typename Ordinal>
377 class MpiComm : public Comm<Ordinal> {
378 public:
380 
381 
402  explicit MpiComm (MPI_Comm rawMpiComm);
403 
418  MpiComm (const RCP<const OpaqueWrapper<MPI_Comm> >& rawMpiComm);
419 
437  MpiComm (const RCP<const OpaqueWrapper<MPI_Comm> >& rawMpiComm,
438  const int defaultTag);
439 
456  MpiComm (const MpiComm<Ordinal>& other);
457 
459  RCP<const OpaqueWrapper<MPI_Comm> > getRawMpiComm () const {
460  return rawMpiComm_;
461  }
462 
527  void setErrorHandler (const RCP<const OpaqueWrapper<MPI_Errhandler> >& errHandler);
528 
530 
532 
534  virtual int getRank() const;
535 
537  virtual int getSize() const;
538 
540  virtual void barrier() const;
541 
543  virtual void broadcast(
544  const int rootRank, const Ordinal bytes, char buffer[]
545  ) const;
546 
548  virtual void
549  gather (const Ordinal sendBytes, const char sendBuffer[],
550  const Ordinal recvBytes, char recvBuffer[],
551  const int root) const;
553  virtual void gatherAll(
554  const Ordinal sendBytes, const char sendBuffer[]
555  ,const Ordinal recvBytes, char recvBuffer[]
556  ) const;
558  virtual void reduceAll(
559  const ValueTypeReductionOp<Ordinal,char> &reductOp
560  ,const Ordinal bytes, const char sendBuffer[], char globalReducts[]
561  ) const;
563  virtual void scan(
564  const ValueTypeReductionOp<Ordinal,char> &reductOp
565  ,const Ordinal bytes, const char sendBuffer[], char scanReducts[]
566  ) const;
568  virtual void send(
569  const Ordinal bytes, const char sendBuffer[], const int destRank
570  ) const;
572  virtual void
573  send (const Ordinal bytes,
574  const char sendBuffer[],
575  const int destRank,
576  const int tag) const;
578  virtual void ssend(
579  const Ordinal bytes, const char sendBuffer[], const int destRank
580  ) const;
582  virtual void
583  ssend (const Ordinal bytes,
584  const char sendBuffer[],
585  const int destRank,
586  const int tag) const;
588  virtual int receive(
589  const int sourceRank, const Ordinal bytes, char recvBuffer[]
590  ) const;
592  virtual void readySend(
593  const ArrayView<const char> &sendBuffer,
594  const int destRank
595  ) const;
597  virtual void
598  readySend (const Ordinal bytes,
599  const char sendBuffer[],
600  const int destRank,
601  const int tag) const;
603  virtual RCP<CommRequest<Ordinal> > isend(
604  const ArrayView<const char> &sendBuffer,
605  const int destRank
606  ) const;
608  virtual RCP<CommRequest<Ordinal> >
609  isend (const ArrayView<const char> &sendBuffer,
610  const int destRank,
611  const int tag) const;
613  virtual RCP<CommRequest<Ordinal> > ireceive(
614  const ArrayView<char> &Buffer,
615  const int sourceRank
616  ) const;
618  virtual RCP<CommRequest<Ordinal> >
619  ireceive (const ArrayView<char> &Buffer,
620  const int sourceRank,
621  const int tag) const;
623  virtual void waitAll(
624  const ArrayView<RCP<CommRequest<Ordinal> > > &requests
625  ) const;
627  virtual void
628  waitAll (const ArrayView<RCP<CommRequest<Ordinal> > >& requests,
629  const ArrayView<RCP<CommStatus<Ordinal> > >& statuses) const;
631  virtual RCP<CommStatus<Ordinal> >
632  wait (const Ptr<RCP<CommRequest<Ordinal> > >& request) const;
634  virtual RCP< Comm<Ordinal> > duplicate() const;
636  virtual RCP< Comm<Ordinal> > split(const int color, const int key) const;
638  virtual RCP< Comm<Ordinal> > createSubcommunicator(
639  const ArrayView<const int>& ranks) const;
640 
642 
644 
646  std::string description() const;
647 
649 
650  // These should be private but the PGI compiler requires them be public
651 
652  static int const minTag_ = 26000; // These came from Teuchos::MpiComm???
653  static int const maxTag_ = 26099; // ""
654 
660  int getTag () const { return tag_; }
661 
662 private:
663 
667  void setupMembersFromComm();
668  static int tagCounter_;
669 
677  RCP<const OpaqueWrapper<MPI_Comm> > rawMpiComm_;
678 
680  int rank_;
681 
683  int size_;
684 
692  int tag_;
693 
695  RCP<const OpaqueWrapper<MPI_Errhandler> > customErrorHandler_;
696 
697  void assertRank(const int rank, const std::string &rankName) const;
698 
699  // Not defined and not to be called!
700  MpiComm();
701 
702 #ifdef TEUCHOS_MPI_COMM_DUMP
703 public:
704  static bool show_dump;
705 #endif // TEUCHOS_MPI_COMM_DUMP
706 
707 };
708 
709 
723 template<typename Ordinal>
724 RCP<MpiComm<Ordinal> >
725 createMpiComm(
726  const RCP<const OpaqueWrapper<MPI_Comm> > &rawMpiComm
727  );
728 
729 
757 template<typename Ordinal>
758 MPI_Comm
759 getRawMpiComm(const Comm<Ordinal> &comm);
760 
761 
762 // ////////////////////////
763 // Implementations
764 
765 
766 // Static members
767 
768 
769 template<typename Ordinal>
770 int MpiComm<Ordinal>::tagCounter_ = MpiComm<Ordinal>::minTag_;
771 
772 
773 // Constructors
774 
775 
776 template<typename Ordinal>
777 MpiComm<Ordinal>::
778 MpiComm (const RCP<const OpaqueWrapper<MPI_Comm> >& rawMpiComm)
779 {
781  rawMpiComm.get () == NULL, std::invalid_argument,
782  "Teuchos::MpiComm constructor: The input RCP is null.");
784  *rawMpiComm == MPI_COMM_NULL, std::invalid_argument,
785  "Teuchos::MpiComm constructor: The given MPI_Comm is MPI_COMM_NULL.");
786 
787  rawMpiComm_ = rawMpiComm;
788 
789  // mfh 09 Jul 2013: Please resist the temptation to modify the given
790  // MPI communicator's error handler here. See Bug 5943. Note that
791  // an MPI communicator's default error handler is
792  // MPI_ERRORS_ARE_FATAL, which immediately aborts on error (without
793  // returning an error code from the MPI function). Users who want
794  // MPI functions instead to return an error code if they encounter
795  // an error, should set the error handler to MPI_ERRORS_RETURN. DO
796  // NOT SET THE ERROR HANDLER HERE!!! Teuchos' MPI wrappers should
797  // always check the error code returned by an MPI function,
798  // regardless of the error handler. Users who want to set the error
799  // handler on an MpiComm may call its setErrorHandler method.
800 
801  setupMembersFromComm ();
802 }
803 
804 
805 template<typename Ordinal>
806 MpiComm<Ordinal>::
807 MpiComm (const RCP<const OpaqueWrapper<MPI_Comm> >& rawMpiComm,
808  const int defaultTag)
809 {
811  rawMpiComm.get () == NULL, std::invalid_argument,
812  "Teuchos::MpiComm constructor: The input RCP is null.");
814  *rawMpiComm == MPI_COMM_NULL, std::invalid_argument,
815  "Teuchos::MpiComm constructor: The given MPI_Comm is MPI_COMM_NULL.");
816 
817  rawMpiComm_ = rawMpiComm;
818  // Set size_ (the number of processes in the communicator).
819  int err = MPI_Comm_size (*rawMpiComm_, &size_);
820  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
821  "Teuchos::MpiComm constructor: MPI_Comm_size failed with "
822  "error \"" << mpiErrorCodeToString (err) << "\".");
823  // Set rank_ (the calling process' rank).
824  err = MPI_Comm_rank (*rawMpiComm_, &rank_);
825  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
826  "Teuchos::MpiComm constructor: MPI_Comm_rank failed with "
827  "error \"" << mpiErrorCodeToString (err) << "\".");
828  tag_ = defaultTag; // set the default message tag
829 }
830 
831 
832 template<typename Ordinal>
833 MpiComm<Ordinal>::MpiComm (MPI_Comm rawMpiComm)
834 {
835  TEUCHOS_TEST_FOR_EXCEPTION(rawMpiComm == MPI_COMM_NULL,
836  std::invalid_argument, "Teuchos::MpiComm constructor: The given MPI_Comm "
837  "is MPI_COMM_NULL.");
838  // We don't supply a "free" function here, since this version of the
839  // constructor makes the caller responsible for freeing rawMpiComm
840  // after use if necessary.
841  rawMpiComm_ = opaqueWrapper<MPI_Comm> (rawMpiComm);
842 
843  // mfh 09 Jul 2013: Please resist the temptation to modify the given
844  // MPI communicator's error handler here. See Bug 5943. Note that
845  // an MPI communicator's default error handler is
846  // MPI_ERRORS_ARE_FATAL, which immediately aborts on error (without
847  // returning an error code from the MPI function). Users who want
848  // MPI functions instead to return an error code if they encounter
849  // an error, should set the error handler to MPI_ERRORS_RETURN. DO
850  // NOT SET THE ERROR HANDLER HERE!!! Teuchos' MPI wrappers should
851  // always check the error code returned by an MPI function,
852  // regardless of the error handler. Users who want to set the error
853  // handler on an MpiComm may call its setErrorHandler method.
854 
855  setupMembersFromComm ();
856 }
857 
858 
859 template<typename Ordinal>
860 MpiComm<Ordinal>::MpiComm (const MpiComm<Ordinal>& other) :
861  rawMpiComm_ (opaqueWrapper<MPI_Comm> (MPI_COMM_NULL)) // <- This will be set below
862 {
863  // These are logic errors, since they violate MpiComm's invariants.
864  RCP<const OpaqueWrapper<MPI_Comm> > origCommPtr = other.getRawMpiComm ();
865  TEUCHOS_TEST_FOR_EXCEPTION(origCommPtr == null, std::logic_error,
866  "Teuchos::MpiComm copy constructor: "
867  "The input's getRawMpiComm() method returns null.");
868  MPI_Comm origComm = *origCommPtr;
869  TEUCHOS_TEST_FOR_EXCEPTION(origComm == MPI_COMM_NULL, std::logic_error,
870  "Teuchos::MpiComm copy constructor: "
871  "The input's raw MPI_Comm is MPI_COMM_NULL.");
872 
873  // mfh 19 Oct 2012: Don't change the behavior of MpiComm's copy
874  // constructor for now. Later, we'll switch to the version that
875  // calls MPI_Comm_dup. For now, we just copy other's handle over.
876  // Note that the new MpiComm's tag is still different than the input
877  // MpiComm's tag. See Bug 5740.
878  if (true) {
879  rawMpiComm_ = origCommPtr;
880  }
881  else { // false (not run)
882  MPI_Comm newComm;
883  const int err = MPI_Comm_dup (origComm, &newComm);
884  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
885  "Teuchos::MpiComm copy constructor: MPI_Comm_dup failed with "
886  "the following error: " << mpiErrorCodeToString (err));
887  // No side effects until after everything has succeeded.
888  rawMpiComm_ = opaqueWrapper (newComm, details::safeCommFree);
889  }
890 
891  setupMembersFromComm ();
892 }
893 
894 
895 template<typename Ordinal>
896 void MpiComm<Ordinal>::setupMembersFromComm ()
897 {
898  int err = MPI_Comm_size (*rawMpiComm_, &size_);
899  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
900  "Teuchos::MpiComm constructor: MPI_Comm_size failed with "
901  "error \"" << mpiErrorCodeToString (err) << "\".");
902  err = MPI_Comm_rank (*rawMpiComm_, &rank_);
903  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
904  "Teuchos::MpiComm constructor: MPI_Comm_rank failed with "
905  "error \"" << mpiErrorCodeToString (err) << "\".");
906 
907  // Set the default tag to make unique across all communicators
908  if (tagCounter_ > maxTag_) {
909  tagCounter_ = minTag_;
910  }
911  tag_ = tagCounter_++;
912  // Ensure that the same tag is used on all processes.
913  //
914  // FIXME (mfh 09 Jul 2013) This would not be necessary if MpiComm
915  // were just to call MPI_Comm_dup (as every library should) when
916  // given its communicator. Of course, MPI_Comm_dup may also be
917  // implemented as a collective, and may even be more expensive than
918  // a broadcast. If we do decide to use MPI_Comm_dup, we can get rid
919  // of the broadcast below, and also get rid of tag_, tagCounter_,
920  // minTag_, and maxTag_.
921  MPI_Bcast (&tag_, 1, MPI_INT, 0, *rawMpiComm_);
922 }
923 
924 
925 template<typename Ordinal>
926 void
927 MpiComm<Ordinal>::
928 setErrorHandler (const RCP<const OpaqueWrapper<MPI_Errhandler> >& errHandler)
929 {
930  if (! is_null (errHandler)) {
931  const int err = details::setCommErrhandler (*getRawMpiComm (), *errHandler);
932  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
933  "Teuchos::MpiComm: Setting the MPI_Comm's error handler failed with "
934  "error \"" << mpiErrorCodeToString (err) << "\".");
935  }
936  // Wait to set this until the end, in case setting the error handler
937  // doesn't succeed.
938  customErrorHandler_ = errHandler;
939 }
940 
941 //
942 // Overridden from Comm
943 //
944 
945 template<typename Ordinal>
946 int MpiComm<Ordinal>::getRank() const
947 {
948  return rank_;
949 }
950 
951 
952 template<typename Ordinal>
953 int MpiComm<Ordinal>::getSize() const
954 {
955  return size_;
956 }
957 
958 
959 template<typename Ordinal>
960 void MpiComm<Ordinal>::barrier() const
961 {
963  "Teuchos::MpiComm<"<<OrdinalTraits<Ordinal>::name()<<">::barrier()"
964  );
965  const int err = MPI_Barrier (*rawMpiComm_);
966  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
967  "Teuchos::MpiComm::barrier: MPI_Barrier failed with error \""
968  << mpiErrorCodeToString (err) << "\".");
969 }
970 
971 
972 template<typename Ordinal>
973 void MpiComm<Ordinal>::broadcast(
974  const int rootRank, const Ordinal bytes, char buffer[]
975  ) const
976 {
978  "Teuchos::MpiComm<"<<OrdinalTraits<Ordinal>::name()<<">::broadcast(...)"
979  );
980  const int err = MPI_Bcast (buffer, bytes, MPI_CHAR, rootRank, *rawMpiComm_);
981  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
982  "Teuchos::MpiComm::broadcast: MPI_Bcast failed with error \""
983  << mpiErrorCodeToString (err) << "\".");
984 }
985 
986 
987 template<typename Ordinal>
988 void MpiComm<Ordinal>::gatherAll(
989  const Ordinal sendBytes, const char sendBuffer[],
990  const Ordinal recvBytes, char recvBuffer[]
991  ) const
992 {
994  "Teuchos::MpiComm<"<<OrdinalTraits<Ordinal>::name()<<">::gatherAll(...)"
995  );
996  TEUCHOS_ASSERT_EQUALITY((sendBytes*size_), recvBytes );
997  const int err =
998  MPI_Allgather (const_cast<char *>(sendBuffer), sendBytes, MPI_CHAR,
999  recvBuffer, sendBytes, MPI_CHAR, *rawMpiComm_);
1000  // NOTE: 'sendBytes' is being sent above for the MPI arg recvcount (which is
1001  // very confusing in the MPI documentation) for MPI_Allgether(...).
1002 
1003  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1004  "Teuchos::MpiComm::gatherAll: MPI_Allgather failed with error \""
1005  << mpiErrorCodeToString (err) << "\".");
1006 }
1007 
1008 
1009 template<typename Ordinal>
1010 void
1011 MpiComm<Ordinal>::gather (const Ordinal sendBytes,
1012  const char sendBuffer[],
1013  const Ordinal recvBytes,
1014  char recvBuffer[],
1015  const int root) const
1016 {
1017  (void) recvBytes; // silence compile warning for "unused parameter"
1018 
1020  "Teuchos::MpiComm<"<<OrdinalTraits<Ordinal>::name()<<">::gather(...)"
1021  );
1022  const int err =
1023  MPI_Gather (const_cast<char *> (sendBuffer), sendBytes, MPI_CHAR,
1024  recvBuffer, sendBytes, MPI_CHAR, root, *rawMpiComm_);
1025  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1026  "Teuchos::MpiComm::gather: MPI_Gather failed with error \""
1027  << mpiErrorCodeToString (err) << "\".");
1028 }
1029 
1030 
1031 template<typename Ordinal>
1032 void
1034 reduceAll (const ValueTypeReductionOp<Ordinal,char> &reductOp,
1035  const Ordinal bytes,
1036  const char sendBuffer[],
1037  char globalReducts[]) const
1038 {
1039  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::reduceAll(...)" );
1040  int err = MPI_SUCCESS;
1041 
1042  Details::MpiReductionOp<Ordinal> opWrap (reductOp);
1043  MPI_Op op = Details::setMpiReductionOp (opWrap);
1044 
1045  // FIXME (mfh 23 Nov 2014) Ross decided to mash every type into
1046  // char. This can cause correctness issues if we're actually doing
1047  // a reduction over, say, double. Thus, he creates a custom
1048  // MPI_Datatype here that represents a contiguous block of char, so
1049  // that MPI doesn't split up the reduction type and thus do the sum
1050  // wrong. It's a hack but it works.
1051 
1052  MPI_Datatype char_block;
1053  err = MPI_Type_contiguous (bytes, MPI_CHAR, &char_block);
1055  err != MPI_SUCCESS, std::runtime_error, "Teuchos::reduceAll: "
1056  "MPI_Type_contiguous failed with error \"" << mpiErrorCodeToString (err)
1057  << "\".");
1058  err = MPI_Type_commit (&char_block);
1060  err != MPI_SUCCESS, std::runtime_error, "Teuchos::reduceAll: "
1061  "MPI_Type_commit failed with error \"" << mpiErrorCodeToString (err)
1062  << "\".");
1063 
1064  if (sendBuffer == globalReducts) {
1065  // NOTE (mfh 31 May 2017) This is only safe if the communicator is
1066  // NOT an intercomm. The usual case is that communicators are
1067  // intracomms.
1068  err = MPI_Allreduce (MPI_IN_PLACE, globalReducts, 1,
1069  char_block, op, *rawMpiComm_);
1070  }
1071  else {
1072  err = MPI_Allreduce (const_cast<char*> (sendBuffer), globalReducts, 1,
1073  char_block, op, *rawMpiComm_);
1074  }
1075  if (err != MPI_SUCCESS) {
1076  // Don't throw until we release the type resources we allocated
1077  // above. If freeing fails for some reason, let the memory leak
1078  // go; we already have more serious problems if MPI_Allreduce
1079  // doesn't work.
1080  (void) MPI_Type_free (&char_block);
1082  true, std::runtime_error, "Teuchos::reduceAll (MPI, custom op): "
1083  "MPI_Allreduce failed with error \"" << mpiErrorCodeToString (err)
1084  << "\".");
1085  }
1086  err = MPI_Type_free (&char_block);
1088  err != MPI_SUCCESS, std::runtime_error, "Teuchos::reduceAll: "
1089  "MPI_Type_free failed with error \"" << mpiErrorCodeToString (err)
1090  << "\".");
1091 }
1092 
1093 
1094 template<typename Ordinal>
1096  const ValueTypeReductionOp<Ordinal,char> &reductOp
1097  ,const Ordinal bytes, const char sendBuffer[], char scanReducts[]
1098  ) const
1099 {
1100  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::scan(...)" );
1101 
1102  Details::MpiReductionOp<Ordinal> opWrap (reductOp);
1103  MPI_Op op = Details::setMpiReductionOp (opWrap);
1104  const int err =
1105  MPI_Scan (const_cast<char*> (sendBuffer), scanReducts, bytes, MPI_CHAR,
1106  op, *rawMpiComm_);
1107  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1108  "Teuchos::MpiComm::scan: MPI_Scan() failed with error \""
1109  << mpiErrorCodeToString (err) << "\".");
1110 }
1111 
1112 
1113 template<typename Ordinal>
1114 void
1115 MpiComm<Ordinal>::send (const Ordinal bytes,
1116  const char sendBuffer[],
1117  const int destRank) const
1118 {
1119  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::send(...)" );
1120 
1121 #ifdef TEUCHOS_MPI_COMM_DUMP
1122  if(show_dump) {
1123  dumpBuffer<Ordinal,char>(
1124  "Teuchos::MpiComm<Ordinal>::send(...)"
1125  ,"sendBuffer", bytes, sendBuffer
1126  );
1127  }
1128 #endif // TEUCHOS_MPI_COMM_DUMP
1129 
1130  const int err = MPI_Send (const_cast<char*>(sendBuffer), bytes, MPI_CHAR,
1131  destRank, tag_, *rawMpiComm_);
1132  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1133  "Teuchos::MpiComm::send: MPI_Send() failed with error \""
1134  << mpiErrorCodeToString (err) << "\".");
1135 }
1136 
1137 
1138 template<typename Ordinal>
1139 void
1140 MpiComm<Ordinal>::send (const Ordinal bytes,
1141  const char sendBuffer[],
1142  const int destRank,
1143  const int tag) const
1144 {
1145  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::send(...)" );
1146  const int err = MPI_Send (const_cast<char*> (sendBuffer), bytes, MPI_CHAR,
1147  destRank, tag, *rawMpiComm_);
1148  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1149  "Teuchos::MpiComm::send: MPI_Send() failed with error \""
1150  << mpiErrorCodeToString (err) << "\".");
1151 }
1152 
1153 
1154 template<typename Ordinal>
1155 void
1156 MpiComm<Ordinal>::ssend (const Ordinal bytes,
1157  const char sendBuffer[],
1158  const int destRank) const
1159 {
1160  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::ssend(...)" );
1161 
1162 #ifdef TEUCHOS_MPI_COMM_DUMP
1163  if(show_dump) {
1164  dumpBuffer<Ordinal,char>(
1165  "Teuchos::MpiComm<Ordinal>::send(...)"
1166  ,"sendBuffer", bytes, sendBuffer
1167  );
1168  }
1169 #endif // TEUCHOS_MPI_COMM_DUMP
1170 
1171  const int err = MPI_Ssend (const_cast<char*>(sendBuffer), bytes, MPI_CHAR,
1172  destRank, tag_, *rawMpiComm_);
1173  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1174  "Teuchos::MpiComm::send: MPI_Ssend() failed with error \""
1175  << mpiErrorCodeToString (err) << "\".");
1176 }
1177 
1178 template<typename Ordinal>
1179 void
1180 MpiComm<Ordinal>::ssend (const Ordinal bytes,
1181  const char sendBuffer[],
1182  const int destRank,
1183  const int tag) const
1184 {
1185  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::ssend(...)" );
1186  const int err =
1187  MPI_Ssend (const_cast<char*>(sendBuffer), bytes, MPI_CHAR,
1188  destRank, tag, *rawMpiComm_);
1189  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1190  "Teuchos::MpiComm::send: MPI_Ssend() failed with error \""
1191  << mpiErrorCodeToString (err) << "\".");
1192 }
1193 
1194 template<typename Ordinal>
1196  const ArrayView<const char> &sendBuffer,
1197  const int destRank
1198  ) const
1199 {
1200  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::readySend" );
1201 
1202 #ifdef TEUCHOS_MPI_COMM_DUMP
1203  if(show_dump) {
1204  dumpBuffer<Ordinal,char>(
1205  "Teuchos::MpiComm<Ordinal>::readySend(...)"
1206  ,"sendBuffer", bytes, sendBuffer
1207  );
1208  }
1209 #endif // TEUCHOS_MPI_COMM_DUMP
1210 
1211  const int err =
1212  MPI_Rsend (const_cast<char*>(sendBuffer.getRawPtr()), static_cast<int>(sendBuffer.size()),
1213  MPI_CHAR, destRank, tag_, *rawMpiComm_);
1214  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1215  "Teuchos::MpiComm::readySend: MPI_Rsend() failed with error \""
1216  << mpiErrorCodeToString (err) << "\".");
1217 }
1218 
1219 
1220 template<typename Ordinal>
1221 void MpiComm<Ordinal>::
1222 readySend (const Ordinal bytes,
1223  const char sendBuffer[],
1224  const int destRank,
1225  const int tag) const
1226 {
1227  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::readySend" );
1228  const int err =
1229  MPI_Rsend (const_cast<char*> (sendBuffer), bytes,
1230  MPI_CHAR, destRank, tag, *rawMpiComm_);
1231  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1232  "Teuchos::MpiComm::readySend: MPI_Rsend() failed with error \""
1233  << mpiErrorCodeToString (err) << "\".");
1234 }
1235 
1236 
1237 template<typename Ordinal>
1238 int
1239 MpiComm<Ordinal>::receive (const int sourceRank,
1240  const Ordinal bytes,
1241  char recvBuffer[]) const
1242 {
1243  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::receive(...)" );
1244 
1245  // A negative source rank indicates MPI_ANY_SOURCE, namely that we
1246  // will take an incoming message from any process, as long as the
1247  // tag matches.
1248  const int theSrcRank = (sourceRank < 0) ? MPI_ANY_SOURCE : sourceRank;
1249 
1250  MPI_Status status;
1251  const int err = MPI_Recv (recvBuffer, bytes, MPI_CHAR, theSrcRank, tag_,
1252  *rawMpiComm_, &status);
1253  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1254  "Teuchos::MpiComm::receive: MPI_Recv() failed with error \""
1255  << mpiErrorCodeToString (err) << "\".");
1256 
1257 #ifdef TEUCHOS_MPI_COMM_DUMP
1258  if (show_dump) {
1259  dumpBuffer<Ordinal,char> ("Teuchos::MpiComm<Ordinal>::receive(...)",
1260  "recvBuffer", bytes, recvBuffer);
1261  }
1262 #endif // TEUCHOS_MPI_COMM_DUMP
1263 
1264  // Returning the source rank is useful in the MPI_ANY_SOURCE case.
1265  return status.MPI_SOURCE;
1266 }
1267 
1268 
1269 template<typename Ordinal>
1270 RCP<CommRequest<Ordinal> >
1271 MpiComm<Ordinal>::isend (const ArrayView<const char> &sendBuffer,
1272  const int destRank) const
1273 {
1274  using Teuchos::as;
1275  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::isend(...)" );
1276 
1277  MPI_Request rawMpiRequest = MPI_REQUEST_NULL;
1278  const int err =
1279  MPI_Isend (const_cast<char*> (sendBuffer.getRawPtr ()),
1280  as<Ordinal> (sendBuffer.size ()), MPI_CHAR,
1281  destRank, tag_, *rawMpiComm_, &rawMpiRequest);
1282  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1283  "Teuchos::MpiComm::isend: MPI_Isend() failed with error \""
1284  << mpiErrorCodeToString (err) << "\".");
1285 
1286  return mpiCommRequest<Ordinal> (rawMpiRequest, sendBuffer.size ());
1287 }
1288 
1289 
1290 template<typename Ordinal>
1291 RCP<CommRequest<Ordinal> >
1293 isend (const ArrayView<const char> &sendBuffer,
1294  const int destRank,
1295  const int tag) const
1296 {
1297  using Teuchos::as;
1298  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::isend(...)" );
1299 
1300  MPI_Request rawMpiRequest = MPI_REQUEST_NULL;
1301  const int err =
1302  MPI_Isend (const_cast<char*> (sendBuffer.getRawPtr ()),
1303  as<Ordinal> (sendBuffer.size ()), MPI_CHAR,
1304  destRank, tag, *rawMpiComm_, &rawMpiRequest);
1305  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1306  "Teuchos::MpiComm::isend: MPI_Isend() failed with error \""
1307  << mpiErrorCodeToString (err) << "\".");
1308 
1309  return mpiCommRequest<Ordinal> (rawMpiRequest, sendBuffer.size ());
1310 }
1311 
1312 
1313 template<typename Ordinal>
1314 RCP<CommRequest<Ordinal> >
1315 MpiComm<Ordinal>::ireceive (const ArrayView<char> &recvBuffer,
1316  const int sourceRank) const
1317 {
1318  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::ireceive(...)" );
1319 
1320  // A negative source rank indicates MPI_ANY_SOURCE, namely that we
1321  // will take an incoming message from any process, as long as the
1322  // tag matches.
1323  const int theSrcRank = (sourceRank < 0) ? MPI_ANY_SOURCE : sourceRank;
1324 
1325  MPI_Request rawMpiRequest = MPI_REQUEST_NULL;
1326  const int err =
1327  MPI_Irecv (const_cast<char*>(recvBuffer.getRawPtr()), recvBuffer.size(),
1328  MPI_CHAR, theSrcRank, tag_, *rawMpiComm_, &rawMpiRequest);
1329  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1330  "Teuchos::MpiComm::ireceive: MPI_Irecv() failed with error \""
1331  << mpiErrorCodeToString (err) << "\".");
1332 
1333  return mpiCommRequest<Ordinal> (rawMpiRequest, recvBuffer.size());
1334 }
1335 
1336 template<typename Ordinal>
1337 RCP<CommRequest<Ordinal> >
1338 MpiComm<Ordinal>::ireceive (const ArrayView<char> &recvBuffer,
1339  const int sourceRank,
1340  const int tag) const
1341 {
1342  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::ireceive(...)" );
1343 
1344  // A negative source rank indicates MPI_ANY_SOURCE, namely that we
1345  // will take an incoming message from any process, as long as the
1346  // tag matches.
1347  const int theSrcRank = (sourceRank < 0) ? MPI_ANY_SOURCE : sourceRank;
1348 
1349  MPI_Request rawMpiRequest = MPI_REQUEST_NULL;
1350  const int err =
1351  MPI_Irecv (const_cast<char*> (recvBuffer.getRawPtr ()), recvBuffer.size (),
1352  MPI_CHAR, theSrcRank, tag, *rawMpiComm_, &rawMpiRequest);
1353  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1354  "Teuchos::MpiComm::ireceive: MPI_Irecv() failed with error \""
1355  << mpiErrorCodeToString (err) << "\".");
1356 
1357  return mpiCommRequest<Ordinal> (rawMpiRequest, recvBuffer.size ());
1358 }
1359 
1360 namespace {
1361  // Called by the two-argument MpiComm::waitAll() variant.
1362  template<typename Ordinal>
1363  void
1364  waitAllImpl (const ArrayView<RCP<CommRequest<Ordinal> > >& requests,
1365  const ArrayView<MPI_Status>& rawMpiStatuses)
1366  {
1367  typedef typename ArrayView<RCP<CommRequest<Ordinal> > >::size_type size_type;
1368  const size_type count = requests.size();
1369  // waitAllImpl() is not meant to be called by users, so it's a bug
1370  // for the two views to have different lengths.
1371  TEUCHOS_TEST_FOR_EXCEPTION(rawMpiStatuses.size() != count,
1372  std::logic_error, "Teuchos::MpiComm's waitAllImpl: rawMpiStatus.size() = "
1373  << rawMpiStatuses.size() << " != requests.size() = " << requests.size()
1374  << ". Please report this bug to the Tpetra developers.");
1375  if (count == 0) {
1376  return; // No requests on which to wait
1377  }
1378 
1379  // MpiComm wraps MPI and can't expose any MPI structs or opaque
1380  // objects. Thus, we have to unpack requests into a separate array.
1381  // If that's too slow, then your code should just call into MPI
1382  // directly.
1383  //
1384  // Pull out the raw MPI requests from the wrapped requests.
1385  // MPI_Waitall should not fail if a request is MPI_REQUEST_NULL, but
1386  // we keep track just to inform the user.
1387  bool someNullRequests = false;
1388  Array<MPI_Request> rawMpiRequests (count, MPI_REQUEST_NULL);
1389  for (int i = 0; i < count; ++i) {
1390  RCP<CommRequest<Ordinal> > request = requests[i];
1391  if (! is_null (request)) {
1392  RCP<MpiCommRequestBase<Ordinal> > mpiRequest =
1393  rcp_dynamic_cast<MpiCommRequestBase<Ordinal> > (request);
1394  // releaseRawMpiRequest() sets the MpiCommRequest's raw
1395  // MPI_Request to MPI_REQUEST_NULL. This makes waitAll() not
1396  // satisfy the strong exception guarantee. That's OK because
1397  // MPI_Waitall() doesn't promise that it satisfies the strong
1398  // exception guarantee, and we would rather conservatively
1399  // invalidate the handles than leave dangling requests around
1400  // and risk users trying to wait on the same request twice.
1401  rawMpiRequests[i] = mpiRequest->releaseRawMpiRequest();
1402  }
1403  else { // Null requests map to MPI_REQUEST_NULL
1404  rawMpiRequests[i] = MPI_REQUEST_NULL;
1405  someNullRequests = true;
1406  }
1407  }
1408 
1409  // This is the part where we've finally peeled off the wrapper and
1410  // we can now interact with MPI directly.
1411  //
1412  // One option in the one-argument version of waitAll() is to ignore
1413  // the statuses completely. MPI lets you pass in the named constant
1414  // MPI_STATUSES_IGNORE for the MPI_Status array output argument in
1415  // MPI_Waitall(), which would tell MPI not to bother with the
1416  // statuses. However, we want the statuses because we can use them
1417  // for detailed error diagnostics in case something goes wrong.
1418  const int err = MPI_Waitall (count, rawMpiRequests.getRawPtr(),
1419  rawMpiStatuses.getRawPtr());
1420 
1421  // In MPI_Waitall(), an error indicates that one or more requests
1422  // failed. In that case, there could be requests that completed
1423  // (their MPI_Status' error field is MPI_SUCCESS), and other
1424  // requests that have not completed yet but have not necessarily
1425  // failed (MPI_PENDING). We make no attempt here to wait on the
1426  // pending requests. It doesn't make sense for us to do so, because
1427  // in general Teuchos::Comm doesn't attempt to provide robust
1428  // recovery from failed messages.
1429  if (err != MPI_SUCCESS) {
1430  if (err == MPI_ERR_IN_STATUS) {
1431  //
1432  // When MPI_Waitall returns MPI_ERR_IN_STATUS (a standard error
1433  // class), it's telling us to check the error codes in the
1434  // returned statuses. In that case, we do so and generate a
1435  // detailed exception message.
1436  //
1437  // Figure out which of the requests failed.
1438  Array<std::pair<size_type, int> > errorLocationsAndCodes;
1439  for (size_type k = 0; k < rawMpiStatuses.size(); ++k) {
1440  const int curErr = rawMpiStatuses[k].MPI_ERROR;
1441  if (curErr != MPI_SUCCESS) {
1442  errorLocationsAndCodes.push_back (std::make_pair (k, curErr));
1443  }
1444  }
1445  const size_type numErrs = errorLocationsAndCodes.size();
1446  if (numErrs > 0) {
1447  // There was at least one error. Assemble a detailed
1448  // exception message reporting which requests failed,
1449  // their error codes, and their source
1450  std::ostringstream os;
1451  os << "Teuchos::MpiComm::waitAll: MPI_Waitall() failed with error \""
1452  << mpiErrorCodeToString (err) << "\". Of the " << count
1453  << " total request" << (count != 1 ? "s" : "") << ", " << numErrs
1454  << " failed. Here are the indices of the failed requests, and the "
1455  "error codes extracted from their returned MPI_Status objects:"
1456  << std::endl;
1457  for (size_type k = 0; k < numErrs; ++k) {
1458  const size_type errInd = errorLocationsAndCodes[k].first;
1459  os << "Request " << errInd << ": MPI_ERROR = "
1460  << mpiErrorCodeToString (rawMpiStatuses[errInd].MPI_ERROR)
1461  << std::endl;
1462  }
1463  if (someNullRequests) {
1464  os << " On input to MPI_Waitall, there was at least one MPI_"
1465  "Request that was MPI_REQUEST_NULL. MPI_Waitall should not "
1466  "normally fail in that case, but we thought we should let you know "
1467  "regardless.";
1468  }
1469  TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, os.str());
1470  }
1471  // If there were no actual errors in the returned statuses,
1472  // well, then I guess everything is OK. Just keep going.
1473  }
1474  else {
1475  std::ostringstream os;
1476  os << "Teuchos::MpiComm::waitAll: MPI_Waitall() failed with error \""
1477  << mpiErrorCodeToString (err) << "\".";
1478  if (someNullRequests) {
1479  os << " On input to MPI_Waitall, there was at least one MPI_Request "
1480  "that was MPI_REQUEST_NULL. MPI_Waitall should not normally fail in "
1481  "that case, but we thought we should let you know regardless.";
1482  }
1483  TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, os.str());
1484  }
1485  }
1486 
1487  // Invalidate the input array of requests by setting all entries
1488  // to null.
1489  std::fill (requests.begin(), requests.end(), null);
1490  }
1491 
1492 
1493 
1494  // Called by the one-argument MpiComm::waitAll() variant.
1495  template<typename Ordinal>
1496  void
1497  waitAllImpl (const ArrayView<RCP<CommRequest<Ordinal> > >& requests)
1498  {
1499  typedef typename ArrayView<RCP<CommRequest<Ordinal> > >::size_type size_type;
1500  const size_type count = requests.size ();
1501  if (count == 0) {
1502  return; // No requests on which to wait
1503  }
1504 
1505  // MpiComm wraps MPI and can't expose any MPI structs or opaque
1506  // objects. Thus, we have to unpack requests into a separate
1507  // array. If that's too slow, then your code should just call
1508  // into MPI directly.
1509  //
1510  // Pull out the raw MPI requests from the wrapped requests.
1511  // MPI_Waitall should not fail if a request is MPI_REQUEST_NULL,
1512  // but we keep track just to inform the user.
1513  bool someNullRequests = false;
1514  Array<MPI_Request> rawMpiRequests (count, MPI_REQUEST_NULL);
1515  for (int i = 0; i < count; ++i) {
1516  RCP<CommRequest<Ordinal> > request = requests[i];
1517  if (! request.is_null ()) {
1518  RCP<MpiCommRequestBase<Ordinal> > mpiRequest =
1519  rcp_dynamic_cast<MpiCommRequestBase<Ordinal> > (request);
1520  // releaseRawMpiRequest() sets the MpiCommRequest's raw
1521  // MPI_Request to MPI_REQUEST_NULL. This makes waitAll() not
1522  // satisfy the strong exception guarantee. That's OK because
1523  // MPI_Waitall() doesn't promise that it satisfies the strong
1524  // exception guarantee, and we would rather conservatively
1525  // invalidate the handles than leave dangling requests around
1526  // and risk users trying to wait on the same request twice.
1527  rawMpiRequests[i] = mpiRequest->releaseRawMpiRequest ();
1528  }
1529  else { // Null requests map to MPI_REQUEST_NULL
1530  rawMpiRequests[i] = MPI_REQUEST_NULL;
1531  someNullRequests = true;
1532  }
1533  }
1534 
1535  // This is the part where we've finally peeled off the wrapper and
1536  // we can now interact with MPI directly.
1537  //
1538  // MPI lets us pass in the named constant MPI_STATUSES_IGNORE for
1539  // the MPI_Status array output argument in MPI_Waitall(), which
1540  // tells MPI not to bother writing out the statuses.
1541  const int err = MPI_Waitall (count, rawMpiRequests.getRawPtr(),
1542  MPI_STATUSES_IGNORE);
1543 
1544  // In MPI_Waitall(), an error indicates that one or more requests
1545  // failed. In that case, there could be requests that completed
1546  // (their MPI_Status' error field is MPI_SUCCESS), and other
1547  // requests that have not completed yet but have not necessarily
1548  // failed (MPI_PENDING). We make no attempt here to wait on the
1549  // pending requests. It doesn't make sense for us to do so,
1550  // because in general Teuchos::Comm doesn't attempt to provide
1551  // robust recovery from failed messages.
1552  if (err != MPI_SUCCESS) {
1553  std::ostringstream os;
1554  os << "Teuchos::MpiComm::waitAll: MPI_Waitall() failed with error \""
1555  << mpiErrorCodeToString (err) << "\".";
1556  if (someNullRequests) {
1557  os << std::endl << "On input to MPI_Waitall, there was at least one "
1558  "MPI_Request that was MPI_REQUEST_NULL. MPI_Waitall should not "
1559  "normally fail in that case, but we thought we should let you know "
1560  "regardless.";
1561  }
1562  TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, os.str());
1563  }
1564 
1565  // Invalidate the input array of requests by setting all entries
1566  // to null. We delay this until the end, since some
1567  // implementations of CommRequest might hold the only reference to
1568  // the communication buffer, and we don't want that to go away
1569  // until we've waited on the communication operation.
1570  std::fill (requests.begin(), requests.end(), null);
1571  }
1572 
1573 } // namespace (anonymous)
1574 
1575 
1576 
1577 template<typename Ordinal>
1578 void
1579 MpiComm<Ordinal>::
1580 waitAll (const ArrayView<RCP<CommRequest<Ordinal> > >& requests) const
1581 {
1582  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::waitAll(requests)" );
1583  // Call the one-argument version of waitAllImpl, to avoid overhead
1584  // of handling statuses (which the user didn't want anyway).
1585  waitAllImpl<Ordinal> (requests);
1586 }
1587 
1588 
1589 template<typename Ordinal>
1590 void
1591 MpiComm<Ordinal>::
1592 waitAll (const ArrayView<RCP<CommRequest<Ordinal> > >& requests,
1593  const ArrayView<RCP<CommStatus<Ordinal> > >& statuses) const
1594 {
1595  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::waitAll(requests, statuses)" );
1596 
1597  typedef typename ArrayView<RCP<CommRequest<Ordinal> > >::size_type size_type;
1598  const size_type count = requests.size();
1599 
1600  TEUCHOS_TEST_FOR_EXCEPTION(count != statuses.size(),
1601  std::invalid_argument, "Teuchos::MpiComm::waitAll: requests.size() = "
1602  << count << " != statuses.size() = " << statuses.size() << ".");
1603 
1604  Array<MPI_Status> rawMpiStatuses (count);
1605  waitAllImpl<Ordinal> (requests, rawMpiStatuses());
1606 
1607  // Repackage the raw MPI_Status structs into the wrappers.
1608  for (size_type i = 0; i < count; ++i) {
1609  statuses[i] = mpiCommStatus<Ordinal> (rawMpiStatuses[i]);
1610  }
1611 }
1612 
1613 
1614 template<typename Ordinal>
1615 RCP<CommStatus<Ordinal> >
1616 MpiComm<Ordinal>::wait (const Ptr<RCP<CommRequest<Ordinal> > >& request) const
1617 {
1618  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::wait(...)" );
1619 
1620  if (is_null (*request)) {
1621  return null; // Nothing to wait on ...
1622  }
1623  else {
1624  RCP<CommStatus<Ordinal> > status = (*request)->wait ();
1625  // mfh 22 Oct 2012: The unit tests expect waiting on the
1626  // CommRequest to invalidate it by setting it to null.
1627  *request = null;
1628  return status;
1629  }
1630 }
1631 
1632 template<typename Ordinal>
1633 RCP< Comm<Ordinal> >
1634 MpiComm<Ordinal>::duplicate() const
1635 {
1636  MPI_Comm origRawComm = *rawMpiComm_;
1637  MPI_Comm newRawComm = MPI_COMM_NULL;
1638  const int err = MPI_Comm_dup (origRawComm, &newRawComm);
1639  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error, "Teuchos"
1640  "::MpiComm::duplicate: MPI_Comm_dup failed with the following error: "
1641  << mpiErrorCodeToString (err));
1642 
1643  // Wrap the raw communicator, and pass the (const) wrapped
1644  // communicator to MpiComm's constructor. We created the raw comm,
1645  // so we have to supply a function that frees it after use.
1646  RCP<OpaqueWrapper<MPI_Comm> > wrapped =
1647  opaqueWrapper<MPI_Comm> (newRawComm, details::safeCommFree);
1648  // Since newComm's raw MPI_Comm is the result of an MPI_Comm_dup,
1649  // its messages cannot collide with those of any other MpiComm.
1650  // This means we can assign its tag without an MPI_Bcast.
1651  RCP<MpiComm<Ordinal> > newComm =
1652  rcp (new MpiComm<Ordinal> (wrapped.getConst (), minTag_));
1653  return rcp_implicit_cast<Comm<Ordinal> > (newComm);
1654 }
1655 
1656 
1657 template<typename Ordinal>
1658 RCP< Comm<Ordinal> >
1659 MpiComm<Ordinal>::split(const int color, const int key) const
1660 {
1661  MPI_Comm newComm;
1662  const int splitReturn =
1663  MPI_Comm_split (*rawMpiComm_,
1664  color < 0 ? MPI_UNDEFINED : color,
1665  key,
1666  &newComm);
1668  splitReturn != MPI_SUCCESS,
1669  std::logic_error,
1670  "Teuchos::MpiComm::split: Failed to create communicator with color "
1671  << color << "and key " << key << ". MPI_Comm_split failed with error \""
1672  << mpiErrorCodeToString (splitReturn) << "\".");
1673  if (newComm == MPI_COMM_NULL) {
1674  return RCP< Comm<Ordinal> >();
1675  } else {
1676  RCP<const OpaqueWrapper<MPI_Comm> > wrapped =
1677  opaqueWrapper<MPI_Comm> (newComm, details::safeCommFree);
1678  // Since newComm's raw MPI_Comm is the result of an
1679  // MPI_Comm_split, its messages cannot collide with those of any
1680  // other MpiComm. This means we can assign its tag without an
1681  // MPI_Bcast.
1682  return rcp (new MpiComm<Ordinal> (wrapped, minTag_));
1683  }
1684 }
1685 
1686 
1687 template<typename Ordinal>
1688 RCP< Comm<Ordinal> >
1689 MpiComm<Ordinal>::createSubcommunicator(const ArrayView<const int> &ranks) const
1690 {
1691  int err = MPI_SUCCESS; // For error codes returned by MPI functions
1692 
1693  // Get the group that this communicator is in.
1694  MPI_Group thisGroup;
1695  err = MPI_Comm_group (*rawMpiComm_, &thisGroup);
1696  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::logic_error,
1697  "Failed to obtain the current communicator's group. "
1698  "MPI_Comm_group failed with error \""
1699  << mpiErrorCodeToString (err) << "\".");
1700 
1701  // Create a new group with the specified members.
1702  MPI_Group newGroup;
1703  // It's rude to cast away const, but MPI functions demand it.
1704  //
1705  // NOTE (mfh 14 Aug 2012) Please don't ask for &ranks[0] unless you
1706  // know that ranks.size() > 0. That's why I'm using getRawPtr().
1707  err = MPI_Group_incl (thisGroup, ranks.size(),
1708  const_cast<int*> (ranks.getRawPtr ()), &newGroup);
1709  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::logic_error,
1710  "Failed to create subgroup. MPI_Group_incl failed with error \""
1711  << mpiErrorCodeToString (err) << "\".");
1712 
1713  // Create a new communicator from the new group.
1714  MPI_Comm newComm;
1715  try {
1716  err = MPI_Comm_create (*rawMpiComm_, newGroup, &newComm);
1717  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::logic_error,
1718  "Failed to create subcommunicator. MPI_Comm_create failed with error \""
1719  << mpiErrorCodeToString (err) << "\".");
1720  } catch (...) {
1721  // Attempt to free the new group before rethrowing. If
1722  // successful, this will prevent a memory leak due to the "lost"
1723  // group that was allocated successfully above. Since we're
1724  // throwing std::logic_error anyway, we can only promise
1725  // best-effort recovery; thus, we don't check the error code.
1726  (void) MPI_Group_free (&newGroup);
1727  (void) MPI_Group_free (&thisGroup);
1728  throw;
1729  }
1730 
1731  // We don't need the group any more, so free it.
1732  err = MPI_Group_free (&newGroup);
1733  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::logic_error,
1734  "Failed to free subgroup. MPI_Group_free failed with error \""
1735  << mpiErrorCodeToString (err) << "\".");
1736  err = MPI_Group_free (&thisGroup);
1737  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::logic_error,
1738  "Failed to free subgroup. MPI_Group_free failed with error \""
1739  << mpiErrorCodeToString (err) << "\".");
1740 
1741  if (newComm == MPI_COMM_NULL) {
1742  return RCP<Comm<Ordinal> > ();
1743  } else {
1744  using Teuchos::details::safeCommFree;
1745  typedef OpaqueWrapper<MPI_Comm> ow_type;
1746  RCP<const ow_type> wrapper =
1747  rcp_implicit_cast<const ow_type> (opaqueWrapper (newComm, safeCommFree));
1748  // Since newComm's raw MPI_Comm is the result of an
1749  // MPI_Comm_create, its messages cannot collide with those of any
1750  // other MpiComm. This means we can assign its tag without an
1751  // MPI_Bcast.
1752  return rcp (new MpiComm<Ordinal> (wrapper, minTag_));
1753  }
1754 }
1755 
1756 
1757 // Overridden from Describable
1758 
1759 
1760 template<typename Ordinal>
1761 std::string MpiComm<Ordinal>::description() const
1762 {
1763  std::ostringstream oss;
1764  oss
1765  << typeName(*this)
1766  << "{"
1767  << "size="<<size_
1768  << ",rank="<<rank_
1769  << ",rawMpiComm="<<static_cast<MPI_Comm>(*rawMpiComm_)
1770  <<"}";
1771  return oss.str();
1772 }
1773 
1774 
1775 #ifdef TEUCHOS_MPI_COMM_DUMP
1776 template<typename Ordinal>
1777 bool MpiComm<Ordinal>::show_dump = false;
1778 #endif
1779 
1780 
1781 // private
1782 
1783 
1784 template<typename Ordinal>
1785 void MpiComm<Ordinal>::assertRank(const int rank, const std::string &rankName) const
1786 {
1788  ! ( 0 <= rank && rank < size_ ), std::logic_error
1789  ,"Error, "<<rankName<<" = " << rank << " is not < 0 or is not"
1790  " in the range [0,"<<size_-1<<"]!"
1791  );
1792 }
1793 
1794 
1795 } // namespace Teuchos
1796 
1797 
1798 template<typename Ordinal>
1800 Teuchos::createMpiComm(
1801  const RCP<const OpaqueWrapper<MPI_Comm> > &rawMpiComm
1802  )
1803 {
1804  if( rawMpiComm.get()!=NULL && *rawMpiComm != MPI_COMM_NULL )
1805  return rcp(new MpiComm<Ordinal>(rawMpiComm));
1806  return Teuchos::null;
1807 }
1808 
1809 
1810 template<typename Ordinal>
1811 MPI_Comm
1812 Teuchos::getRawMpiComm(const Comm<Ordinal> &comm)
1813 {
1814  return *(
1815  dyn_cast<const MpiComm<Ordinal> >(comm).getRawMpiComm()
1816  );
1817 }
1818 
1819 
1820 #endif // HAVE_TEUCHOS_MPI
1821 #endif // TEUCHOS_MPI_COMM_HPP
1822 
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...
std::string typeName(const T &t)
Template function for returning the concrete type name of a passed-in 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.
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...
#define TEUCHOS_COMM_TIME_MONITOR(FUNCNAME)
std::vector< std::string > split(const std::string &str, const std::string &delimiters, const size_t start)
Split the given string using the given set of delimiters.
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Deprecated.
TEUCHOS_DEPRECATED void scan(const Comm< Ordinal > &comm, const EReductionType reductType, const Packet &send, Packet *scanReduct)
Deprecated.
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...
static RCP< FancyOStream > getDefaultOStream()
Get the default output stream object.
TEUCHOS_DEPRECATED void reduceAll(const Comm< Ordinal > &comm, const EReductionType reductType, const Packet &send, Packet *globalReduct)
Deprecated .
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). ...
TypeTo as(const TypeFrom &t)
Convert from one value type to another.
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.
RCP< Teuchos::CommRequest< int > > isend(const ArrayRCP< const double > &sendBuffer, const int destRank, const int tag, const Comm< int > &comm)
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.
RCP< MpiCommRequest > mpiCommRequest(MPI_Request rawMpiRequest, const ArrayRCP< const char > &buffer)
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.