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 // @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 
12 #include "Teuchos_CommHelpers.hpp"
13 #include "Teuchos_DefaultComm.hpp"
14 #include "Teuchos_getConst.hpp"
15 #include "Teuchos_as.hpp"
16 
17 namespace std {
18 
19 template <typename Packet>
20 ostream & operator<< (ostream& os, const pair<Packet, Packet>& arg)
21 {
22  os << "(" << arg.first << "," << arg.second << ")";
23  return os;
24 }
25 
26 } // namespace std
27 
28 namespace {
29 using Teuchos::Array;
30 using Teuchos::ArrayRCP;
31 using Teuchos::ArrayView;
32 using Teuchos::as;
33 using Teuchos::Comm;
36 using Teuchos::ireceive;
37 using Teuchos::isend;
38 using Teuchos::MpiComm;
39 using Teuchos::outArg;
40 using Teuchos::RCP;
41 using Teuchos::rcp;
42 using Teuchos::send;
43 using Teuchos::waitAll;
44 using std::endl;
45 
47 {
49  clp.addOutputSetupOptions (true);
50 }
51 
52 TEUCHOS_UNIT_TEST( MpiCommTag, IrecvSend )
53 {
54  typedef ArrayRCP<int>::size_type size_type;
55 
56  RCP<const Comm<int> > comm = rcp (new MpiComm<int> (MPI_COMM_WORLD));
57  const int myRank = comm->getRank ();
58  const int numProcs = comm->getSize ();
59 
60  // If there is only one process, then the left and right neighbors
61  // are the same, namely the calling process. MPI allows a process
62  // to send to and receive from itself. On the other hand, we want
63  // to test blocking sends, and we want to post two sends, so we only
64  // allow > 1 processes.
65  if (numProcs == 1) {
66  out << "numProcs == 1, test passes trivially." << endl;
67  return;
68  }
69  out << "Test setup" << endl;
70 
71  // If there are only two processes, the left neighbor and the right
72  // neighbor are the same, namely the other process.
73  int leftNeighbor = (myRank - 1) % numProcs;
74  int rightNeighbor = (myRank + 1) % numProcs;
75  // C doesn't guarantee nonnegativity of the result of the % operator.
76  if (leftNeighbor < 0) {
77  leftNeighbor += numProcs;
78  }
79  if (rightNeighbor < 0) {
80  rightNeighbor += numProcs;
81  }
82  Array<int> expectedSourceRanks (2); // expected source ranks for receives
83  expectedSourceRanks[0] = leftNeighbor;
84  expectedSourceRanks[1] = rightNeighbor;
85  std::sort (expectedSourceRanks.begin (), expectedSourceRanks.end ());
86 
87  // Receive buffer, with subbuffers for each neighbor.
88  ArrayRCP<int> recvBuf (2);
89  ArrayRCP<int> leftRecvBuf = recvBuf.persistingView (0, 1);
90  ArrayRCP<int> rightRecvBuf = recvBuf.persistingView (1, 1);
91 
92  // Send buffer, with subbuffers for each neighbor.
93  Array<int> sendBuf (2);
94  ArrayView<int> leftSendBuf = sendBuf.view (0, 1);
95  ArrayView<int> rightSendBuf = sendBuf.view (1, 1);
96 
98  // First round of messages
100  out << "Round 1 of messages" << endl;
101 
102  // Tag to use for the first set of messages.
103  const int tag1 = 42;
104 
105  // Fill receive buffer with error flags.
106  for (size_type k = 0; k < recvBuf.size (); ++k) {
107  recvBuf[k] = -1;
108  }
109 
110  // Send my process rank plus the current tag to all neighbors.
111  for (size_type k = 0; k < sendBuf.size (); ++k) {
112  sendBuf[k] = myRank + tag1;
113  }
114 
115  // Post receives from left and right neighbors.
116  Array<RCP<CommRequest<int> > > requests (2);
117  requests[0] = ireceive<int, int> (leftRecvBuf, leftNeighbor, tag1, *comm);
118  requests[1] = ireceive<int, int> (rightRecvBuf, rightNeighbor, tag1, *comm);
119 
120  // Post sends to left and right neighbors.
121  send<int, int> (leftSendBuf.getRawPtr (), as<int> (leftSendBuf.size ()),
122  leftNeighbor, tag1, *comm);
123  send<int, int> (rightSendBuf.getRawPtr (), as<int> (rightSendBuf.size ()),
124  rightNeighbor, tag1, *comm);
125 
126  // Wait for the receives to complete.
127  Array<RCP<CommStatus<int> > > statuses (2);
128  waitAll (*comm, requests (), statuses ());
129 
130  // Make sure the source ranks are correct.
131  Array<int> sourceRanks (2);
132  for (size_type k = 0; k < 2; ++k) {
133  sourceRanks[k] = statuses[k]->getSourceRank ();
134  }
135  std::sort (sourceRanks.begin (), sourceRanks.end ());
136  TEST_EQUALITY( sourceRanks.size (), expectedSourceRanks.size () );
137  for (size_type k = 0; k < sourceRanks.size (); ++k) {
138  TEST_EQUALITY( sourceRanks[k], expectedSourceRanks[k] );
139  }
140 
141  // Make sure the source tags are correct.
142  for (size_type k = 0; k < statuses.size (); ++k) {
143  TEST_EQUALITY( statuses[k]->getTag (), tag1 );
144  }
145 
146  // Make sure the message contents are correct.
147  TEST_EQUALITY( leftRecvBuf[0], leftNeighbor + tag1 );
148  TEST_EQUALITY( rightRecvBuf[0], rightNeighbor + tag1 );
149 
151  // Second round of messages
153  out << "Round 2 of messages" << endl;
154 
155  // Tag to use for the second set of messages.
156  const int tag2 = 100;
157 
158  // Fill receive buffer with error flags.
159  for (size_type k = 0; k < recvBuf.size (); ++k) {
160  recvBuf[k] = -1;
161  }
162 
163  // Send my process rank plus the current tag to all neighbors.
164  for (size_type k = 0; k < sendBuf.size (); ++k) {
165  sendBuf[k] = myRank + tag2;
166  }
167 
168  // Post receives from left and right neighbors.
169  requests[0] = ireceive<int, int> (leftRecvBuf, leftNeighbor, tag2, *comm);
170  requests[1] = ireceive<int, int> (rightRecvBuf, rightNeighbor, tag2, *comm);
171 
172  // Post sends to left and right neighbors.
173  send<int, int> (leftSendBuf.getRawPtr (), as<int> (leftSendBuf.size ()),
174  leftNeighbor, tag2, *comm);
175  send<int, int> (rightSendBuf.getRawPtr (), as<int> (rightSendBuf.size ()),
176  rightNeighbor, tag2, *comm);
177 
178  // Wait for the receives to complete.
179  waitAll (*comm, requests (), statuses ());
180 
181  // Make sure the source ranks are correct.
182  for (size_type k = 0; k < 2; ++k) {
183  sourceRanks[k] = statuses[k]->getSourceRank ();
184  }
185  std::sort (sourceRanks.begin (), sourceRanks.end ());
186  TEST_EQUALITY( sourceRanks.size (), expectedSourceRanks.size () );
187  for (size_type k = 0; k < sourceRanks.size (); ++k) {
188  TEST_EQUALITY( sourceRanks[k], expectedSourceRanks[k] );
189  }
190 
191  // Make sure the source tags are correct.
192  for (size_type k = 0; k < statuses.size (); ++k) {
193  TEST_EQUALITY( statuses[k]->getTag (), tag2 );
194  }
195 
196  // Make sure the message contents are correct.
197  TEST_EQUALITY( leftRecvBuf[0], leftNeighbor + tag2 );
198  TEST_EQUALITY( rightRecvBuf[0], rightNeighbor + tag2 );
199 
201  // Third round of messages
203  out << "Round 3 of messages" << endl;
204 
205  // In this round, we try again with the first tag. This will tell
206  // us if any first-round messages got mixed up with second-round
207  // messages.
208  const int tag3 = tag1;
209 
210  // Fill receive buffer with error flags.
211  for (size_type k = 0; k < recvBuf.size (); ++k) {
212  recvBuf[k] = -1;
213  }
214 
215  // Send my process rank plus the current tag to all neighbors.
216  for (size_type k = 0; k < sendBuf.size (); ++k) {
217  sendBuf[k] = myRank + tag3;
218  }
219 
220  // Post receives from left and right neighbors.
221  requests[0] = ireceive<int, int> (leftRecvBuf, leftNeighbor, tag3, *comm);
222  requests[1] = ireceive<int, int> (rightRecvBuf, rightNeighbor, tag3, *comm);
223 
224  // Post sends to left and right neighbors.
225  send<int, int> (leftSendBuf.getRawPtr (), as<int> (leftSendBuf.size ()),
226  leftNeighbor, tag3, *comm);
227  send<int, int> (rightSendBuf.getRawPtr (), as<int> (rightSendBuf.size ()),
228  rightNeighbor, tag3, *comm);
229 
230  // Wait for the receives to complete.
231  waitAll (*comm, requests (), statuses ());
232 
233  // Make sure the source ranks are correct.
234  for (size_type k = 0; k < 2; ++k) {
235  sourceRanks[k] = statuses[k]->getSourceRank ();
236  }
237  std::sort (sourceRanks.begin (), sourceRanks.end ());
238  TEST_EQUALITY( sourceRanks.size (), expectedSourceRanks.size () );
239  for (size_type k = 0; k < sourceRanks.size (); ++k) {
240  TEST_EQUALITY( sourceRanks[k], expectedSourceRanks[k] );
241  }
242 
243  // Make sure the source tags are correct.
244  for (size_type k = 0; k < statuses.size (); ++k) {
245  TEST_EQUALITY( statuses[k]->getTag (), tag3 );
246  }
247 
248  // Make sure the message contents are correct.
249  TEST_EQUALITY( leftRecvBuf[0], leftNeighbor + tag3 );
250  TEST_EQUALITY( rightRecvBuf[0], rightNeighbor + tag3 );
251 
253  // Final check
255  out << "Final check" << endl;
256 
257  // At this point, if we do a barrier, all the processes should reach
258  // it. None should hang. If this test times out, it probably means
259  // that not all the processes reached this point.
260  comm->barrier ();
261  out << "All processes successfully completed this test." << endl;
262 }
263 
264 
265 TEUCHOS_UNIT_TEST( MpiCommTag, IrecvIsend )
266 {
267  typedef ArrayRCP<int>::size_type size_type;
268 
269  RCP<const Comm<int> > comm = rcp (new MpiComm<int> (MPI_COMM_WORLD));
270  const int myRank = comm->getRank ();
271  const int numProcs = comm->getSize ();
272 
273  // If there is only one process, then the left and right neighbors
274  // are the same, namely the calling process. MPI allows a process
275  // to send to and receive from itself. On the other hand, we want
276  // to test blocking sends, and we want to post two sends, so we only
277  // allow > 1 processes.
278  if (numProcs == 1) {
279  out << "numProcs == 1, test passes trivially." << endl;
280  return;
281  }
282  out << "Test setup" << endl;
283 
284  // If there are only two processes, the left neighbor and the right
285  // neighbor are the same, namely the other process.
286  int leftNeighbor = (myRank - 1) % numProcs;
287  int rightNeighbor = (myRank + 1) % numProcs;
288  // C doesn't guarantee nonnegativity of the result of the % operator.
289  if (leftNeighbor < 0) {
290  leftNeighbor += numProcs;
291  }
292  if (rightNeighbor < 0) {
293  rightNeighbor += numProcs;
294  }
295  Array<int> expectedSourceRanks (2); // expected source ranks for receives
296  expectedSourceRanks[0] = leftNeighbor;
297  expectedSourceRanks[1] = rightNeighbor;
298  std::sort (expectedSourceRanks.begin (), expectedSourceRanks.end ());
299 
300  // Receive buffer, with subbuffers for each neighbor.
301  ArrayRCP<int> recvBuf (2);
302  ArrayRCP<int> leftRecvBuf = recvBuf.persistingView (0, 1);
303  ArrayRCP<int> rightRecvBuf = recvBuf.persistingView (1, 1);
304 
305  // Send buffer, with subbuffers for each neighbor.
306  ArrayRCP<int> sendBuf (2);
307  ArrayRCP<int> leftSendBuf = sendBuf.persistingView (0, 1);
308  ArrayRCP<int> rightSendBuf = sendBuf.persistingView (1, 1);
309 
310  // Requests for both nonblocking receives and nonblocking sends.
311  Array<RCP<CommRequest<int> > > requests (4);
312  // Statuses for both nonblocking receives and nonblocking sends. We
313  // only use these to test that the ranks of the received messages
314  // were correct.
315  Array<RCP<CommStatus<int> > > statuses (4);
316 
318  // First round of messages
320  out << "Round 1 of messages" << endl;
321 
322  // Tag to use for the first set of messages.
323  const int tag1 = 101;
324 
325  // Fill receive buffer with error flags.
326  for (size_type k = 0; k < recvBuf.size (); ++k) {
327  recvBuf[k] = -1;
328  }
329 
330  // Send my process rank plus the current tag to all neighbors.
331  for (size_type k = 0; k < sendBuf.size (); ++k) {
332  sendBuf[k] = myRank + tag1;
333  }
334 
335  // Post receives from left and right neighbors.
336  requests[0] = ireceive<int, int> (leftRecvBuf, leftNeighbor, tag1, *comm);
337  requests[1] = ireceive<int, int> (rightRecvBuf, rightNeighbor, tag1, *comm);
338 
339  // Post sends to left and right neighbors.
340  requests[2] = isend<int, int> (leftSendBuf, leftNeighbor, tag1, *comm);
341  requests[3] = isend<int, int> (rightSendBuf, rightNeighbor, tag1, *comm);
342 
343  // Wait for the receives to complete.
344  waitAll (*comm, requests (), statuses ());
345 
346  // Make sure the source tags are correct.
347  for (size_type k = 0; k < 2; ++k) {
348  TEST_EQUALITY( statuses[k]->getTag (), tag1 );
349  }
350 
351  // Make sure the message contents are correct.
352  TEST_EQUALITY( leftRecvBuf[0], leftNeighbor + tag1 );
353  TEST_EQUALITY( rightRecvBuf[0], rightNeighbor + tag1 );
354 
356  // Second round of messages
358  out << "Round 2 of messages" << endl;
359 
360  // Tag to use for the second set of messages.
361  const int tag2 = 202;
362 
363  // Fill receive buffer with error flags.
364  for (size_type k = 0; k < recvBuf.size (); ++k) {
365  recvBuf[k] = -1;
366  }
367 
368  // Send my process rank plus the current tag to all neighbors.
369  for (size_type k = 0; k < sendBuf.size (); ++k) {
370  sendBuf[k] = myRank + tag2;
371  }
372 
373  // Post receives from left and right neighbors.
374  requests[0] = ireceive<int, int> (leftRecvBuf, leftNeighbor, tag2, *comm);
375  requests[1] = ireceive<int, int> (rightRecvBuf, rightNeighbor, tag2, *comm);
376 
377  // Post sends to left and right neighbors.
378  requests[2] = isend<int, int> (leftSendBuf, leftNeighbor, tag2, *comm);
379  requests[3] = isend<int, int> (rightSendBuf, rightNeighbor, tag2, *comm);
380 
381  // Wait for the receives to complete.
382  waitAll (*comm, requests (), statuses ());
383 
384  // Make sure the source tags are correct.
385  for (size_type k = 0; k < 2; ++k) {
386  TEST_EQUALITY( statuses[k]->getTag (), tag2 );
387  }
388 
389  // Make sure the message contents are correct.
390  TEST_EQUALITY( leftRecvBuf[0], leftNeighbor + tag2 );
391  TEST_EQUALITY( rightRecvBuf[0], rightNeighbor + tag2 );
392 
394  // Third round of messages
396  out << "Round 3 of messages" << endl;
397 
398  // In this round, we try again with the first tag. This will tell
399  // us if any first-round messages got mixed up with second-round
400  // messages.
401  const int tag3 = tag1;
402 
403  // Fill receive buffer with error flags.
404  for (size_type k = 0; k < recvBuf.size (); ++k) {
405  recvBuf[k] = -1;
406  }
407 
408  // Send my process rank plus the current tag to all neighbors.
409  for (size_type k = 0; k < sendBuf.size (); ++k) {
410  sendBuf[k] = myRank + tag3;
411  }
412 
413  // Post receives from left and right neighbors.
414  requests[0] = ireceive<int, int> (leftRecvBuf, leftNeighbor, tag3, *comm);
415  requests[1] = ireceive<int, int> (rightRecvBuf, rightNeighbor, tag3, *comm);
416 
417  // Post sends to left and right neighbors.
418  requests[2] = isend<int, int> (leftSendBuf, leftNeighbor, tag3, *comm);
419  requests[3] = isend<int, int> (rightSendBuf, rightNeighbor, tag3, *comm);
420 
421  // Wait for the receives to complete.
422  waitAll (*comm, requests (), statuses ());
423 
424  // Make sure the source tags are correct.
425  for (size_type k = 0; k < 2; ++k) {
426  TEST_EQUALITY( statuses[k]->getTag (), tag3 );
427  }
428 
429  // Make sure the message contents are correct.
430  TEST_EQUALITY( leftRecvBuf[0], leftNeighbor + tag3 );
431  TEST_EQUALITY( rightRecvBuf[0], rightNeighbor + tag3 );
432 
434  // Final check
436  out << "Final check" << endl;
437 
438  // At this point, if we do a barrier, all the processes should reach
439  // it. None should hang. If this test times out, it probably means
440  // that not all the processes reached this point.
441  comm->barrier ();
442  out << "All processes successfully completed this test." << endl;
443 }
444 
445 } // 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...