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  TEUCHOS_DEPRECATED virtual void reduceAllAndScatter(
564  const ValueTypeReductionOp<Ordinal,char> &reductOp
565  ,const Ordinal sendBytes, const char sendBuffer[]
566  ,const Ordinal recvCounts[], char myGlobalReducts[]
567  ) const;
569  virtual void scan(
570  const ValueTypeReductionOp<Ordinal,char> &reductOp
571  ,const Ordinal bytes, const char sendBuffer[], char scanReducts[]
572  ) const;
574  virtual void send(
575  const Ordinal bytes, const char sendBuffer[], const int destRank
576  ) const;
578  virtual void
579  send (const Ordinal bytes,
580  const char sendBuffer[],
581  const int destRank,
582  const int tag) const;
584  virtual void ssend(
585  const Ordinal bytes, const char sendBuffer[], const int destRank
586  ) const;
588  virtual void
589  ssend (const Ordinal bytes,
590  const char sendBuffer[],
591  const int destRank,
592  const int tag) const;
594  virtual int receive(
595  const int sourceRank, const Ordinal bytes, char recvBuffer[]
596  ) const;
598  virtual void readySend(
599  const ArrayView<const char> &sendBuffer,
600  const int destRank
601  ) const;
603  virtual void
604  readySend (const Ordinal bytes,
605  const char sendBuffer[],
606  const int destRank,
607  const int tag) const;
609  virtual RCP<CommRequest<Ordinal> > isend(
610  const ArrayView<const char> &sendBuffer,
611  const int destRank
612  ) const;
614  virtual RCP<CommRequest<Ordinal> >
615  isend (const ArrayView<const char> &sendBuffer,
616  const int destRank,
617  const int tag) const;
619  virtual RCP<CommRequest<Ordinal> > ireceive(
620  const ArrayView<char> &Buffer,
621  const int sourceRank
622  ) const;
624  virtual RCP<CommRequest<Ordinal> >
625  ireceive (const ArrayView<char> &Buffer,
626  const int sourceRank,
627  const int tag) const;
629  virtual void waitAll(
630  const ArrayView<RCP<CommRequest<Ordinal> > > &requests
631  ) const;
633  virtual void
634  waitAll (const ArrayView<RCP<CommRequest<Ordinal> > >& requests,
635  const ArrayView<RCP<CommStatus<Ordinal> > >& statuses) const;
637  virtual RCP<CommStatus<Ordinal> >
638  wait (const Ptr<RCP<CommRequest<Ordinal> > >& request) const;
640  virtual RCP< Comm<Ordinal> > duplicate() const;
642  virtual RCP< Comm<Ordinal> > split(const int color, const int key) const;
644  virtual RCP< Comm<Ordinal> > createSubcommunicator(
645  const ArrayView<const int>& ranks) const;
646 
648 
650 
652  std::string description() const;
653 
655 
656  // These should be private but the PGI compiler requires them be public
657 
658  static int const minTag_ = 26000; // These came from Teuchos::MpiComm???
659  static int const maxTag_ = 26099; // ""
660 
666  int getTag () const { return tag_; }
667 
668 private:
669 
673  void setupMembersFromComm();
674  static int tagCounter_;
675 
683  RCP<const OpaqueWrapper<MPI_Comm> > rawMpiComm_;
684 
686  int rank_;
687 
689  int size_;
690 
698  int tag_;
699 
701  RCP<const OpaqueWrapper<MPI_Errhandler> > customErrorHandler_;
702 
703  void assertRank(const int rank, const std::string &rankName) const;
704 
705  // Not defined and not to be called!
706  MpiComm();
707 
708 #ifdef TEUCHOS_MPI_COMM_DUMP
709 public:
710  static bool show_dump;
711 #endif // TEUCHOS_MPI_COMM_DUMP
712 
713 };
714 
715 
729 template<typename Ordinal>
730 RCP<MpiComm<Ordinal> >
731 createMpiComm(
732  const RCP<const OpaqueWrapper<MPI_Comm> > &rawMpiComm
733  );
734 
735 
763 template<typename Ordinal>
764 MPI_Comm
765 getRawMpiComm(const Comm<Ordinal> &comm);
766 
767 
768 // ////////////////////////
769 // Implementations
770 
771 
772 // Static members
773 
774 
775 template<typename Ordinal>
776 int MpiComm<Ordinal>::tagCounter_ = MpiComm<Ordinal>::minTag_;
777 
778 
779 // Constructors
780 
781 
782 template<typename Ordinal>
783 MpiComm<Ordinal>::
784 MpiComm (const RCP<const OpaqueWrapper<MPI_Comm> >& rawMpiComm)
785 {
787  rawMpiComm.get () == NULL, std::invalid_argument,
788  "Teuchos::MpiComm constructor: The input RCP is null.");
790  *rawMpiComm == MPI_COMM_NULL, std::invalid_argument,
791  "Teuchos::MpiComm constructor: The given MPI_Comm is MPI_COMM_NULL.");
792 
793  rawMpiComm_ = rawMpiComm;
794 
795  // mfh 09 Jul 2013: Please resist the temptation to modify the given
796  // MPI communicator's error handler here. See Bug 5943. Note that
797  // an MPI communicator's default error handler is
798  // MPI_ERRORS_ARE_FATAL, which immediately aborts on error (without
799  // returning an error code from the MPI function). Users who want
800  // MPI functions instead to return an error code if they encounter
801  // an error, should set the error handler to MPI_ERRORS_RETURN. DO
802  // NOT SET THE ERROR HANDLER HERE!!! Teuchos' MPI wrappers should
803  // always check the error code returned by an MPI function,
804  // regardless of the error handler. Users who want to set the error
805  // handler on an MpiComm may call its setErrorHandler method.
806 
807  setupMembersFromComm ();
808 }
809 
810 
811 template<typename Ordinal>
812 MpiComm<Ordinal>::
813 MpiComm (const RCP<const OpaqueWrapper<MPI_Comm> >& rawMpiComm,
814  const int defaultTag)
815 {
817  rawMpiComm.get () == NULL, std::invalid_argument,
818  "Teuchos::MpiComm constructor: The input RCP is null.");
820  *rawMpiComm == MPI_COMM_NULL, std::invalid_argument,
821  "Teuchos::MpiComm constructor: The given MPI_Comm is MPI_COMM_NULL.");
822 
823  rawMpiComm_ = rawMpiComm;
824  // Set size_ (the number of processes in the communicator).
825  int err = MPI_Comm_size (*rawMpiComm_, &size_);
826  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
827  "Teuchos::MpiComm constructor: MPI_Comm_size failed with "
828  "error \"" << mpiErrorCodeToString (err) << "\".");
829  // Set rank_ (the calling process' rank).
830  err = MPI_Comm_rank (*rawMpiComm_, &rank_);
831  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
832  "Teuchos::MpiComm constructor: MPI_Comm_rank failed with "
833  "error \"" << mpiErrorCodeToString (err) << "\".");
834  tag_ = defaultTag; // set the default message tag
835 }
836 
837 
838 template<typename Ordinal>
839 MpiComm<Ordinal>::MpiComm (MPI_Comm rawMpiComm)
840 {
841  TEUCHOS_TEST_FOR_EXCEPTION(rawMpiComm == MPI_COMM_NULL,
842  std::invalid_argument, "Teuchos::MpiComm constructor: The given MPI_Comm "
843  "is MPI_COMM_NULL.");
844  // We don't supply a "free" function here, since this version of the
845  // constructor makes the caller responsible for freeing rawMpiComm
846  // after use if necessary.
847  rawMpiComm_ = opaqueWrapper<MPI_Comm> (rawMpiComm);
848 
849  // mfh 09 Jul 2013: Please resist the temptation to modify the given
850  // MPI communicator's error handler here. See Bug 5943. Note that
851  // an MPI communicator's default error handler is
852  // MPI_ERRORS_ARE_FATAL, which immediately aborts on error (without
853  // returning an error code from the MPI function). Users who want
854  // MPI functions instead to return an error code if they encounter
855  // an error, should set the error handler to MPI_ERRORS_RETURN. DO
856  // NOT SET THE ERROR HANDLER HERE!!! Teuchos' MPI wrappers should
857  // always check the error code returned by an MPI function,
858  // regardless of the error handler. Users who want to set the error
859  // handler on an MpiComm may call its setErrorHandler method.
860 
861  setupMembersFromComm ();
862 }
863 
864 
865 template<typename Ordinal>
866 MpiComm<Ordinal>::MpiComm (const MpiComm<Ordinal>& other) :
867  rawMpiComm_ (opaqueWrapper<MPI_Comm> (MPI_COMM_NULL)) // <- This will be set below
868 {
869  // These are logic errors, since they violate MpiComm's invariants.
870  RCP<const OpaqueWrapper<MPI_Comm> > origCommPtr = other.getRawMpiComm ();
871  TEUCHOS_TEST_FOR_EXCEPTION(origCommPtr == null, std::logic_error,
872  "Teuchos::MpiComm copy constructor: "
873  "The input's getRawMpiComm() method returns null.");
874  MPI_Comm origComm = *origCommPtr;
875  TEUCHOS_TEST_FOR_EXCEPTION(origComm == MPI_COMM_NULL, std::logic_error,
876  "Teuchos::MpiComm copy constructor: "
877  "The input's raw MPI_Comm is MPI_COMM_NULL.");
878 
879  // mfh 19 Oct 2012: Don't change the behavior of MpiComm's copy
880  // constructor for now. Later, we'll switch to the version that
881  // calls MPI_Comm_dup. For now, we just copy other's handle over.
882  // Note that the new MpiComm's tag is still different than the input
883  // MpiComm's tag. See Bug 5740.
884  if (true) {
885  rawMpiComm_ = origCommPtr;
886  }
887  else { // false (not run)
888  MPI_Comm newComm;
889  const int err = MPI_Comm_dup (origComm, &newComm);
890  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
891  "Teuchos::MpiComm copy constructor: MPI_Comm_dup failed with "
892  "the following error: " << mpiErrorCodeToString (err));
893  // No side effects until after everything has succeeded.
894  rawMpiComm_ = opaqueWrapper (newComm, details::safeCommFree);
895  }
896 
897  setupMembersFromComm ();
898 }
899 
900 
901 template<typename Ordinal>
902 void MpiComm<Ordinal>::setupMembersFromComm ()
903 {
904  int err = MPI_Comm_size (*rawMpiComm_, &size_);
905  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
906  "Teuchos::MpiComm constructor: MPI_Comm_size failed with "
907  "error \"" << mpiErrorCodeToString (err) << "\".");
908  err = MPI_Comm_rank (*rawMpiComm_, &rank_);
909  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
910  "Teuchos::MpiComm constructor: MPI_Comm_rank failed with "
911  "error \"" << mpiErrorCodeToString (err) << "\".");
912 
913  // Set the default tag to make unique across all communicators
914  if (tagCounter_ > maxTag_) {
915  tagCounter_ = minTag_;
916  }
917  tag_ = tagCounter_++;
918  // Ensure that the same tag is used on all processes.
919  //
920  // FIXME (mfh 09 Jul 2013) This would not be necessary if MpiComm
921  // were just to call MPI_Comm_dup (as every library should) when
922  // given its communicator. Of course, MPI_Comm_dup may also be
923  // implemented as a collective, and may even be more expensive than
924  // a broadcast. If we do decide to use MPI_Comm_dup, we can get rid
925  // of the broadcast below, and also get rid of tag_, tagCounter_,
926  // minTag_, and maxTag_.
927  MPI_Bcast (&tag_, 1, MPI_INT, 0, *rawMpiComm_);
928 }
929 
930 
931 template<typename Ordinal>
932 void
933 MpiComm<Ordinal>::
934 setErrorHandler (const RCP<const OpaqueWrapper<MPI_Errhandler> >& errHandler)
935 {
936  if (! is_null (errHandler)) {
937  const int err = details::setCommErrhandler (*getRawMpiComm (), *errHandler);
938  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
939  "Teuchos::MpiComm: Setting the MPI_Comm's error handler failed with "
940  "error \"" << mpiErrorCodeToString (err) << "\".");
941  }
942  // Wait to set this until the end, in case setting the error handler
943  // doesn't succeed.
944  customErrorHandler_ = errHandler;
945 }
946 
947 //
948 // Overridden from Comm
949 //
950 
951 template<typename Ordinal>
952 int MpiComm<Ordinal>::getRank() const
953 {
954  return rank_;
955 }
956 
957 
958 template<typename Ordinal>
959 int MpiComm<Ordinal>::getSize() const
960 {
961  return size_;
962 }
963 
964 
965 template<typename Ordinal>
966 void MpiComm<Ordinal>::barrier() const
967 {
968  TEUCHOS_COMM_TIME_MONITOR(
969  "Teuchos::MpiComm<"<<OrdinalTraits<Ordinal>::name()<<">::barrier()"
970  );
971  const int err = MPI_Barrier (*rawMpiComm_);
972  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
973  "Teuchos::MpiComm::barrier: MPI_Barrier failed with error \""
974  << mpiErrorCodeToString (err) << "\".");
975 }
976 
977 
978 template<typename Ordinal>
979 void MpiComm<Ordinal>::broadcast(
980  const int rootRank, const Ordinal bytes, char buffer[]
981  ) const
982 {
983  TEUCHOS_COMM_TIME_MONITOR(
984  "Teuchos::MpiComm<"<<OrdinalTraits<Ordinal>::name()<<">::broadcast(...)"
985  );
986  const int err = MPI_Bcast (buffer, bytes, MPI_CHAR, rootRank, *rawMpiComm_);
987  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
988  "Teuchos::MpiComm::broadcast: MPI_Bcast failed with error \""
989  << mpiErrorCodeToString (err) << "\".");
990 }
991 
992 
993 template<typename Ordinal>
994 void MpiComm<Ordinal>::gatherAll(
995  const Ordinal sendBytes, const char sendBuffer[],
996  const Ordinal recvBytes, char recvBuffer[]
997  ) const
998 {
999  TEUCHOS_COMM_TIME_MONITOR(
1000  "Teuchos::MpiComm<"<<OrdinalTraits<Ordinal>::name()<<">::gatherAll(...)"
1001  );
1002  TEUCHOS_ASSERT_EQUALITY((sendBytes*size_), recvBytes );
1003  const int err =
1004  MPI_Allgather (const_cast<char *>(sendBuffer), sendBytes, MPI_CHAR,
1005  recvBuffer, sendBytes, MPI_CHAR, *rawMpiComm_);
1006  // NOTE: 'sendBytes' is being sent above for the MPI arg recvcount (which is
1007  // very confusing in the MPI documentation) for MPI_Allgether(...).
1008 
1009  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1010  "Teuchos::MpiComm::gatherAll: MPI_Allgather failed with error \""
1011  << mpiErrorCodeToString (err) << "\".");
1012 }
1013 
1014 
1015 template<typename Ordinal>
1016 void
1017 MpiComm<Ordinal>::gather (const Ordinal sendBytes,
1018  const char sendBuffer[],
1019  const Ordinal recvBytes,
1020  char recvBuffer[],
1021  const int root) const
1022 {
1023  (void) recvBytes; // silence compile warning for "unused parameter"
1024 
1025  TEUCHOS_COMM_TIME_MONITOR(
1026  "Teuchos::MpiComm<"<<OrdinalTraits<Ordinal>::name()<<">::gather(...)"
1027  );
1028  const int err =
1029  MPI_Gather (const_cast<char *> (sendBuffer), sendBytes, MPI_CHAR,
1030  recvBuffer, sendBytes, MPI_CHAR, root, *rawMpiComm_);
1031  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1032  "Teuchos::MpiComm::gather: MPI_Gather failed with error \""
1033  << mpiErrorCodeToString (err) << "\".");
1034 }
1035 
1036 
1037 template<typename Ordinal>
1038 void
1039 MpiComm<Ordinal>::
1040 reduceAll (const ValueTypeReductionOp<Ordinal,char> &reductOp,
1041  const Ordinal bytes,
1042  const char sendBuffer[],
1043  char globalReducts[]) const
1044 {
1045  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::reduceAll(...)" );
1046  int err = MPI_SUCCESS;
1047 
1048  Details::MpiReductionOp<Ordinal> opWrap (reductOp);
1049  MPI_Op op = Details::setMpiReductionOp (opWrap);
1050 
1051  // FIXME (mfh 23 Nov 2014) Ross decided to mash every type into
1052  // char. This can cause correctness issues if we're actually doing
1053  // a reduction over, say, double. Thus, he creates a custom
1054  // MPI_Datatype here that represents a contiguous block of char, so
1055  // that MPI doesn't split up the reduction type and thus do the sum
1056  // wrong. It's a hack but it works.
1057 
1058  MPI_Datatype char_block;
1059  err = MPI_Type_contiguous (bytes, MPI_CHAR, &char_block);
1061  err != MPI_SUCCESS, std::runtime_error, "Teuchos::reduceAll: "
1062  "MPI_Type_contiguous failed with error \"" << mpiErrorCodeToString (err)
1063  << "\".");
1064  err = MPI_Type_commit (&char_block);
1066  err != MPI_SUCCESS, std::runtime_error, "Teuchos::reduceAll: "
1067  "MPI_Type_commit failed with error \"" << mpiErrorCodeToString (err)
1068  << "\".");
1069 
1070  err = MPI_Allreduce (const_cast<char*> (sendBuffer), globalReducts, 1,
1071  char_block, op, *rawMpiComm_);
1072  if (err != MPI_SUCCESS) {
1073  // Don't throw until we release the type resources we allocated
1074  // above. If freeing fails for some reason, let the memory leak
1075  // go; we already have more serious problems if MPI_Allreduce
1076  // doesn't work.
1077  (void) MPI_Type_free (&char_block);
1079  true, std::runtime_error, "Teuchos::reduceAll (MPI, custom op): "
1080  "MPI_Allreduce failed with error \"" << mpiErrorCodeToString (err)
1081  << "\".");
1082  }
1083  err = MPI_Type_free (&char_block);
1085  err != MPI_SUCCESS, std::runtime_error, "Teuchos::reduceAll: "
1086  "MPI_Type_free failed with error \"" << mpiErrorCodeToString (err)
1087  << "\".");
1088 }
1089 
1090 
1091 template<typename Ordinal>
1092 TEUCHOS_DEPRECATED void MpiComm<Ordinal>::reduceAllAndScatter(
1093  const ValueTypeReductionOp<Ordinal,char> &reductOp
1094  ,const Ordinal sendBytes, const char sendBuffer[]
1095  ,const Ordinal recvCounts[], char myGlobalReducts[]
1096  ) const
1097 {
1098 
1099  (void)sendBytes; // Ignore if not in debug mode
1100 
1101  TEUCHOS_COMM_TIME_MONITOR(
1102  "Teuchos::MpiComm<"<<OrdinalTraits<Ordinal>::name()<<">::reduceAllAndScatter(...)"
1103  );
1104 
1105 #ifdef TEUCHOS_DEBUG
1106  Ordinal sumRecvBytes = 0;
1107  for( Ordinal i = 0; i < size_; ++i ) {
1108  sumRecvBytes += recvCounts[i];
1109  }
1110  TEUCHOS_TEST_FOR_EXCEPT(!(sumRecvBytes==sendBytes));
1111 #endif // TEUCHOS_DEBUG
1112 
1113 #ifdef TEUCHOS_MPI_COMM_DUMP
1114  if(show_dump) {
1115  dumpBuffer<Ordinal,char>(
1116  "Teuchos::MpiComm<Ordinal>::reduceAllAndScatter(...)",
1117  "sendBuffer", sendBytes, sendBuffer );
1118  dumpBuffer<Ordinal,Ordinal>(
1119  "Teuchos::MpiComm<Ordinal>::reduceAllAndScatter(...)",
1120  "recvCounts", as<Ordinal>(size_), recvCounts );
1121  dumpBuffer<Ordinal,char>(
1122  "Teuchos::MpiComm<Ordinal>::reduceAllAndScatter(...)",
1123  "myGlobalReducts", as<char>(recvCounts[rank_]), myGlobalReducts );
1124  }
1125 #endif // TEUCHOS_MPI_COMM_DUMP
1126 
1127  // Create a new recvCount[] if Ordinal!=int
1128  WorkspaceStore* wss = get_default_workspace_store().get();
1129  const bool Ordinal_is_int = typeid(int)==typeid(Ordinal);
1130  Workspace<int> ws_int_recvCounts(wss,Ordinal_is_int?0:size_);
1131  const int *int_recvCounts = 0;
1132  if(Ordinal_is_int) {
1133  int_recvCounts = reinterpret_cast<const int*>(recvCounts);
1134  // Note: We must do an reinterpet cast since this must
1135  // compile even if it is not executed. I could implement
1136  // code that would not need to do this using template
1137  // conditionals but I don't want to bother.
1138  }
1139  else {
1140  std::copy(recvCounts, recvCounts+size_, &ws_int_recvCounts[0]);
1141  int_recvCounts = &ws_int_recvCounts[0];
1142  }
1143 
1144  Details::MpiReductionOp<Ordinal> opWrap (reductOp);
1145  MPI_Op op = Details::setMpiReductionOp (opWrap);
1146  const int err =
1147  MPI_Reduce_scatter (const_cast<char*> (sendBuffer), myGlobalReducts,
1148  const_cast<int*> (int_recvCounts), MPI_CHAR,
1149  op, *rawMpiComm_);
1151  err != MPI_SUCCESS, std::runtime_error, "Teuchos::MpiComm::"
1152  "reduceAllAndScatter: MPI_Reduce_scatter failed with error \""
1153  << mpiErrorCodeToString (err) << "\".");
1154 }
1155 
1156 
1157 template<typename Ordinal>
1158 void MpiComm<Ordinal>::scan(
1159  const ValueTypeReductionOp<Ordinal,char> &reductOp
1160  ,const Ordinal bytes, const char sendBuffer[], char scanReducts[]
1161  ) const
1162 {
1163  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::scan(...)" );
1164 
1165  Details::MpiReductionOp<Ordinal> opWrap (reductOp);
1166  MPI_Op op = Details::setMpiReductionOp (opWrap);
1167  const int err =
1168  MPI_Scan (const_cast<char*> (sendBuffer), scanReducts, bytes, MPI_CHAR,
1169  op, *rawMpiComm_);
1170  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1171  "Teuchos::MpiComm::scan: MPI_Scan() failed with error \""
1172  << mpiErrorCodeToString (err) << "\".");
1173 }
1174 
1175 
1176 template<typename Ordinal>
1177 void
1178 MpiComm<Ordinal>::send (const Ordinal bytes,
1179  const char sendBuffer[],
1180  const int destRank) const
1181 {
1182  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::send(...)" );
1183 
1184 #ifdef TEUCHOS_MPI_COMM_DUMP
1185  if(show_dump) {
1186  dumpBuffer<Ordinal,char>(
1187  "Teuchos::MpiComm<Ordinal>::send(...)"
1188  ,"sendBuffer", bytes, sendBuffer
1189  );
1190  }
1191 #endif // TEUCHOS_MPI_COMM_DUMP
1192 
1193  const int err = MPI_Send (const_cast<char*>(sendBuffer), bytes, MPI_CHAR,
1194  destRank, tag_, *rawMpiComm_);
1195  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1196  "Teuchos::MpiComm::send: MPI_Send() failed with error \""
1197  << mpiErrorCodeToString (err) << "\".");
1198 }
1199 
1200 
1201 template<typename Ordinal>
1202 void
1203 MpiComm<Ordinal>::send (const Ordinal bytes,
1204  const char sendBuffer[],
1205  const int destRank,
1206  const int tag) const
1207 {
1208  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::send(...)" );
1209  const int err = MPI_Send (const_cast<char*> (sendBuffer), bytes, MPI_CHAR,
1210  destRank, tag, *rawMpiComm_);
1211  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1212  "Teuchos::MpiComm::send: MPI_Send() failed with error \""
1213  << mpiErrorCodeToString (err) << "\".");
1214 }
1215 
1216 
1217 template<typename Ordinal>
1218 void
1219 MpiComm<Ordinal>::ssend (const Ordinal bytes,
1220  const char sendBuffer[],
1221  const int destRank) const
1222 {
1223  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::ssend(...)" );
1224 
1225 #ifdef TEUCHOS_MPI_COMM_DUMP
1226  if(show_dump) {
1227  dumpBuffer<Ordinal,char>(
1228  "Teuchos::MpiComm<Ordinal>::send(...)"
1229  ,"sendBuffer", bytes, sendBuffer
1230  );
1231  }
1232 #endif // TEUCHOS_MPI_COMM_DUMP
1233 
1234  const int err = MPI_Ssend (const_cast<char*>(sendBuffer), bytes, MPI_CHAR,
1235  destRank, tag_, *rawMpiComm_);
1236  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1237  "Teuchos::MpiComm::send: MPI_Ssend() failed with error \""
1238  << mpiErrorCodeToString (err) << "\".");
1239 }
1240 
1241 template<typename Ordinal>
1242 void
1243 MpiComm<Ordinal>::ssend (const Ordinal bytes,
1244  const char sendBuffer[],
1245  const int destRank,
1246  const int tag) const
1247 {
1248  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::ssend(...)" );
1249  const int err =
1250  MPI_Ssend (const_cast<char*>(sendBuffer), bytes, MPI_CHAR,
1251  destRank, tag, *rawMpiComm_);
1252  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1253  "Teuchos::MpiComm::send: MPI_Ssend() failed with error \""
1254  << mpiErrorCodeToString (err) << "\".");
1255 }
1256 
1257 template<typename Ordinal>
1258 void MpiComm<Ordinal>::readySend(
1259  const ArrayView<const char> &sendBuffer,
1260  const int destRank
1261  ) const
1262 {
1263  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::readySend" );
1264 
1265 #ifdef TEUCHOS_MPI_COMM_DUMP
1266  if(show_dump) {
1267  dumpBuffer<Ordinal,char>(
1268  "Teuchos::MpiComm<Ordinal>::readySend(...)"
1269  ,"sendBuffer", bytes, sendBuffer
1270  );
1271  }
1272 #endif // TEUCHOS_MPI_COMM_DUMP
1273 
1274  const int err =
1275  MPI_Rsend (const_cast<char*>(sendBuffer.getRawPtr()), sendBuffer.size(),
1276  MPI_CHAR, destRank, tag_, *rawMpiComm_);
1277  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1278  "Teuchos::MpiComm::readySend: MPI_Rsend() failed with error \""
1279  << mpiErrorCodeToString (err) << "\".");
1280 }
1281 
1282 
1283 template<typename Ordinal>
1284 void MpiComm<Ordinal>::
1285 readySend (const Ordinal bytes,
1286  const char sendBuffer[],
1287  const int destRank,
1288  const int tag) const
1289 {
1290  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::readySend" );
1291  const int err =
1292  MPI_Rsend (const_cast<char*> (sendBuffer), bytes,
1293  MPI_CHAR, destRank, tag, *rawMpiComm_);
1294  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1295  "Teuchos::MpiComm::readySend: MPI_Rsend() failed with error \""
1296  << mpiErrorCodeToString (err) << "\".");
1297 }
1298 
1299 
1300 template<typename Ordinal>
1301 int
1302 MpiComm<Ordinal>::receive (const int sourceRank,
1303  const Ordinal bytes,
1304  char recvBuffer[]) const
1305 {
1306  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::receive(...)" );
1307 
1308  // A negative source rank indicates MPI_ANY_SOURCE, namely that we
1309  // will take an incoming message from any process, as long as the
1310  // tag matches.
1311  const int theSrcRank = (sourceRank < 0) ? MPI_ANY_SOURCE : sourceRank;
1312 
1313  MPI_Status status;
1314  const int err = MPI_Recv (recvBuffer, bytes, MPI_CHAR, theSrcRank, tag_,
1315  *rawMpiComm_, &status);
1316  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1317  "Teuchos::MpiComm::receive: MPI_Recv() failed with error \""
1318  << mpiErrorCodeToString (err) << "\".");
1319 
1320 #ifdef TEUCHOS_MPI_COMM_DUMP
1321  if (show_dump) {
1322  dumpBuffer<Ordinal,char> ("Teuchos::MpiComm<Ordinal>::receive(...)",
1323  "recvBuffer", bytes, recvBuffer);
1324  }
1325 #endif // TEUCHOS_MPI_COMM_DUMP
1326 
1327  // Returning the source rank is useful in the MPI_ANY_SOURCE case.
1328  return status.MPI_SOURCE;
1329 }
1330 
1331 
1332 template<typename Ordinal>
1333 RCP<CommRequest<Ordinal> >
1334 MpiComm<Ordinal>::isend (const ArrayView<const char> &sendBuffer,
1335  const int destRank) const
1336 {
1337  using Teuchos::as;
1338  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::isend(...)" );
1339 
1340  MPI_Request rawMpiRequest = MPI_REQUEST_NULL;
1341  const int err =
1342  MPI_Isend (const_cast<char*> (sendBuffer.getRawPtr ()),
1343  as<Ordinal> (sendBuffer.size ()), MPI_CHAR,
1344  destRank, tag_, *rawMpiComm_, &rawMpiRequest);
1345  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1346  "Teuchos::MpiComm::isend: MPI_Isend() failed with error \""
1347  << mpiErrorCodeToString (err) << "\".");
1348 
1349  return mpiCommRequest<Ordinal> (rawMpiRequest, sendBuffer.size ());
1350 }
1351 
1352 
1353 template<typename Ordinal>
1354 RCP<CommRequest<Ordinal> >
1355 MpiComm<Ordinal>::
1356 isend (const ArrayView<const char> &sendBuffer,
1357  const int destRank,
1358  const int tag) const
1359 {
1360  using Teuchos::as;
1361  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::isend(...)" );
1362 
1363  MPI_Request rawMpiRequest = MPI_REQUEST_NULL;
1364  const int err =
1365  MPI_Isend (const_cast<char*> (sendBuffer.getRawPtr ()),
1366  as<Ordinal> (sendBuffer.size ()), MPI_CHAR,
1367  destRank, tag, *rawMpiComm_, &rawMpiRequest);
1368  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1369  "Teuchos::MpiComm::isend: MPI_Isend() failed with error \""
1370  << mpiErrorCodeToString (err) << "\".");
1371 
1372  return mpiCommRequest<Ordinal> (rawMpiRequest, sendBuffer.size ());
1373 }
1374 
1375 
1376 template<typename Ordinal>
1377 RCP<CommRequest<Ordinal> >
1378 MpiComm<Ordinal>::ireceive (const ArrayView<char> &recvBuffer,
1379  const int sourceRank) const
1380 {
1381  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::ireceive(...)" );
1382 
1383  // A negative source rank indicates MPI_ANY_SOURCE, namely that we
1384  // will take an incoming message from any process, as long as the
1385  // tag matches.
1386  const int theSrcRank = (sourceRank < 0) ? MPI_ANY_SOURCE : sourceRank;
1387 
1388  MPI_Request rawMpiRequest = MPI_REQUEST_NULL;
1389  const int err =
1390  MPI_Irecv (const_cast<char*>(recvBuffer.getRawPtr()), recvBuffer.size(),
1391  MPI_CHAR, theSrcRank, tag_, *rawMpiComm_, &rawMpiRequest);
1392  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1393  "Teuchos::MpiComm::ireceive: MPI_Irecv() failed with error \""
1394  << mpiErrorCodeToString (err) << "\".");
1395 
1396  return mpiCommRequest<Ordinal> (rawMpiRequest, recvBuffer.size());
1397 }
1398 
1399 template<typename Ordinal>
1400 RCP<CommRequest<Ordinal> >
1401 MpiComm<Ordinal>::ireceive (const ArrayView<char> &recvBuffer,
1402  const int sourceRank,
1403  const int tag) const
1404 {
1405  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::ireceive(...)" );
1406 
1407  // A negative source rank indicates MPI_ANY_SOURCE, namely that we
1408  // will take an incoming message from any process, as long as the
1409  // tag matches.
1410  const int theSrcRank = (sourceRank < 0) ? MPI_ANY_SOURCE : sourceRank;
1411 
1412  MPI_Request rawMpiRequest = MPI_REQUEST_NULL;
1413  const int err =
1414  MPI_Irecv (const_cast<char*> (recvBuffer.getRawPtr ()), recvBuffer.size (),
1415  MPI_CHAR, theSrcRank, tag, *rawMpiComm_, &rawMpiRequest);
1416  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
1417  "Teuchos::MpiComm::ireceive: MPI_Irecv() failed with error \""
1418  << mpiErrorCodeToString (err) << "\".");
1419 
1420  return mpiCommRequest<Ordinal> (rawMpiRequest, recvBuffer.size ());
1421 }
1422 
1423 namespace {
1424  // Called by the two-argument MpiComm::waitAll() variant.
1425  template<typename Ordinal>
1426  void
1427  waitAllImpl (const ArrayView<RCP<CommRequest<Ordinal> > >& requests,
1428  const ArrayView<MPI_Status>& rawMpiStatuses)
1429  {
1430  typedef typename ArrayView<RCP<CommRequest<Ordinal> > >::size_type size_type;
1431  const size_type count = requests.size();
1432  // waitAllImpl() is not meant to be called by users, so it's a bug
1433  // for the two views to have different lengths.
1434  TEUCHOS_TEST_FOR_EXCEPTION(rawMpiStatuses.size() != count,
1435  std::logic_error, "Teuchos::MpiComm's waitAllImpl: rawMpiStatus.size() = "
1436  << rawMpiStatuses.size() << " != requests.size() = " << requests.size()
1437  << ". Please report this bug to the Tpetra developers.");
1438  if (count == 0) {
1439  return; // No requests on which to wait
1440  }
1441 
1442  // MpiComm wraps MPI and can't expose any MPI structs or opaque
1443  // objects. Thus, we have to unpack requests into a separate array.
1444  // If that's too slow, then your code should just call into MPI
1445  // directly.
1446  //
1447  // Pull out the raw MPI requests from the wrapped requests.
1448  // MPI_Waitall should not fail if a request is MPI_REQUEST_NULL, but
1449  // we keep track just to inform the user.
1450  bool someNullRequests = false;
1451  Array<MPI_Request> rawMpiRequests (count, MPI_REQUEST_NULL);
1452  for (int i = 0; i < count; ++i) {
1453  RCP<CommRequest<Ordinal> > request = requests[i];
1454  if (! is_null (request)) {
1455  RCP<MpiCommRequestBase<Ordinal> > mpiRequest =
1456  rcp_dynamic_cast<MpiCommRequestBase<Ordinal> > (request);
1457  // releaseRawMpiRequest() sets the MpiCommRequest's raw
1458  // MPI_Request to MPI_REQUEST_NULL. This makes waitAll() not
1459  // satisfy the strong exception guarantee. That's OK because
1460  // MPI_Waitall() doesn't promise that it satisfies the strong
1461  // exception guarantee, and we would rather conservatively
1462  // invalidate the handles than leave dangling requests around
1463  // and risk users trying to wait on the same request twice.
1464  rawMpiRequests[i] = mpiRequest->releaseRawMpiRequest();
1465  }
1466  else { // Null requests map to MPI_REQUEST_NULL
1467  rawMpiRequests[i] = MPI_REQUEST_NULL;
1468  someNullRequests = true;
1469  }
1470  }
1471 
1472  // This is the part where we've finally peeled off the wrapper and
1473  // we can now interact with MPI directly.
1474  //
1475  // One option in the one-argument version of waitAll() is to ignore
1476  // the statuses completely. MPI lets you pass in the named constant
1477  // MPI_STATUSES_IGNORE for the MPI_Status array output argument in
1478  // MPI_Waitall(), which would tell MPI not to bother with the
1479  // statuses. However, we want the statuses because we can use them
1480  // for detailed error diagnostics in case something goes wrong.
1481  const int err = MPI_Waitall (count, rawMpiRequests.getRawPtr(),
1482  rawMpiStatuses.getRawPtr());
1483 
1484  // In MPI_Waitall(), an error indicates that one or more requests
1485  // failed. In that case, there could be requests that completed
1486  // (their MPI_Status' error field is MPI_SUCCESS), and other
1487  // requests that have not completed yet but have not necessarily
1488  // failed (MPI_PENDING). We make no attempt here to wait on the
1489  // pending requests. It doesn't make sense for us to do so, because
1490  // in general Teuchos::Comm doesn't attempt to provide robust
1491  // recovery from failed messages.
1492  if (err != MPI_SUCCESS) {
1493  if (err == MPI_ERR_IN_STATUS) {
1494  //
1495  // When MPI_Waitall returns MPI_ERR_IN_STATUS (a standard error
1496  // class), it's telling us to check the error codes in the
1497  // returned statuses. In that case, we do so and generate a
1498  // detailed exception message.
1499  //
1500  // Figure out which of the requests failed.
1501  Array<std::pair<size_type, int> > errorLocationsAndCodes;
1502  for (size_type k = 0; k < rawMpiStatuses.size(); ++k) {
1503  const int curErr = rawMpiStatuses[k].MPI_ERROR;
1504  if (curErr != MPI_SUCCESS) {
1505  errorLocationsAndCodes.push_back (std::make_pair (k, curErr));
1506  }
1507  }
1508  const size_type numErrs = errorLocationsAndCodes.size();
1509  if (numErrs > 0) {
1510  // There was at least one error. Assemble a detailed
1511  // exception message reporting which requests failed,
1512  // their error codes, and their source
1513  std::ostringstream os;
1514  os << "Teuchos::MpiComm::waitAll: MPI_Waitall() failed with error \""
1515  << mpiErrorCodeToString (err) << "\". Of the " << count
1516  << " total request" << (count != 1 ? "s" : "") << ", " << numErrs
1517  << " failed. Here are the indices of the failed requests, and the "
1518  "error codes extracted from their returned MPI_Status objects:"
1519  << std::endl;
1520  for (size_type k = 0; k < numErrs; ++k) {
1521  const size_type errInd = errorLocationsAndCodes[k].first;
1522  os << "Request " << errInd << ": MPI_ERROR = "
1523  << mpiErrorCodeToString (rawMpiStatuses[errInd].MPI_ERROR)
1524  << std::endl;
1525  }
1526  if (someNullRequests) {
1527  os << " On input to MPI_Waitall, there was at least one MPI_"
1528  "Request that was MPI_REQUEST_NULL. MPI_Waitall should not "
1529  "normally fail in that case, but we thought we should let you know "
1530  "regardless.";
1531  }
1532  TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, os.str());
1533  }
1534  // If there were no actual errors in the returned statuses,
1535  // well, then I guess everything is OK. Just keep going.
1536  }
1537  else {
1538  std::ostringstream os;
1539  os << "Teuchos::MpiComm::waitAll: MPI_Waitall() failed with error \""
1540  << mpiErrorCodeToString (err) << "\".";
1541  if (someNullRequests) {
1542  os << " On input to MPI_Waitall, there was at least one MPI_Request "
1543  "that was MPI_REQUEST_NULL. MPI_Waitall should not normally fail in "
1544  "that case, but we thought we should let you know regardless.";
1545  }
1546  TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, os.str());
1547  }
1548  }
1549 
1550  // Invalidate the input array of requests by setting all entries
1551  // to null.
1552  std::fill (requests.begin(), requests.end(), null);
1553  }
1554 
1555 
1556 
1557  // Called by the one-argument MpiComm::waitAll() variant.
1558  template<typename Ordinal>
1559  void
1560  waitAllImpl (const ArrayView<RCP<CommRequest<Ordinal> > >& requests)
1561  {
1562  typedef typename ArrayView<RCP<CommRequest<Ordinal> > >::size_type size_type;
1563  const size_type count = requests.size ();
1564  if (count == 0) {
1565  return; // No requests on which to wait
1566  }
1567 
1568  // MpiComm wraps MPI and can't expose any MPI structs or opaque
1569  // objects. Thus, we have to unpack requests into a separate
1570  // array. If that's too slow, then your code should just call
1571  // into MPI directly.
1572  //
1573  // Pull out the raw MPI requests from the wrapped requests.
1574  // MPI_Waitall should not fail if a request is MPI_REQUEST_NULL,
1575  // but we keep track just to inform the user.
1576  bool someNullRequests = false;
1577  Array<MPI_Request> rawMpiRequests (count, MPI_REQUEST_NULL);
1578  for (int i = 0; i < count; ++i) {
1579  RCP<CommRequest<Ordinal> > request = requests[i];
1580  if (! request.is_null ()) {
1581  RCP<MpiCommRequestBase<Ordinal> > mpiRequest =
1582  rcp_dynamic_cast<MpiCommRequestBase<Ordinal> > (request);
1583  // releaseRawMpiRequest() sets the MpiCommRequest's raw
1584  // MPI_Request to MPI_REQUEST_NULL. This makes waitAll() not
1585  // satisfy the strong exception guarantee. That's OK because
1586  // MPI_Waitall() doesn't promise that it satisfies the strong
1587  // exception guarantee, and we would rather conservatively
1588  // invalidate the handles than leave dangling requests around
1589  // and risk users trying to wait on the same request twice.
1590  rawMpiRequests[i] = mpiRequest->releaseRawMpiRequest ();
1591  }
1592  else { // Null requests map to MPI_REQUEST_NULL
1593  rawMpiRequests[i] = MPI_REQUEST_NULL;
1594  someNullRequests = true;
1595  }
1596  }
1597 
1598  // This is the part where we've finally peeled off the wrapper and
1599  // we can now interact with MPI directly.
1600  //
1601  // MPI lets us pass in the named constant MPI_STATUSES_IGNORE for
1602  // the MPI_Status array output argument in MPI_Waitall(), which
1603  // tells MPI not to bother writing out the statuses.
1604  const int err = MPI_Waitall (count, rawMpiRequests.getRawPtr(),
1605  MPI_STATUSES_IGNORE);
1606 
1607  // In MPI_Waitall(), an error indicates that one or more requests
1608  // failed. In that case, there could be requests that completed
1609  // (their MPI_Status' error field is MPI_SUCCESS), and other
1610  // requests that have not completed yet but have not necessarily
1611  // failed (MPI_PENDING). We make no attempt here to wait on the
1612  // pending requests. It doesn't make sense for us to do so,
1613  // because in general Teuchos::Comm doesn't attempt to provide
1614  // robust recovery from failed messages.
1615  if (err != MPI_SUCCESS) {
1616  std::ostringstream os;
1617  os << "Teuchos::MpiComm::waitAll: MPI_Waitall() failed with error \""
1618  << mpiErrorCodeToString (err) << "\".";
1619  if (someNullRequests) {
1620  os << std::endl << "On input to MPI_Waitall, there was at least one "
1621  "MPI_Request that was MPI_REQUEST_NULL. MPI_Waitall should not "
1622  "normally fail in that case, but we thought we should let you know "
1623  "regardless.";
1624  }
1625  TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, os.str());
1626  }
1627 
1628  // Invalidate the input array of requests by setting all entries
1629  // to null. We delay this until the end, since some
1630  // implementations of CommRequest might hold the only reference to
1631  // the communication buffer, and we don't want that to go away
1632  // until we've waited on the communication operation.
1633  std::fill (requests.begin(), requests.end(), null);
1634  }
1635 
1636 } // namespace (anonymous)
1637 
1638 
1639 
1640 template<typename Ordinal>
1641 void
1642 MpiComm<Ordinal>::
1643 waitAll (const ArrayView<RCP<CommRequest<Ordinal> > >& requests) const
1644 {
1645  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::waitAll(requests)" );
1646  // Call the one-argument version of waitAllImpl, to avoid overhead
1647  // of handling statuses (which the user didn't want anyway).
1648  waitAllImpl<Ordinal> (requests);
1649 }
1650 
1651 
1652 template<typename Ordinal>
1653 void
1654 MpiComm<Ordinal>::
1655 waitAll (const ArrayView<RCP<CommRequest<Ordinal> > >& requests,
1656  const ArrayView<RCP<CommStatus<Ordinal> > >& statuses) const
1657 {
1658  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::waitAll(requests, statuses)" );
1659 
1660  typedef typename ArrayView<RCP<CommRequest<Ordinal> > >::size_type size_type;
1661  const size_type count = requests.size();
1662 
1663  TEUCHOS_TEST_FOR_EXCEPTION(count != statuses.size(),
1664  std::invalid_argument, "Teuchos::MpiComm::waitAll: requests.size() = "
1665  << count << " != statuses.size() = " << statuses.size() << ".");
1666 
1667  Array<MPI_Status> rawMpiStatuses (count);
1668  waitAllImpl<Ordinal> (requests, rawMpiStatuses());
1669 
1670  // Repackage the raw MPI_Status structs into the wrappers.
1671  for (size_type i = 0; i < count; ++i) {
1672  statuses[i] = mpiCommStatus<Ordinal> (rawMpiStatuses[i]);
1673  }
1674 }
1675 
1676 
1677 template<typename Ordinal>
1678 RCP<CommStatus<Ordinal> >
1679 MpiComm<Ordinal>::wait (const Ptr<RCP<CommRequest<Ordinal> > >& request) const
1680 {
1681  TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::wait(...)" );
1682 
1683  if (is_null (*request)) {
1684  return null; // Nothing to wait on ...
1685  }
1686  else {
1687  RCP<CommStatus<Ordinal> > status = (*request)->wait ();
1688  // mfh 22 Oct 2012: The unit tests expect waiting on the
1689  // CommRequest to invalidate it by setting it to null.
1690  *request = null;
1691  return status;
1692  }
1693 }
1694 
1695 template<typename Ordinal>
1696 RCP< Comm<Ordinal> >
1697 MpiComm<Ordinal>::duplicate() const
1698 {
1699  MPI_Comm origRawComm = *rawMpiComm_;
1700  MPI_Comm newRawComm = MPI_COMM_NULL;
1701  const int err = MPI_Comm_dup (origRawComm, &newRawComm);
1702  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error, "Teuchos"
1703  "::MpiComm::duplicate: MPI_Comm_dup failed with the following error: "
1704  << mpiErrorCodeToString (err));
1705 
1706  // Wrap the raw communicator, and pass the (const) wrapped
1707  // communicator to MpiComm's constructor. We created the raw comm,
1708  // so we have to supply a function that frees it after use.
1709  RCP<OpaqueWrapper<MPI_Comm> > wrapped =
1710  opaqueWrapper<MPI_Comm> (newRawComm, details::safeCommFree);
1711  // Since newComm's raw MPI_Comm is the result of an MPI_Comm_dup,
1712  // its messages cannot collide with those of any other MpiComm.
1713  // This means we can assign its tag without an MPI_Bcast.
1714  RCP<MpiComm<Ordinal> > newComm =
1715  rcp (new MpiComm<Ordinal> (wrapped.getConst (), minTag_));
1716  return rcp_implicit_cast<Comm<Ordinal> > (newComm);
1717 }
1718 
1719 
1720 template<typename Ordinal>
1721 RCP< Comm<Ordinal> >
1722 MpiComm<Ordinal>::split(const int color, const int key) const
1723 {
1724  MPI_Comm newComm;
1725  const int splitReturn =
1726  MPI_Comm_split (*rawMpiComm_,
1727  color < 0 ? MPI_UNDEFINED : color,
1728  key,
1729  &newComm);
1731  splitReturn != MPI_SUCCESS,
1732  std::logic_error,
1733  "Teuchos::MpiComm::split: Failed to create communicator with color "
1734  << color << "and key " << key << ". MPI_Comm_split failed with error \""
1735  << mpiErrorCodeToString (splitReturn) << "\".");
1736  if (newComm == MPI_COMM_NULL) {
1737  return RCP< Comm<Ordinal> >();
1738  } else {
1739  RCP<const OpaqueWrapper<MPI_Comm> > wrapped =
1740  opaqueWrapper<MPI_Comm> (newComm, details::safeCommFree);
1741  // Since newComm's raw MPI_Comm is the result of an
1742  // MPI_Comm_split, its messages cannot collide with those of any
1743  // other MpiComm. This means we can assign its tag without an
1744  // MPI_Bcast.
1745  return rcp (new MpiComm<Ordinal> (wrapped, minTag_));
1746  }
1747 }
1748 
1749 
1750 template<typename Ordinal>
1751 RCP< Comm<Ordinal> >
1752 MpiComm<Ordinal>::createSubcommunicator(const ArrayView<const int> &ranks) const
1753 {
1754  int err = MPI_SUCCESS; // For error codes returned by MPI functions
1755 
1756  // Get the group that this communicator is in.
1757  MPI_Group thisGroup;
1758  err = MPI_Comm_group (*rawMpiComm_, &thisGroup);
1759  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::logic_error,
1760  "Failed to obtain the current communicator's group. "
1761  "MPI_Comm_group failed with error \""
1762  << mpiErrorCodeToString (err) << "\".");
1763 
1764  // Create a new group with the specified members.
1765  MPI_Group newGroup;
1766  // It's rude to cast away const, but MPI functions demand it.
1767  //
1768  // NOTE (mfh 14 Aug 2012) Please don't ask for &ranks[0] unless you
1769  // know that ranks.size() > 0. That's why I'm using getRawPtr().
1770  err = MPI_Group_incl (thisGroup, ranks.size(),
1771  const_cast<int*> (ranks.getRawPtr ()), &newGroup);
1772  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::logic_error,
1773  "Failed to create subgroup. MPI_Group_incl failed with error \""
1774  << mpiErrorCodeToString (err) << "\".");
1775 
1776  // Create a new communicator from the new group.
1777  MPI_Comm newComm;
1778  try {
1779  err = MPI_Comm_create (*rawMpiComm_, newGroup, &newComm);
1780  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::logic_error,
1781  "Failed to create subcommunicator. MPI_Comm_create failed with error \""
1782  << mpiErrorCodeToString (err) << "\".");
1783  } catch (...) {
1784  // Attempt to free the new group before rethrowing. If
1785  // successful, this will prevent a memory leak due to the "lost"
1786  // group that was allocated successfully above. Since we're
1787  // throwing std::logic_error anyway, we can only promise
1788  // best-effort recovery; thus, we don't check the error code.
1789  (void) MPI_Group_free (&newGroup);
1790  (void) MPI_Group_free (&thisGroup);
1791  throw;
1792  }
1793 
1794  // We don't need the group any more, so free it.
1795  err = MPI_Group_free (&newGroup);
1796  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::logic_error,
1797  "Failed to free subgroup. MPI_Group_free failed with error \""
1798  << mpiErrorCodeToString (err) << "\".");
1799  err = MPI_Group_free (&thisGroup);
1800  TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::logic_error,
1801  "Failed to free subgroup. MPI_Group_free failed with error \""
1802  << mpiErrorCodeToString (err) << "\".");
1803 
1804  if (newComm == MPI_COMM_NULL) {
1805  return RCP<Comm<Ordinal> > ();
1806  } else {
1807  using Teuchos::details::safeCommFree;
1808  typedef OpaqueWrapper<MPI_Comm> ow_type;
1809  RCP<const ow_type> wrapper =
1810  rcp_implicit_cast<const ow_type> (opaqueWrapper (newComm, safeCommFree));
1811  // Since newComm's raw MPI_Comm is the result of an
1812  // MPI_Comm_create, its messages cannot collide with those of any
1813  // other MpiComm. This means we can assign its tag without an
1814  // MPI_Bcast.
1815  return rcp (new MpiComm<Ordinal> (wrapper, minTag_));
1816  }
1817 }
1818 
1819 
1820 // Overridden from Describable
1821 
1822 
1823 template<typename Ordinal>
1824 std::string MpiComm<Ordinal>::description() const
1825 {
1826  std::ostringstream oss;
1827  oss
1828  << typeName(*this)
1829  << "{"
1830  << "size="<<size_
1831  << ",rank="<<rank_
1832  << ",rawMpiComm="<<static_cast<MPI_Comm>(*rawMpiComm_)
1833  <<"}";
1834  return oss.str();
1835 }
1836 
1837 
1838 #ifdef TEUCHOS_MPI_COMM_DUMP
1839 template<typename Ordinal>
1840 bool MpiComm<Ordinal>::show_dump = false;
1841 #endif
1842 
1843 
1844 // private
1845 
1846 
1847 template<typename Ordinal>
1848 void MpiComm<Ordinal>::assertRank(const int rank, const std::string &rankName) const
1849 {
1851  ! ( 0 <= rank && rank < size_ ), std::logic_error
1852  ,"Error, "<<rankName<<" = " << rank << " is not < 0 or is not"
1853  " in the range [0,"<<size_-1<<"]!"
1854  );
1855 }
1856 
1857 
1858 } // namespace Teuchos
1859 
1860 
1861 template<typename Ordinal>
1863 Teuchos::createMpiComm(
1864  const RCP<const OpaqueWrapper<MPI_Comm> > &rawMpiComm
1865  )
1866 {
1867  if( rawMpiComm.get()!=NULL && *rawMpiComm != MPI_COMM_NULL )
1868  return rcp(new MpiComm<Ordinal>(rawMpiComm));
1869  return Teuchos::null;
1870 }
1871 
1872 
1873 template<typename Ordinal>
1874 MPI_Comm
1875 Teuchos::getRawMpiComm(const Comm<Ordinal> &comm)
1876 {
1877  return *(
1878  dyn_cast<const MpiComm<Ordinal> >(comm).getRawMpiComm()
1879  );
1880 }
1881 
1882 
1883 #endif // HAVE_TEUCHOS_MPI
1884 #endif // TEUCHOS_MPI_COMM_HPP
1885 
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.
#define TEUCHOS_TEST_FOR_EXCEPT(throw_exception_test)
This macro is designed to be a short version of TEUCHOS_TEST_FOR_EXCEPTION() that is easier to call...
TEUCHOSCORE_LIB_DLL_EXPORT Teuchos::RCP< WorkspaceStore > get_default_workspace_store()
Get the global workspace object set by set_default_workspace_store().
std::string typeName(const T &t)
Template function for returning the concrete type name of a passed-in object.