Teuchos Package Browser (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DefaultMpiComm_TagTests.cpp
Go to the documentation of this file.
1 /*
2 // @HEADER
3 // ***********************************************************************
4 //
5 // Teuchos: Common Tools Package
6 // Copyright (2004) Sandia Corporation
7 //
8 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
9 // license for use of this work by or on behalf of the U.S. Government.
10 //
11 // Redistribution and use in source and binary forms, with or without
12 // modification, are permitted provided that the following conditions are
13 // met:
14 //
15 // 1. Redistributions of source code must retain the above copyright
16 // notice, this list of conditions and the following disclaimer.
17 //
18 // 2. Redistributions in binary form must reproduce the above copyright
19 // notice, this list of conditions and the following disclaimer in the
20 // documentation and/or other materials provided with the distribution.
21 //
22 // 3. Neither the name of the Corporation nor the names of the
23 // contributors may be used to endorse or promote products derived from
24 // this software without specific prior written permission.
25 //
26 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 //
38 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
39 //
40 // ***********************************************************************
41 // @HEADER
42 */
43 
46 #include "Teuchos_CommHelpers.hpp"
47 #include "Teuchos_DefaultComm.hpp"
48 #include "Teuchos_getConst.hpp"
49 #include "Teuchos_as.hpp"
50 
51 namespace std {
52 
53 template <typename Packet>
54 ostream & operator<< (ostream& os, const pair<Packet, Packet>& arg)
55 {
56  os << "(" << arg.first << "," << arg.second << ")";
57  return os;
58 }
59 
60 } // namespace std
61 
62 namespace {
63 using Teuchos::Array;
64 using Teuchos::ArrayRCP;
65 using Teuchos::ArrayView;
66 using Teuchos::as;
67 using Teuchos::Comm;
70 using Teuchos::ireceive;
71 using Teuchos::isend;
72 using Teuchos::MpiComm;
73 using Teuchos::outArg;
74 using Teuchos::RCP;
75 using Teuchos::rcp;
76 using Teuchos::send;
77 using Teuchos::waitAll;
78 using std::endl;
79 
81 {
83  clp.addOutputSetupOptions (true);
84 }
85 
86 TEUCHOS_UNIT_TEST( MpiCommTag, IrecvSend )
87 {
88  typedef ArrayRCP<int>::size_type size_type;
89 
90  RCP<const Comm<int> > comm = rcp (new MpiComm<int> (MPI_COMM_WORLD));
91  const int myRank = comm->getRank ();
92  const int numProcs = comm->getSize ();
93 
94  // If there is only one process, then the left and right neighbors
95  // are the same, namely the calling process. MPI allows a process
96  // to send to and receive from itself. On the other hand, we want
97  // to test blocking sends, and we want to post two sends, so we only
98  // allow > 1 processes.
99  if (numProcs == 1) {
100  out << "numProcs == 1, test passes trivially." << endl;
101  return;
102  }
103  out << "Test setup" << endl;
104 
105  // If there are only two processes, the left neighbor and the right
106  // neighbor are the same, namely the other process.
107  int leftNeighbor = (myRank - 1) % numProcs;
108  int rightNeighbor = (myRank + 1) % numProcs;
109  // C doesn't guarantee nonnegativity of the result of the % operator.
110  if (leftNeighbor < 0) {
111  leftNeighbor += numProcs;
112  }
113  if (rightNeighbor < 0) {
114  rightNeighbor += numProcs;
115  }
116  Array<int> expectedSourceRanks (2); // expected source ranks for receives
117  expectedSourceRanks[0] = leftNeighbor;
118  expectedSourceRanks[1] = rightNeighbor;
119  std::sort (expectedSourceRanks.begin (), expectedSourceRanks.end ());
120 
121  // Receive buffer, with subbuffers for each neighbor.
122  ArrayRCP<int> recvBuf (2);
123  ArrayRCP<int> leftRecvBuf = recvBuf.persistingView (0, 1);
124  ArrayRCP<int> rightRecvBuf = recvBuf.persistingView (1, 1);
125 
126  // Send buffer, with subbuffers for each neighbor.
127  Array<int> sendBuf (2);
128  ArrayView<int> leftSendBuf = sendBuf.view (0, 1);
129  ArrayView<int> rightSendBuf = sendBuf.view (1, 1);
130 
132  // First round of messages
134  out << "Round 1 of messages" << endl;
135 
136  // Tag to use for the first set of messages.
137  const int tag1 = 42;
138 
139  // Fill receive buffer with error flags.
140  for (size_type k = 0; k < recvBuf.size (); ++k) {
141  recvBuf[k] = -1;
142  }
143 
144  // Send my process rank plus the current tag to all neighbors.
145  for (size_type k = 0; k < sendBuf.size (); ++k) {
146  sendBuf[k] = myRank + tag1;
147  }
148 
149  // Post receives from left and right neighbors.
150  Array<RCP<CommRequest<int> > > requests (2);
151  requests[0] = ireceive<int, int> (leftRecvBuf, leftNeighbor, tag1, *comm);
152  requests[1] = ireceive<int, int> (rightRecvBuf, rightNeighbor, tag1, *comm);
153 
154  // Post sends to left and right neighbors.
155  send<int, int> (leftSendBuf.getRawPtr (), as<int> (leftSendBuf.size ()),
156  leftNeighbor, tag1, *comm);
157  send<int, int> (rightSendBuf.getRawPtr (), as<int> (rightSendBuf.size ()),
158  rightNeighbor, tag1, *comm);
159 
160  // Wait for the receives to complete.
161  Array<RCP<CommStatus<int> > > statuses (2);
162  waitAll (*comm, requests (), statuses ());
163 
164  // Make sure the source ranks are correct.
165  Array<int> sourceRanks (2);
166  for (size_type k = 0; k < 2; ++k) {
167  sourceRanks[k] = statuses[k]->getSourceRank ();
168  }
169  std::sort (sourceRanks.begin (), sourceRanks.end ());
170  TEST_EQUALITY( sourceRanks.size (), expectedSourceRanks.size () );
171  for (size_type k = 0; k < sourceRanks.size (); ++k) {
172  TEST_EQUALITY( sourceRanks[k], expectedSourceRanks[k] );
173  }
174 
175  // Make sure the source tags are correct.
176  for (size_type k = 0; k < statuses.size (); ++k) {
177  TEST_EQUALITY( statuses[k]->getTag (), tag1 );
178  }
179 
180  // Make sure the message contents are correct.
181  TEST_EQUALITY( leftRecvBuf[0], leftNeighbor + tag1 );
182  TEST_EQUALITY( rightRecvBuf[0], rightNeighbor + tag1 );
183 
185  // Second round of messages
187  out << "Round 2 of messages" << endl;
188 
189  // Tag to use for the second set of messages.
190  const int tag2 = 100;
191 
192  // Fill receive buffer with error flags.
193  for (size_type k = 0; k < recvBuf.size (); ++k) {
194  recvBuf[k] = -1;
195  }
196 
197  // Send my process rank plus the current tag to all neighbors.
198  for (size_type k = 0; k < sendBuf.size (); ++k) {
199  sendBuf[k] = myRank + tag2;
200  }
201 
202  // Post receives from left and right neighbors.
203  requests[0] = ireceive<int, int> (leftRecvBuf, leftNeighbor, tag2, *comm);
204  requests[1] = ireceive<int, int> (rightRecvBuf, rightNeighbor, tag2, *comm);
205 
206  // Post sends to left and right neighbors.
207  send<int, int> (leftSendBuf.getRawPtr (), as<int> (leftSendBuf.size ()),
208  leftNeighbor, tag2, *comm);
209  send<int, int> (rightSendBuf.getRawPtr (), as<int> (rightSendBuf.size ()),
210  rightNeighbor, tag2, *comm);
211 
212  // Wait for the receives to complete.
213  waitAll (*comm, requests (), statuses ());
214 
215  // Make sure the source ranks are correct.
216  for (size_type k = 0; k < 2; ++k) {
217  sourceRanks[k] = statuses[k]->getSourceRank ();
218  }
219  std::sort (sourceRanks.begin (), sourceRanks.end ());
220  TEST_EQUALITY( sourceRanks.size (), expectedSourceRanks.size () );
221  for (size_type k = 0; k < sourceRanks.size (); ++k) {
222  TEST_EQUALITY( sourceRanks[k], expectedSourceRanks[k] );
223  }
224 
225  // Make sure the source tags are correct.
226  for (size_type k = 0; k < statuses.size (); ++k) {
227  TEST_EQUALITY( statuses[k]->getTag (), tag2 );
228  }
229 
230  // Make sure the message contents are correct.
231  TEST_EQUALITY( leftRecvBuf[0], leftNeighbor + tag2 );
232  TEST_EQUALITY( rightRecvBuf[0], rightNeighbor + tag2 );
233 
235  // Third round of messages
237  out << "Round 3 of messages" << endl;
238 
239  // In this round, we try again with the first tag. This will tell
240  // us if any first-round messages got mixed up with second-round
241  // messages.
242  const int tag3 = tag1;
243 
244  // Fill receive buffer with error flags.
245  for (size_type k = 0; k < recvBuf.size (); ++k) {
246  recvBuf[k] = -1;
247  }
248 
249  // Send my process rank plus the current tag to all neighbors.
250  for (size_type k = 0; k < sendBuf.size (); ++k) {
251  sendBuf[k] = myRank + tag3;
252  }
253 
254  // Post receives from left and right neighbors.
255  requests[0] = ireceive<int, int> (leftRecvBuf, leftNeighbor, tag3, *comm);
256  requests[1] = ireceive<int, int> (rightRecvBuf, rightNeighbor, tag3, *comm);
257 
258  // Post sends to left and right neighbors.
259  send<int, int> (leftSendBuf.getRawPtr (), as<int> (leftSendBuf.size ()),
260  leftNeighbor, tag3, *comm);
261  send<int, int> (rightSendBuf.getRawPtr (), as<int> (rightSendBuf.size ()),
262  rightNeighbor, tag3, *comm);
263 
264  // Wait for the receives to complete.
265  waitAll (*comm, requests (), statuses ());
266 
267  // Make sure the source ranks are correct.
268  for (size_type k = 0; k < 2; ++k) {
269  sourceRanks[k] = statuses[k]->getSourceRank ();
270  }
271  std::sort (sourceRanks.begin (), sourceRanks.end ());
272  TEST_EQUALITY( sourceRanks.size (), expectedSourceRanks.size () );
273  for (size_type k = 0; k < sourceRanks.size (); ++k) {
274  TEST_EQUALITY( sourceRanks[k], expectedSourceRanks[k] );
275  }
276 
277  // Make sure the source tags are correct.
278  for (size_type k = 0; k < statuses.size (); ++k) {
279  TEST_EQUALITY( statuses[k]->getTag (), tag3 );
280  }
281 
282  // Make sure the message contents are correct.
283  TEST_EQUALITY( leftRecvBuf[0], leftNeighbor + tag3 );
284  TEST_EQUALITY( rightRecvBuf[0], rightNeighbor + tag3 );
285 
287  // Final check
289  out << "Final check" << endl;
290 
291  // At this point, if we do a barrier, all the processes should reach
292  // it. None should hang. If this test times out, it probably means
293  // that not all the processes reached this point.
294  comm->barrier ();
295  out << "All processes successfully completed this test." << endl;
296 }
297 
298 
299 TEUCHOS_UNIT_TEST( MpiCommTag, IrecvIsend )
300 {
301  typedef ArrayRCP<int>::size_type size_type;
302 
303  RCP<const Comm<int> > comm = rcp (new MpiComm<int> (MPI_COMM_WORLD));
304  const int myRank = comm->getRank ();
305  const int numProcs = comm->getSize ();
306 
307  // If there is only one process, then the left and right neighbors
308  // are the same, namely the calling process. MPI allows a process
309  // to send to and receive from itself. On the other hand, we want
310  // to test blocking sends, and we want to post two sends, so we only
311  // allow > 1 processes.
312  if (numProcs == 1) {
313  out << "numProcs == 1, test passes trivially." << endl;
314  return;
315  }
316  out << "Test setup" << endl;
317 
318  // If there are only two processes, the left neighbor and the right
319  // neighbor are the same, namely the other process.
320  int leftNeighbor = (myRank - 1) % numProcs;
321  int rightNeighbor = (myRank + 1) % numProcs;
322  // C doesn't guarantee nonnegativity of the result of the % operator.
323  if (leftNeighbor < 0) {
324  leftNeighbor += numProcs;
325  }
326  if (rightNeighbor < 0) {
327  rightNeighbor += numProcs;
328  }
329  Array<int> expectedSourceRanks (2); // expected source ranks for receives
330  expectedSourceRanks[0] = leftNeighbor;
331  expectedSourceRanks[1] = rightNeighbor;
332  std::sort (expectedSourceRanks.begin (), expectedSourceRanks.end ());
333 
334  // Receive buffer, with subbuffers for each neighbor.
335  ArrayRCP<int> recvBuf (2);
336  ArrayRCP<int> leftRecvBuf = recvBuf.persistingView (0, 1);
337  ArrayRCP<int> rightRecvBuf = recvBuf.persistingView (1, 1);
338 
339  // Send buffer, with subbuffers for each neighbor.
340  ArrayRCP<int> sendBuf (2);
341  ArrayRCP<int> leftSendBuf = sendBuf.persistingView (0, 1);
342  ArrayRCP<int> rightSendBuf = sendBuf.persistingView (1, 1);
343 
344  // Requests for both nonblocking receives and nonblocking sends.
345  Array<RCP<CommRequest<int> > > requests (4);
346  // Statuses for both nonblocking receives and nonblocking sends. We
347  // only use these to test that the ranks of the received messages
348  // were correct.
349  Array<RCP<CommStatus<int> > > statuses (4);
350 
352  // First round of messages
354  out << "Round 1 of messages" << endl;
355 
356  // Tag to use for the first set of messages.
357  const int tag1 = 101;
358 
359  // Fill receive buffer with error flags.
360  for (size_type k = 0; k < recvBuf.size (); ++k) {
361  recvBuf[k] = -1;
362  }
363 
364  // Send my process rank plus the current tag to all neighbors.
365  for (size_type k = 0; k < sendBuf.size (); ++k) {
366  sendBuf[k] = myRank + tag1;
367  }
368 
369  // Post receives from left and right neighbors.
370  requests[0] = ireceive<int, int> (leftRecvBuf, leftNeighbor, tag1, *comm);
371  requests[1] = ireceive<int, int> (rightRecvBuf, rightNeighbor, tag1, *comm);
372 
373  // Post sends to left and right neighbors.
374  requests[2] = isend<int, int> (leftSendBuf, leftNeighbor, tag1, *comm);
375  requests[3] = isend<int, int> (rightSendBuf, rightNeighbor, tag1, *comm);
376 
377  // Wait for the receives to complete.
378  waitAll (*comm, requests (), statuses ());
379 
380  // Make sure the source tags are correct.
381  for (size_type k = 0; k < 2; ++k) {
382  TEST_EQUALITY( statuses[k]->getTag (), tag1 );
383  }
384 
385  // Make sure the message contents are correct.
386  TEST_EQUALITY( leftRecvBuf[0], leftNeighbor + tag1 );
387  TEST_EQUALITY( rightRecvBuf[0], rightNeighbor + tag1 );
388 
390  // Second round of messages
392  out << "Round 2 of messages" << endl;
393 
394  // Tag to use for the second set of messages.
395  const int tag2 = 202;
396 
397  // Fill receive buffer with error flags.
398  for (size_type k = 0; k < recvBuf.size (); ++k) {
399  recvBuf[k] = -1;
400  }
401 
402  // Send my process rank plus the current tag to all neighbors.
403  for (size_type k = 0; k < sendBuf.size (); ++k) {
404  sendBuf[k] = myRank + tag2;
405  }
406 
407  // Post receives from left and right neighbors.
408  requests[0] = ireceive<int, int> (leftRecvBuf, leftNeighbor, tag2, *comm);
409  requests[1] = ireceive<int, int> (rightRecvBuf, rightNeighbor, tag2, *comm);
410 
411  // Post sends to left and right neighbors.
412  requests[2] = isend<int, int> (leftSendBuf, leftNeighbor, tag2, *comm);
413  requests[3] = isend<int, int> (rightSendBuf, rightNeighbor, tag2, *comm);
414 
415  // Wait for the receives to complete.
416  waitAll (*comm, requests (), statuses ());
417 
418  // Make sure the source tags are correct.
419  for (size_type k = 0; k < 2; ++k) {
420  TEST_EQUALITY( statuses[k]->getTag (), tag2 );
421  }
422 
423  // Make sure the message contents are correct.
424  TEST_EQUALITY( leftRecvBuf[0], leftNeighbor + tag2 );
425  TEST_EQUALITY( rightRecvBuf[0], rightNeighbor + tag2 );
426 
428  // Third round of messages
430  out << "Round 3 of messages" << endl;
431 
432  // In this round, we try again with the first tag. This will tell
433  // us if any first-round messages got mixed up with second-round
434  // messages.
435  const int tag3 = tag1;
436 
437  // Fill receive buffer with error flags.
438  for (size_type k = 0; k < recvBuf.size (); ++k) {
439  recvBuf[k] = -1;
440  }
441 
442  // Send my process rank plus the current tag to all neighbors.
443  for (size_type k = 0; k < sendBuf.size (); ++k) {
444  sendBuf[k] = myRank + tag3;
445  }
446 
447  // Post receives from left and right neighbors.
448  requests[0] = ireceive<int, int> (leftRecvBuf, leftNeighbor, tag3, *comm);
449  requests[1] = ireceive<int, int> (rightRecvBuf, rightNeighbor, tag3, *comm);
450 
451  // Post sends to left and right neighbors.
452  requests[2] = isend<int, int> (leftSendBuf, leftNeighbor, tag3, *comm);
453  requests[3] = isend<int, int> (rightSendBuf, rightNeighbor, tag3, *comm);
454 
455  // Wait for the receives to complete.
456  waitAll (*comm, requests (), statuses ());
457 
458  // Make sure the source tags are correct.
459  for (size_type k = 0; k < 2; ++k) {
460  TEST_EQUALITY( statuses[k]->getTag (), tag3 );
461  }
462 
463  // Make sure the message contents are correct.
464  TEST_EQUALITY( leftRecvBuf[0], leftNeighbor + tag3 );
465  TEST_EQUALITY( rightRecvBuf[0], rightNeighbor + tag3 );
466 
468  // Final check
470  out << "Final check" << endl;
471 
472  // At this point, if we do a barrier, all the processes should reach
473  // it. None should hang. If this test times out, it probably means
474  // that not all the processes reached this point.
475  comm->barrier ();
476  out << "All processes successfully completed this test." << endl;
477 }
478 
479 } // namespace
RCP< T > rcp(const boost::shared_ptr< T > &sptr)
Conversion function that takes in a boost::shared_ptr object and spits out a Teuchos::RCP object...
void addOutputSetupOptions(const bool &addOutputSetupOptions)
Set if options will be automatically added to setup Teuchos::VerboseObjectBase::getDefaultOStream().
static CommandLineProcessor & getCLP()
Return the CLP to add options to.
#define TEST_EQUALITY(v1, v2)
Assert the equality of v1 and v2.
#define TEUCHOS_UNIT_TEST(TEST_GROUP, TEST_NAME)
Macro for defining a (non-templated) unit test.
void send< int, int >(const Comm< int > &comm, const int count, const int sendBuffer[], const int destRank)
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Deprecated.
void waitAll(const Comm< Ordinal > &comm, const ArrayView< RCP< CommRequest< Ordinal > > > &requests)
Wait for an array of Teuchos::CommRequest objects.
Unit testing support.
Implementation of Teuchos wrappers for MPI.
Encapsulation of the result of a receive (blocking or nonblocking).
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). ...
TypeTo as(const TypeFrom &t)
Convert from one value type to another.
TEUCHOSCOMM_LIB_DLL_EXPORT RCP< CommRequest< int > > isend< int, int >(const ArrayRCP< const int > &sendBuffer, const int destRank, const int tag, const Comm< int > &comm)
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).
RCP< Teuchos::CommRequest< int > > ireceive< int, int >(const Comm< int > &comm, const ArrayRCP< int > &recvBuffer, const int sourceRank)
Abstract interface for distributed-memory communication.
Nonowning array view.
RCP< Teuchos::CommRequest< int > > isend(const ArrayRCP< const double > &sendBuffer, const int destRank, const int tag, const Comm< int > &comm)
Smart reference counting pointer class for automatic garbage collection.
Encapsulation of a pending nonblocking communication operation.
Definition of Teuchos::as, for conversions between types.
Class that helps parse command line input arguments from (argc,argv[]) and set options.
TEUCHOS_STATIC_SETUP()
Reference-counted smart pointer for managing arrays.
Replacement for std::vector that is compatible with the Teuchos Memory Management classes...