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