Teuchos Package Browser (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
reduceAllInPlace.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 
10 // Test that Teuchos::reduceAll allows aliasing input and output
11 // buffers, if the communicator is not an intercomm. Motivation:
12 // https://github.com/trilinos/Trilinos/issues/1389
13 
14 #include "Teuchos_DefaultComm.hpp"
15 #include "Teuchos_CommHelpers.hpp"
16 #ifdef HAVE_TEUCHOS_MPI
17 # include "mpi.h"
19 #endif // HAVE_TEUCHOS_MPI
21 
22 namespace { // (anonymous)
23 
24 #ifdef HAVE_TEUCHOS_MPI
25 MPI_Comm
26 getRawMpiCommFromTeuchosComm (const ::Teuchos::Comm<int>& comm)
27 {
28  using ::Teuchos::Comm;
29  using ::Teuchos::MpiComm;
30  using ::Teuchos::RCP;
31 
32  const Comm<int>* commPtr = &comm;
33  const MpiComm<int>* mpiCommPtr = dynamic_cast<const MpiComm<int>* > (commPtr);
34  if (mpiCommPtr == NULL) {
35  return MPI_COMM_SELF;
36  }
37  else {
38  using ::Teuchos::OpaqueWrapper;
39  using ::Teuchos::RCP;
40  RCP<const OpaqueWrapper<MPI_Comm> > wrapper = mpiCommPtr->getRawMpiComm ();
41  if (wrapper.is_null ()) {
42  return MPI_COMM_SELF;
43  }
44  else {
45  return *wrapper;
46  }
47  }
48 }
49 #endif // HAVE_TEUCHOS_MPI
50 
51 TEUCHOS_UNIT_TEST( Comm, ReduceAllInPlace )
52 {
53  using Teuchos::Comm;
54  using Teuchos::outArg;
55  using Teuchos::reduceAll;
56  using Teuchos::REDUCE_SUM;
57  using Teuchos::RCP;
58  using std::endl;
59 
60  out << "Test Teuchos::reduceAll with both intracomms and intercomms" << endl;
61  Teuchos::OSTab tab1 (out);
62 
63  RCP<const Comm<int> > comm = Teuchos::DefaultComm<int>::getComm ();
64  const int numProcs = comm->getSize ();
65  TEST_ASSERT( numProcs > 1 );
66  if (numProcs > 1) {
67  out << "This test requires > 1 processes in the input communicator "
68  "in order to be meaningful." << endl;
69  return;
70  }
71 
72  typedef int reduce_type; // type of reductions' input & output, for this test
73  reduce_type inputVal = 3;
74  reduce_type outputVal = 0; // output of reduceAll
75  const reduce_type expectedOutputVal = inputVal * numProcs;
76 
77  // Sanity check for reduceAll.
78  reduceAll<int, reduce_type> (*comm, REDUCE_SUM, inputVal, outArg (outputVal));
79  TEST_EQUALITY( outputVal, expectedOutputVal );
80 
81 #ifdef HAVE_TEUCHOS_MPI
82  MPI_Comm rawMpiComm = getRawMpiCommFromTeuchosComm (*comm);
83  int isInter = 0;
84  // This is a "local routine" (MPI 3.1, Section 6.6.1, p. 259).
85  (void) MPI_Comm_test_inter (rawMpiComm, &isInter);
86  if (isInter != 0) { // input communicator is an intercomm.
87  out << "Input communicator is an intercomm; "
88  "no point in continuing (not safe to exercise MPI_IN_PLACE)." << endl;
89  }
90  else { // input communicator is NOT an intercomm (is an intracomm)
91  out << "Input communicator is NOT an intercomm; "
92  "we may safely exercise MPI_IN_PLACE." << endl;
93 
94  // We hide use of MPI_IN_PLACE, by letting users alias the input
95  // and output buffers.
96  inputVal = 3;
97  reduceAll<int, reduce_type> (*comm, REDUCE_SUM, inputVal, outArg (inputVal));
98  TEST_EQUALITY( inputVal, expectedOutputVal );
99  }
100 
101  // Test whether we succeeded on all processes. This is particularly
102  // important when exercising MPI_IN_PLACE, since incorrect use of
103  // aliasing may cause only some processes to have incorrect results.
104  int lclSuccess = success ? 1 : 0;
105  int gblSuccess = 0; // output argument
106  const int err = MPI_Allreduce (&lclSuccess, &gblSuccess, 1, MPI_INT, MPI_MIN, rawMpiComm);
108  (err != MPI_SUCCESS, std::logic_error, "MPI_Allreduce failed!");
109  success = (gblSuccess == 1);
110  TEST_ASSERT( gblSuccess == 1 );
111 #endif // HAVE_TEUCHOS_MPI
112 }
113 
114 } // namespace (anonymous)
#define TEST_ASSERT(v1)
Assert the given statement is true.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Macro for throwing an exception with breakpointing to ease debugging.
#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.
static Teuchos::RCP< const Comm< OrdinalType > > getComm()
Return the default global communicator.
Tabbing class for helping to create formated, indented output for a basic_FancyOStream object...
Unit testing support.
Implementation of Teuchos wrappers for MPI.
Abstract interface for distributed-memory communication.
Smart reference counting pointer class for automatic garbage collection.
Ptr< T > outArg(T &arg)
create a non-persisting (required or optional) output argument for a function call.