Teuchos Package Browser (Single Doxygen Collection) Version of the Day
DefaultMpiComm_TagTests.cpp
Go to the documentation of this file.
00001 /*
00002 // @HEADER
00003 // ***********************************************************************
00004 //
00005 //                    Teuchos: Common Tools Package
00006 //                 Copyright (2004) Sandia Corporation
00007 //
00008 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
00009 // license for use of this work by or on behalf of the U.S. Government.
00010 //
00011 // Redistribution and use in source and binary forms, with or without
00012 // modification, are permitted provided that the following conditions are
00013 // met:
00014 //
00015 // 1. Redistributions of source code must retain the above copyright
00016 // notice, this list of conditions and the following disclaimer.
00017 //
00018 // 2. Redistributions in binary form must reproduce the above copyright
00019 // notice, this list of conditions and the following disclaimer in the
00020 // documentation and/or other materials provided with the distribution.
00021 //
00022 // 3. Neither the name of the Corporation nor the names of the
00023 // contributors may be used to endorse or promote products derived from
00024 // this software without specific prior written permission.
00025 //
00026 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
00027 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00028 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00029 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
00030 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00031 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00032 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00033 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00034 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00035 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00036 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00037 //
00038 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
00039 //
00040 // ***********************************************************************
00041 // @HEADER
00042 */
00043 
00044 #include "Teuchos_UnitTestHarness.hpp"
00045 #include "Teuchos_DefaultMpiComm.hpp"
00046 #include "Teuchos_CommHelpers.hpp"
00047 #include "Teuchos_DefaultComm.hpp"
00048 #include "Teuchos_getConst.hpp"
00049 #include "Teuchos_as.hpp"
00050 
00051 namespace std { 
00052 
00053 template <typename Packet>
00054 ostream & operator<< (ostream& os, const pair<Packet, Packet>& arg)
00055 {
00056   os << "(" << arg.first << "," << arg.second << ")";
00057   return os;
00058 }
00059 
00060 } // namespace std
00061 
00062 namespace {
00063 using Teuchos::Array;
00064 using Teuchos::ArrayRCP;
00065 using Teuchos::ArrayView;
00066 using Teuchos::as;
00067 using Teuchos::Comm;
00068 using Teuchos::CommRequest;
00069 using Teuchos::CommStatus;
00070 using Teuchos::ireceive;
00071 using Teuchos::isend;
00072 using Teuchos::MpiComm;
00073 using Teuchos::outArg;
00074 using Teuchos::RCP;
00075 using Teuchos::rcp;
00076 using Teuchos::send;
00077 using Teuchos::waitAll;
00078 using std::endl;
00079 
00080 TEUCHOS_STATIC_SETUP()
00081 {
00082   Teuchos::CommandLineProcessor& clp = Teuchos::UnitTestRepository::getCLP ();
00083   clp.addOutputSetupOptions (true);
00084 }
00085 
00086 TEUCHOS_UNIT_TEST( MpiCommTag, IrecvSend )
00087 {
00088   typedef ArrayRCP<int>::size_type size_type;
00089 
00090   RCP<const Comm<int> > comm = rcp (new MpiComm<int> (MPI_COMM_WORLD));
00091   const int myRank = comm->getRank ();
00092   const int numProcs = comm->getSize ();
00093 
00094   // If there is only one process, then the left and right neighbors
00095   // are the same, namely the calling process.  MPI allows a process
00096   // to send to and receive from itself.  On the other hand, we want
00097   // to test blocking sends, and we want to post two sends, so we only
00098   // allow > 1 processes.
00099   if (numProcs == 1) {
00100     out << "numProcs == 1, test passes trivially." << endl;
00101     return;
00102   }
00103   out << "Test setup" << endl;
00104 
00105   // If there are only two processes, the left neighbor and the right
00106   // neighbor are the same, namely the other process.
00107   int leftNeighbor = (myRank - 1) % numProcs;
00108   int rightNeighbor = (myRank + 1) % numProcs;
00109   // C doesn't guarantee nonnegativity of the result of the % operator.
00110   if (leftNeighbor < 0) {
00111     leftNeighbor += numProcs;
00112   }
00113   if (rightNeighbor < 0) {
00114     rightNeighbor += numProcs;
00115   }
00116   Array<int> expectedSourceRanks (2); // expected source ranks for receives
00117   expectedSourceRanks[0] = leftNeighbor;
00118   expectedSourceRanks[1] = rightNeighbor;
00119   std::sort (expectedSourceRanks.begin (), expectedSourceRanks.end ());
00120 
00121   // Receive buffer, with subbuffers for each neighbor.
00122   ArrayRCP<int> recvBuf (2);
00123   ArrayRCP<int> leftRecvBuf = recvBuf.persistingView (0, 1);
00124   ArrayRCP<int> rightRecvBuf = recvBuf.persistingView (1, 1);
00125   
00126   // Send buffer, with subbuffers for each neighbor.
00127   Array<int> sendBuf (2);
00128   ArrayView<int> leftSendBuf = sendBuf.view (0, 1);
00129   ArrayView<int> rightSendBuf = sendBuf.view (1, 1);
00130 
00132   // First round of messages
00134   out << "Round 1 of messages" << endl;
00135 
00136   // Tag to use for the first set of messages.
00137   const int tag1 = 42;
00138 
00139   // Fill receive buffer with error flags.
00140   for (size_type k = 0; k < recvBuf.size (); ++k) {
00141     recvBuf[k] = -1;
00142   }
00143   
00144   // Send my process rank plus the current tag to all neighbors.
00145   for (size_type k = 0; k < sendBuf.size (); ++k) {
00146     sendBuf[k] = myRank + tag1;
00147   }
00148   
00149   // Post receives from left and right neighbors.
00150   Array<RCP<CommRequest<int> > > requests (2);
00151   requests[0] = ireceive<int, int> (leftRecvBuf, leftNeighbor, tag1, *comm);
00152   requests[1] = ireceive<int, int> (rightRecvBuf, rightNeighbor, tag1, *comm);
00153 
00154   // Post sends to left and right neighbors.
00155   send<int, int> (leftSendBuf.getRawPtr (), as<int> (leftSendBuf.size ()), 
00156       leftNeighbor, tag1, *comm);
00157   send<int, int> (rightSendBuf.getRawPtr (), as<int> (rightSendBuf.size ()),
00158       rightNeighbor, tag1, *comm);
00159 
00160   // Wait for the receives to complete.
00161   Array<RCP<CommStatus<int> > > statuses (2);
00162   waitAll (*comm, requests (), statuses ());
00163 
00164   // Make sure the source ranks are correct.
00165   Array<int> sourceRanks (2);
00166   for (size_type k = 0; k < 2; ++k) {
00167     sourceRanks[k] = statuses[k]->getSourceRank ();
00168   }
00169   std::sort (sourceRanks.begin (), sourceRanks.end ());
00170   TEST_EQUALITY( sourceRanks.size (), expectedSourceRanks.size () );
00171   for (size_type k = 0; k < sourceRanks.size (); ++k) {
00172     TEST_EQUALITY( sourceRanks[k], expectedSourceRanks[k] );
00173   }
00174 
00175   // Make sure the source tags are correct.
00176   for (size_type k = 0; k < statuses.size (); ++k) {
00177     TEST_EQUALITY( statuses[k]->getTag (), tag1 );
00178   }
00179 
00180   // Make sure the message contents are correct.
00181   TEST_EQUALITY( leftRecvBuf[0], leftNeighbor + tag1 );
00182   TEST_EQUALITY( rightRecvBuf[0], rightNeighbor + tag1 );
00183 
00185   // Second round of messages
00187   out << "Round 2 of messages" << endl;
00188 
00189   // Tag to use for the second set of messages.
00190   const int tag2 = 100;
00191 
00192   // Fill receive buffer with error flags.
00193   for (size_type k = 0; k < recvBuf.size (); ++k) {
00194     recvBuf[k] = -1;
00195   }
00196   
00197   // Send my process rank plus the current tag to all neighbors.
00198   for (size_type k = 0; k < sendBuf.size (); ++k) {
00199     sendBuf[k] = myRank + tag2;
00200   }
00201   
00202   // Post receives from left and right neighbors.
00203   requests[0] = ireceive<int, int> (leftRecvBuf, leftNeighbor, tag2, *comm);
00204   requests[1] = ireceive<int, int> (rightRecvBuf, rightNeighbor, tag2, *comm);
00205 
00206   // Post sends to left and right neighbors.
00207   send<int, int> (leftSendBuf.getRawPtr (), as<int> (leftSendBuf.size ()), 
00208       leftNeighbor, tag2, *comm);
00209   send<int, int> (rightSendBuf.getRawPtr (), as<int> (rightSendBuf.size ()),
00210       rightNeighbor, tag2, *comm);
00211 
00212   // Wait for the receives to complete.
00213   waitAll (*comm, requests (), statuses ());
00214 
00215   // Make sure the source ranks are correct.
00216   for (size_type k = 0; k < 2; ++k) {
00217     sourceRanks[k] = statuses[k]->getSourceRank ();
00218   }
00219   std::sort (sourceRanks.begin (), sourceRanks.end ());
00220   TEST_EQUALITY( sourceRanks.size (), expectedSourceRanks.size () );
00221   for (size_type k = 0; k < sourceRanks.size (); ++k) {
00222     TEST_EQUALITY( sourceRanks[k], expectedSourceRanks[k] );
00223   }
00224 
00225   // Make sure the source tags are correct.
00226   for (size_type k = 0; k < statuses.size (); ++k) {
00227     TEST_EQUALITY( statuses[k]->getTag (), tag2 );
00228   }
00229 
00230   // Make sure the message contents are correct.
00231   TEST_EQUALITY( leftRecvBuf[0], leftNeighbor + tag2 );
00232   TEST_EQUALITY( rightRecvBuf[0], rightNeighbor + tag2 );
00233 
00235   // Third round of messages
00237   out << "Round 3 of messages" << endl;
00238 
00239   // In this round, we try again with the first tag.  This will tell
00240   // us if any first-round messages got mixed up with second-round
00241   // messages.
00242   const int tag3 = tag1;
00243 
00244   // Fill receive buffer with error flags.
00245   for (size_type k = 0; k < recvBuf.size (); ++k) {
00246     recvBuf[k] = -1;
00247   }
00248   
00249   // Send my process rank plus the current tag to all neighbors.
00250   for (size_type k = 0; k < sendBuf.size (); ++k) {
00251     sendBuf[k] = myRank + tag3;
00252   }
00253   
00254   // Post receives from left and right neighbors.
00255   requests[0] = ireceive<int, int> (leftRecvBuf, leftNeighbor, tag3, *comm);
00256   requests[1] = ireceive<int, int> (rightRecvBuf, rightNeighbor, tag3, *comm);
00257 
00258   // Post sends to left and right neighbors.
00259   send<int, int> (leftSendBuf.getRawPtr (), as<int> (leftSendBuf.size ()), 
00260       leftNeighbor, tag3, *comm);
00261   send<int, int> (rightSendBuf.getRawPtr (), as<int> (rightSendBuf.size ()),
00262       rightNeighbor, tag3, *comm);
00263 
00264   // Wait for the receives to complete.
00265   waitAll (*comm, requests (), statuses ());
00266 
00267   // Make sure the source ranks are correct.
00268   for (size_type k = 0; k < 2; ++k) {
00269     sourceRanks[k] = statuses[k]->getSourceRank ();
00270   }
00271   std::sort (sourceRanks.begin (), sourceRanks.end ());
00272   TEST_EQUALITY( sourceRanks.size (), expectedSourceRanks.size () );
00273   for (size_type k = 0; k < sourceRanks.size (); ++k) {
00274     TEST_EQUALITY( sourceRanks[k], expectedSourceRanks[k] );
00275   }
00276 
00277   // Make sure the source tags are correct.
00278   for (size_type k = 0; k < statuses.size (); ++k) {
00279     TEST_EQUALITY( statuses[k]->getTag (), tag3 );
00280   }
00281 
00282   // Make sure the message contents are correct.
00283   TEST_EQUALITY( leftRecvBuf[0], leftNeighbor + tag3 );
00284   TEST_EQUALITY( rightRecvBuf[0], rightNeighbor + tag3 );
00285 
00287   // Final check
00289   out << "Final check" << endl;
00290 
00291   // At this point, if we do a barrier, all the processes should reach
00292   // it.  None should hang.  If this test times out, it probably means
00293   // that not all the processes reached this point.
00294   comm->barrier ();
00295   out << "All processes successfully completed this test." << endl;
00296 }
00297 
00298 
00299 TEUCHOS_UNIT_TEST( MpiCommTag, IrecvIsend )
00300 {
00301   typedef ArrayRCP<int>::size_type size_type;
00302 
00303   RCP<const Comm<int> > comm = rcp (new MpiComm<int> (MPI_COMM_WORLD));
00304   const int myRank = comm->getRank ();
00305   const int numProcs = comm->getSize ();
00306 
00307   // If there is only one process, then the left and right neighbors
00308   // are the same, namely the calling process.  MPI allows a process
00309   // to send to and receive from itself.  On the other hand, we want
00310   // to test blocking sends, and we want to post two sends, so we only
00311   // allow > 1 processes.
00312   if (numProcs == 1) {
00313     out << "numProcs == 1, test passes trivially." << endl;
00314     return;
00315   }
00316   out << "Test setup" << endl;
00317 
00318   // If there are only two processes, the left neighbor and the right
00319   // neighbor are the same, namely the other process.
00320   int leftNeighbor = (myRank - 1) % numProcs;
00321   int rightNeighbor = (myRank + 1) % numProcs;
00322   // C doesn't guarantee nonnegativity of the result of the % operator.
00323   if (leftNeighbor < 0) {
00324     leftNeighbor += numProcs;
00325   }
00326   if (rightNeighbor < 0) {
00327     rightNeighbor += numProcs;
00328   }
00329   Array<int> expectedSourceRanks (2); // expected source ranks for receives
00330   expectedSourceRanks[0] = leftNeighbor;
00331   expectedSourceRanks[1] = rightNeighbor;
00332   std::sort (expectedSourceRanks.begin (), expectedSourceRanks.end ());
00333 
00334   // Receive buffer, with subbuffers for each neighbor.
00335   ArrayRCP<int> recvBuf (2);
00336   ArrayRCP<int> leftRecvBuf = recvBuf.persistingView (0, 1);
00337   ArrayRCP<int> rightRecvBuf = recvBuf.persistingView (1, 1);
00338   
00339   // Send buffer, with subbuffers for each neighbor.
00340   ArrayRCP<int> sendBuf (2);
00341   ArrayRCP<int> leftSendBuf = sendBuf.persistingView (0, 1);
00342   ArrayRCP<int> rightSendBuf = sendBuf.persistingView (1, 1);
00343 
00344   // Requests for both nonblocking receives and nonblocking sends.
00345   Array<RCP<CommRequest<int> > > requests (4);
00346   // Statuses for both nonblocking receives and nonblocking sends.  We
00347   // only use these to test that the ranks of the received messages
00348   // were correct.
00349   Array<RCP<CommStatus<int> > > statuses (4);
00350 
00352   // First round of messages
00354   out << "Round 1 of messages" << endl;
00355 
00356   // Tag to use for the first set of messages.
00357   const int tag1 = 101;
00358 
00359   // Fill receive buffer with error flags.
00360   for (size_type k = 0; k < recvBuf.size (); ++k) {
00361     recvBuf[k] = -1;
00362   }
00363   
00364   // Send my process rank plus the current tag to all neighbors.
00365   for (size_type k = 0; k < sendBuf.size (); ++k) {
00366     sendBuf[k] = myRank + tag1;
00367   }
00368   
00369   // Post receives from left and right neighbors.
00370   requests[0] = ireceive<int, int> (leftRecvBuf, leftNeighbor, tag1, *comm);
00371   requests[1] = ireceive<int, int> (rightRecvBuf, rightNeighbor, tag1, *comm);
00372 
00373   // Post sends to left and right neighbors.
00374   requests[2] = isend<int, int> (leftSendBuf, leftNeighbor, tag1, *comm);
00375   requests[3] = isend<int, int> (rightSendBuf, rightNeighbor, tag1, *comm);
00376 
00377   // Wait for the receives to complete.
00378   waitAll (*comm, requests (), statuses ());
00379 
00380   // Make sure the source tags are correct.
00381   for (size_type k = 0; k < statuses.size (); ++k) {
00382     TEST_EQUALITY( statuses[k]->getTag (), tag1 );
00383   }
00384 
00385   // Make sure the message contents are correct.
00386   TEST_EQUALITY( leftRecvBuf[0], leftNeighbor + tag1 );
00387   TEST_EQUALITY( rightRecvBuf[0], rightNeighbor + tag1 );
00388 
00390   // Second round of messages
00392   out << "Round 2 of messages" << endl;
00393 
00394   // Tag to use for the second set of messages.
00395   const int tag2 = 202;
00396 
00397   // Fill receive buffer with error flags.
00398   for (size_type k = 0; k < recvBuf.size (); ++k) {
00399     recvBuf[k] = -1;
00400   }
00401   
00402   // Send my process rank plus the current tag to all neighbors.
00403   for (size_type k = 0; k < sendBuf.size (); ++k) {
00404     sendBuf[k] = myRank + tag2;
00405   }
00406   
00407   // Post receives from left and right neighbors.
00408   requests[0] = ireceive<int, int> (leftRecvBuf, leftNeighbor, tag2, *comm);
00409   requests[1] = ireceive<int, int> (rightRecvBuf, rightNeighbor, tag2, *comm);
00410 
00411   // Post sends to left and right neighbors.
00412   requests[2] = isend<int, int> (leftSendBuf, leftNeighbor, tag2, *comm);
00413   requests[3] = isend<int, int> (rightSendBuf, rightNeighbor, tag2, *comm);
00414 
00415   // Wait for the receives to complete.
00416   waitAll (*comm, requests (), statuses ());
00417 
00418   // Make sure the source tags are correct.
00419   for (size_type k = 0; k < statuses.size (); ++k) {
00420     TEST_EQUALITY( statuses[k]->getTag (), tag2 );
00421   }
00422 
00423   // Make sure the message contents are correct.
00424   TEST_EQUALITY( leftRecvBuf[0], leftNeighbor + tag2 );
00425   TEST_EQUALITY( rightRecvBuf[0], rightNeighbor + tag2 );
00426 
00428   // Third round of messages
00430   out << "Round 3 of messages" << endl;
00431 
00432   // In this round, we try again with the first tag.  This will tell
00433   // us if any first-round messages got mixed up with second-round
00434   // messages.
00435   const int tag3 = tag1;
00436 
00437   // Fill receive buffer with error flags.
00438   for (size_type k = 0; k < recvBuf.size (); ++k) {
00439     recvBuf[k] = -1;
00440   }
00441   
00442   // Send my process rank plus the current tag to all neighbors.
00443   for (size_type k = 0; k < sendBuf.size (); ++k) {
00444     sendBuf[k] = myRank + tag3;
00445   }
00446   
00447   // Post receives from left and right neighbors.
00448   requests[0] = ireceive<int, int> (leftRecvBuf, leftNeighbor, tag3, *comm);
00449   requests[1] = ireceive<int, int> (rightRecvBuf, rightNeighbor, tag3, *comm);
00450 
00451   // Post sends to left and right neighbors.
00452   requests[2] = isend<int, int> (leftSendBuf, leftNeighbor, tag3, *comm);
00453   requests[3] = isend<int, int> (rightSendBuf, rightNeighbor, tag3, *comm);
00454 
00455   // Wait for the receives to complete.
00456   waitAll (*comm, requests (), statuses ());
00457 
00458   // Make sure the source tags are correct.
00459   for (size_type k = 0; k < statuses.size (); ++k) {
00460     TEST_EQUALITY( statuses[k]->getTag (), tag3 );
00461   }
00462 
00463   // Make sure the message contents are correct.
00464   TEST_EQUALITY( leftRecvBuf[0], leftNeighbor + tag3 );
00465   TEST_EQUALITY( rightRecvBuf[0], rightNeighbor + tag3 );
00466 
00468   // Final check
00470   out << "Final check" << endl;
00471 
00472   // At this point, if we do a barrier, all the processes should reach
00473   // it.  None should hang.  If this test times out, it probably means
00474   // that not all the processes reached this point.
00475   comm->barrier ();
00476   out << "All processes successfully completed this test." << endl;
00477 }
00478 
00479 } // namespace
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines