Ticket #6704: mpi_all_red-r85156-6704.patch
File mpi_all_red-r85156-6704.patch, 13.0 KB (added by , 9 years ago) |
---|
-
boost/mpi/inplace.hpp
1 // Copyright (C) 2005-2006 Alain Miniussi <alain.miniussi -at- oca.eu>. 2 3 // Use, modification and distribution is subject to the Boost Software 4 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at 5 // http://www.boost.org/LICENSE_1_0.txt) 6 7 // Message Passing Interface 1.1 -- Section 4. MPI Collectives 8 9 /** @file inplace.hpp 10 * 11 * This header provides helpers to indicate to MPI collective operation 12 * that a buffer can be use both as an input and output. 13 */ 14 #ifndef BOOST_MPI_INPLACE_HPP 15 #define BOOST_MPI_INPLACE_HPP 16 17 #include <boost/mpi/communicator.hpp> 18 #include <vector> 19 20 namespace boost { namespace mpi { 21 22 /** 23 * @brief Wrapper type to explicitly indicate that a input data 24 * can be overriden with an output value. 25 */ 26 template <typename T> 27 struct inplace_t { 28 inplace_t(T& inout) : buffer(inout) {} 29 T& buffer; 30 }; 31 32 template <typename T> 33 struct inplace_t<T*> { 34 inplace_t(T* inout) : buffer(inout) {} 35 T* buffer; 36 }; 37 38 39 /** 40 * @brief Wrapp a input data to indicate that it can be overriden 41 * with an ouput value. 42 * @param inout the contributing input value, it will be overriden 43 * with the output value where one is expected. If it is a pointer, 44 * the number of elements will be provided separatly. 45 * @returns The wrapped value or pointer. 46 */ 47 template<typename T> 48 inplace_t<T> 49 inplace(T& inout) { 50 return inplace_t<T>(inout); 51 } 52 /** 53 * \overload 54 */ 55 template<typename T> 56 inplace_t<T*> 57 inplace(T* inout) { 58 return inplace_t<T*>(inout); 59 } 60 } } // end namespace boost::mpi 61 62 #endif // BOOST_MPI_INPLACE_HPP 63 -
boost/mpi/collectives.hpp
19 19 #define BOOST_MPI_COLLECTIVES_HPP 20 20 21 21 #include <boost/mpi/communicator.hpp> 22 #include <boost/mpi/inplace.hpp> 22 23 #include <vector> 23 24 24 25 namespace boost { namespace mpi { 25 26 26 /** 27 27 * @brief Gather the values stored at every process into vectors of 28 28 * values from each process. … … 94 94 * 95 95 * @param comm The communicator over which the reduction will 96 96 * occur. 97 * 98 * @param in_value The local value to be combined with the local 97 * @param value The local value to be combined with the local 99 98 * values of every other process. For reducing arrays, @c in_values 100 99 * is a pointer to the local values to be reduced and @c n is the 101 100 * number of values to reduce. See @c reduce for more information. 102 101 * 102 * If wrapped in a @c inplace_t object, combine the usage of both 103 * input and $c out_value and the local value will be overwritten 104 * (a convenience function @c inplace is provided for the wrapping). 105 * 103 106 * @param out_value Will receive the result of the reduction 104 107 * operation. If this parameter is omitted, the outgoing value will 105 108 * instead be returned. … … 116 119 * gives the implementation additional lattitude to optimize the 117 120 * reduction operation. 118 121 * 122 * @param n Indicated the size of the buffers of array type. 119 123 * @returns If no @p out_value parameter is supplied, returns the 120 124 * result of the reduction operation. 121 125 */ 122 126 template<typename T, typename Op> 123 127 void 124 all_reduce(const communicator& comm, const T & in_value, T& out_value, Op op);125 128 all_reduce(const communicator& comm, const T* value, int n, T* out_value, 129 Op op); 126 130 /** 127 131 * \overload 128 132 */ 129 133 template<typename T, typename Op> 130 T all_reduce(const communicator& comm, const T& in_value, Op op); 134 void 135 all_reduce(const communicator& comm, const T& value, T& out_value, Op op); 136 /** 137 * \overload 138 */ 139 template<typename T, typename Op> 140 T all_reduce(const communicator& comm, const T& value, Op op); 131 141 132 142 /** 133 143 * \overload 134 144 */ 135 145 template<typename T, typename Op> 136 146 void 137 all_reduce(const communicator& comm, const T* in_values, int n, T* out_values,147 all_reduce(const communicator& comm, inplace_t<T*> value, int n, 138 148 Op op); 149 /** 150 * \overload 151 */ 152 template<typename T, typename Op> 153 void 154 all_reduce(const communicator& comm, inplace_t<T> value, Op op); 139 155 140 156 /** 141 157 * @brief Send data from every process to every other process. -
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 17 #include <boost/mpi/inplace.hpp> 18 15 19 // All-reduce falls back to reduce() + broadcast() in some cases. 16 20 #include <boost/mpi/collectives/broadcast.hpp> 17 21 #include <boost/mpi/collectives/reduce.hpp> 18 22 19 23 namespace boost { namespace mpi { 20 21 24 namespace detail { 22 25 /********************************************************************** 23 26 * Simple reduction with MPI_Allreduce * … … 67 70 T* out_values, Op op, mpl::false_ /*is_mpi_op*/, 68 71 mpl::false_ /*is_mpi_datatype*/) 69 72 { 70 reduce(comm, in_values, n, out_values, op, 0); 73 if (in_values == MPI_IN_PLACE) { 74 // if in_values matches the in place tag, then the output 75 // buffer actually contains the input data. 76 // But we can just go back to the out of place 77 // implementation in this case. 78 // it's not clear how/if we can avoid the copy. 79 std::vector<T> tmp_in( out_values, out_values + n); 80 reduce(comm, &(tmp_in[0]), n, out_values, op, 0); 81 } else { 82 reduce(comm, in_values, n, out_values, op, 0); 83 } 71 84 broadcast(comm, out_values, n, 0); 72 85 } 73 86 } // end namespace detail … … 83 96 84 97 template<typename T, typename Op> 85 98 inline void 99 all_reduce(const communicator& comm, inplace_t<T*> inout_values, int n, Op op) 100 { 101 all_reduce(comm, static_cast<const T*>(MPI_IN_PLACE), n, inout_values.buffer, op); 102 } 103 104 template<typename T, typename Op> 105 inline void 106 all_reduce(const communicator& comm, inplace_t<T> inout_values, Op op) 107 { 108 all_reduce(comm, static_cast<const T*>(MPI_IN_PLACE), 1, &(inout_values.buffer), op); 109 } 110 111 template<typename T, typename Op> 112 inline void 86 113 all_reduce(const communicator& comm, const T& in_value, T& out_value, Op op) 87 114 { 88 115 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, bool in_place) 73 84 { 74 85 typedef typename Generator::result_type value_type; 75 86 value_type value = generator(comm.rank()); 76 87 77 88 using boost::mpi::all_reduce; 89 using boost::mpi::inplace; 78 90 79 91 if (comm.rank() == 0) { 80 92 std::cout << "Reducing to " << op_kind << " of " << type_kind << "..."; 81 93 std::cout.flush(); 82 94 } 83 95 84 value_type result_value = all_reduce(comm, value, op); 85 96 value_type result_value; 97 if (in_place) { 98 all_reduce(comm, inplace(value), op); 99 result_value = value; 100 } else { 101 result_value = all_reduce(comm, value, op); 102 } 103 86 104 // Compute expected result 87 105 std::vector<value_type> generated_values; 88 106 for (int p = 0; p < comm.size(); ++p) … … 97 115 (comm.barrier)(); 98 116 } 99 117 118 template<typename Generator, typename Op> 119 void 120 all_reduce_array_test(const communicator& comm, Generator generator, 121 const char* type_kind, Op op, const char* op_kind, 122 typename Generator::result_type init, bool in_place) 123 { 124 typedef typename Generator::result_type value_type; 125 value_type value = generator(comm.rank()); 126 std::vector<value_type> send(10, value); 127 128 using boost::mpi::all_reduce; 129 using boost::mpi::inplace; 130 131 if (comm.rank() == 0) { 132 char const* place = in_place ? "in place" : "out of place"; 133 std::cout << "Reducing (" << place << ") array to " << op_kind << " of " << type_kind << "..."; 134 std::cout.flush(); 135 } 136 std::vector<value_type> result; 137 if (in_place) { 138 all_reduce(comm, inplace(&(send[0])), send.size(), op); 139 result.swap(send); 140 } else { 141 std::vector<value_type> recv(10, value_type()); 142 all_reduce(comm, &(send[0]), send.size(), &(recv[0]), op); 143 result.swap(recv); 144 } 145 146 // Compute expected result 147 std::vector<value_type> generated_values; 148 for (int p = 0; p < comm.size(); ++p) 149 generated_values.push_back(generator(p)); 150 value_type expected_result = std::accumulate(generated_values.begin(), 151 generated_values.end(), 152 init, op); 153 154 bool got_expected_result = (std::equal_range(result.begin(), result.end(), 155 expected_result) 156 == std::make_pair(result.begin(), result.end())); 157 BOOST_CHECK(got_expected_result); 158 if (got_expected_result && comm.rank() == 0) 159 std::cout << "OK." << std::endl; 160 161 (comm.barrier)(); 162 } 163 164 // Test the 4 families of all reduce: (value, array) X (in place, out of place) 165 template<typename Generator, typename Op> 166 void 167 all_reduce_test(const communicator& comm, Generator generator, 168 const char* type_kind, Op op, const char* op_kind, 169 typename Generator::result_type init) 170 { 171 const bool in_place = true; 172 const bool out_of_place = false; 173 all_reduce_one_test(comm, generator, type_kind, op, op_kind, init, in_place); 174 all_reduce_one_test(comm, generator, type_kind, op, op_kind, init, out_of_place); 175 all_reduce_array_test(comm, generator, type_kind, op, op_kind, 176 init, in_place); 177 all_reduce_array_test(comm, generator, type_kind, op, op_kind, 178 init, out_of_place); 179 } 180 100 181 // Generates integers to test with all_reduce() 101 182 struct int_generator 102 183 { … … 168 249 return x.value == y.value; 169 250 } 170 251 252 bool operator<(const wrapped_int& x, const wrapped_int& y) 253 { 254 return x.value < y.value; 255 } 256 171 257 // Generates wrapped_its to test with all_reduce() 172 258 struct wrapped_int_generator 173 259 { … … 196 282 environment env(argc, argv); 197 283 198 284 communicator comm; 285 const bool in_place = true; 286 const bool out_of_place = false; 199 287 200 288 // Built-in MPI datatypes with built-in MPI operations 201 289 all_reduce_test(comm, int_generator(), "integers", std::plus<int>(), "sum", … … 215 303 // Built-in MPI datatypes with user-defined operations 216 304 all_reduce_test(comm, int_generator(17), "integers", secret_int_bit_and(), 217 305 "bitwise and", -1); 218 219 306 307 // Arbitrary types with user-defined, commutative operations. 220 308 all_reduce_test(comm, wrapped_int_generator(17), "wrapped integers", 221 309 std::plus<wrapped_int>(), "sum", wrapped_int(0)); 222 310 -
libs/mpi/doc/mpi.qbk
2 2 [authors [Gregor, Douglas], [Troyer, Matthias] ] 3 3 [copyright 2005 2006 2007 Douglas Gregor, Matthias Troyer, Trustees of Indiana University] 4 4 [purpose 5 A ngeneric, user-friendly interface to MPI, the Message5 A generic, user-friendly interface to MPI, the Message 6 6 Passing Interface. 7 7 ] 8 8 [id mpi] -
libs/mpi/doc/Jamfile.v2
31 31 ../../../boost/mpi/status.hpp 32 32 ../../../boost/mpi/request.hpp 33 33 ../../../boost/mpi/timer.hpp 34 ../../../boost/mpi/inplace.hpp 34 35 ../../../boost/mpi/python.hpp 35 36 ] 36 37 : <doxygen:param>MACRO_EXPANSION=YES