Ticket #6704: mpi_all_reduce_in_place.patch

File mpi_all_reduce_in_place.patch, 8.1 KB (added by Alain Miniussi <alain.miniussi@…>, 10 years ago)

updated patch for revision 80953

  • boost/mpi/collectives.hpp

     
    104104 *    operation. If this parameter is omitted, the outgoing value will
    105105 *    instead be returned.
    106106 *
     107 *    @param inout_value Combine the usage of both in_value and out_value.
     108 *    Contain in input the local value to be combined with the local
     109 *    values of every other process. Will also receive the result of the
     110 *    reduction operation. Local value will be overwritten.
     111 *
    107112 *    @param op The binary operation that combines two values of type
    108113 *    @c T and returns a third value of type @c T. For types @c T that has
    109114 *    ssociated MPI data types, @c op will either be translated into
     
    138143           Op op);
    139144
    140145/**
     146 * \overload
     147 */
     148template<typename T, typename Op>
     149void
     150all_reduce(const communicator& comm, T* inout_values, int n,
     151           Op op);
     152
     153/**
    141154 *  @brief Send data from every process to every other process.
    142155 *
    143156 *  @c all_to_all is a collective algorithm that transmits @c p values
  • boost/mpi/collectives/all_reduce.hpp

     
    1212#ifndef BOOST_MPI_ALL_REDUCE_HPP
    1313#define BOOST_MPI_ALL_REDUCE_HPP
    1414
     15#include <vector>
     16
    1517// All-reduce falls back to reduce() + broadcast() in some cases.
    1618#include <boost/mpi/collectives/broadcast.hpp>
    1719#include <boost/mpi/collectives/reduce.hpp>
     
    6769                  T* out_values, Op op, mpl::false_ /*is_mpi_op*/,
    6870                  mpl::false_ /*is_mpi_datatype*/)
    6971  {
    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    }
    7183    broadcast(comm, out_values, n, 0);
    7284  }
    7385} // end namespace detail
     
    8395
    8496template<typename T, typename Op>
    8597inline void
     98all_reduce(const communicator& comm, T* inout_values, int n, Op op)
     99{
     100  all_reduce(comm, static_cast<const T*>(MPI_IN_PLACE), n, inout_values, op);
     101}
     102
     103template<typename T, typename Op>
     104inline void
    86105all_reduce(const communicator& comm, const T& in_value, T& out_value, Op op)
    87106{
    88107  detail::all_reduce_impl(comm, &in_value, 1, &out_value, op,
  • libs/mpi/test/all_reduce_test.cpp

     
    99#include <boost/mpi/communicator.hpp>
    1010#include <boost/mpi/environment.hpp>
    1111#include <boost/test/minimal.hpp>
     12#include <vector>
    1213#include <algorithm>
    1314#include <boost/serialization/string.hpp>
    1415#include <boost/iterator/counting_iterator.hpp>
     
    5859  return point(p1.x + p2.x, p1.y + p2.y, p1.z + p2.z);
    5960}
    6061
     62// test lexical order
     63bool 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
    6172namespace boost { namespace mpi {
    6273
    6374  template <>
     
    6778
    6879template<typename Generator, typename Op>
    6980void
    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)
     81all_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)
    7384{
    7485  typedef typename Generator::result_type value_type;
    7586  value_type value = generator(comm.rank());
     
    97108  (comm.barrier)();
    98109}
    99110
     111template<typename Generator, typename Op>
     112void
     113all_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
     157template<typename Generator, typename Op>
     158void
     159all_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
    100172// Generates integers to test with all_reduce()
    101173struct int_generator
    102174{
     
    168240  return x.value == y.value;
    169241}
    170242
     243bool operator<(const wrapped_int& x, const wrapped_int& y)
     244{
     245  return x.value < y.value;
     246}
     247
    171248// Generates wrapped_its to test with all_reduce()
    172249struct wrapped_int_generator
    173250{
     
    196273  environment env(argc, argv);
    197274
    198275  communicator comm;
     276  const bool in_place = true;
     277  const bool out_of_place = false;
    199278
    200279  // Built-in MPI datatypes with built-in MPI operations
    201280  all_reduce_test(comm, int_generator(), "integers", std::plus<int>(), "sum",
     
    215294  // Built-in MPI datatypes with user-defined operations
    216295  all_reduce_test(comm, int_generator(17), "integers", secret_int_bit_and(),
    217296                  "bitwise and", -1);
    218 
    219     // Arbitrary types with user-defined, commutative operations.
     297 
     298  // Arbitrary types with user-defined, commutative operations.
    220299  all_reduce_test(comm, wrapped_int_generator(17), "wrapped integers",
    221300                  std::plus<wrapped_int>(), "sum", wrapped_int(0));
    222301
  • libs/mpi/doc/mpi.qbk

     
    22    [authors [Gregor, Douglas], [Troyer, Matthias] ]
    33    [copyright 2005 2006 2007 Douglas Gregor, Matthias Troyer, Trustees of Indiana University]
    44    [purpose
    5         An generic, user-friendly interface to MPI, the Message
     5        A generic, user-friendly interface to MPI, the Message
    66        Passing Interface.
    77    ]
    88    [id mpi]