Teuchos Package Browser (Single Doxygen Collection) Version of the Day
Loading...
Searching...
No Matches
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
48#include "Teuchos_getConst.hpp"
49#include "Teuchos_as.hpp"
50
51namespace std {
52
53template <typename Packet>
54ostream & operator<< (ostream& os, const pair<Packet, Packet>& arg)
55{
56 os << "(" << arg.first << "," << arg.second << ")";
57 return os;
58}
59
60} // namespace std
61
62namespace {
63using Teuchos::Array;
66using Teuchos::as;
67using Teuchos::Comm;
71using Teuchos::isend;
72using Teuchos::MpiComm;
73using Teuchos::outArg;
74using Teuchos::RCP;
75using Teuchos::rcp;
76using Teuchos::send;
77using Teuchos::waitAll;
78using std::endl;
79
81{
83 clp.addOutputSetupOptions (true);
84}
85
86TEUCHOS_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
299TEUCHOS_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
Implementation of Teuchos wrappers for MPI.
#define TEST_EQUALITY(v1, v2)
Assert the equality of v1 and v2.
#define TEUCHOS_STATIC_SETUP()
Run setup code statically in a translation unit.
Unit testing support.
#define TEUCHOS_UNIT_TEST(TEST_GROUP, TEST_NAME)
Macro for defining a (non-templated) unit test.
Definition of Teuchos::as, for conversions between types.
Reference-counted smart pointer for managing arrays.
Nonowning array view.
Replacement for std::vector that is compatible with the Teuchos Memory Management classes.
Encapsulation of a pending nonblocking communication operation.
Encapsulation of the result of a receive (blocking or nonblocking).
Abstract interface for distributed-memory communication.
Class that helps parse command line input arguments from (argc,argv[]) and set options.
void addOutputSetupOptions(const bool &addOutputSetupOptions)
Set if options will be automatically added to setup Teuchos::VerboseObjectBase::getDefaultOStream().
Smart reference counting pointer class for automatic garbage collection.
static CommandLineProcessor & getCLP()
Return the CLP to add options to.
TypeTo as(const TypeFrom &t)
Convert from one value type to another.
RCP< Teuchos::CommRequest< int > > isend(const ArrayRCP< const double > &sendBuffer, const int destRank, const int tag, const Comm< int > &comm)
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).
ostream & operator<<(ostream &os, const pair< Packet, Packet > &arg)