Teuchos - Trilinos Tools Package  Version of the Day
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"
56 #include "Teuchos_CommUtilities.hpp"
58 #include "Teuchos_OpaqueWrapper.hpp"
60 #include "Teuchos_SerializationTraitsHelpers.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 {
962  TEUCHOS_COMM_TIME_MONITOR(
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 {
977  TEUCHOS_COMM_TIME_MONITOR(
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 {
993  TEUCHOS_COMM_TIME_MONITOR(
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 
1019  TEUCHOS_COMM_TIME_MONITOR(
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
1033 MpiComm<Ordinal>::
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  err = MPI_Allreduce (const_cast<char*> (sendBuffer), globalReducts, 1,
1065  char_block, op, *rawMpiComm_);
1066  if (err != MPI_SUCCESS) {
1067  // Don't throw until we release the type resources we allocated
1068  // above. If freeing fails for some reason, let the memory leak
1069  // go; we already have more serious problems if MPI_Allreduce
1070  // doesn't work.
1071  (void) MPI_Type_free (&char_block);
1073  true, std::runtime_error, "Teuchos::reduceAll (MPI, custom op): "
1074  "MPI_Allreduce failed with error \"" << mpiErrorCodeToString (err)
1075  << "\".");
1076  }
1077  err = MPI_Type_free (&char_block);
1079  err != MPI_SUCCESS, std::runtime_error, "Teuchos::reduceAll: "
1080  "MPI_Type_free failed with error \"" << mpiErrorCodeToString (err)
1081  << "\".");
1082 }
1083 
1084 
1085 template<typename Ordinal>
1086 void MpiComm<Ordinal>::scan(
1087  const ValueTypeReductionOp<Ordinal,char> &reductOp
1088  ,const Ordinal bytes, const char sendBuffer[], char scanReducts[]
1089  ) const
1090 {
1091  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::scan(...)" );
1092 
1093  Details::MpiReductionOp<Ordinal> opWrap (reductOp);
1094  MPI_Op op = Details::setMpiReductionOp (opWrap);
1095  const int err =
1096  MPI_Scan (const_cast<char*> (sendBuffer), scanReducts, bytes, MPI_CHAR,
1097  op, *rawMpiComm_);
1098  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1099  "Teuchos::MpiComm::scan: MPI_Scan() failed with error \""
1100  << mpiErrorCodeToString (err) << "\".");
1101 }
1102 
1103 
1104 template<typename Ordinal>
1105 void
1106 MpiComm<Ordinal>::send (const Ordinal bytes,
1107  const char sendBuffer[],
1108  const int destRank) const
1109 {
1110  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::send(...)" );
1111 
1112 #ifdef TEUCHOS_MPI_COMM_DUMP
1113  if(show_dump) {
1114  dumpBuffer<Ordinal,char>(
1115  "Teuchos::MpiComm<Ordinal>::send(...)"
1116  ,"sendBuffer", bytes, sendBuffer
1117  );
1118  }
1119 #endif // TEUCHOS_MPI_COMM_DUMP
1120 
1121  const int err = MPI_Send (const_cast<char*>(sendBuffer), bytes, MPI_CHAR,
1122  destRank, tag_, *rawMpiComm_);
1123  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1124  "Teuchos::MpiComm::send: MPI_Send() failed with error \""
1125  << mpiErrorCodeToString (err) << "\".");
1126 }
1127 
1128 
1129 template<typename Ordinal>
1130 void
1131 MpiComm<Ordinal>::send (const Ordinal bytes,
1132  const char sendBuffer[],
1133  const int destRank,
1134  const int tag) const
1135 {
1136  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::send(...)" );
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>::ssend (const Ordinal bytes,
1148  const char sendBuffer[],
1149  const int destRank) const
1150 {
1151  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::ssend(...)" );
1152 
1153 #ifdef TEUCHOS_MPI_COMM_DUMP
1154  if(show_dump) {
1155  dumpBuffer<Ordinal,char>(
1156  "Teuchos::MpiComm<Ordinal>::send(...)"
1157  ,"sendBuffer", bytes, sendBuffer
1158  );
1159  }
1160 #endif // TEUCHOS_MPI_COMM_DUMP
1161 
1162  const int err = MPI_Ssend (const_cast<char*>(sendBuffer), bytes, MPI_CHAR,
1163  destRank, tag_, *rawMpiComm_);
1164  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1165  "Teuchos::MpiComm::send: MPI_Ssend() failed with error \""
1166  << mpiErrorCodeToString (err) << "\".");
1167 }
1168 
1169 template<typename Ordinal>
1170 void
1171 MpiComm<Ordinal>::ssend (const Ordinal bytes,
1172  const char sendBuffer[],
1173  const int destRank,
1174  const int tag) const
1175 {
1176  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::ssend(...)" );
1177  const int err =
1178  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 MpiComm<Ordinal>::readySend(
1187  const ArrayView<const char> &sendBuffer,
1188  const int destRank
1189  ) const
1190 {
1191  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::readySend" );
1192 
1193 #ifdef TEUCHOS_MPI_COMM_DUMP
1194  if(show_dump) {
1195  dumpBuffer<Ordinal,char>(
1196  "Teuchos::MpiComm<Ordinal>::readySend(...)"
1197  ,"sendBuffer", bytes, sendBuffer
1198  );
1199  }
1200 #endif // TEUCHOS_MPI_COMM_DUMP
1201 
1202  const int err =
1203  MPI_Rsend (const_cast<char*>(sendBuffer.getRawPtr()), sendBuffer.size(),
1204  MPI_CHAR, destRank, tag_, *rawMpiComm_);
1205  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1206  "Teuchos::MpiComm::readySend: MPI_Rsend() failed with error \""
1207  << mpiErrorCodeToString (err) << "\".");
1208 }
1209 
1210 
1211 template<typename Ordinal>
1212 void MpiComm<Ordinal>::
1213 readySend (const Ordinal bytes,
1214  const char sendBuffer[],
1215  const int destRank,
1216  const int tag) const
1217 {
1218  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::readySend" );
1219  const int err =
1220  MPI_Rsend (const_cast<char*> (sendBuffer), bytes,
1221  MPI_CHAR, destRank, tag, *rawMpiComm_);
1222  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1223  "Teuchos::MpiComm::readySend: MPI_Rsend() failed with error \""
1224  << mpiErrorCodeToString (err) << "\".");
1225 }
1226 
1227 
1228 template<typename Ordinal>
1229 int
1230 MpiComm<Ordinal>::receive (const int sourceRank,
1231  const Ordinal bytes,
1232  char recvBuffer[]) const
1233 {
1234  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::receive(...)" );
1235 
1236  // A negative source rank indicates MPI_ANY_SOURCE, namely that we
1237  // will take an incoming message from any process, as long as the
1238  // tag matches.
1239  const int theSrcRank = (sourceRank < 0) ? MPI_ANY_SOURCE : sourceRank;
1240 
1241  MPI_Status status;
1242  const int err = MPI_Recv (recvBuffer, bytes, MPI_CHAR, theSrcRank, tag_,
1243  *rawMpiComm_, &status);
1244  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1245  "Teuchos::MpiComm::receive: MPI_Recv() failed with error \""
1246  << mpiErrorCodeToString (err) << "\".");
1247 
1248 #ifdef TEUCHOS_MPI_COMM_DUMP
1249  if (show_dump) {
1250  dumpBuffer<Ordinal,char> ("Teuchos::MpiComm<Ordinal>::receive(...)",
1251  "recvBuffer", bytes, recvBuffer);
1252  }
1253 #endif // TEUCHOS_MPI_COMM_DUMP
1254 
1255  // Returning the source rank is useful in the MPI_ANY_SOURCE case.
1256  return status.MPI_SOURCE;
1257 }
1258 
1259 
1260 template<typename Ordinal>
1261 RCP<CommRequest<Ordinal> >
1262 MpiComm<Ordinal>::isend (const ArrayView<const char> &sendBuffer,
1263  const int destRank) const
1264 {
1265  using Teuchos::as;
1266  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::isend(...)" );
1267 
1268  MPI_Request rawMpiRequest = MPI_REQUEST_NULL;
1269  const int err =
1270  MPI_Isend (const_cast<char*> (sendBuffer.getRawPtr ()),
1271  as<Ordinal> (sendBuffer.size ()), MPI_CHAR,
1272  destRank, tag_, *rawMpiComm_, &rawMpiRequest);
1273  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1274  "Teuchos::MpiComm::isend: MPI_Isend() failed with error \""
1275  << mpiErrorCodeToString (err) << "\".");
1276 
1277  return mpiCommRequest<Ordinal> (rawMpiRequest, sendBuffer.size ());
1278 }
1279 
1280 
1281 template<typename Ordinal>
1282 RCP<CommRequest<Ordinal> >
1283 MpiComm<Ordinal>::
1284 isend (const ArrayView<const char> &sendBuffer,
1285  const int destRank,
1286  const int tag) const
1287 {
1288  using Teuchos::as;
1289  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::isend(...)" );
1290 
1291  MPI_Request rawMpiRequest = MPI_REQUEST_NULL;
1292  const int err =
1293  MPI_Isend (const_cast<char*> (sendBuffer.getRawPtr ()),
1294  as<Ordinal> (sendBuffer.size ()), MPI_CHAR,
1295  destRank, tag, *rawMpiComm_, &rawMpiRequest);
1296  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1297  "Teuchos::MpiComm::isend: MPI_Isend() failed with error \""
1298  << mpiErrorCodeToString (err) << "\".");
1299 
1300  return mpiCommRequest<Ordinal> (rawMpiRequest, sendBuffer.size ());
1301 }
1302 
1303 
1304 template<typename Ordinal>
1305 RCP<CommRequest<Ordinal> >
1306 MpiComm<Ordinal>::ireceive (const ArrayView<char> &recvBuffer,
1307  const int sourceRank) const
1308 {
1309  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::ireceive(...)" );
1310 
1311  // A negative source rank indicates MPI_ANY_SOURCE, namely that we
1312  // will take an incoming message from any process, as long as the
1313  // tag matches.
1314  const int theSrcRank = (sourceRank < 0) ? MPI_ANY_SOURCE : sourceRank;
1315 
1316  MPI_Request rawMpiRequest = MPI_REQUEST_NULL;
1317  const int err =
1318  MPI_Irecv (const_cast<char*>(recvBuffer.getRawPtr()), recvBuffer.size(),
1319  MPI_CHAR, theSrcRank, tag_, *rawMpiComm_, &rawMpiRequest);
1320  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1321  "Teuchos::MpiComm::ireceive: MPI_Irecv() failed with error \""
1322  << mpiErrorCodeToString (err) << "\".");
1323 
1324  return mpiCommRequest<Ordinal> (rawMpiRequest, recvBuffer.size());
1325 }
1326 
1327 template<typename Ordinal>
1328 RCP<CommRequest<Ordinal> >
1329 MpiComm<Ordinal>::ireceive (const ArrayView<char> &recvBuffer,
1330  const int sourceRank,
1331  const int tag) const
1332 {
1333  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::ireceive(...)" );
1334 
1335  // A negative source rank indicates MPI_ANY_SOURCE, namely that we
1336  // will take an incoming message from any process, as long as the
1337  // tag matches.
1338  const int theSrcRank = (sourceRank < 0) ? MPI_ANY_SOURCE : sourceRank;
1339 
1340  MPI_Request rawMpiRequest = MPI_REQUEST_NULL;
1341  const int err =
1342  MPI_Irecv (const_cast<char*> (recvBuffer.getRawPtr ()), recvBuffer.size (),
1343  MPI_CHAR, theSrcRank, tag, *rawMpiComm_, &rawMpiRequest);
1344  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1345  "Teuchos::MpiComm::ireceive: MPI_Irecv() failed with error \""
1346  << mpiErrorCodeToString (err) << "\".");
1347 
1348  return mpiCommRequest<Ordinal> (rawMpiRequest, recvBuffer.size ());
1349 }
1350 
1351 namespace {
1352  // Called by the two-argument MpiComm::waitAll() variant.
1353  template<typename Ordinal>
1354  void
1355  waitAllImpl (const ArrayView<RCP<CommRequest<Ordinal> > >& requests,
1356  const ArrayView<MPI_Status>& rawMpiStatuses)
1357  {
1358  typedef typename ArrayView<RCP<CommRequest<Ordinal> > >::size_type size_type;
1359  const size_type count = requests.size();
1360  // waitAllImpl() is not meant to be called by users, so it's a bug
1361  // for the two views to have different lengths.
1362  TEUCHOS_TEST_FOR_EXCEPTION(rawMpiStatuses.size() != count,
1363  std::logic_error, "Teuchos::MpiComm's waitAllImpl: rawMpiStatus.size() = "
1364  << rawMpiStatuses.size() << " != requests.size() = " << requests.size()
1365  << ". Please report this bug to the Tpetra developers.");
1366  if (count == 0) {
1367  return; // No requests on which to wait
1368  }
1369 
1370  // MpiComm wraps MPI and can't expose any MPI structs or opaque
1371  // objects. Thus, we have to unpack requests into a separate array.
1372  // If that's too slow, then your code should just call into MPI
1373  // directly.
1374  //
1375  // Pull out the raw MPI requests from the wrapped requests.
1376  // MPI_Waitall should not fail if a request is MPI_REQUEST_NULL, but
1377  // we keep track just to inform the user.
1378  bool someNullRequests = false;
1379  Array<MPI_Request> rawMpiRequests (count, MPI_REQUEST_NULL);
1380  for (int i = 0; i < count; ++i) {
1381  RCP<CommRequest<Ordinal> > request = requests[i];
1382  if (! is_null (request)) {
1383  RCP<MpiCommRequestBase<Ordinal> > mpiRequest =
1384  rcp_dynamic_cast<MpiCommRequestBase<Ordinal> > (request);
1385  // releaseRawMpiRequest() sets the MpiCommRequest's raw
1386  // MPI_Request to MPI_REQUEST_NULL. This makes waitAll() not
1387  // satisfy the strong exception guarantee. That's OK because
1388  // MPI_Waitall() doesn't promise that it satisfies the strong
1389  // exception guarantee, and we would rather conservatively
1390  // invalidate the handles than leave dangling requests around
1391  // and risk users trying to wait on the same request twice.
1392  rawMpiRequests[i] = mpiRequest->releaseRawMpiRequest();
1393  }
1394  else { // Null requests map to MPI_REQUEST_NULL
1395  rawMpiRequests[i] = MPI_REQUEST_NULL;
1396  someNullRequests = true;
1397  }
1398  }
1399 
1400  // This is the part where we've finally peeled off the wrapper and
1401  // we can now interact with MPI directly.
1402  //
1403  // One option in the one-argument version of waitAll() is to ignore
1404  // the statuses completely. MPI lets you pass in the named constant
1405  // MPI_STATUSES_IGNORE for the MPI_Status array output argument in
1406  // MPI_Waitall(), which would tell MPI not to bother with the
1407  // statuses. However, we want the statuses because we can use them
1408  // for detailed error diagnostics in case something goes wrong.
1409  const int err = MPI_Waitall (count, rawMpiRequests.getRawPtr(),
1410  rawMpiStatuses.getRawPtr());
1411 
1412  // In MPI_Waitall(), an error indicates that one or more requests
1413  // failed. In that case, there could be requests that completed
1414  // (their MPI_Status' error field is MPI_SUCCESS), and other
1415  // requests that have not completed yet but have not necessarily
1416  // failed (MPI_PENDING). We make no attempt here to wait on the
1417  // pending requests. It doesn't make sense for us to do so, because
1418  // in general Teuchos::Comm doesn't attempt to provide robust
1419  // recovery from failed messages.
1420  if (err != MPI_SUCCESS) {
1421  if (err == MPI_ERR_IN_STATUS) {
1422  //
1423  // When MPI_Waitall returns MPI_ERR_IN_STATUS (a standard error
1424  // class), it's telling us to check the error codes in the
1425  // returned statuses. In that case, we do so and generate a
1426  // detailed exception message.
1427  //
1428  // Figure out which of the requests failed.
1429  Array<std::pair<size_type, int> > errorLocationsAndCodes;
1430  for (size_type k = 0; k < rawMpiStatuses.size(); ++k) {
1431  const int curErr = rawMpiStatuses[k].MPI_ERROR;
1432  if (curErr != MPI_SUCCESS) {
1433  errorLocationsAndCodes.push_back (std::make_pair (k, curErr));
1434  }
1435  }
1436  const size_type numErrs = errorLocationsAndCodes.size();
1437  if (numErrs > 0) {
1438  // There was at least one error. Assemble a detailed
1439  // exception message reporting which requests failed,
1440  // their error codes, and their source
1441  std::ostringstream os;
1442  os << "Teuchos::MpiComm::waitAll: MPI_Waitall() failed with error \""
1443  << mpiErrorCodeToString (err) << "\". Of the " << count
1444  << " total request" << (count != 1 ? "s" : "") << ", " << numErrs
1445  << " failed. Here are the indices of the failed requests, and the "
1446  "error codes extracted from their returned MPI_Status objects:"
1447  << std::endl;
1448  for (size_type k = 0; k < numErrs; ++k) {
1449  const size_type errInd = errorLocationsAndCodes[k].first;
1450  os << "Request " << errInd << ": MPI_ERROR = "
1451  << mpiErrorCodeToString (rawMpiStatuses[errInd].MPI_ERROR)
1452  << std::endl;
1453  }
1454  if (someNullRequests) {
1455  os << " On input to MPI_Waitall, there was at least one MPI_"
1456  "Request that was MPI_REQUEST_NULL. MPI_Waitall should not "
1457  "normally fail in that case, but we thought we should let you know "
1458  "regardless.";
1459  }
1460  TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, os.str());
1461  }
1462  // If there were no actual errors in the returned statuses,
1463  // well, then I guess everything is OK. Just keep going.
1464  }
1465  else {
1466  std::ostringstream os;
1467  os << "Teuchos::MpiComm::waitAll: MPI_Waitall() failed with error \""
1468  << mpiErrorCodeToString (err) << "\".";
1469  if (someNullRequests) {
1470  os << " On input to MPI_Waitall, there was at least one MPI_Request "
1471  "that was MPI_REQUEST_NULL. MPI_Waitall should not normally fail in "
1472  "that case, but we thought we should let you know regardless.";
1473  }
1474  TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, os.str());
1475  }
1476  }
1477 
1478  // Invalidate the input array of requests by setting all entries
1479  // to null.
1480  std::fill (requests.begin(), requests.end(), null);
1481  }
1482 
1483 
1484 
1485  // Called by the one-argument MpiComm::waitAll() variant.
1486  template<typename Ordinal>
1487  void
1488  waitAllImpl (const ArrayView<RCP<CommRequest<Ordinal> > >& requests)
1489  {
1490  typedef typename ArrayView<RCP<CommRequest<Ordinal> > >::size_type size_type;
1491  const size_type count = requests.size ();
1492  if (count == 0) {
1493  return; // No requests on which to wait
1494  }
1495 
1496  // MpiComm wraps MPI and can't expose any MPI structs or opaque
1497  // objects. Thus, we have to unpack requests into a separate
1498  // array. If that's too slow, then your code should just call
1499  // into MPI directly.
1500  //
1501  // Pull out the raw MPI requests from the wrapped requests.
1502  // MPI_Waitall should not fail if a request is MPI_REQUEST_NULL,
1503  // but we keep track just to inform the user.
1504  bool someNullRequests = false;
1505  Array<MPI_Request> rawMpiRequests (count, MPI_REQUEST_NULL);
1506  for (int i = 0; i < count; ++i) {
1507  RCP<CommRequest<Ordinal> > request = requests[i];
1508  if (! request.is_null ()) {
1509  RCP<MpiCommRequestBase<Ordinal> > mpiRequest =
1510  rcp_dynamic_cast<MpiCommRequestBase<Ordinal> > (request);
1511  // releaseRawMpiRequest() sets the MpiCommRequest's raw
1512  // MPI_Request to MPI_REQUEST_NULL. This makes waitAll() not
1513  // satisfy the strong exception guarantee. That's OK because
1514  // MPI_Waitall() doesn't promise that it satisfies the strong
1515  // exception guarantee, and we would rather conservatively
1516  // invalidate the handles than leave dangling requests around
1517  // and risk users trying to wait on the same request twice.
1518  rawMpiRequests[i] = mpiRequest->releaseRawMpiRequest ();
1519  }
1520  else { // Null requests map to MPI_REQUEST_NULL
1521  rawMpiRequests[i] = MPI_REQUEST_NULL;
1522  someNullRequests = true;
1523  }
1524  }
1525 
1526  // This is the part where we've finally peeled off the wrapper and
1527  // we can now interact with MPI directly.
1528  //
1529  // MPI lets us pass in the named constant MPI_STATUSES_IGNORE for
1530  // the MPI_Status array output argument in MPI_Waitall(), which
1531  // tells MPI not to bother writing out the statuses.
1532  const int err = MPI_Waitall (count, rawMpiRequests.getRawPtr(),
1533  MPI_STATUSES_IGNORE);
1534 
1535  // In MPI_Waitall(), an error indicates that one or more requests
1536  // failed. In that case, there could be requests that completed
1537  // (their MPI_Status' error field is MPI_SUCCESS), and other
1538  // requests that have not completed yet but have not necessarily
1539  // failed (MPI_PENDING). We make no attempt here to wait on the
1540  // pending requests. It doesn't make sense for us to do so,
1541  // because in general Teuchos::Comm doesn't attempt to provide
1542  // robust recovery from failed messages.
1543  if (err != MPI_SUCCESS) {
1544  std::ostringstream os;
1545  os << "Teuchos::MpiComm::waitAll: MPI_Waitall() failed with error \""
1546  << mpiErrorCodeToString (err) << "\".";
1547  if (someNullRequests) {
1548  os << std::endl << "On input to MPI_Waitall, there was at least one "
1549  "MPI_Request that was MPI_REQUEST_NULL. MPI_Waitall should not "
1550  "normally fail in that case, but we thought we should let you know "
1551  "regardless.";
1552  }
1553  TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, os.str());
1554  }
1555 
1556  // Invalidate the input array of requests by setting all entries
1557  // to null. We delay this until the end, since some
1558  // implementations of CommRequest might hold the only reference to
1559  // the communication buffer, and we don't want that to go away
1560  // until we've waited on the communication operation.
1561  std::fill (requests.begin(), requests.end(), null);
1562  }
1563 
1564 } // namespace (anonymous)
1565 
1566 
1567 
1568 template<typename Ordinal>
1569 void
1570 MpiComm<Ordinal>::
1571 waitAll (const ArrayView<RCP<CommRequest<Ordinal> > >& requests) const
1572 {
1573  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::waitAll(requests)" );
1574  // Call the one-argument version of waitAllImpl, to avoid overhead
1575  // of handling statuses (which the user didn't want anyway).
1576  waitAllImpl<Ordinal> (requests);
1577 }
1578 
1579 
1580 template<typename Ordinal>
1581 void
1582 MpiComm<Ordinal>::
1583 waitAll (const ArrayView<RCP<CommRequest<Ordinal> > >& requests,
1584  const ArrayView<RCP<CommStatus<Ordinal> > >& statuses) const
1585 {
1586  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::waitAll(requests, statuses)" );
1587 
1588  typedef typename ArrayView<RCP<CommRequest<Ordinal> > >::size_type size_type;
1589  const size_type count = requests.size();
1590 
1591  TEUCHOS_TEST_FOR_EXCEPTION(count != statuses.size(),
1592  std::invalid_argument, "Teuchos::MpiComm::waitAll: requests.size() = "
1593  << count << " != statuses.size() = " << statuses.size() << ".");
1594 
1595  Array<MPI_Status> rawMpiStatuses (count);
1596  waitAllImpl<Ordinal> (requests, rawMpiStatuses());
1597 
1598  // Repackage the raw MPI_Status structs into the wrappers.
1599  for (size_type i = 0; i < count; ++i) {
1600  statuses[i] = mpiCommStatus<Ordinal> (rawMpiStatuses[i]);
1601  }
1602 }
1603 
1604 
1605 template<typename Ordinal>
1606 RCP<CommStatus<Ordinal> >
1607 MpiComm<Ordinal>::wait (const Ptr<RCP<CommRequest<Ordinal> > >& request) const
1608 {
1609  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::wait(...)" );
1610 
1611  if (is_null (*request)) {
1612  return null; // Nothing to wait on ...
1613  }
1614  else {
1615  RCP<CommStatus<Ordinal> > status = (*request)->wait ();
1616  // mfh 22 Oct 2012: The unit tests expect waiting on the
1617  // CommRequest to invalidate it by setting it to null.
1618  *request = null;
1619  return status;
1620  }
1621 }
1622 
1623 template<typename Ordinal>
1624 RCP< Comm<Ordinal> >
1625 MpiComm<Ordinal>::duplicate() const
1626 {
1627  MPI_Comm origRawComm = *rawMpiComm_;
1628  MPI_Comm newRawComm = MPI_COMM_NULL;
1629  const int err = MPI_Comm_dup (origRawComm, &newRawComm);
1630  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error, "Teuchos"
1631  "::MpiComm::duplicate: MPI_Comm_dup failed with the following error: "
1632  << mpiErrorCodeToString (err));
1633 
1634  // Wrap the raw communicator, and pass the (const) wrapped
1635  // communicator to MpiComm's constructor. We created the raw comm,
1636  // so we have to supply a function that frees it after use.
1637  RCP<OpaqueWrapper<MPI_Comm> > wrapped =
1638  opaqueWrapper<MPI_Comm> (newRawComm, details::safeCommFree);
1639  // Since newComm's raw MPI_Comm is the result of an MPI_Comm_dup,
1640  // its messages cannot collide with those of any other MpiComm.
1641  // This means we can assign its tag without an MPI_Bcast.
1642  RCP<MpiComm<Ordinal> > newComm =
1643  rcp (new MpiComm<Ordinal> (wrapped.getConst (), minTag_));
1644  return rcp_implicit_cast<Comm<Ordinal> > (newComm);
1645 }
1646 
1647 
1648 template<typename Ordinal>
1649 RCP< Comm<Ordinal> >
1650 MpiComm<Ordinal>::split(const int color, const int key) const
1651 {
1652  MPI_Comm newComm;
1653  const int splitReturn =
1654  MPI_Comm_split (*rawMpiComm_,
1655  color < 0 ? MPI_UNDEFINED : color,
1656  key,
1657  &newComm);
1659  splitReturn != MPI_SUCCESS,
1660  std::logic_error,
1661  "Teuchos::MpiComm::split: Failed to create communicator with color "
1662  << color << "and key " << key << ". MPI_Comm_split failed with error \""
1663  << mpiErrorCodeToString (splitReturn) << "\".");
1664  if (newComm == MPI_COMM_NULL) {
1665  return RCP< Comm<Ordinal> >();
1666  } else {
1667  RCP<const OpaqueWrapper<MPI_Comm> > wrapped =
1668  opaqueWrapper<MPI_Comm> (newComm, details::safeCommFree);
1669  // Since newComm's raw MPI_Comm is the result of an
1670  // MPI_Comm_split, its messages cannot collide with those of any
1671  // other MpiComm. This means we can assign its tag without an
1672  // MPI_Bcast.
1673  return rcp (new MpiComm<Ordinal> (wrapped, minTag_));
1674  }
1675 }
1676 
1677 
1678 template<typename Ordinal>
1679 RCP< Comm<Ordinal> >
1680 MpiComm<Ordinal>::createSubcommunicator(const ArrayView<const int> &ranks) const
1681 {
1682  int err = MPI_SUCCESS; // For error codes returned by MPI functions
1683 
1684  // Get the group that this communicator is in.
1685  MPI_Group thisGroup;
1686  err = MPI_Comm_group (*rawMpiComm_, &thisGroup);
1687  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::logic_error,
1688  "Failed to obtain the current communicator's group. "
1689  "MPI_Comm_group failed with error \""
1690  << mpiErrorCodeToString (err) << "\".");
1691 
1692  // Create a new group with the specified members.
1693  MPI_Group newGroup;
1694  // It's rude to cast away const, but MPI functions demand it.
1695  //
1696  // NOTE (mfh 14 Aug 2012) Please don't ask for &ranks[0] unless you
1697  // know that ranks.size() > 0. That's why I'm using getRawPtr().
1698  err = MPI_Group_incl (thisGroup, ranks.size(),
1699  const_cast<int*> (ranks.getRawPtr ()), &newGroup);
1700  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::logic_error,
1701  "Failed to create subgroup. MPI_Group_incl failed with error \""
1702  << mpiErrorCodeToString (err) << "\".");
1703 
1704  // Create a new communicator from the new group.
1705  MPI_Comm newComm;
1706  try {
1707  err = MPI_Comm_create (*rawMpiComm_, newGroup, &newComm);
1708  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::logic_error,
1709  "Failed to create subcommunicator. MPI_Comm_create failed with error \""
1710  << mpiErrorCodeToString (err) << "\".");
1711  } catch (...) {
1712  // Attempt to free the new group before rethrowing. If
1713  // successful, this will prevent a memory leak due to the "lost"
1714  // group that was allocated successfully above. Since we're
1715  // throwing std::logic_error anyway, we can only promise
1716  // best-effort recovery; thus, we don't check the error code.
1717  (void) MPI_Group_free (&newGroup);
1718  (void) MPI_Group_free (&thisGroup);
1719  throw;
1720  }
1721 
1722  // We don't need the group any more, so free it.
1723  err = MPI_Group_free (&newGroup);
1724  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::logic_error,
1725  "Failed to free subgroup. MPI_Group_free failed with error \""
1726  << mpiErrorCodeToString (err) << "\".");
1727  err = MPI_Group_free (&thisGroup);
1728  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::logic_error,
1729  "Failed to free subgroup. MPI_Group_free failed with error \""
1730  << mpiErrorCodeToString (err) << "\".");
1731 
1732  if (newComm == MPI_COMM_NULL) {
1733  return RCP<Comm<Ordinal> > ();
1734  } else {
1735  using Teuchos::details::safeCommFree;
1736  typedef OpaqueWrapper<MPI_Comm> ow_type;
1737  RCP<const ow_type> wrapper =
1738  rcp_implicit_cast<const ow_type> (opaqueWrapper (newComm, safeCommFree));
1739  // Since newComm's raw MPI_Comm is the result of an
1740  // MPI_Comm_create, its messages cannot collide with those of any
1741  // other MpiComm. This means we can assign its tag without an
1742  // MPI_Bcast.
1743  return rcp (new MpiComm<Ordinal> (wrapper, minTag_));
1744  }
1745 }
1746 
1747 
1748 // Overridden from Describable
1749 
1750 
1751 template<typename Ordinal>
1752 std::string MpiComm<Ordinal>::description() const
1753 {
1754  std::ostringstream oss;
1755  oss
1756  << typeName(*this)
1757  << "{"
1758  << "size="<<size_
1759  << ",rank="<<rank_
1760  << ",rawMpiComm="<<static_cast<MPI_Comm>(*rawMpiComm_)
1761  <<"}";
1762  return oss.str();
1763 }
1764 
1765 
1766 #ifdef TEUCHOS_MPI_COMM_DUMP
1767 template<typename Ordinal>
1768 bool MpiComm<Ordinal>::show_dump = false;
1769 #endif
1770 
1771 
1772 // private
1773 
1774 
1775 template<typename Ordinal>
1776 void MpiComm<Ordinal>::assertRank(const int rank, const std::string &rankName) const
1777 {
1779  ! ( 0 <= rank && rank < size_ ), std::logic_error
1780  ,"Error, "<<rankName<<" = " << rank << " is not < 0 or is not"
1781  " in the range [0,"<<size_-1<<"]!"
1782  );
1783 }
1784 
1785 
1786 } // namespace Teuchos
1787 
1788 
1789 template<typename Ordinal>
1791 Teuchos::createMpiComm(
1792  const RCP<const OpaqueWrapper<MPI_Comm> > &rawMpiComm
1793  )
1794 {
1795  if( rawMpiComm.get()!=NULL && *rawMpiComm != MPI_COMM_NULL )
1796  return rcp(new MpiComm<Ordinal>(rawMpiComm));
1797  return Teuchos::null;
1798 }
1799 
1800 
1801 template<typename Ordinal>
1802 MPI_Comm
1803 Teuchos::getRawMpiComm(const Comm<Ordinal> &comm)
1804 {
1805  return *(
1806  dyn_cast<const MpiComm<Ordinal> >(comm).getRawMpiComm()
1807  );
1808 }
1809 
1810 
1811 #endif // HAVE_TEUCHOS_MPI
1812 #endif // TEUCHOS_MPI_COMM_HPP
1813 
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.
Ordinal size_type
Type representing the number of elements in an ArrayRCP or view thereof.
T_To & dyn_cast(T_From &from)
Dynamic casting utility function meant to replace dynamic_cast<T&> 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.
Teuchos implementation details.
TEUCHOS_DEPRECATED void scan(const Comm< Ordinal > &comm, const EReductionType reductType, const Packet &send, Packet *scanReduct)
Deprecated.
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). ...
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.
The Teuchos namespace contains all of the classes, structs and enums used by Teuchos, as well as a number of utility routines.
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).
static std::string name()
Returns name of this ordinal type.
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.