Ticket #6704: mpi_in_place_tck6704_rev77427.patch
File mpi_in_place_tck6704_rev77427.patch, 6.4 KB (added by , 11 years ago) |
---|
-
boost/mpi/collectives/all_reduce.hpp
12 12 #ifndef BOOST_MPI_ALL_REDUCE_HPP 13 13 #define BOOST_MPI_ALL_REDUCE_HPP 14 14 15 #include <vector> 16 15 17 // All-reduce falls back to reduce() + broadcast() in some cases. 16 18 #include <boost/mpi/collectives/broadcast.hpp> 17 19 #include <boost/mpi/collectives/reduce.hpp> … … 67 69 T* out_values, Op op, mpl::false_ /*is_mpi_op*/, 68 70 mpl::false_ /*is_mpi_datatype*/) 69 71 { 70 reduce(comm, in_values, n, out_values, op, 0); 72 if (in_values == MPI_IN_PLACE) { 73 // if in_values matches the in place tag, then the output 74 // buffer actually contains the input data. 75 // But we can just go back to the out of place 76 // implementation in this case. 77 // it's not clear how/if we can avoid the copy. 78 std::vector<T> tmp_in( out_values, out_values + n); 79 reduce(comm, &(tmp_in[0]), n, out_values, op, 0); 80 } else { 81 reduce(comm, in_values, n, out_values, op, 0); 82 } 71 83 broadcast(comm, out_values, n, 0); 72 84 } 73 85 } // end namespace detail … … 83 95 84 96 template<typename T, typename Op> 85 97 inline void 98 all_reduce(const communicator& comm, T* values, int n, Op op) 99 { 100 all_reduce(comm, static_cast<const T*>(MPI_IN_PLACE), n, values, op); 101 } 102 103 template<typename T, typename Op> 104 inline void 86 105 all_reduce(const communicator& comm, const T& in_value, T& out_value, Op op) 87 106 { 88 107 detail::all_reduce_impl(comm, &in_value, 1, &out_value, op, -
libs/mpi/test/all_reduce_test.cpp
9 9 #include <boost/mpi/communicator.hpp> 10 10 #include <boost/mpi/environment.hpp> 11 11 #include <boost/test/minimal.hpp> 12 #include <vector> 12 13 #include <algorithm> 13 14 #include <boost/serialization/string.hpp> 14 15 #include <boost/iterator/counting_iterator.hpp> … … 58 59 return point(p1.x + p2.x, p1.y + p2.y, p1.z + p2.z); 59 60 } 60 61 62 // test lexical order 63 bool operator<(const point& p1, const point& p2) 64 { 65 return (p1.x < p2.x 66 ? true 67 : (p1.x > p2.x 68 ? false 69 : p1.y < p2.y )); 70 } 71 61 72 namespace boost { namespace mpi { 62 73 63 74 template <> … … 67 78 68 79 template<typename Generator, typename Op> 69 80 void 70 all_reduce_ test(const communicator& comm, Generator generator,71 const char* type_kind, Op op, const char* op_kind,72 typename Generator::result_type init)81 all_reduce_one_test(const communicator& comm, Generator generator, 82 const char* type_kind, Op op, const char* op_kind, 83 typename Generator::result_type init) 73 84 { 74 85 typedef typename Generator::result_type value_type; 75 86 value_type value = generator(comm.rank()); … … 97 108 (comm.barrier)(); 98 109 } 99 110 111 template<typename Generator, typename Op> 112 void 113 all_reduce_array_test(const communicator& comm, Generator generator, 114 const char* type_kind, Op op, const char* op_kind, 115 typename Generator::result_type init, bool in_place) 116 { 117 typedef typename Generator::result_type value_type; 118 value_type value = generator(comm.rank()); 119 std::vector<value_type> send(10, value); 120 121 using boost::mpi::all_reduce; 122 123 if (comm.rank() == 0) { 124 char const* place = in_place ? "in place" : "out of place"; 125 std::cout << "Reducing (" << place << ") array to " << op_kind << " of " << type_kind << "..."; 126 std::cout.flush(); 127 } 128 std::vector<value_type> result; 129 if (in_place) { 130 all_reduce(comm, &(send[0]), send.size(), op); 131 result.swap(send); 132 } else { 133 std::vector<value_type> recv(10, value_type()); 134 all_reduce(comm, &(send[0]), send.size(), &(recv[0]), op); 135 result.swap(recv); 136 } 137 138 // Compute expected result 139 std::vector<value_type> generated_values; 140 for (int p = 0; p < comm.size(); ++p) 141 generated_values.push_back(generator(p)); 142 value_type expected_result = std::accumulate(generated_values.begin(), 143 generated_values.end(), 144 init, op); 145 146 bool got_expected_result = (std::equal_range(result.begin(), result.end(), 147 expected_result) 148 == std::make_pair(result.begin(), result.end())); 149 BOOST_CHECK(got_expected_result); 150 if (got_expected_result && comm.rank() == 0) 151 std::cout << "OK." << std::endl; 152 153 (comm.barrier)(); 154 } 155 156 // Test the 3 families of all reduce: value, array in place, array ou of place 157 template<typename Generator, typename Op> 158 void 159 all_reduce_test(const communicator& comm, Generator generator, 160 const char* type_kind, Op op, const char* op_kind, 161 typename Generator::result_type init) 162 { 163 const bool in_place = true; 164 const bool out_of_place = false; 165 all_reduce_one_test(comm, generator, type_kind, op, op_kind, init); 166 all_reduce_array_test(comm, generator, type_kind, op, op_kind, 167 init, in_place); 168 all_reduce_array_test(comm, generator, type_kind, op, op_kind, 169 init, out_of_place); 170 } 171 100 172 // Generates integers to test with all_reduce() 101 173 struct int_generator 102 174 { … … 168 240 return x.value == y.value; 169 241 } 170 242 243 bool operator<(const wrapped_int& x, const wrapped_int& y) 244 { 245 return x.value < y.value; 246 } 247 171 248 // Generates wrapped_its to test with all_reduce() 172 249 struct wrapped_int_generator 173 250 { … … 196 273 environment env(argc, argv); 197 274 198 275 communicator comm; 276 const bool in_place = true; 277 const bool out_of_place = false; 199 278 200 279 // Built-in MPI datatypes with built-in MPI operations 201 280 all_reduce_test(comm, int_generator(), "integers", std::plus<int>(), "sum", … … 215 294 // Built-in MPI datatypes with user-defined operations 216 295 all_reduce_test(comm, int_generator(17), "integers", secret_int_bit_and(), 217 296 "bitwise and", -1); 218 219 297 298 // Arbitrary types with user-defined, commutative operations. 220 299 all_reduce_test(comm, wrapped_int_generator(17), "wrapped integers", 221 300 std::plus<wrapped_int>(), "sum", wrapped_int(0)); 222 301