00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #ifndef TEUCHOS_MPI_COMM_HPP
00030 #define TEUCHOS_MPI_COMM_HPP
00031
00032
00033 #include "Teuchos_Comm.hpp"
00034 #include "Teuchos_CommUtilities.hpp"
00035 #include "Teuchos_OrdinalTraits.hpp"
00036 #include "Teuchos_OpaqueWrapper.hpp"
00037 #include "Teuchos_MpiReductionOpSetter.hpp"
00038 #include "Teuchos_SerializationTraitsHelpers.hpp"
00039 #include "Teuchos_Workspace.hpp"
00040 #include "Teuchos_TypeNameTraits.hpp"
00041 #include "Teuchos_as.hpp"
00042 #include "mpi.h"
00043
00044
00045
00046
00047
00048
00049 #ifdef TEUCHOS_MPI_COMM_DUMP
00050 # include "Teuchos_VerboseObject.hpp"
00051 #endif
00052
00053
00054 namespace Teuchos {
00055
00056
00057 #ifdef TEUCHOS_MPI_COMM_DUMP
00058 template<typename Ordinal, typename T>
00059 void dumpBuffer(
00060 const std::string &funcName, const std::string &buffName
00061 ,const Ordinal bytes, const T buff[]
00062 )
00063 {
00064 Teuchos::RCP<Teuchos::FancyOStream>
00065 out = Teuchos::VerboseObjectBase::getDefaultOStream();
00066 Teuchos::OSTab tab(out);
00067 *out
00068 << "\n" << funcName << "::" << buffName << ":\n";
00069 tab.incrTab();
00070 for( Ordinal i = 0; i < bytes; ++i ) {
00071 *out << buffName << "[" << i << "] = '" << buff[i] << "'\n";
00072 }
00073 *out << "\n";
00074 }
00075 #endif // TEUCHOS_MPI_COMM_DUMP
00076
00077
00079 class MpiCommRequest : public CommRequest {
00080 public:
00082 MpiCommRequest( MPI_Request rawMpiRequest )
00083 :rawMpiRequest_(rawMpiRequest)
00084 {}
00086 MPI_Request releaseRawMpiRequest()
00087 {
00088 MPI_Request tmp_rawMpiRequest = rawMpiRequest_;
00089 rawMpiRequest_ = MPI_REQUEST_NULL;
00090 return tmp_rawMpiRequest;
00091 }
00092 private:
00093 MPI_Request rawMpiRequest_;
00094 MpiCommRequest();
00095 };
00096
00097
00102 inline
00103 const RCP<MpiCommRequest>
00104 mpiCommRequest( MPI_Request rawMpiRequest )
00105 {
00106 return Teuchos::rcp(new MpiCommRequest(rawMpiRequest));
00107 }
00108
00109
00120 template<typename Ordinal>
00121 class MpiComm : public Comm<Ordinal> {
00122 public:
00123
00125
00126
00133 MpiComm(
00134 const RCP<const OpaqueWrapper<MPI_Comm> > &rawMpiComm
00135 );
00136
00138 RCP<const OpaqueWrapper<MPI_Comm> > getRawMpiComm() const
00139 {return rawMpiComm_;}
00140
00142
00144
00145
00147 virtual int getRank() const;
00149 virtual int getSize() const;
00151 virtual void barrier() const;
00153 virtual void broadcast(
00154 const int rootRank, const Ordinal bytes, char buffer[]
00155 ) const;
00157 virtual void gatherAll(
00158 const Ordinal sendBytes, const char sendBuffer[]
00159 ,const Ordinal recvBytes, char recvBuffer[]
00160 ) const;
00162 virtual void reduceAll(
00163 const ValueTypeReductionOp<Ordinal,char> &reductOp
00164 ,const Ordinal bytes, const char sendBuffer[], char globalReducts[]
00165 ) const;
00167 virtual void reduceAllAndScatter(
00168 const ValueTypeReductionOp<Ordinal,char> &reductOp
00169 ,const Ordinal sendBytes, const char sendBuffer[]
00170 ,const Ordinal recvCounts[], char myGlobalReducts[]
00171 ) const;
00173 virtual void scan(
00174 const ValueTypeReductionOp<Ordinal,char> &reductOp
00175 ,const Ordinal bytes, const char sendBuffer[], char scanReducts[]
00176 ) const;
00178 virtual void send(
00179 const Ordinal bytes, const char sendBuffer[], const int destRank
00180 ) const;
00182 virtual int receive(
00183 const int sourceRank, const Ordinal bytes, char recvBuffer[]
00184 ) const;
00186 virtual void readySend(
00187 const ArrayView<const char> &sendBuffer,
00188 const int destRank
00189 ) const;
00191 virtual RCP<CommRequest> isend(
00192 const ArrayView<const char> &sendBuffer,
00193 const int destRank
00194 ) const;
00196 virtual RCP<CommRequest> ireceive(
00197 const ArrayView<char> &Buffer,
00198 const int sourceRank
00199 ) const;
00201 virtual void waitAll(
00202 const ArrayView<RCP<CommRequest> > &requests
00203 ) const;
00205 virtual void wait(
00206 const Ptr<RCP<CommRequest> > &request
00207 ) const;
00208
00210
00212
00213
00215 std::string description() const;
00216
00218
00219 private:
00220
00221 static int const minTag_ = 26000;
00222 static int const maxTag_ = 26099;
00223 static int tagCounter_;
00224
00225 RCP<const OpaqueWrapper<MPI_Comm> > rawMpiComm_;
00226 int rank_;
00227 int size_;
00228 int tag_;
00229
00230 void assertRank(const int rank, const std::string &rankName) const;
00231
00232
00233 MpiComm();
00234
00235 #ifdef TEUCHOS_MPI_COMM_DUMP
00236 public:
00237 static bool show_dump;
00238 #endif // TEUCHOS_MPI_COMM_DUMP
00239
00240 };
00241
00242
00256 template<typename Ordinal>
00257 RCP<MpiComm<Ordinal> >
00258 createMpiComm(
00259 const RCP<const OpaqueWrapper<MPI_Comm> > &rawMpiComm
00260 );
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270 template<typename Ordinal>
00271 int MpiComm<Ordinal>::tagCounter_ = MpiComm<Ordinal>::minTag_;
00272
00273
00274
00275
00276
00277 template<typename Ordinal>
00278 MpiComm<Ordinal>::MpiComm(
00279 const RCP<const OpaqueWrapper<MPI_Comm> > &rawMpiComm
00280 )
00281 {
00282 TEST_FOR_EXCEPT( rawMpiComm.get()==NULL );
00283 TEST_FOR_EXCEPT( *rawMpiComm == MPI_COMM_NULL );
00284 rawMpiComm_ = rawMpiComm;
00285 MPI_Comm_size(*rawMpiComm_,&size_);
00286 MPI_Comm_rank(*rawMpiComm_,&rank_);
00287 if(tagCounter_ > maxTag_)
00288 tagCounter_ = minTag_;
00289 tag_ = tagCounter_++;
00290 }
00291
00292
00293
00294
00295
00296 template<typename Ordinal>
00297 int MpiComm<Ordinal>::getRank() const
00298 {
00299 return rank_;
00300 }
00301
00302
00303 template<typename Ordinal>
00304 int MpiComm<Ordinal>::getSize() const
00305 {
00306 return size_;
00307 }
00308
00309
00310 template<typename Ordinal>
00311 void MpiComm<Ordinal>::barrier() const
00312 {
00313 TEUCHOS_COMM_TIME_MONITOR(
00314 "Teuchos::MpiComm<"<<OrdinalTraits<Ordinal>::name()<<">::barrier()"
00315 );
00316 MPI_Barrier(*rawMpiComm_);
00317 }
00318
00319
00320 template<typename Ordinal>
00321 void MpiComm<Ordinal>::broadcast(
00322 const int rootRank, const Ordinal bytes, char buffer[]
00323 ) const
00324 {
00325 TEUCHOS_COMM_TIME_MONITOR(
00326 "Teuchos::MpiComm<"<<OrdinalTraits<Ordinal>::name()<<">::broadcast(...)"
00327 );
00328 MPI_Bcast(buffer,bytes,MPI_CHAR,rootRank,*rawMpiComm_);
00329 }
00330
00331
00332 template<typename Ordinal>
00333 void MpiComm<Ordinal>::gatherAll(
00334 const Ordinal sendBytes, const char sendBuffer[]
00335 ,const Ordinal recvBytes, char recvBuffer[]
00336 ) const
00337 {
00338 TEUCHOS_COMM_TIME_MONITOR(
00339 "Teuchos::MpiComm<"<<OrdinalTraits<Ordinal>::name()<<">::gatherAll(...)"
00340 );
00341 TEST_FOR_EXCEPT(!(sendBytes*size_==recvBytes));
00342 MPI_Allgather(
00343 const_cast<char *>(sendBuffer),sendBytes,MPI_CHAR
00344 ,recvBuffer,sendBytes,MPI_CHAR
00345 ,*rawMpiComm_
00346 );
00347 }
00348
00349
00350 template<typename Ordinal>
00351 void MpiComm<Ordinal>::reduceAll(
00352 const ValueTypeReductionOp<Ordinal,char> &reductOp
00353 ,const Ordinal bytes, const char sendBuffer[], char globalReducts[]
00354 ) const
00355 {
00356 TEUCHOS_COMM_TIME_MONITOR(
00357 "Teuchos::MpiComm<"<<OrdinalTraits<Ordinal>::name()<<">::reduceAll(...)"
00358 );
00359 MpiReductionOpSetter op(mpiReductionOp(rcp(&reductOp,false)));
00360 MPI_Allreduce(
00361 const_cast<char*>(sendBuffer),globalReducts,bytes,MPI_CHAR,op.mpi_op()
00362 ,*rawMpiComm_
00363 );
00364 }
00365
00366
00367 template<typename Ordinal>
00368 void MpiComm<Ordinal>::reduceAllAndScatter(
00369 const ValueTypeReductionOp<Ordinal,char> &reductOp
00370 ,const Ordinal sendBytes, const char sendBuffer[]
00371 ,const Ordinal recvCounts[], char myGlobalReducts[]
00372 ) const
00373 {
00374
00375 (void)sendBytes;
00376
00377 TEUCHOS_COMM_TIME_MONITOR(
00378 "Teuchos::MpiComm<"<<OrdinalTraits<Ordinal>::name()<<">::reduceAllAndScatter(...)"
00379 );
00380
00381 #ifdef TEUCHOS_DEBUG
00382 Ordinal sumRecvBytes = 0;
00383 for( Ordinal i = 0; i < size_; ++i ) {
00384 sumRecvBytes += recvCounts[i];
00385 }
00386 TEST_FOR_EXCEPT(!(sumRecvBytes==sendBytes));
00387 #endif // TEUCHOS_DEBUG
00388
00389 #ifdef TEUCHOS_MPI_COMM_DUMP
00390 if(show_dump) {
00391 dumpBuffer<Ordinal,char>(
00392 "Teuchos::MpiComm<Ordinal>::reduceAllAndScatter(...)",
00393 "sendBuffer", sendBytes, sendBuffer );
00394 dumpBuffer<Ordinal,Ordinal>(
00395 "Teuchos::MpiComm<Ordinal>::reduceAllAndScatter(...)",
00396 "recvCounts", as<Ordinal>(size_), recvCounts );
00397 dumpBuffer<Ordinal,char>(
00398 "Teuchos::MpiComm<Ordinal>::reduceAllAndScatter(...)",
00399 "myGlobalReducts", as<char>(recvCounts[rank_]), myGlobalReducts );
00400 }
00401 #endif // TEUCHOS_MPI_COMM_DUMP
00402
00403
00404 WorkspaceStore* wss = get_default_workspace_store().get();
00405 const bool Ordinal_is_int = typeid(int)==typeid(Ordinal);
00406 Workspace<int> ws_int_recvCounts(wss,Ordinal_is_int?0:size_);
00407 const int *int_recvCounts = 0;
00408 if(Ordinal_is_int) {
00409 int_recvCounts = reinterpret_cast<const int*>(recvCounts);
00410
00411
00412
00413
00414 }
00415 else {
00416 std::copy(recvCounts, recvCounts+size_, &ws_int_recvCounts[0]);
00417 int_recvCounts = &ws_int_recvCounts[0];
00418 }
00419
00420
00421 MpiReductionOpSetter op(mpiReductionOp(rcp(&reductOp, false)));
00422 MPI_Reduce_scatter(
00423 const_cast<char*>(sendBuffer), myGlobalReducts,
00424 const_cast<int*>(int_recvCounts),
00425 MPI_CHAR,
00426 op.mpi_op(),
00427 *rawMpiComm_
00428 );
00429
00430 }
00431
00432
00433 template<typename Ordinal>
00434 void MpiComm<Ordinal>::scan(
00435 const ValueTypeReductionOp<Ordinal,char> &reductOp
00436 ,const Ordinal bytes, const char sendBuffer[], char scanReducts[]
00437 ) const
00438 {
00439 TEUCHOS_COMM_TIME_MONITOR(
00440 "Teuchos::MpiComm<"<<OrdinalTraits<Ordinal>::name()<<">::scan(...)"
00441 );
00442 MpiReductionOpSetter op(mpiReductionOp(rcp(&reductOp,false)));
00443 MPI_Scan(
00444 const_cast<char*>(sendBuffer),scanReducts,bytes,MPI_CHAR,op.mpi_op()
00445 ,*rawMpiComm_
00446 );
00447 }
00448
00449
00450 template<typename Ordinal>
00451 void MpiComm<Ordinal>::send(
00452 const Ordinal bytes, const char sendBuffer[], const int destRank
00453 ) const
00454 {
00455 TEUCHOS_COMM_TIME_MONITOR(
00456 "Teuchos::MpiComm<"<<OrdinalTraits<Ordinal>::name()<<">::send(...)"
00457 );
00458 #ifdef TEUCHOS_DEBUG
00459 TEST_FOR_EXCEPTION(
00460 ! ( 0 <= destRank && destRank < size_ ), std::logic_error
00461 ,"Error, destRank = " << destRank << " is not < 0 or is not"
00462 " in the range [0,"<<size_-1<<"]!"
00463 );
00464 #endif // TEUCHOS_DEBUG
00465 #ifdef TEUCHOS_MPI_COMM_DUMP
00466 if(show_dump) {
00467 dumpBuffer<Ordinal,char>(
00468 "Teuchos::MpiComm<Ordinal>::send(...)"
00469 ,"sendBuffer", bytes, sendBuffer
00470 );
00471 }
00472 #endif // TEUCHOS_MPI_COMM_DUMP
00473 MPI_Send(
00474 const_cast<char*>(sendBuffer),bytes,MPI_CHAR,destRank,tag_,*rawMpiComm_
00475 );
00476
00477 }
00478
00479
00480 template<typename Ordinal>
00481 void MpiComm<Ordinal>::readySend(
00482 const ArrayView<const char> &sendBuffer,
00483 const int destRank
00484 ) const
00485 {
00486 TEUCHOS_COMM_TIME_MONITOR(
00487 "Teuchos::MpiComm<"<<OrdinalTraits<Ordinal>::name()<<">::readySend(...)"
00488 );
00489 #ifdef TEUCHOS_DEBUG
00490 TEST_FOR_EXCEPTION(
00491 ! ( 0 <= destRank && destRank < size_ ), std::logic_error
00492 ,"Error, destRank = " << destRank << " is not < 0 or is not"
00493 " in the range [0,"<<size_-1<<"]!"
00494 );
00495 #endif // TEUCHOS_DEBUG
00496 #ifdef TEUCHOS_MPI_COMM_DUMP
00497 if(show_dump) {
00498 dumpBuffer<Ordinal,char>(
00499 "Teuchos::MpiComm<Ordinal>::readySend(...)"
00500 ,"sendBuffer", bytes, sendBuffer
00501 );
00502 }
00503 #endif // TEUCHOS_MPI_COMM_DUMP
00504 MPI_Rsend(
00505 const_cast<char*>(sendBuffer.getRawPtr()),sendBuffer.size(),MPI_CHAR,destRank,tag_,*rawMpiComm_
00506 );
00507
00508 }
00509
00510
00511 template<typename Ordinal>
00512 int MpiComm<Ordinal>::receive(
00513 const int sourceRank, const Ordinal bytes, char recvBuffer[]
00514 ) const
00515 {
00516 TEUCHOS_COMM_TIME_MONITOR(
00517 "Teuchos::MpiComm<"<<OrdinalTraits<Ordinal>::name()<<">::receive(...)"
00518 );
00519 #ifdef TEUCHOS_DEBUG
00520 TEST_FOR_EXCEPTION(
00521 sourceRank >=0 && !(sourceRank < size_), std::logic_error
00522 ,"Error, sourceRank = " << sourceRank << " is not < 0 or is not"
00523 " in the range [0,"<<(size_-1)<<"]!"
00524 );
00525 #endif // TEUCHOS_DEBUG
00526 MPI_Status status;
00527 MPI_Recv(
00528 recvBuffer,bytes,MPI_CHAR
00529 ,sourceRank >= 0 ? sourceRank : MPI_ANY_SOURCE
00530 ,tag_,*rawMpiComm_
00531 ,&status
00532 );
00533 #ifdef TEUCHOS_MPI_COMM_DUMP
00534 if(show_dump) {
00535 dumpBuffer<Ordinal,char>(
00536 "Teuchos::MpiComm<Ordinal>::receive(...)"
00537 ,"recvBuffer", bytes, recvBuffer
00538 );
00539 }
00540 #endif // TEUCHOS_MPI_COMM_DUMP
00541 return status.MPI_SOURCE;
00542
00543 }
00544
00545
00546 template<typename Ordinal>
00547 RCP<CommRequest> MpiComm<Ordinal>::isend(
00548 const ArrayView<const char> &sendBuffer,
00549 const int destRank
00550 ) const
00551 {
00552 TEUCHOS_COMM_TIME_MONITOR(
00553 "Teuchos::MpiComm<"<<OrdinalTraits<Ordinal>::name()<<">::isend(...)"
00554 );
00555 #ifdef TEUCHOS_DEBUG
00556 assertRank(destRank, "destRank");
00557 #endif // TEUCHOS_DEBUG
00558 MPI_Request rawMpiRequest = MPI_REQUEST_NULL;
00559 MPI_Isend(
00560 const_cast<char*>(sendBuffer.getRawPtr()), sendBuffer.size(), MPI_CHAR, destRank,
00561 tag_, *rawMpiComm_, &rawMpiRequest );
00562 return mpiCommRequest(rawMpiRequest);
00563
00564 }
00565
00566
00567 template<typename Ordinal>
00568 RCP<CommRequest> MpiComm<Ordinal>::ireceive(
00569 const ArrayView<char> &recvBuffer,
00570 const int sourceRank
00571 ) const
00572 {
00573 TEUCHOS_COMM_TIME_MONITOR(
00574 "Teuchos::MpiComm<"<<OrdinalTraits<Ordinal>::name()<<">::ireceive(...)"
00575 );
00576 #ifdef TEUCHOS_DEBUG
00577 assertRank(sourceRank, "sourceRank");
00578 #endif // TEUCHOS_DEBUG
00579 MPI_Request rawMpiRequest = MPI_REQUEST_NULL;
00580 MPI_Irecv(
00581 const_cast<char*>(recvBuffer.getRawPtr()), recvBuffer.size(), MPI_CHAR, sourceRank,
00582 tag_, *rawMpiComm_, &rawMpiRequest );
00583 return mpiCommRequest(rawMpiRequest);
00584
00585 }
00586
00587
00588 template<typename Ordinal>
00589 void MpiComm<Ordinal>::waitAll(
00590 const ArrayView<RCP<CommRequest> > &requests
00591 ) const
00592 {
00593 TEUCHOS_COMM_TIME_MONITOR(
00594 "Teuchos::MpiComm<"<<OrdinalTraits<Ordinal>::name()<<">::waitAll(...)"
00595 );
00596 const int count = requests.size();
00597 #ifdef TEUCHOS_DEBUG
00598 TEST_FOR_EXCEPT( requests.size() == 0 );
00599 #endif
00600
00601 Array<MPI_Request> rawMpiRequests(count, MPI_REQUEST_NULL);
00602 for (int i = 0; i < count; ++i) {
00603 RCP<CommRequest> &request = requests[i];
00604 if (!is_null(request)) {
00605 const RCP<MpiCommRequest> mpiCommRequest =
00606 rcp_dynamic_cast<MpiCommRequest>(request);
00607 rawMpiRequests[i] = mpiCommRequest->releaseRawMpiRequest();
00608 }
00609
00610 request = null;
00611 }
00612
00613 Array<MPI_Status> rawMpiStatuses(count);
00614 MPI_Waitall( count, rawMpiRequests.getRawPtr(), rawMpiStatuses.getRawPtr() );
00615
00616
00617 }
00618
00619
00620 template<typename Ordinal>
00621 void MpiComm<Ordinal>::wait(
00622 const Ptr<RCP<CommRequest> > &request
00623 ) const
00624 {
00625 TEUCHOS_COMM_TIME_MONITOR(
00626 "Teuchos::MpiComm<"<<OrdinalTraits<Ordinal>::name()<<">::wait(...)"
00627 );
00628 if (is_null(*request)) {
00629 return;
00630 }
00631 const RCP<MpiCommRequest> mpiCommRequest =
00632 rcp_dynamic_cast<MpiCommRequest>(*request);
00633 MPI_Request rawMpiRequest = mpiCommRequest->releaseRawMpiRequest();
00634 MPI_Status status;
00635 MPI_Wait( &rawMpiRequest, &status );
00636
00637 *request = null;
00638 }
00639
00640
00641
00642
00643
00644 template<typename Ordinal>
00645 std::string MpiComm<Ordinal>::description() const
00646 {
00647 std::ostringstream oss;
00648 oss
00649 << typeName(*this)
00650 << "{"
00651 << "size="<<size_
00652 << ",rank="<<rank_
00653 << ",rawMpiComm="<<static_cast<MPI_Comm>(*rawMpiComm_)
00654 <<"}";
00655 return oss.str();
00656 }
00657
00658
00659 #ifdef TEUCHOS_MPI_COMM_DUMP
00660 template<typename Ordinal>
00661 bool MpiComm<Ordinal>::show_dump = false;
00662 #endif
00663
00664
00665
00666
00667
00668 template<typename Ordinal>
00669 void MpiComm<Ordinal>::assertRank(const int rank, const std::string &rankName) const
00670 {
00671 TEST_FOR_EXCEPTION(
00672 ! ( 0 <= rank && rank < size_ ), std::logic_error
00673 ,"Error, "<<rankName<<" = " << rank << " is not < 0 or is not"
00674 " in the range [0,"<<size_-1<<"]!"
00675 );
00676 }
00677
00678
00679 }
00680
00681
00682 template<typename Ordinal>
00683 Teuchos::RCP<Teuchos::MpiComm<Ordinal> >
00684 Teuchos::createMpiComm(
00685 const RCP<const OpaqueWrapper<MPI_Comm> > &rawMpiComm
00686 )
00687 {
00688 if( rawMpiComm.get()!=NULL && *rawMpiComm != MPI_COMM_NULL )
00689 return rcp(new MpiComm<Ordinal>(rawMpiComm));
00690 return Teuchos::null;
00691 }
00692
00693
00694 #endif // TEUCHOS_MPI_COMM_HPP