Teuchos - Trilinos Tools Package Version of the Day
Teuchos_DefaultMpiComm.hpp
00001 // @HEADER
00002 // ***********************************************************************
00003 //
00004 //                    Teuchos: Common Tools Package
00005 //                 Copyright (2004) Sandia Corporation
00006 //
00007 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
00008 // license for use of this work by or on behalf of the U.S. Government.
00009 //
00010 // Redistribution and use in source and binary forms, with or without
00011 // modification, are permitted provided that the following conditions are
00012 // met:
00013 //
00014 // 1. Redistributions of source code must retain the above copyright
00015 // notice, this list of conditions and the following disclaimer.
00016 //
00017 // 2. Redistributions in binary form must reproduce the above copyright
00018 // notice, this list of conditions and the following disclaimer in the
00019 // documentation and/or other materials provided with the distribution.
00020 //
00021 // 3. Neither the name of the Corporation nor the names of the
00022 // contributors may be used to endorse or promote products derived from
00023 // this software without specific prior written permission.
00024 //
00025 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
00026 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00027 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00028 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
00029 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00030 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00031 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00032 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00033 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00034 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00035 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00036 //
00037 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
00038 //
00039 // ***********************************************************************
00040 // @HEADER
00041 
00042 #ifndef TEUCHOS_MPI_COMM_HPP
00043 #define TEUCHOS_MPI_COMM_HPP
00044 
00045 
00046 #include "Teuchos_Comm.hpp"
00047 #include "Teuchos_CommUtilities.hpp"
00048 #include "Teuchos_OrdinalTraits.hpp"
00049 #include "Teuchos_OpaqueWrapper.hpp"
00050 #include "Teuchos_MpiReductionOpSetter.hpp"
00051 #include "Teuchos_SerializationTraitsHelpers.hpp"
00052 #include "Teuchos_Workspace.hpp"
00053 #include "Teuchos_TypeNameTraits.hpp"
00054 #include "Teuchos_as.hpp"
00055 #include "Teuchos_Assert.hpp"
00056 #include "mpi.h"
00057 #include <iterator>
00058 
00059 // This must be defined globally for the whole program!
00060 //#define TEUCHOS_MPI_COMM_DUMP
00061 
00062 
00063 #ifdef TEUCHOS_MPI_COMM_DUMP
00064 #  include "Teuchos_VerboseObject.hpp"
00065 #endif
00066 
00067 
00068 namespace Teuchos {
00069 
00071 std::string
00072 mpiErrorCodeToString (const int err);
00073 
00074 namespace details {
00088   void safeCommFree (MPI_Comm* comm);
00089 
00094   int setCommErrhandler (MPI_Comm comm, MPI_Errhandler handler);
00095 
00096 } // namespace details
00097 
00098 #ifdef TEUCHOS_MPI_COMM_DUMP
00099 template<typename Ordinal, typename T>
00100 void dumpBuffer(
00101   const std::string &funcName, const std::string &buffName
00102   ,const Ordinal bytes, const T buff[]
00103   )
00104 {
00105   Teuchos::RCP<Teuchos::FancyOStream>
00106     out = Teuchos::VerboseObjectBase::getDefaultOStream();
00107   Teuchos::OSTab tab(out);
00108   *out
00109     << "\n" << funcName << "::" << buffName << ":\n";
00110   tab.incrTab();
00111   for( Ordinal i = 0; i < bytes; ++i ) {
00112     *out << buffName << "[" << i << "] = '" << buff[i] << "'\n";
00113   }
00114   *out << "\n";
00115 }
00116 #endif // TEUCHOS_MPI_COMM_DUMP
00117 
00118 
00130 template<class OrdinalType>
00131 class MpiCommStatus : public CommStatus<OrdinalType> {
00132 public:
00133   MpiCommStatus (MPI_Status status) : status_ (status) {}
00134 
00136   virtual ~MpiCommStatus() {}
00137 
00139   OrdinalType getSourceRank () { return status_.MPI_SOURCE; }
00140 
00142   OrdinalType getTag () { return status_.MPI_TAG; }
00143 
00145   OrdinalType getError () { return status_.MPI_ERROR; }
00146 
00147 private:
00149   MpiCommStatus ();
00150 
00152   MPI_Status status_;
00153 };
00154 
00158 template<class OrdinalType>
00159 inline RCP<MpiCommStatus<OrdinalType> >
00160 mpiCommStatus (MPI_Status rawMpiStatus)
00161 {
00162   return rcp (new MpiCommStatus<OrdinalType> (rawMpiStatus));
00163 }
00164 
00165 
00181 template<class OrdinalType>
00182 class MpiCommRequestBase : public CommRequest<OrdinalType> {
00183 public:
00185   MpiCommRequestBase () :
00186     rawMpiRequest_ (MPI_REQUEST_NULL)
00187   {}
00188 
00190   MpiCommRequestBase (MPI_Request rawMpiRequest) :
00191     rawMpiRequest_ (rawMpiRequest)
00192   {}
00193 
00201   MPI_Request releaseRawMpiRequest()
00202   {
00203     MPI_Request tmp_rawMpiRequest = rawMpiRequest_;
00204     rawMpiRequest_ = MPI_REQUEST_NULL;
00205     return tmp_rawMpiRequest;
00206   }
00207 
00209   bool isNull() const {
00210     return rawMpiRequest_ == MPI_REQUEST_NULL;
00211   }
00212 
00218   RCP<CommStatus<OrdinalType> > wait () {
00219     MPI_Status rawMpiStatus;
00220     // Whether this function satisfies the strong exception guarantee
00221     // depends on whether MPI_Wait modifies its input request on error.
00222     const int err = MPI_Wait (&rawMpiRequest_, &rawMpiStatus);
00223     TEUCHOS_TEST_FOR_EXCEPTION(
00224       err != MPI_SUCCESS, std::runtime_error,
00225       "Teuchos: MPI_Wait() failed with error \""
00226       << mpiErrorCodeToString (err));
00227     // MPI_Wait sets the MPI_Request to MPI_REQUEST_NULL on success.
00228     return mpiCommStatus<OrdinalType> (rawMpiStatus);
00229   }
00230 
00235   RCP<CommStatus<OrdinalType> > cancel () {
00236     if (rawMpiRequest_ == MPI_REQUEST_NULL) {
00237       return null;
00238     }
00239     else {
00240       int err = MPI_Cancel (&rawMpiRequest_);
00241       TEUCHOS_TEST_FOR_EXCEPTION(
00242         err != MPI_SUCCESS, std::runtime_error,
00243         "Teuchos: MPI_Cancel failed with the following error: "
00244         << mpiErrorCodeToString (err));
00245 
00246       // Wait on the request.  If successful, MPI_Wait will set the
00247       // MPI_Request to MPI_REQUEST_NULL.  The returned status may
00248       // still be useful; for example, one may call MPI_Test_cancelled
00249       // to test an MPI_Status from a nonblocking send.
00250       MPI_Status status;
00251       err = MPI_Wait (&rawMpiRequest_, &status);
00252       TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
00253         "Teuchos::MpiCommStatus::cancel: MPI_Wait failed with the following "
00254         "error: " << mpiErrorCodeToString (err));
00255       return mpiCommStatus<OrdinalType> (status);
00256     }
00257   }
00258 
00260   virtual ~MpiCommRequestBase () {
00261     if (rawMpiRequest_ != MPI_REQUEST_NULL) {
00262       // We're in a destructor, so don't throw errors.  However, if
00263       // MPI_Cancel fails, it's probably a bad idea to call MPI_Wait.
00264       const int err = MPI_Cancel (&rawMpiRequest_);
00265       if (err == MPI_SUCCESS) {
00266         // The MPI_Cancel succeeded.  Now wait on the request.  Ignore
00267         // any reported error, since we can't do anything about those
00268         // in the destructor (other than kill the program).  If
00269         // successful, MPI_Wait will set the MPI_Request to
00270         // MPI_REQUEST_NULL.  We ignore the returned MPI_Status, since
00271         // if the user let the request fall out of scope, she must not
00272         // care about the status.
00273         //
00274         // mfh 21 Oct 2012: The MPI standard requires completing a
00275         // canceled request by calling a function like MPI_Wait,
00276         // MPI_Test, or MPI_Request_free.  MPI_Wait on a canceled
00277         // request behaves like a local operation (it does not
00278         // communicate or block waiting for communication).  One could
00279         // also call MPI_Request_free instead of MPI_Wait, but
00280         // MPI_Request_free is intended more for persistent requests
00281         // (created with functions like MPI_Recv_init).
00282         (void) MPI_Wait (&rawMpiRequest_, MPI_STATUS_IGNORE);
00283       }
00284     }
00285   }
00286 
00287 private:
00289   MPI_Request rawMpiRequest_;
00290 };
00291 
00292 
00308 template<class OrdinalType>
00309 class MpiCommRequest : public MpiCommRequestBase<OrdinalType> {
00310 public:
00312   MpiCommRequest () :
00313     MpiCommRequestBase<OrdinalType> (MPI_REQUEST_NULL),
00314     numBytes_ (0)
00315   {}
00316 
00318   MpiCommRequest (MPI_Request rawMpiRequest,
00319                   const ArrayView<char>::size_type numBytesInMessage) :
00320     MpiCommRequestBase<OrdinalType> (rawMpiRequest),
00321     numBytes_ (numBytesInMessage)
00322   {}
00323 
00329   ArrayView<char>::size_type numBytes () const {
00330     return numBytes_;
00331   }
00332 
00334   virtual ~MpiCommRequest () {}
00335 
00336 private:
00338   ArrayView<char>::size_type numBytes_;
00339 };
00340 
00349 template<class OrdinalType>
00350 inline RCP<MpiCommRequest<OrdinalType> >
00351 mpiCommRequest (MPI_Request rawMpiRequest,
00352                 const ArrayView<char>::size_type numBytes)
00353 {
00354   return rcp (new MpiCommRequest<OrdinalType> (rawMpiRequest, numBytes));
00355 }
00356 
00372 template<typename Ordinal>
00373 class MpiComm : public Comm<Ordinal> {
00374 public:
00375 
00377 
00378 
00399   explicit MpiComm (MPI_Comm rawMpiComm);
00400 
00415   MpiComm(
00416     const RCP<const OpaqueWrapper<MPI_Comm> > &rawMpiComm
00417     );
00418 
00419 private:
00437   MpiComm (const RCP<const OpaqueWrapper<MPI_Comm> >& rawMpiComm,
00438            const int defaultTag);
00439 
00440 public:
00441 
00458   MpiComm(const MpiComm<Ordinal>& other);
00459 
00461   RCP<const OpaqueWrapper<MPI_Comm> > getRawMpiComm() const
00462   {return rawMpiComm_;}
00463 
00528   void setErrorHandler (const RCP<const OpaqueWrapper<MPI_Errhandler> >& errHandler);
00529 
00531 
00532 
00533 
00535   virtual int getRank() const;
00537   virtual int getSize() const;
00539   virtual void barrier() const;
00541   virtual void broadcast(
00542     const int rootRank, const Ordinal bytes, char buffer[]
00543     ) const;
00545   virtual void
00546   gather (const Ordinal sendBytes, const char sendBuffer[],
00547           const Ordinal recvBytes, char recvBuffer[],
00548           const int root) const;
00550   virtual void gatherAll(
00551     const Ordinal sendBytes, const char sendBuffer[]
00552     ,const Ordinal recvBytes, char recvBuffer[]
00553     ) const;
00555   virtual void reduceAll(
00556     const ValueTypeReductionOp<Ordinal,char> &reductOp
00557     ,const Ordinal bytes, const char sendBuffer[], char globalReducts[]
00558     ) const;
00560   virtual void reduceAllAndScatter(
00561     const ValueTypeReductionOp<Ordinal,char> &reductOp
00562     ,const Ordinal sendBytes, const char sendBuffer[]
00563     ,const Ordinal recvCounts[], char myGlobalReducts[]
00564     ) const;
00566   virtual void scan(
00567     const ValueTypeReductionOp<Ordinal,char> &reductOp
00568     ,const Ordinal bytes, const char sendBuffer[], char scanReducts[]
00569     ) const;
00571   virtual void send(
00572     const Ordinal bytes, const char sendBuffer[], const int destRank
00573     ) const;
00575   virtual void
00576   send (const Ordinal bytes,
00577         const char sendBuffer[],
00578         const int destRank,
00579         const int tag) const;
00581   virtual void ssend(
00582     const Ordinal bytes, const char sendBuffer[], const int destRank
00583     ) const;
00585   virtual void
00586   ssend (const Ordinal bytes,
00587          const char sendBuffer[],
00588          const int destRank,
00589          const int tag) const;
00591   virtual int receive(
00592     const int sourceRank, const Ordinal bytes, char recvBuffer[]
00593     ) const;
00595   virtual void readySend(
00596     const ArrayView<const char> &sendBuffer,
00597     const int destRank
00598     ) const;
00600   virtual void
00601   readySend (const Ordinal bytes,
00602              const char sendBuffer[],
00603              const int destRank,
00604              const int tag) const;
00606   virtual RCP<CommRequest<Ordinal> > isend(
00607     const ArrayView<const char> &sendBuffer,
00608     const int destRank
00609     ) const;
00611   virtual RCP<CommRequest<Ordinal> >
00612   isend (const ArrayView<const char> &sendBuffer,
00613          const int destRank,
00614          const int tag) const;
00616   virtual RCP<CommRequest<Ordinal> > ireceive(
00617     const ArrayView<char> &Buffer,
00618     const int sourceRank
00619     ) const;
00621   virtual RCP<CommRequest<Ordinal> >
00622   ireceive (const ArrayView<char> &Buffer,
00623             const int sourceRank,
00624             const int tag) const;
00626   virtual void waitAll(
00627     const ArrayView<RCP<CommRequest<Ordinal> > > &requests
00628     ) const;
00630   virtual void
00631   waitAll (const ArrayView<RCP<CommRequest<Ordinal> > >& requests,
00632            const ArrayView<RCP<CommStatus<Ordinal> > >& statuses) const;
00634   virtual RCP<CommStatus<Ordinal> >
00635   wait (const Ptr<RCP<CommRequest<Ordinal> > >& request) const;
00637   virtual RCP< Comm<Ordinal> > duplicate() const;
00639   virtual RCP< Comm<Ordinal> > split(const int color, const int key) const;
00641   virtual RCP< Comm<Ordinal> > createSubcommunicator(
00642     const ArrayView<const int>& ranks) const;
00643 
00645 
00646 
00647 
00649   std::string description() const;
00650 
00652 
00653   // These should be private but the PGI compiler requires them be public
00654 
00655   static int const minTag_ = 26000; // These came from Teuchos::MpiComm???
00656   static int const maxTag_ = 26099; // ""
00657 
00663   int getTag () const { return tag_; }
00664 
00665 private:
00666 
00670   void setupMembersFromComm();
00671   static int tagCounter_;
00672 
00680   RCP<const OpaqueWrapper<MPI_Comm> > rawMpiComm_;
00681 
00683   int rank_;
00684 
00686   int size_;
00687 
00695   int tag_;
00696 
00698   RCP<const OpaqueWrapper<MPI_Errhandler> > customErrorHandler_;
00699 
00700   void assertRank(const int rank, const std::string &rankName) const;
00701 
00702   // Not defined and not to be called!
00703   MpiComm();
00704 
00705 #ifdef TEUCHOS_MPI_COMM_DUMP
00706 public:
00707   static bool show_dump;
00708 #endif // TEUCHOS_MPI_COMM_DUMP
00709 
00710 };
00711 
00712 
00726 template<typename Ordinal>
00727 RCP<MpiComm<Ordinal> >
00728 createMpiComm(
00729   const RCP<const OpaqueWrapper<MPI_Comm> > &rawMpiComm
00730   );
00731 
00732 
00733 // ////////////////////////
00734 // Implementations
00735 
00736 
00737 // Static members
00738 
00739 
00740 template<typename Ordinal>
00741 int MpiComm<Ordinal>::tagCounter_ = MpiComm<Ordinal>::minTag_;
00742 
00743 
00744 // Constructors
00745 
00746 
00747 template<typename Ordinal>
00748 MpiComm<Ordinal>::
00749 MpiComm (const RCP<const OpaqueWrapper<MPI_Comm> >& rawMpiComm)
00750 {
00751   TEUCHOS_TEST_FOR_EXCEPTION(
00752     rawMpiComm.get () == NULL, std::invalid_argument,
00753     "Teuchos::MpiComm constructor: The input RCP is null.");
00754   TEUCHOS_TEST_FOR_EXCEPTION(
00755     *rawMpiComm == MPI_COMM_NULL, std::invalid_argument,
00756     "Teuchos::MpiComm constructor: The given MPI_Comm is MPI_COMM_NULL.");
00757 
00758   rawMpiComm_ = rawMpiComm;
00759 
00760   // mfh 09 Jul 2013: Please resist the temptation to modify the given
00761   // MPI communicator's error handler here.  See Bug 5943.  Note that
00762   // an MPI communicator's default error handler is
00763   // MPI_ERRORS_ARE_FATAL, which immediately aborts on error (without
00764   // returning an error code from the MPI function).  Users who want
00765   // MPI functions instead to return an error code if they encounter
00766   // an error, should set the error handler to MPI_ERRORS_RETURN.  DO
00767   // NOT SET THE ERROR HANDLER HERE!!!  Teuchos' MPI wrappers should
00768   // always check the error code returned by an MPI function,
00769   // regardless of the error handler.  Users who want to set the error
00770   // handler on an MpiComm may call its setErrorHandler method.
00771 
00772   setupMembersFromComm ();
00773 }
00774 
00775 
00776 template<typename Ordinal>
00777 MpiComm<Ordinal>::
00778 MpiComm (const RCP<const OpaqueWrapper<MPI_Comm> >& rawMpiComm,
00779          const int defaultTag)
00780 {
00781   TEUCHOS_TEST_FOR_EXCEPTION(
00782     rawMpiComm.get () == NULL, std::invalid_argument,
00783     "Teuchos::MpiComm constructor: The input RCP is null.");
00784   TEUCHOS_TEST_FOR_EXCEPTION(
00785     *rawMpiComm == MPI_COMM_NULL, std::invalid_argument,
00786     "Teuchos::MpiComm constructor: The given MPI_Comm is MPI_COMM_NULL.");
00787 
00788   rawMpiComm_ = rawMpiComm;
00789   // Set size_ (the number of processes in the communicator).
00790   int err = MPI_Comm_size (*rawMpiComm_, &size_);
00791   TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
00792     "Teuchos::MpiComm constructor: MPI_Comm_size failed with "
00793     "error \"" << mpiErrorCodeToString (err) << "\".");
00794   // Set rank_ (the calling process' rank).
00795   err = MPI_Comm_rank (*rawMpiComm_, &rank_);
00796   TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
00797     "Teuchos::MpiComm constructor: MPI_Comm_rank failed with "
00798     "error \"" << mpiErrorCodeToString (err) << "\".");
00799   tag_ = defaultTag; // set the default message tag
00800 }
00801 
00802 
00803 template<typename Ordinal>
00804 MpiComm<Ordinal>::MpiComm (MPI_Comm rawMpiComm)
00805 {
00806   TEUCHOS_TEST_FOR_EXCEPTION(rawMpiComm == MPI_COMM_NULL,
00807     std::invalid_argument, "Teuchos::MpiComm constructor: The given MPI_Comm "
00808     "is MPI_COMM_NULL.");
00809   // We don't supply a "free" function here, since this version of the
00810   // constructor makes the caller responsible for freeing rawMpiComm
00811   // after use if necessary.
00812   rawMpiComm_ = opaqueWrapper<MPI_Comm> (rawMpiComm);
00813 
00814   // mfh 09 Jul 2013: Please resist the temptation to modify the given
00815   // MPI communicator's error handler here.  See Bug 5943.  Note that
00816   // an MPI communicator's default error handler is
00817   // MPI_ERRORS_ARE_FATAL, which immediately aborts on error (without
00818   // returning an error code from the MPI function).  Users who want
00819   // MPI functions instead to return an error code if they encounter
00820   // an error, should set the error handler to MPI_ERRORS_RETURN.  DO
00821   // NOT SET THE ERROR HANDLER HERE!!!  Teuchos' MPI wrappers should
00822   // always check the error code returned by an MPI function,
00823   // regardless of the error handler.  Users who want to set the error
00824   // handler on an MpiComm may call its setErrorHandler method.
00825 
00826   setupMembersFromComm ();
00827 }
00828 
00829 
00830 template<typename Ordinal>
00831 MpiComm<Ordinal>::MpiComm (const MpiComm<Ordinal>& other) :
00832   rawMpiComm_ (opaqueWrapper<MPI_Comm> (MPI_COMM_NULL)) // <- This will be set below
00833 {
00834   // These are logic errors, since they violate MpiComm's invariants.
00835   RCP<const OpaqueWrapper<MPI_Comm> > origCommPtr = other.getRawMpiComm ();
00836   TEUCHOS_TEST_FOR_EXCEPTION(origCommPtr == null, std::logic_error,
00837     "Teuchos::MpiComm copy constructor: "
00838     "The input's getRawMpiComm() method returns null.");
00839   MPI_Comm origComm = *origCommPtr;
00840   TEUCHOS_TEST_FOR_EXCEPTION(origComm == MPI_COMM_NULL, std::logic_error,
00841     "Teuchos::MpiComm copy constructor: "
00842     "The input's raw MPI_Comm is MPI_COMM_NULL.");
00843 
00844   // mfh 19 Oct 2012: Don't change the behavior of MpiComm's copy
00845   // constructor for now.  Later, we'll switch to the version that
00846   // calls MPI_Comm_dup.  For now, we just copy other's handle over.
00847   // Note that the new MpiComm's tag is still different than the input
00848   // MpiComm's tag.  See Bug 5740.
00849   if (true) {
00850     rawMpiComm_ = origCommPtr;
00851   }
00852   else { // false (not run)
00853     MPI_Comm newComm;
00854     const int err = MPI_Comm_dup (origComm, &newComm);
00855     TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
00856       "Teuchos::MpiComm copy constructor: MPI_Comm_dup failed with "
00857       "the following error: " << mpiErrorCodeToString (err));
00858     // No side effects until after everything has succeeded.
00859     rawMpiComm_ = opaqueWrapper (newComm, details::safeCommFree);
00860   }
00861 
00862   setupMembersFromComm ();
00863 }
00864 
00865 
00866 template<typename Ordinal>
00867 void MpiComm<Ordinal>::setupMembersFromComm ()
00868 {
00869   int err = MPI_Comm_size (*rawMpiComm_, &size_);
00870   TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
00871     "Teuchos::MpiComm constructor: MPI_Comm_size failed with "
00872     "error \"" << mpiErrorCodeToString (err) << "\".");
00873   err = MPI_Comm_rank (*rawMpiComm_, &rank_);
00874   TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
00875     "Teuchos::MpiComm constructor: MPI_Comm_rank failed with "
00876     "error \"" << mpiErrorCodeToString (err) << "\".");
00877 
00878   // Set the default tag to make unique across all communicators
00879   if (tagCounter_ > maxTag_) {
00880     tagCounter_ = minTag_;
00881   }
00882   tag_ = tagCounter_++;
00883   // Ensure that the same tag is used on all processes.
00884   //
00885   // FIXME (mfh 09 Jul 2013) This would not be necessary if MpiComm
00886   // were just to call MPI_Comm_dup (as every library should) when
00887   // given its communicator.  Of course, MPI_Comm_dup may also be
00888   // implemented as a collective, and may even be more expensive than
00889   // a broadcast.  If we do decide to use MPI_Comm_dup, we can get rid
00890   // of the broadcast below, and also get rid of tag_, tagCounter_,
00891   // minTag_, and maxTag_.
00892   MPI_Bcast (&tag_, 1, MPI_INT, 0, *rawMpiComm_);
00893 }
00894 
00895 
00896 template<typename Ordinal>
00897 void
00898 MpiComm<Ordinal>::
00899 setErrorHandler (const RCP<const OpaqueWrapper<MPI_Errhandler> >& errHandler)
00900 {
00901   if (! is_null (errHandler)) {
00902     const int err = details::setCommErrhandler (*getRawMpiComm (), *errHandler);
00903     TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
00904       "Teuchos::MpiComm: Setting the MPI_Comm's error handler failed with "
00905       "error \"" << mpiErrorCodeToString (err) << "\".");
00906   }
00907   // Wait to set this until the end, in case setting the error handler
00908   // doesn't succeed.
00909   customErrorHandler_ = errHandler;
00910 }
00911 
00912 //
00913 // Overridden from Comm
00914 //
00915 
00916 template<typename Ordinal>
00917 int MpiComm<Ordinal>::getRank() const
00918 {
00919   return rank_;
00920 }
00921 
00922 
00923 template<typename Ordinal>
00924 int MpiComm<Ordinal>::getSize() const
00925 {
00926   return size_;
00927 }
00928 
00929 
00930 template<typename Ordinal>
00931 void MpiComm<Ordinal>::barrier() const
00932 {
00933   TEUCHOS_COMM_TIME_MONITOR(
00934     "Teuchos::MpiComm<"<<OrdinalTraits<Ordinal>::name()<<">::barrier()"
00935     );
00936   const int err = MPI_Barrier (*rawMpiComm_);
00937   TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
00938     "Teuchos::MpiComm::barrier: MPI_Barrier failed with error \""
00939     << mpiErrorCodeToString (err) << "\".");
00940 }
00941 
00942 
00943 template<typename Ordinal>
00944 void MpiComm<Ordinal>::broadcast(
00945   const int rootRank, const Ordinal bytes, char buffer[]
00946   ) const
00947 {
00948   TEUCHOS_COMM_TIME_MONITOR(
00949     "Teuchos::MpiComm<"<<OrdinalTraits<Ordinal>::name()<<">::broadcast(...)"
00950     );
00951   const int err = MPI_Bcast (buffer, bytes, MPI_CHAR, rootRank, *rawMpiComm_);
00952   TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
00953     "Teuchos::MpiComm::broadcast: MPI_Bcast failed with error \""
00954     << mpiErrorCodeToString (err) << "\".");
00955 }
00956 
00957 
00958 template<typename Ordinal>
00959 void MpiComm<Ordinal>::gatherAll(
00960   const Ordinal sendBytes, const char sendBuffer[],
00961   const Ordinal recvBytes, char recvBuffer[]
00962   ) const
00963 {
00964   TEUCHOS_COMM_TIME_MONITOR(
00965     "Teuchos::MpiComm<"<<OrdinalTraits<Ordinal>::name()<<">::gatherAll(...)"
00966     );
00967   TEUCHOS_ASSERT_EQUALITY((sendBytes*size_), recvBytes );
00968   const int err =
00969     MPI_Allgather (const_cast<char *>(sendBuffer), sendBytes, MPI_CHAR,
00970                    recvBuffer, sendBytes, MPI_CHAR, *rawMpiComm_);
00971   // NOTE: 'sendBytes' is being sent above for the MPI arg recvcount (which is
00972   // very confusing in the MPI documentation) for MPI_Allgether(...).
00973 
00974   TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
00975     "Teuchos::MpiComm::gatherAll: MPI_Allgather failed with error \""
00976     << mpiErrorCodeToString (err) << "\".");
00977 }
00978 
00979 
00980 template<typename Ordinal>
00981 void
00982 MpiComm<Ordinal>::gather (const Ordinal sendBytes,
00983                           const char sendBuffer[],
00984                           const Ordinal recvBytes,
00985                           char recvBuffer[],
00986                           const int root) const
00987 {
00988   (void) recvBytes; // silence compile warning for "unused parameter"
00989 
00990   TEUCHOS_COMM_TIME_MONITOR(
00991     "Teuchos::MpiComm<"<<OrdinalTraits<Ordinal>::name()<<">::gather(...)"
00992     );
00993   const int err =
00994     MPI_Gather (const_cast<char *> (sendBuffer), sendBytes, MPI_CHAR,
00995                 recvBuffer, sendBytes, MPI_CHAR, root, *rawMpiComm_);
00996   TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
00997     "Teuchos::MpiComm::gather: MPI_Gather failed with error \""
00998     << mpiErrorCodeToString (err) << "\".");
00999 }
01000 
01001 
01002 template<typename Ordinal>
01003 void
01004 MpiComm<Ordinal>::
01005 reduceAll (const ValueTypeReductionOp<Ordinal,char> &reductOp,
01006            const Ordinal bytes,
01007            const char sendBuffer[],
01008            char globalReducts[]) const
01009 {
01010   TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::reduceAll(...)" );
01011 
01012   MpiReductionOpSetter op(mpiReductionOp(rcp(&reductOp,false)));
01013   MPI_Datatype char_block;
01014 
01015   // TODO (mfh 26 Mar 2012) Check returned error codes of the MPI
01016   // custom datatype functions.
01017   MPI_Type_contiguous(bytes, MPI_CHAR, &char_block);
01018   MPI_Type_commit(&char_block);
01019 
01020   const int err =
01021     MPI_Allreduce (const_cast<char*>(sendBuffer), globalReducts, 1, char_block,
01022                    op.mpi_op(), *rawMpiComm_);
01023   TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
01024     "Teuchos::MpiComm::reduceAll (custom op): MPI_Allreduce failed with error \""
01025     << mpiErrorCodeToString (err) << "\".");
01026 
01027   // TODO (mfh 26 Mar 2012) Check returned error codes of the MPI
01028   // custom datatype functions.
01029   MPI_Type_free(&char_block);
01030 }
01031 
01032 
01033 template<typename Ordinal>
01034 void MpiComm<Ordinal>::reduceAllAndScatter(
01035   const ValueTypeReductionOp<Ordinal,char> &reductOp
01036   ,const Ordinal sendBytes, const char sendBuffer[]
01037   ,const Ordinal recvCounts[], char myGlobalReducts[]
01038   ) const
01039 {
01040 
01041   (void)sendBytes; // Ignore if not in debug mode
01042 
01043   TEUCHOS_COMM_TIME_MONITOR(
01044     "Teuchos::MpiComm<"<<OrdinalTraits<Ordinal>::name()<<">::reduceAllAndScatter(...)"
01045     );
01046 
01047 #ifdef TEUCHOS_DEBUG
01048   Ordinal sumRecvBytes = 0;
01049   for( Ordinal i = 0; i < size_; ++i ) {
01050     sumRecvBytes += recvCounts[i];
01051   }
01052   TEUCHOS_TEST_FOR_EXCEPT(!(sumRecvBytes==sendBytes));
01053 #endif // TEUCHOS_DEBUG
01054 
01055 #ifdef TEUCHOS_MPI_COMM_DUMP
01056   if(show_dump) {
01057     dumpBuffer<Ordinal,char>(
01058       "Teuchos::MpiComm<Ordinal>::reduceAllAndScatter(...)",
01059       "sendBuffer", sendBytes, sendBuffer );
01060     dumpBuffer<Ordinal,Ordinal>(
01061       "Teuchos::MpiComm<Ordinal>::reduceAllAndScatter(...)",
01062       "recvCounts", as<Ordinal>(size_), recvCounts );
01063     dumpBuffer<Ordinal,char>(
01064       "Teuchos::MpiComm<Ordinal>::reduceAllAndScatter(...)",
01065       "myGlobalReducts", as<char>(recvCounts[rank_]), myGlobalReducts );
01066   }
01067 #endif // TEUCHOS_MPI_COMM_DUMP
01068 
01069   // Create a new recvCount[] if Ordinal!=int
01070   WorkspaceStore* wss = get_default_workspace_store().get();
01071   const bool Ordinal_is_int = typeid(int)==typeid(Ordinal);
01072   Workspace<int> ws_int_recvCounts(wss,Ordinal_is_int?0:size_);
01073   const int *int_recvCounts = 0;
01074   if(Ordinal_is_int) {
01075     int_recvCounts = reinterpret_cast<const int*>(recvCounts);
01076     // Note: We must do an reinterpet cast since this must
01077     // compile even if it is not executed.  I could implement
01078     // code that would not need to do this using template
01079     // conditionals but I don't want to bother.
01080   }
01081   else {
01082     std::copy(recvCounts, recvCounts+size_, &ws_int_recvCounts[0]);
01083     int_recvCounts = &ws_int_recvCounts[0];
01084   }
01085 
01086   // Perform the operation
01087   MpiReductionOpSetter op(mpiReductionOp(rcp(&reductOp, false)));
01088 
01089   const int err = MPI_Reduce_scatter(
01090     const_cast<char*>(sendBuffer), myGlobalReducts,
01091     const_cast<int*>(int_recvCounts),
01092     MPI_CHAR,
01093     op.mpi_op(),
01094     *rawMpiComm_
01095     );
01096   TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
01097     "Teuchos::MpiComm::reduceAllAndScatter: MPI_Reduce_scatter failed with "
01098     "error \"" << mpiErrorCodeToString (err) << "\".");
01099 }
01100 
01101 
01102 template<typename Ordinal>
01103 void MpiComm<Ordinal>::scan(
01104   const ValueTypeReductionOp<Ordinal,char> &reductOp
01105   ,const Ordinal bytes, const char sendBuffer[], char scanReducts[]
01106   ) const
01107 {
01108   TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::scan(...)" );
01109 
01110   MpiReductionOpSetter op(mpiReductionOp(rcp(&reductOp,false)));
01111   const int err =
01112     MPI_Scan (const_cast<char*>(sendBuffer), scanReducts, bytes, MPI_CHAR,
01113               op.mpi_op(), *rawMpiComm_);
01114   TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
01115     "Teuchos::MpiComm::scan: MPI_Scan() failed with error \""
01116     << mpiErrorCodeToString (err) << "\".");
01117 }
01118 
01119 
01120 template<typename Ordinal>
01121 void
01122 MpiComm<Ordinal>::send (const Ordinal bytes,
01123                         const char sendBuffer[],
01124                         const int destRank) const
01125 {
01126   TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::send(...)" );
01127 
01128 #ifdef TEUCHOS_MPI_COMM_DUMP
01129   if(show_dump) {
01130     dumpBuffer<Ordinal,char>(
01131       "Teuchos::MpiComm<Ordinal>::send(...)"
01132       ,"sendBuffer", bytes, sendBuffer
01133       );
01134   }
01135 #endif // TEUCHOS_MPI_COMM_DUMP
01136 
01137   const int err = MPI_Send (const_cast<char*>(sendBuffer), bytes, MPI_CHAR,
01138                             destRank, tag_, *rawMpiComm_);
01139   TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
01140     "Teuchos::MpiComm::send: MPI_Send() failed with error \""
01141     << mpiErrorCodeToString (err) << "\".");
01142 }
01143 
01144 
01145 template<typename Ordinal>
01146 void
01147 MpiComm<Ordinal>::send (const Ordinal bytes,
01148                         const char sendBuffer[],
01149                         const int destRank,
01150                         const int tag) const
01151 {
01152   TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::send(...)" );
01153   const int err = MPI_Send (const_cast<char*> (sendBuffer), bytes, MPI_CHAR,
01154                             destRank, tag, *rawMpiComm_);
01155   TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
01156     "Teuchos::MpiComm::send: MPI_Send() failed with error \""
01157     << mpiErrorCodeToString (err) << "\".");
01158 }
01159 
01160 
01161 template<typename Ordinal>
01162 void
01163 MpiComm<Ordinal>::ssend (const Ordinal bytes,
01164                          const char sendBuffer[],
01165                          const int destRank) const
01166 {
01167   TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::ssend(...)" );
01168 
01169 #ifdef TEUCHOS_MPI_COMM_DUMP
01170   if(show_dump) {
01171     dumpBuffer<Ordinal,char>(
01172       "Teuchos::MpiComm<Ordinal>::send(...)"
01173       ,"sendBuffer", bytes, sendBuffer
01174       );
01175   }
01176 #endif // TEUCHOS_MPI_COMM_DUMP
01177 
01178   const int err = MPI_Ssend (const_cast<char*>(sendBuffer), bytes, MPI_CHAR,
01179                              destRank, tag_, *rawMpiComm_);
01180   TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
01181     "Teuchos::MpiComm::send: MPI_Ssend() failed with error \""
01182     << mpiErrorCodeToString (err) << "\".");
01183 }
01184 
01185 template<typename Ordinal>
01186 void
01187 MpiComm<Ordinal>::ssend (const Ordinal bytes,
01188                          const char sendBuffer[],
01189                          const int destRank,
01190                          const int tag) const
01191 {
01192   TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::ssend(...)" );
01193   const int err =
01194     MPI_Ssend (const_cast<char*>(sendBuffer), bytes, MPI_CHAR,
01195                destRank, tag, *rawMpiComm_);
01196   TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
01197     "Teuchos::MpiComm::send: MPI_Ssend() failed with error \""
01198     << mpiErrorCodeToString (err) << "\".");
01199 }
01200 
01201 template<typename Ordinal>
01202 void MpiComm<Ordinal>::readySend(
01203   const ArrayView<const char> &sendBuffer,
01204   const int destRank
01205   ) const
01206 {
01207   TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::readySend" );
01208 
01209 #ifdef TEUCHOS_MPI_COMM_DUMP
01210   if(show_dump) {
01211     dumpBuffer<Ordinal,char>(
01212       "Teuchos::MpiComm<Ordinal>::readySend(...)"
01213       ,"sendBuffer", bytes, sendBuffer
01214       );
01215   }
01216 #endif // TEUCHOS_MPI_COMM_DUMP
01217 
01218   const int err =
01219     MPI_Rsend (const_cast<char*>(sendBuffer.getRawPtr()), sendBuffer.size(),
01220                MPI_CHAR, destRank, tag_, *rawMpiComm_);
01221   TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
01222     "Teuchos::MpiComm::readySend: MPI_Rsend() failed with error \""
01223     << mpiErrorCodeToString (err) << "\".");
01224 }
01225 
01226 
01227 template<typename Ordinal>
01228 void MpiComm<Ordinal>::
01229 readySend (const Ordinal bytes,
01230            const char sendBuffer[],
01231            const int destRank,
01232            const int tag) const
01233 {
01234   TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::readySend" );
01235   const int err =
01236     MPI_Rsend (const_cast<char*> (sendBuffer), bytes,
01237                MPI_CHAR, destRank, tag, *rawMpiComm_);
01238   TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
01239     "Teuchos::MpiComm::readySend: MPI_Rsend() failed with error \""
01240     << mpiErrorCodeToString (err) << "\".");
01241 }
01242 
01243 
01244 template<typename Ordinal>
01245 int
01246 MpiComm<Ordinal>::receive (const int sourceRank,
01247                            const Ordinal bytes,
01248                            char recvBuffer[]) const
01249 {
01250   TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::receive(...)" );
01251 
01252   // A negative source rank indicates MPI_ANY_SOURCE, namely that we
01253   // will take an incoming message from any process, as long as the
01254   // tag matches.
01255   const int theSrcRank = (sourceRank < 0) ? MPI_ANY_SOURCE : sourceRank;
01256 
01257   MPI_Status status;
01258   const int err = MPI_Recv (recvBuffer, bytes, MPI_CHAR, theSrcRank, tag_,
01259                             *rawMpiComm_, &status);
01260   TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
01261     "Teuchos::MpiComm::receive: MPI_Recv() failed with error \""
01262     << mpiErrorCodeToString (err) << "\".");
01263 
01264 #ifdef TEUCHOS_MPI_COMM_DUMP
01265   if (show_dump) {
01266     dumpBuffer<Ordinal,char> ("Teuchos::MpiComm<Ordinal>::receive(...)",
01267                               "recvBuffer", bytes, recvBuffer);
01268   }
01269 #endif // TEUCHOS_MPI_COMM_DUMP
01270 
01271   // Returning the source rank is useful in the MPI_ANY_SOURCE case.
01272   return status.MPI_SOURCE;
01273 }
01274 
01275 
01276 template<typename Ordinal>
01277 RCP<CommRequest<Ordinal> >
01278 MpiComm<Ordinal>::isend (const ArrayView<const char> &sendBuffer,
01279                          const int destRank) const
01280 {
01281   using Teuchos::as;
01282   TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::isend(...)" );
01283 
01284   MPI_Request rawMpiRequest = MPI_REQUEST_NULL;
01285   const int err =
01286     MPI_Isend (const_cast<char*> (sendBuffer.getRawPtr ()),
01287                as<Ordinal> (sendBuffer.size ()), MPI_CHAR,
01288                destRank, tag_, *rawMpiComm_, &rawMpiRequest);
01289   TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
01290     "Teuchos::MpiComm::isend: MPI_Isend() failed with error \""
01291     << mpiErrorCodeToString (err) << "\".");
01292 
01293   return mpiCommRequest<Ordinal> (rawMpiRequest, sendBuffer.size ());
01294 }
01295 
01296 
01297 template<typename Ordinal>
01298 RCP<CommRequest<Ordinal> >
01299 MpiComm<Ordinal>::
01300 isend (const ArrayView<const char> &sendBuffer,
01301        const int destRank,
01302        const int tag) const
01303 {
01304   using Teuchos::as;
01305   TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::isend(...)" );
01306 
01307   MPI_Request rawMpiRequest = MPI_REQUEST_NULL;
01308   const int err =
01309     MPI_Isend (const_cast<char*> (sendBuffer.getRawPtr ()),
01310                as<Ordinal> (sendBuffer.size ()), MPI_CHAR,
01311                destRank, tag, *rawMpiComm_, &rawMpiRequest);
01312   TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
01313     "Teuchos::MpiComm::isend: MPI_Isend() failed with error \""
01314     << mpiErrorCodeToString (err) << "\".");
01315 
01316   return mpiCommRequest<Ordinal> (rawMpiRequest, sendBuffer.size ());
01317 }
01318 
01319 
01320 template<typename Ordinal>
01321 RCP<CommRequest<Ordinal> >
01322 MpiComm<Ordinal>::ireceive (const ArrayView<char> &recvBuffer,
01323                             const int sourceRank) const
01324 {
01325   TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::ireceive(...)" );
01326 
01327   // A negative source rank indicates MPI_ANY_SOURCE, namely that we
01328   // will take an incoming message from any process, as long as the
01329   // tag matches.
01330   const int theSrcRank = (sourceRank < 0) ? MPI_ANY_SOURCE : sourceRank;
01331 
01332   MPI_Request rawMpiRequest = MPI_REQUEST_NULL;
01333   const int err =
01334     MPI_Irecv (const_cast<char*>(recvBuffer.getRawPtr()), recvBuffer.size(),
01335                MPI_CHAR, theSrcRank, tag_, *rawMpiComm_, &rawMpiRequest);
01336   TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
01337     "Teuchos::MpiComm::ireceive: MPI_Irecv() failed with error \""
01338     << mpiErrorCodeToString (err) << "\".");
01339 
01340   return mpiCommRequest<Ordinal> (rawMpiRequest, recvBuffer.size());
01341 }
01342 
01343 template<typename Ordinal>
01344 RCP<CommRequest<Ordinal> >
01345 MpiComm<Ordinal>::ireceive (const ArrayView<char> &recvBuffer,
01346                             const int sourceRank,
01347                             const int tag) const
01348 {
01349   TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::ireceive(...)" );
01350 
01351   // A negative source rank indicates MPI_ANY_SOURCE, namely that we
01352   // will take an incoming message from any process, as long as the
01353   // tag matches.
01354   const int theSrcRank = (sourceRank < 0) ? MPI_ANY_SOURCE : sourceRank;
01355 
01356   MPI_Request rawMpiRequest = MPI_REQUEST_NULL;
01357   const int err =
01358     MPI_Irecv (const_cast<char*> (recvBuffer.getRawPtr ()), recvBuffer.size (),
01359                MPI_CHAR, theSrcRank, tag, *rawMpiComm_, &rawMpiRequest);
01360   TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
01361     "Teuchos::MpiComm::ireceive: MPI_Irecv() failed with error \""
01362     << mpiErrorCodeToString (err) << "\".");
01363 
01364   return mpiCommRequest<Ordinal> (rawMpiRequest, recvBuffer.size ());
01365 }
01366 
01367 namespace {
01368   // Called by the two-argument MpiComm::waitAll() variant.
01369   template<typename Ordinal>
01370   void
01371   waitAllImpl (const ArrayView<RCP<CommRequest<Ordinal> > >& requests,
01372                const ArrayView<MPI_Status>& rawMpiStatuses)
01373   {
01374     typedef typename ArrayView<RCP<CommRequest<Ordinal> > >::size_type size_type;
01375     const size_type count = requests.size();
01376     // waitAllImpl() is not meant to be called by users, so it's a bug
01377     // for the two views to have different lengths.
01378     TEUCHOS_TEST_FOR_EXCEPTION(rawMpiStatuses.size() != count,
01379       std::logic_error, "Teuchos::MpiComm's waitAllImpl: rawMpiStatus.size() = "
01380       << rawMpiStatuses.size() << " != requests.size() = " << requests.size()
01381       << ".  Please report this bug to the Tpetra developers.");
01382     if (count == 0) {
01383       return; // No requests on which to wait
01384     }
01385 
01386     // MpiComm wraps MPI and can't expose any MPI structs or opaque
01387     // objects.  Thus, we have to unpack requests into a separate array.
01388     // If that's too slow, then your code should just call into MPI
01389     // directly.
01390     //
01391     // Pull out the raw MPI requests from the wrapped requests.
01392     // MPI_Waitall should not fail if a request is MPI_REQUEST_NULL, but
01393     // we keep track just to inform the user.
01394     bool someNullRequests = false;
01395     Array<MPI_Request> rawMpiRequests (count, MPI_REQUEST_NULL);
01396     for (int i = 0; i < count; ++i) {
01397       RCP<CommRequest<Ordinal> > request = requests[i];
01398       if (! is_null (request)) {
01399         RCP<MpiCommRequestBase<Ordinal> > mpiRequest =
01400           rcp_dynamic_cast<MpiCommRequestBase<Ordinal> > (request);
01401         // releaseRawMpiRequest() sets the MpiCommRequest's raw
01402         // MPI_Request to MPI_REQUEST_NULL.  This makes waitAll() not
01403         // satisfy the strong exception guarantee.  That's OK because
01404         // MPI_Waitall() doesn't promise that it satisfies the strong
01405         // exception guarantee, and we would rather conservatively
01406         // invalidate the handles than leave dangling requests around
01407         // and risk users trying to wait on the same request twice.
01408         rawMpiRequests[i] = mpiRequest->releaseRawMpiRequest();
01409       }
01410       else { // Null requests map to MPI_REQUEST_NULL
01411         rawMpiRequests[i] = MPI_REQUEST_NULL;
01412         someNullRequests = true;
01413       }
01414     }
01415 
01416     // This is the part where we've finally peeled off the wrapper and
01417     // we can now interact with MPI directly.
01418     //
01419     // One option in the one-argument version of waitAll() is to ignore
01420     // the statuses completely.  MPI lets you pass in the named constant
01421     // MPI_STATUSES_IGNORE for the MPI_Status array output argument in
01422     // MPI_Waitall(), which would tell MPI not to bother with the
01423     // statuses.  However, we want the statuses because we can use them
01424     // for detailed error diagnostics in case something goes wrong.
01425     const int err = MPI_Waitall (count, rawMpiRequests.getRawPtr(),
01426                                  rawMpiStatuses.getRawPtr());
01427 
01428     // In MPI_Waitall(), an error indicates that one or more requests
01429     // failed.  In that case, there could be requests that completed
01430     // (their MPI_Status' error field is MPI_SUCCESS), and other
01431     // requests that have not completed yet but have not necessarily
01432     // failed (MPI_PENDING).  We make no attempt here to wait on the
01433     // pending requests.  It doesn't make sense for us to do so, because
01434     // in general Teuchos::Comm doesn't attempt to provide robust
01435     // recovery from failed messages.
01436     if (err != MPI_SUCCESS) {
01437       if (err == MPI_ERR_IN_STATUS) {
01438         //
01439         // When MPI_Waitall returns MPI_ERR_IN_STATUS (a standard error
01440         // class), it's telling us to check the error codes in the
01441         // returned statuses.  In that case, we do so and generate a
01442         // detailed exception message.
01443         //
01444         // Figure out which of the requests failed.
01445         Array<std::pair<size_type, int> > errorLocationsAndCodes;
01446         for (size_type k = 0; k < rawMpiStatuses.size(); ++k) {
01447           const int curErr = rawMpiStatuses[k].MPI_ERROR;
01448           if (curErr != MPI_SUCCESS) {
01449             errorLocationsAndCodes.push_back (std::make_pair (k, curErr));
01450           }
01451         }
01452         const size_type numErrs = errorLocationsAndCodes.size();
01453         if (numErrs > 0) {
01454           // There was at least one error.  Assemble a detailed
01455           // exception message reporting which requests failed,
01456           // their error codes, and their source
01457           std::ostringstream os;
01458           os << "Teuchos::MpiComm::waitAll: MPI_Waitall() failed with error \""
01459              << mpiErrorCodeToString (err) << "\".  Of the " << count
01460              << " total request" << (count != 1 ? "s" : "") << ", " << numErrs
01461              << " failed.  Here are the indices of the failed requests, and the "
01462             "error codes extracted from their returned MPI_Status objects:"
01463              << std::endl;
01464           for (size_type k = 0; k < numErrs; ++k) {
01465             const size_type errInd = errorLocationsAndCodes[k].first;
01466             os << "Request " << errInd << ": MPI_ERROR = "
01467                << mpiErrorCodeToString (rawMpiStatuses[errInd].MPI_ERROR)
01468                << std::endl;
01469           }
01470           if (someNullRequests) {
01471             os << "  On input to MPI_Waitall, there was at least one MPI_"
01472               "Request that was MPI_REQUEST_NULL.  MPI_Waitall should not "
01473               "normally fail in that case, but we thought we should let you know "
01474               "regardless.";
01475           }
01476           TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, os.str());
01477         }
01478         // If there were no actual errors in the returned statuses,
01479         // well, then I guess everything is OK.  Just keep going.
01480       }
01481       else {
01482         std::ostringstream os;
01483         os << "Teuchos::MpiComm::waitAll: MPI_Waitall() failed with error \""
01484            << mpiErrorCodeToString (err) << "\".";
01485         if (someNullRequests) {
01486           os << "  On input to MPI_Waitall, there was at least one MPI_Request "
01487             "that was MPI_REQUEST_NULL.  MPI_Waitall should not normally fail in "
01488             "that case, but we thought we should let you know regardless.";
01489         }
01490         TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, os.str());
01491       }
01492     }
01493 
01494     // Invalidate the input array of requests by setting all entries
01495     // to null.
01496     std::fill (requests.begin(), requests.end(), null);
01497   }
01498 
01499 
01500 
01501   // Called by the one-argument MpiComm::waitAll() variant.
01502   template<typename Ordinal>
01503   void
01504   waitAllImpl (const ArrayView<RCP<CommRequest<Ordinal> > >& requests)
01505   {
01506     typedef typename ArrayView<RCP<CommRequest<Ordinal> > >::size_type size_type;
01507     const size_type count = requests.size ();
01508     if (count == 0) {
01509       return; // No requests on which to wait
01510     }
01511 
01512     // MpiComm wraps MPI and can't expose any MPI structs or opaque
01513     // objects.  Thus, we have to unpack requests into a separate
01514     // array.  If that's too slow, then your code should just call
01515     // into MPI directly.
01516     //
01517     // Pull out the raw MPI requests from the wrapped requests.
01518     // MPI_Waitall should not fail if a request is MPI_REQUEST_NULL,
01519     // but we keep track just to inform the user.
01520     bool someNullRequests = false;
01521     Array<MPI_Request> rawMpiRequests (count, MPI_REQUEST_NULL);
01522     for (int i = 0; i < count; ++i) {
01523       RCP<CommRequest<Ordinal> > request = requests[i];
01524       if (! request.is_null ()) {
01525         RCP<MpiCommRequestBase<Ordinal> > mpiRequest =
01526           rcp_dynamic_cast<MpiCommRequestBase<Ordinal> > (request);
01527         // releaseRawMpiRequest() sets the MpiCommRequest's raw
01528         // MPI_Request to MPI_REQUEST_NULL.  This makes waitAll() not
01529         // satisfy the strong exception guarantee.  That's OK because
01530         // MPI_Waitall() doesn't promise that it satisfies the strong
01531         // exception guarantee, and we would rather conservatively
01532         // invalidate the handles than leave dangling requests around
01533         // and risk users trying to wait on the same request twice.
01534         rawMpiRequests[i] = mpiRequest->releaseRawMpiRequest ();
01535       }
01536       else { // Null requests map to MPI_REQUEST_NULL
01537         rawMpiRequests[i] = MPI_REQUEST_NULL;
01538         someNullRequests = true;
01539       }
01540     }
01541 
01542     // This is the part where we've finally peeled off the wrapper and
01543     // we can now interact with MPI directly.
01544     //
01545     // MPI lets us pass in the named constant MPI_STATUSES_IGNORE for
01546     // the MPI_Status array output argument in MPI_Waitall(), which
01547     // tells MPI not to bother writing out the statuses.
01548     const int err = MPI_Waitall (count, rawMpiRequests.getRawPtr(),
01549                                  MPI_STATUSES_IGNORE);
01550 
01551     // In MPI_Waitall(), an error indicates that one or more requests
01552     // failed.  In that case, there could be requests that completed
01553     // (their MPI_Status' error field is MPI_SUCCESS), and other
01554     // requests that have not completed yet but have not necessarily
01555     // failed (MPI_PENDING).  We make no attempt here to wait on the
01556     // pending requests.  It doesn't make sense for us to do so,
01557     // because in general Teuchos::Comm doesn't attempt to provide
01558     // robust recovery from failed messages.
01559     if (err != MPI_SUCCESS) {
01560       std::ostringstream os;
01561       os << "Teuchos::MpiComm::waitAll: MPI_Waitall() failed with error \""
01562          << mpiErrorCodeToString (err) << "\".";
01563       if (someNullRequests) {
01564         os << std::endl << "On input to MPI_Waitall, there was at least one "
01565           "MPI_Request that was MPI_REQUEST_NULL.  MPI_Waitall should not "
01566           "normally fail in that case, but we thought we should let you know "
01567           "regardless.";
01568       }
01569       TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, os.str());
01570     }
01571 
01572     // Invalidate the input array of requests by setting all entries
01573     // to null.  We delay this until the end, since some
01574     // implementations of CommRequest might hold the only reference to
01575     // the communication buffer, and we don't want that to go away
01576     // until we've waited on the communication operation.
01577     std::fill (requests.begin(), requests.end(), null);
01578   }
01579 
01580 } // namespace (anonymous)
01581 
01582 
01583 
01584 template<typename Ordinal>
01585 void
01586 MpiComm<Ordinal>::
01587 waitAll (const ArrayView<RCP<CommRequest<Ordinal> > >& requests) const
01588 {
01589   TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::waitAll(requests)" );
01590   // Call the one-argument version of waitAllImpl, to avoid overhead
01591   // of handling statuses (which the user didn't want anyway).
01592   waitAllImpl<Ordinal> (requests);
01593 }
01594 
01595 
01596 template<typename Ordinal>
01597 void
01598 MpiComm<Ordinal>::
01599 waitAll (const ArrayView<RCP<CommRequest<Ordinal> > >& requests,
01600          const ArrayView<RCP<CommStatus<Ordinal> > >& statuses) const
01601 {
01602   TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::waitAll(requests, statuses)" );
01603 
01604   typedef typename ArrayView<RCP<CommRequest<Ordinal> > >::size_type size_type;
01605   const size_type count = requests.size();
01606 
01607   TEUCHOS_TEST_FOR_EXCEPTION(count != statuses.size(),
01608     std::invalid_argument, "Teuchos::MpiComm::waitAll: requests.size() = "
01609     << count << " != statuses.size() = " << statuses.size() << ".");
01610 
01611   Array<MPI_Status> rawMpiStatuses (count);
01612   waitAllImpl<Ordinal> (requests, rawMpiStatuses());
01613 
01614   // Repackage the raw MPI_Status structs into the wrappers.
01615   for (size_type i = 0; i < count; ++i) {
01616     statuses[i] = mpiCommStatus<Ordinal> (rawMpiStatuses[i]);
01617   }
01618 }
01619 
01620 
01621 template<typename Ordinal>
01622 RCP<CommStatus<Ordinal> >
01623 MpiComm<Ordinal>::wait (const Ptr<RCP<CommRequest<Ordinal> > >& request) const
01624 {
01625   TEUCHOS_COMM_TIME_MONITOR( "Teuchos::MpiComm::wait(...)" );
01626 
01627   if (is_null (*request)) {
01628     return null; // Nothing to wait on ...
01629   }
01630   else {
01631     RCP<CommStatus<Ordinal> > status = (*request)->wait ();
01632     // mfh 22 Oct 2012: The unit tests expect waiting on the
01633     // CommRequest to invalidate it by setting it to null.
01634     *request = null;
01635     return status;
01636   }
01637 }
01638 
01639 template<typename Ordinal>
01640 RCP< Comm<Ordinal> >
01641 MpiComm<Ordinal>::duplicate() const
01642 {
01643   MPI_Comm origRawComm = *rawMpiComm_;
01644   MPI_Comm newRawComm = MPI_COMM_NULL;
01645   const int err = MPI_Comm_dup (origRawComm, &newRawComm);
01646   TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error, "Teuchos"
01647     "::MpiComm::duplicate: MPI_Comm_dup failed with the following error: "
01648     << mpiErrorCodeToString (err));
01649 
01650   // Wrap the raw communicator, and pass the (const) wrapped
01651   // communicator to MpiComm's constructor.  We created the raw comm,
01652   // so we have to supply a function that frees it after use.
01653   RCP<OpaqueWrapper<MPI_Comm> > wrapped =
01654     opaqueWrapper<MPI_Comm> (newRawComm, details::safeCommFree);
01655   // Since newComm's raw MPI_Comm is the result of an MPI_Comm_dup,
01656   // its messages cannot collide with those of any other MpiComm.
01657   // This means we can assign its tag without an MPI_Bcast.
01658   RCP<MpiComm<Ordinal> > newComm =
01659     rcp (new MpiComm<Ordinal> (wrapped.getConst (), minTag_));
01660   return rcp_implicit_cast<Comm<Ordinal> > (newComm);
01661 }
01662 
01663 
01664 template<typename Ordinal>
01665 RCP< Comm<Ordinal> >
01666 MpiComm<Ordinal>::split(const int color, const int key) const
01667 {
01668   MPI_Comm newComm;
01669   const int splitReturn =
01670     MPI_Comm_split (*rawMpiComm_,
01671                     color < 0 ? MPI_UNDEFINED : color,
01672                     key,
01673                     &newComm);
01674   TEUCHOS_TEST_FOR_EXCEPTION(
01675     splitReturn != MPI_SUCCESS,
01676     std::logic_error,
01677     "Teuchos::MpiComm::split: Failed to create communicator with color "
01678     << color << "and key " << key << ".  MPI_Comm_split failed with error \""
01679     << mpiErrorCodeToString (splitReturn) << "\".");
01680   if (newComm == MPI_COMM_NULL) {
01681     return RCP< Comm<Ordinal> >();
01682   } else {
01683     RCP<const OpaqueWrapper<MPI_Comm> > wrapped =
01684       opaqueWrapper<MPI_Comm> (newComm, details::safeCommFree);
01685     // Since newComm's raw MPI_Comm is the result of an
01686     // MPI_Comm_split, its messages cannot collide with those of any
01687     // other MpiComm.  This means we can assign its tag without an
01688     // MPI_Bcast.
01689     return rcp (new MpiComm<Ordinal> (wrapped, minTag_));
01690   }
01691 }
01692 
01693 
01694 template<typename Ordinal>
01695 RCP< Comm<Ordinal> >
01696 MpiComm<Ordinal>::createSubcommunicator(const ArrayView<const int> &ranks) const
01697 {
01698   int err = MPI_SUCCESS; // For error codes returned by MPI functions
01699 
01700   // Get the group that this communicator is in.
01701   MPI_Group thisGroup;
01702   err = MPI_Comm_group (*rawMpiComm_, &thisGroup);
01703   TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::logic_error,
01704     "Failed to obtain the current communicator's group.  "
01705     "MPI_Comm_group failed with error \""
01706     << mpiErrorCodeToString (err) << "\".");
01707 
01708   // Create a new group with the specified members.
01709   MPI_Group newGroup;
01710   // It's rude to cast away const, but MPI functions demand it.
01711   //
01712   // NOTE (mfh 14 Aug 2012) Please don't ask for &ranks[0] unless you
01713   // know that ranks.size() > 0.  That's why I'm using getRawPtr().
01714   err = MPI_Group_incl (thisGroup, ranks.size(),
01715                         const_cast<int*> (ranks.getRawPtr ()), &newGroup);
01716   TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::logic_error,
01717     "Failed to create subgroup.  MPI_Group_incl failed with error \""
01718     << mpiErrorCodeToString (err) << "\".");
01719 
01720   // Create a new communicator from the new group.
01721   MPI_Comm newComm;
01722   try {
01723     err = MPI_Comm_create (*rawMpiComm_, newGroup, &newComm);
01724     TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::logic_error,
01725       "Failed to create subcommunicator.  MPI_Comm_create failed with error \""
01726       << mpiErrorCodeToString (err) << "\".");
01727   } catch (...) {
01728     // Attempt to free the new group before rethrowing.  If
01729     // successful, this will prevent a memory leak due to the "lost"
01730     // group that was allocated successfully above.  Since we're
01731     // throwing std::logic_error anyway, we can only promise
01732     // best-effort recovery; thus, we don't check the error code.
01733     (void) MPI_Group_free (&newGroup);
01734     (void) MPI_Group_free (&thisGroup);
01735     throw;
01736   }
01737 
01738   // We don't need the group any more, so free it.
01739   err = MPI_Group_free (&newGroup);
01740   TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::logic_error,
01741     "Failed to free subgroup.  MPI_Group_free failed with error \""
01742     << mpiErrorCodeToString (err) << "\".");
01743   err = MPI_Group_free (&thisGroup);
01744   TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::logic_error,
01745     "Failed to free subgroup.  MPI_Group_free failed with error \""
01746     << mpiErrorCodeToString (err) << "\".");
01747 
01748   if (newComm == MPI_COMM_NULL) {
01749     return RCP<Comm<Ordinal> > ();
01750   } else {
01751     using Teuchos::details::safeCommFree;
01752     typedef OpaqueWrapper<MPI_Comm> ow_type;
01753     RCP<const ow_type> wrapper =
01754       rcp_implicit_cast<const ow_type> (opaqueWrapper (newComm, safeCommFree));
01755     // Since newComm's raw MPI_Comm is the result of an
01756     // MPI_Comm_create, its messages cannot collide with those of any
01757     // other MpiComm.  This means we can assign its tag without an
01758     // MPI_Bcast.
01759     return rcp (new MpiComm<Ordinal> (wrapper, minTag_));
01760   }
01761 }
01762 
01763 
01764 // Overridden from Describable
01765 
01766 
01767 template<typename Ordinal>
01768 std::string MpiComm<Ordinal>::description() const
01769 {
01770   std::ostringstream oss;
01771   oss
01772     << typeName(*this)
01773     << "{"
01774     << "size="<<size_
01775     << ",rank="<<rank_
01776     << ",rawMpiComm="<<static_cast<MPI_Comm>(*rawMpiComm_)
01777     <<"}";
01778   return oss.str();
01779 }
01780 
01781 
01782 #ifdef TEUCHOS_MPI_COMM_DUMP
01783 template<typename Ordinal>
01784 bool MpiComm<Ordinal>::show_dump = false;
01785 #endif
01786 
01787 
01788 // private
01789 
01790 
01791 template<typename Ordinal>
01792 void MpiComm<Ordinal>::assertRank(const int rank, const std::string &rankName) const
01793 {
01794   TEUCHOS_TEST_FOR_EXCEPTION(
01795     ! ( 0 <= rank && rank < size_ ), std::logic_error
01796     ,"Error, "<<rankName<<" = " << rank << " is not < 0 or is not"
01797     " in the range [0,"<<size_-1<<"]!"
01798     );
01799 }
01800 
01801 
01802 } // namespace Teuchos
01803 
01804 
01805 template<typename Ordinal>
01806 Teuchos::RCP<Teuchos::MpiComm<Ordinal> >
01807 Teuchos::createMpiComm(
01808   const RCP<const OpaqueWrapper<MPI_Comm> > &rawMpiComm
01809   )
01810 {
01811   if( rawMpiComm.get()!=NULL && *rawMpiComm != MPI_COMM_NULL )
01812     return rcp(new MpiComm<Ordinal>(rawMpiComm));
01813   return Teuchos::null;
01814 }
01815 
01816 
01817 #endif // TEUCHOS_MPI_COMM_HPP
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines