diff options
author | DongHun Kwak <dh0128.kwak@samsung.com> | 2019-12-05 15:12:59 +0900 |
---|---|---|
committer | DongHun Kwak <dh0128.kwak@samsung.com> | 2019-12-05 15:12:59 +0900 |
commit | b8cf34c691623e4ec329053cbbf68522a855882d (patch) | |
tree | 34da08632a99677f6b79ecb65e5b655a5b69a67f /boost/mpi | |
parent | 3fdc3e5ee96dca5b11d1694975a65200787eab86 (diff) | |
download | boost-b8cf34c691623e4ec329053cbbf68522a855882d.tar.gz boost-b8cf34c691623e4ec329053cbbf68522a855882d.tar.bz2 boost-b8cf34c691623e4ec329053cbbf68522a855882d.zip |
Imported Upstream version 1.67.0upstream/1.67.0
Diffstat (limited to 'boost/mpi')
-rw-r--r-- | boost/mpi/cartesian_communicator.hpp | 382 | ||||
-rw-r--r-- | boost/mpi/collectives/all_gather.hpp | 131 | ||||
-rw-r--r-- | boost/mpi/collectives/all_gatherv.hpp | 140 | ||||
-rw-r--r-- | boost/mpi/collectives/all_to_all.hpp | 6 | ||||
-rw-r--r-- | boost/mpi/collectives/broadcast.hpp | 27 | ||||
-rw-r--r-- | boost/mpi/collectives/gather.hpp | 170 | ||||
-rw-r--r-- | boost/mpi/collectives/gatherv.hpp | 37 | ||||
-rw-r--r-- | boost/mpi/collectives/scatter.hpp | 212 | ||||
-rw-r--r-- | boost/mpi/collectives/scatterv.hpp | 203 | ||||
-rw-r--r-- | boost/mpi/communicator.hpp | 264 | ||||
-rw-r--r-- | boost/mpi/detail/antiques.hpp | 33 | ||||
-rw-r--r-- | boost/mpi/detail/binary_buffer_oprimitive.hpp | 7 | ||||
-rw-r--r-- | boost/mpi/detail/mpi_datatype_primitive.hpp | 7 | ||||
-rw-r--r-- | boost/mpi/detail/offsets.hpp | 47 | ||||
-rw-r--r-- | boost/mpi/detail/packed_iprimitive.hpp | 2 | ||||
-rw-r--r-- | boost/mpi/detail/packed_oprimitive.hpp | 11 | ||||
-rw-r--r-- | boost/mpi/environment.hpp | 6 | ||||
-rw-r--r-- | boost/mpi/exception.hpp | 2 | ||||
-rw-r--r-- | boost/mpi/operations.hpp | 30 | ||||
-rw-r--r-- | boost/mpi/python/serialize.hpp | 4 |
20 files changed, 1235 insertions, 486 deletions
diff --git a/boost/mpi/cartesian_communicator.hpp b/boost/mpi/cartesian_communicator.hpp new file mode 100644 index 0000000000..7a31bce093 --- /dev/null +++ b/boost/mpi/cartesian_communicator.hpp @@ -0,0 +1,382 @@ +// Copyright Alain Miniussi 2014. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// Authors: Alain Miniussi + +/** @file cartesian_communicator.hpp + * + * This header defines facilities to support MPI communicators with + * cartesian topologies. + * If known at compiled time, the dimension of the implied grid + * can be statically enforced, through the templatized communicator + * class. Otherwise, a non template, dynamic, base class is provided. + * + */ +#ifndef BOOST_MPI_CARTESIAN_COMMUNICATOR_HPP +#define BOOST_MPI_CARTESIAN_COMMUNICATOR_HPP + +#include <boost/mpi/communicator.hpp> + +#include <vector> +#include <utility> +#include <iostream> +#include <utility> +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) +#include <initializer_list> +#endif // BOOST_NO_CXX11_HDR_INITIALIZER_LIST + +// Headers required to implement cartesian topologies +#include <boost/shared_array.hpp> +#include <boost/assert.hpp> +#include <boost/foreach.hpp> + +namespace boost { namespace mpi { + +/** + * @brief Specify the size and periodicity of the grid in a single dimension. + * + * POD lightweight object. + */ +struct cartesian_dimension { + /** The size of the grid n this dimension. */ + int size; + /** Is the grid periodic in this dimension. */ + bool periodic; + + cartesian_dimension(int sz = 0, bool p = false) : size(sz), periodic(p) {} + +private: + friend class boost::serialization::access; + template<class Archive> + void serialize(Archive & ar, const unsigned int version) + { + ar & size & periodic; + } + +}; + +template <> +struct is_mpi_datatype<cartesian_dimension> : mpl::true_ { }; + +/** + * @brief Test if the dimensions values are identical. + */ +inline +bool +operator==(cartesian_dimension const& d1, cartesian_dimension const& d2) { + return &d1 == &d2 || (d1.size == d2.size && d1.periodic == d2.periodic); +} + +/** + * @brief Test if the dimension values are different. + */ +inline +bool +operator!=(cartesian_dimension const& d1, cartesian_dimension const& d2) { + return !(d1 == d2); +} + +/** + * @brief Pretty printing of a cartesian dimension (size, periodic) + */ +std::ostream& operator<<(std::ostream& out, cartesian_dimension const& d); + +/** + * @brief Describe the topology of a cartesian grid. + * + * Behave mostly like a sequence of @c cartesian_dimension with the notable + * exception that its size is fixed. + * This is a lightweight object, so that any constructor that could be considered + * missing could be replaced with a function (move constructor provided when supported). + */ +class BOOST_MPI_DECL cartesian_topology + : private std::vector<cartesian_dimension> { + friend class cartesian_communicator; + typedef std::vector<cartesian_dimension> super; + public: + /** + * Retrieve a specific dimension. + */ + using super::operator[]; + /** + * @brief Topology dimentionality. + */ + using super::size; + using super::begin; + using super::end; + using super::swap; + +#if !defined(BOOST_NO_CXX11_DELETED_FUNCTIONS) + cartesian_topology() = delete; +#endif +#if !defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS) + cartesian_topology(cartesian_topology const&) = default; + cartesian_topology& operator=(cartesian_topology const&) = default; + // There is apparently no macro for checking the support of move constructor. + // Assume that defaulted function is close enough. + cartesian_topology(cartesian_topology const&& other) : super(other) {} + cartesian_topology& operator=(cartesian_topology const&& other) { + (*this) = std::move(other.stl()); + return *this; + } + + ~cartesian_topology() = default; +#endif + /** + * @brief Create a N dimension space. + * Each dimension is initialized as non periodic of size 0. + */ + cartesian_topology(int ndim) + : super(ndim) {} + + /** + * @brief Use the provided dimensions specification as initial values. + */ + cartesian_topology(std::vector<cartesian_dimension> const& dims) + : super(dims) {} + + /** + * @brief Use dimensions specification provided in the sequence container as initial values. + * #param dims must be a sequence container. + */ + template<class InitArr> + explicit cartesian_topology(InitArr dims) + : super(0) { + BOOST_FOREACH(cartesian_dimension const& d, dims) { + push_back(d); + } + } +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + /** + * @brief Use dimensions specification provided in the initialization list as initial values. + * #param dims can be of the form { dim_1, false}, .... {dim_n, true} + */ + explicit cartesian_topology(std::initializer_list<cartesian_dimension> dims) + : super(dims) {} +#endif + /** + * @brief Use dimensions specification provided in the array. + * #param dims can be of the form { dim_1, false}, .... {dim_n, true} + */ + template<int NDIM> + explicit cartesian_topology(cartesian_dimension (&dims)[NDIM]) + : super(dims, dims+NDIM) {} + + /** + * @brief Use dimensions specification provided in the input ranges + * The ranges do not need to be the same size. If the sizes are different, + * the missing values will be complete with zeros of the dim and assumed non periodic. + * @param dim_rg the dimensions, values must convert to integers. + * @param period_rg the periodicities, values must convert to booleans. + * #param dims can be of the form { dim_1, false}, .... {dim_n, true} + */ + template<class DimRg, class PerRg> + cartesian_topology(DimRg const& dim_rg, PerRg const& period_rg) + : super(0) { + BOOST_FOREACH(int d, dim_rg) { + super::push_back(cartesian_dimension(d)); + } + super::iterator it = begin(); + BOOST_FOREACH(bool p, period_rg) { + if (it < end()) { + it->periodic = p; + } else { + push_back(cartesian_dimension(0,p)); + } + ++it; + } + } + + + /** + * @brief Iterator based initializer. + * Will use the first n iterated values. + * Both iterators can be single pass. + * @param dit dimension iterator, value must convert to integer type. + * @param pit periodicity iterator, value must convert to booleans.. + */ + template<class DimIter, class PerIter> + cartesian_topology(DimIter dit, PerIter pit, int n) + : super(n) { + for(int i = 0; i < n; ++i) { + (*this)[i] = cartesian_dimension(*dit++, *pit++); + } + } + + /** + * Export as an stl sequence. + */ + std::vector<cartesian_dimension>& stl() { return *this; } + /** + * Export as an stl sequence. + */ + std::vector<cartesian_dimension> const& stl() const{ return *this; } + /** + * Split the topology in two sequences of sizes and periodicities. + */ + void split(std::vector<int>& dims, std::vector<bool>& periodics) const; +}; + +inline +bool +operator==(cartesian_topology const& t1, cartesian_topology const& t2) { + return t1.stl() == t2.stl(); +} + +inline +bool +operator!=(cartesian_topology const& t1, cartesian_topology const& t2) { + return t1.stl() != t2.stl(); +} + +/** + * @brief Pretty printing of a cartesian topology + */ +std::ostream& operator<<(std::ostream& out, cartesian_topology const& t); + +/** + * @brief An MPI communicator with a cartesian topology. + * + * A @c cartesian_communicator is a communicator whose topology is + * expressed as a grid. Cartesian communicators have the same + * functionality as (intra)communicators, but also allow one to query + * the relationships among processes and the properties of the grid. + */ +class BOOST_MPI_DECL cartesian_communicator : public communicator +{ + friend class communicator; + + /** + * INTERNAL ONLY + * + * Construct a cartesian communicator given a shared pointer to the + * underlying MPI_Comm (which must have a cartesian topology). + * This operation is used for "casting" from a communicator to + * a cartesian communicator. + */ + explicit cartesian_communicator(const shared_ptr<MPI_Comm>& comm_ptr) + : communicator() + { + this->comm_ptr = comm_ptr; + BOOST_ASSERT(has_cartesian_topology()); + } + +public: + /** + * Build a new Boost.MPI cartesian communicator based on the MPI + * communicator @p comm with cartesian topology. + * + * @p comm may be any valid MPI communicator. If @p comm is + * MPI_COMM_NULL, an empty communicator (that cannot be used for + * communication) is created and the @p kind parameter is + * ignored. Otherwise, the @p kind parameter determines how the + * Boost.MPI communicator will be related to @p comm: + * + * - If @p kind is @c comm_duplicate, duplicate @c comm to create + * a new communicator. This new communicator will be freed when + * the Boost.MPI communicator (and all copies of it) is + * destroyed. This option is only permitted if the underlying MPI + * implementation supports MPI 2.0; duplication of + * intercommunicators is not available in MPI 1.x. + * + * - If @p kind is @c comm_take_ownership, take ownership of @c + * comm. It will be freed automatically when all of the Boost.MPI + * communicators go out of scope. + * + * - If @p kind is @c comm_attach, this Boost.MPI communicator + * will reference the existing MPI communicator @p comm but will + * not free @p comm when the Boost.MPI communicator goes out of + * scope. This option should only be used when the communicator is + * managed by the user. + */ + cartesian_communicator(const MPI_Comm& comm, comm_create_kind kind) + : communicator(comm, kind) + { + BOOST_ASSERT(has_cartesian_topology()); + } + + /** + * Create a new communicator whose topology is described by the + * given cartesian. The indices of the vertices in the cartesian will be + * assumed to be the ranks of the processes within the + * communicator. There may be fewer vertices in the cartesian than + * there are processes in the communicator; in this case, the + * resulting communicator will be a NULL communicator. + * + * @param comm The communicator that the new, cartesian communicator + * will be based on. + * + * @param dims the cartesian dimension of the new communicator. The size indicate + * the number of dimension. Some dimensions be set to zero, in which case + * the corresponding dimension value is left to the system. + * + * @param reorder Whether MPI is permitted to re-order the process + * ranks within the returned communicator, to better optimize + * communication. If false, the ranks of each process in the + * returned process will match precisely the rank of that process + * within the original communicator. + */ + cartesian_communicator(const communicator& comm, + const cartesian_topology& dims, + bool reorder = false); + + /** + * Create a new cartesian communicator whose topology is a subset of + * an existing cartesian cimmunicator. + * @param comm the original communicator. + * @param keep and array containiing the dimension to keep from the existing + * communicator. + */ + cartesian_communicator(const cartesian_communicator& comm, + const std::vector<int>& keep ); + + using communicator::rank; + + /** + * Retrive the number of dimension of the underlying toppology. + */ + int ndims() const; + + /** + * Return the rank of the process at the given coordinates. + * @param coords the coordinates. the size must match the communicator's topology. + */ + int rank(const std::vector<int>& coords) const; + /** + * Return the rank of the source and target destination process through a shift. + * @param dim the dimension in which the shift takes place. 0 <= dim <= ndim(). + * @param disp the shift displacement, can be positive (upward) or negative (downward). + */ + std::pair<int, int> shifted_ranks(int dim, int disp) const; + /** + * Provides the coordinates of the process with the given rank. + * @param rk the ranks in this communicator. + * @returns the coordinates. + */ + std::vector<int> coordinates(int rk) const; + /** + * Retrieve the topology and coordinates of this process in the grid. + * + */ + void topology( cartesian_topology& dims, std::vector<int>& coords ) const; + /** + * Retrieve the topology of the grid. + * + */ + cartesian_topology topology() const; +}; + +/** + * Given en number of processes, and a partially filled sequence + * of dimension, try to complete the dimension sequence. + * @param nb_proc the numer of mpi processes.fill a sequence of dimension. + * @param dims a sequence of positive or null dimensions. Non zero dimension + * will be left untouched. + */ +std::vector<int>& cartesian_dimensions(int nb_proc, std::vector<int>& dims); + +} } // end namespace boost::mpi + +#endif // BOOST_MPI_CARTESIAN_COMMUNICATOR_HPP diff --git a/boost/mpi/collectives/all_gather.hpp b/boost/mpi/collectives/all_gather.hpp index da73186c64..4adaeb9c87 100644 --- a/boost/mpi/collectives/all_gather.hpp +++ b/boost/mpi/collectives/all_gather.hpp @@ -1,52 +1,107 @@ -// Copyright (C) 2005-2006 Douglas Gregor <doug.gregor -at- gmail.com>. +// Copyright (C) 2005, 2006 Douglas Gregor. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -// Message Passing Interface 1.1 -- Section 4.7. Gather-to-all -#ifndef BOOST_MPI_ALL_GATHER_HPP -#define BOOST_MPI_ALL_GATHER_HPP +// Message Passing Interface 1.1 -- Section 4.5. Gather +#ifndef BOOST_MPI_ALLGATHER_HPP +#define BOOST_MPI_ALLGATHER_HPP +#include <cassert> +#include <cstddef> +#include <numeric> #include <boost/mpi/exception.hpp> #include <boost/mpi/datatype.hpp> #include <vector> -#include <boost/serialization/vector.hpp> - -// all_gather falls back to gather+broadcast in some cases -#include <boost/mpi/collectives/broadcast.hpp> -#include <boost/mpi/collectives/gather.hpp> +#include <boost/mpi/packed_oarchive.hpp> +#include <boost/mpi/packed_iarchive.hpp> +#include <boost/mpi/detail/point_to_point.hpp> +#include <boost/mpi/communicator.hpp> +#include <boost/mpi/environment.hpp> +#include <boost/mpi/detail/offsets.hpp> +#include <boost/mpi/detail/antiques.hpp> +#include <boost/assert.hpp> namespace boost { namespace mpi { namespace detail { - // We're all-gathering for a type that has an associated MPI - // datatype, so we'll use MPI_Gather to do all of the work. - template<typename T> - void - all_gather_impl(const communicator& comm, const T* in_values, int n, - T* out_values, mpl::true_) - { - MPI_Datatype type = boost::mpi::get_mpi_datatype<T>(*in_values); - BOOST_MPI_CHECK_RESULT(MPI_Allgather, - (const_cast<T*>(in_values), n, type, - out_values, n, type, comm)); - } +// We're all-gathering for a type that has an associated MPI +// datatype, so we'll use MPI_Gather to do all of the work. +template<typename T> +void +all_gather_impl(const communicator& comm, const T* in_values, int n, + T* out_values, mpl::true_) +{ + MPI_Datatype type = get_mpi_datatype<T>(*in_values); + BOOST_MPI_CHECK_RESULT(MPI_Allgather, + (const_cast<T*>(in_values), n, type, + out_values, n, type, comm)); +} - // We're all-gathering for a type that has no associated MPI - // type. So, we'll do a manual gather followed by a broadcast. - template<typename T> - void - all_gather_impl(const communicator& comm, const T* in_values, int n, - T* out_values, mpl::false_) - { - gather(comm, in_values, n, out_values, 0); - broadcast(comm, out_values, comm.size() * n, 0); +// We're all-gathering for a type that does not have an +// associated MPI datatype, so we'll need to serialize +// it. +template<typename T> +void +all_gather_impl(const communicator& comm, const T* in_values, int n, + T* out_values, int const* sizes, int const* skips, mpl::false_) +{ + int nproc = comm.size(); + // first, gather all size, these size can be different for + // each process + packed_oarchive oa(comm); + for (int i = 0; i < n; ++i) { + oa << in_values[i]; } + std::vector<int> oasizes(nproc); + int oasize = oa.size(); + BOOST_MPI_CHECK_RESULT(MPI_Allgather, + (&oasize, 1, MPI_INTEGER, + c_data(oasizes), 1, MPI_INTEGER, + MPI_Comm(comm))); + // Gather the archives, which can be of different sizes, so + // we need to use allgatherv. + // Every thing is contiguous, so the offsets can be + // deduced from the collected sizes. + std::vector<int> offsets(nproc); + sizes2offsets(oasizes, offsets); + packed_iarchive::buffer_type recv_buffer(std::accumulate(oasizes.begin(), oasizes.end(), 0)); + BOOST_MPI_CHECK_RESULT(MPI_Allgatherv, + (const_cast<void*>(oa.address()), int(oa.size()), MPI_BYTE, + c_data(recv_buffer), c_data(oasizes), c_data(offsets), MPI_BYTE, + MPI_Comm(comm))); + for (int src = 0; src < nproc; ++src) { + int nb = sizes ? sizes[src] : n; + int skip = skips ? skips[src] : 0; + std::advance(out_values, skip); + if (src == comm.rank()) { // this is our local data + for (int i = 0; i < nb; ++i) { + *out_values++ = *in_values++; + } + } else { + packed_iarchive ia(comm, recv_buffer, boost::archive::no_header, offsets[src]); + for (int i = 0; i < nb; ++i) { + ia >> *out_values++; + } + } + } +} + +// We're all-gathering for a type that does not have an +// associated MPI datatype, so we'll need to serialize +// it. +template<typename T> +void +all_gather_impl(const communicator& comm, const T* in_values, int n, + T* out_values, mpl::false_ isnt_mpi_type) +{ + all_gather_impl(comm, in_values, n, out_values, (int const*)0, (int const*)0, isnt_mpi_type); +} } // end namespace detail template<typename T> -inline void +void all_gather(const communicator& comm, const T& in_value, T* out_values) { detail::all_gather_impl(comm, &in_value, 1, out_values, is_mpi_datatype<T>()); @@ -54,15 +109,15 @@ all_gather(const communicator& comm, const T& in_value, T* out_values) template<typename T> void -all_gather(const communicator& comm, const T& in_value, - std::vector<T>& out_values) +all_gather(const communicator& comm, const T& in_value, std::vector<T>& out_values) { + using detail::c_data; out_values.resize(comm.size()); - ::boost::mpi::all_gather(comm, &in_value, 1, &out_values[0]); + ::boost::mpi::all_gather(comm, in_value, c_data(out_values)); } template<typename T> -inline void +void all_gather(const communicator& comm, const T* in_values, int n, T* out_values) { detail::all_gather_impl(comm, in_values, n, out_values, is_mpi_datatype<T>()); @@ -70,11 +125,11 @@ all_gather(const communicator& comm, const T* in_values, int n, T* out_values) template<typename T> void -all_gather(const communicator& comm, const T* in_values, int n, - std::vector<T>& out_values) +all_gather(const communicator& comm, const T* in_values, int n, std::vector<T>& out_values) { + using detail::c_data; out_values.resize(comm.size() * n); - ::boost::mpi::all_gather(comm, in_values, n, &out_values[0]); + ::boost::mpi::all_gather(comm, in_values, n, c_data(out_values)); } } } // end namespace boost::mpi diff --git a/boost/mpi/collectives/all_gatherv.hpp b/boost/mpi/collectives/all_gatherv.hpp new file mode 100644 index 0000000000..064412f5d7 --- /dev/null +++ b/boost/mpi/collectives/all_gatherv.hpp @@ -0,0 +1,140 @@ +// Copyright (C) 2005, 2006 Douglas Gregor. + +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// Message Passing Interface 1.1 -- Section 4.5. Gatherv +#ifndef BOOST_MPI_ALLGATHERV_HPP +#define BOOST_MPI_ALLGATHERV_HPP + +#include <cassert> +#include <cstddef> +#include <numeric> +#include <vector> + +#include <boost/mpi/exception.hpp> +#include <boost/mpi/datatype.hpp> +#include <boost/mpi/packed_oarchive.hpp> +#include <boost/mpi/packed_iarchive.hpp> +#include <boost/mpi/detail/point_to_point.hpp> +#include <boost/mpi/communicator.hpp> +#include <boost/mpi/environment.hpp> +#include <boost/mpi/detail/offsets.hpp> +#include <boost/mpi/detail/antiques.hpp> +#include <boost/assert.hpp> +#include <boost/scoped_array.hpp> + +namespace boost { namespace mpi { + +namespace detail { +// We're all-gathering for a type that has an associated MPI +// datatype, so we'll use MPI_Gather to do all of the work. +template<typename T> +void +all_gatherv_impl(const communicator& comm, const T* in_values, + T* out_values, int const* sizes, int const* displs, mpl::true_) +{ + // Make displacements if not provided + scoped_array<int> new_offsets_mem(make_offsets(comm, sizes, displs, -1)); + if (new_offsets_mem) displs = new_offsets_mem.get(); + MPI_Datatype type = get_mpi_datatype<T>(*in_values); + BOOST_MPI_CHECK_RESULT(MPI_Allgatherv, + (const_cast<T*>(in_values), sizes[comm.rank()], type, + out_values, + const_cast<int*>(sizes), + const_cast<int*>(displs), + type, + comm)); +} + +// We're all-gathering for a type that does not have an +// associated MPI datatype, so we'll need to serialize +// it. +template<typename T> +void +all_gatherv_impl(const communicator& comm, const T* in_values, + T* out_values, int const* sizes, int const* displs, + mpl::false_ isnt_mpi_type) +{ + // convert displacement to offsets to skip + scoped_array<int> skipped(make_skipped_slots(comm, sizes, displs)); + all_gather_impl(comm, in_values, sizes[comm.rank()], out_values, + sizes, skipped.get(), isnt_mpi_type); +} +} // end namespace detail + +template<typename T> +void +all_gatherv(const communicator& comm, const T& in_value, T* out_values, + const std::vector<int>& sizes) +{ + using detail::c_data; + assert(sizes.size() == comm.size()); + assert(sizes[comm.rank()] == 1); + detail::all_gatherv_impl(comm, &in_value, out_values, c_data(sizes), 0, is_mpi_datatype<T>()); +} + +template<typename T> +void +all_gatherv(const communicator& comm, const T* in_values, T* out_values, + const std::vector<int>& sizes) +{ + using detail::c_data; + assert(int(sizes.size()) == comm.size()); + detail::all_gatherv_impl(comm, in_values, out_values, c_data(sizes), 0, is_mpi_datatype<T>()); +} + +template<typename T> +void +all_gatherv(const communicator& comm, std::vector<T> const& in_values, std::vector<T>& out_values, + const std::vector<int>& sizes) +{ + using detail::c_data; + assert(int(sizes.size()) == comm.size()); + assert(int(in_values.size()) == sizes[comm.rank()]); + out_values.resize(std::accumulate(sizes.begin(), sizes.end(), 0)); + ::boost::mpi::all_gatherv(comm, c_data(in_values), c_data(out_values), sizes); +} + + +template<typename T> +void +all_gatherv(const communicator& comm, const T& in_value, T* out_values, + const std::vector<int>& sizes, const std::vector<int>& displs) +{ + using detail::c_data; + assert(sizes.size() == comm.size()); + assert(displs.size() == comm.size()); + detail::all_gatherv_impl(comm, &in_value, 1, out_values, + c_data(sizes), c_data(displs), is_mpi_datatype<T>()); +} + +template<typename T> +void +all_gatherv(const communicator& comm, const T* in_values, T* out_values, + const std::vector<int>& sizes, const std::vector<int>& displs) +{ + using detail::c_data; + assert(sizes.size() == comm.size()); + assert(displs.size() == comm.size()); + detail::all_gatherv_impl(comm, in_values, out_values, + c_data(sizes), c_data(displs), is_mpi_datatype<T>()); +} + +template<typename T> +void +all_gatherv(const communicator& comm, std::vector<T> const& in_values, std::vector<T>& out_values, + const std::vector<int>& sizes, const std::vector<int>& displs) +{ + using detail::c_data; + assert(sizes.size() == comm.size()); + assert(displs.size() == comm.size()); + assert(in_values.size() == sizes[comm.rank()]); + out_values.resize(std::accumulate(sizes.begin(), sizes.end(), 0)); + ::boost::mpi::all_gatherv(comm, c_data(in_values), c_data(out_values), sizes, displs); +} + +} } // end namespace boost::mpi + +#endif // BOOST_MPI_ALL_GATHERV_HPP diff --git a/boost/mpi/collectives/all_to_all.hpp b/boost/mpi/collectives/all_to_all.hpp index 8c33c2a167..4f20be73d5 100644 --- a/boost/mpi/collectives/all_to_all.hpp +++ b/boost/mpi/collectives/all_to_all.hpp @@ -22,7 +22,7 @@ namespace boost { namespace mpi { namespace detail { - // We're performaing an all-to-all with a type that has an + // We're performing an all-to-all with a type that has an // associated MPI datatype, so we'll use MPI_Alltoall to do all of // the work. template<typename T> @@ -38,9 +38,7 @@ namespace detail { // We're performing an all-to-all with a type that does not have an // associated MPI datatype, so we'll need to serialize - // it. Unfortunately, this means that we cannot use MPI_Alltoall, so - // we'll just have to send individual messages to the other - // processes. + // it. template<typename T> void all_to_all_impl(const communicator& comm, const T* in_values, int n, diff --git a/boost/mpi/collectives/broadcast.hpp b/boost/mpi/collectives/broadcast.hpp index d5160cff7f..f8b27f0b4f 100644 --- a/boost/mpi/collectives/broadcast.hpp +++ b/boost/mpi/collectives/broadcast.hpp @@ -100,22 +100,35 @@ namespace detail { } // We're sending a type that does not have an associated MPI - // datatype, so we'll need to serialize it. Unfortunately, this - // means that we cannot use MPI_Bcast, so we'll just send from the - // root to everyone else. + // datatype, so we'll need to serialize it. template<typename T> void broadcast_impl(const communicator& comm, T* values, int n, int root, - mpl::false_) + mpl::false_ non_mpi_datatype) { + // Implementation proposed by Lorenz Hübschle-Schneider if (comm.rank() == root) { packed_oarchive oa(comm); - for (int i = 0; i < n; ++i) + for (int i = 0; i < n; ++i) { oa << values[i]; - broadcast(comm, oa, root); + } + std::size_t asize = oa.size(); + broadcast(comm, asize, root); + void const* aptr = oa.address(); + BOOST_MPI_CHECK_RESULT(MPI_Bcast, + (const_cast<void*>(aptr), asize, + MPI_BYTE, + root, MPI_Comm(comm))); } else { packed_iarchive ia(comm); - broadcast(comm, ia, root); + std::size_t asize; + broadcast(comm, asize, root); + ia.resize(asize); + void* aptr = ia.address(); + BOOST_MPI_CHECK_RESULT(MPI_Bcast, + (aptr, asize, + MPI_BYTE, + root, MPI_Comm(comm))); for (int i = 0; i < n; ++i) ia >> values[i]; } diff --git a/boost/mpi/collectives/gather.hpp b/boost/mpi/collectives/gather.hpp index 70dfd65313..386bfdd1a1 100644 --- a/boost/mpi/collectives/gather.hpp +++ b/boost/mpi/collectives/gather.hpp @@ -8,6 +8,9 @@ #ifndef BOOST_MPI_GATHER_HPP #define BOOST_MPI_GATHER_HPP +#include <cassert> +#include <cstddef> +#include <numeric> #include <boost/mpi/exception.hpp> #include <boost/mpi/datatype.hpp> #include <vector> @@ -16,89 +19,116 @@ #include <boost/mpi/detail/point_to_point.hpp> #include <boost/mpi/communicator.hpp> #include <boost/mpi/environment.hpp> +#include <boost/mpi/detail/offsets.hpp> +#include <boost/mpi/detail/antiques.hpp> #include <boost/assert.hpp> namespace boost { namespace mpi { namespace detail { - // We're gathering at the root for a type that has an associated MPI - // datatype, so we'll use MPI_Gather to do all of the work. - template<typename T> - void - gather_impl(const communicator& comm, const T* in_values, int n, - T* out_values, int root, mpl::true_) - { - MPI_Datatype type = get_mpi_datatype<T>(*in_values); - BOOST_MPI_CHECK_RESULT(MPI_Gather, - (const_cast<T*>(in_values), n, type, - out_values, n, type, root, comm)); - } +// We're gathering at the root for a type that has an associated MPI +// datatype, so we'll use MPI_Gather to do all of the work. +template<typename T> +void +gather_impl(const communicator& comm, const T* in_values, int n, + T* out_values, int root, mpl::true_) +{ + MPI_Datatype type = get_mpi_datatype<T>(*in_values); + BOOST_MPI_CHECK_RESULT(MPI_Gather, + (const_cast<T*>(in_values), n, type, + out_values, n, type, root, comm)); +} - // We're gathering from a non-root for a type that has an associated MPI - // datatype, so we'll use MPI_Gather to do all of the work. - template<typename T> - void - gather_impl(const communicator& comm, const T* in_values, int n, int root, - mpl::true_) - { - MPI_Datatype type = get_mpi_datatype<T>(*in_values); - BOOST_MPI_CHECK_RESULT(MPI_Gather, - (const_cast<T*>(in_values), n, type, - 0, n, type, root, comm)); - } +// We're gathering from a non-root for a type that has an associated MPI +// datatype, so we'll use MPI_Gather to do all of the work. +template<typename T> +void +gather_impl(const communicator& comm, const T* in_values, int n, int root, + mpl::true_ is_mpi_type) +{ + assert(comm.rank() != root); + gather_impl(comm, in_values, n, (T*)0, root, is_mpi_type); +} - // We're gathering at the root for a type that does not have an - // associated MPI datatype, so we'll need to serialize - // it. Unfortunately, this means that we cannot use MPI_Gather, so - // we'll just have all of the non-root nodes send individual - // messages to the root. - template<typename T> - void - gather_impl(const communicator& comm, const T* in_values, int n, - T* out_values, int root, mpl::false_) - { - int tag = environment::collectives_tag(); - int size = comm.size(); - - for (int src = 0; src < size; ++src) { - if (src == root) - std::copy(in_values, in_values + n, out_values + n * src); - else - comm.recv(src, tag, out_values + n * src, n); +// We're gathering at the root for a type that does not have an +// associated MPI datatype, so we'll need to serialize +// it. +template<typename T> +void +gather_impl(const communicator& comm, const T* in_values, int n, T* out_values, + int const* nslot, int const* nskip, int root, mpl::false_) +{ + int nproc = comm.size(); + // first, gather all size, these size can be different for + // each process + packed_oarchive oa(comm); + for (int i = 0; i < n; ++i) { + oa << in_values[i]; + } + bool is_root = comm.rank() == root; + std::vector<int> oasizes(is_root ? nproc : 0); + int oasize = oa.size(); + BOOST_MPI_CHECK_RESULT(MPI_Gather, + (&oasize, 1, MPI_INTEGER, + c_data(oasizes), 1, MPI_INTEGER, + root, MPI_Comm(comm))); + // Gather the archives, which can be of different sizes, so + // we need to use gatherv. + // Everything is contiguous (in the transmitted archive), so + // the offsets can be deduced from the collected sizes. + std::vector<int> offsets; + if (is_root) sizes2offsets(oasizes, offsets); + packed_iarchive::buffer_type recv_buffer(is_root ? std::accumulate(oasizes.begin(), oasizes.end(), 0) : 0); + BOOST_MPI_CHECK_RESULT(MPI_Gatherv, + (const_cast<void*>(oa.address()), int(oa.size()), MPI_BYTE, + c_data(recv_buffer), c_data(oasizes), c_data(offsets), MPI_BYTE, + root, MPI_Comm(comm))); + if (is_root) { + for (int src = 0; src < nproc; ++src) { + // handle variadic case + int nb = nslot ? nslot[src] : n; + int skip = nskip ? nskip[src] : 0; + std::advance(out_values, skip); + if (src == root) { + BOOST_ASSERT(nb == n); + for (int i = 0; i < nb; ++i) { + *out_values++ = *in_values++; + } + } else { + packed_iarchive ia(comm, recv_buffer, boost::archive::no_header, offsets[src]); + for (int i = 0; i < nb; ++i) { + ia >> *out_values++; + } + } } } +} - // We're gathering at a non-root for a type that does not have an - // associated MPI datatype, so we'll need to serialize - // it. Unfortunately, this means that we cannot use MPI_Gather, so - // we'll just have all of the non-root nodes send individual - // messages to the root. - template<typename T> - void - gather_impl(const communicator& comm, const T* in_values, int n, int root, - mpl::false_) - { - int tag = environment::collectives_tag(); - comm.send(root, tag, in_values, n); - } +// We're gathering at a non-root for a type that does not have an +// associated MPI datatype, so we'll need to serialize +// it. +template<typename T> +void +gather_impl(const communicator& comm, const T* in_values, int n, T* out_values,int root, + mpl::false_ is_mpi_type) +{ + gather_impl(comm, in_values, n, out_values, (int const*)0, (int const*)0, root, is_mpi_type); +} } // end namespace detail template<typename T> void gather(const communicator& comm, const T& in_value, T* out_values, int root) { - if (comm.rank() == root) - detail::gather_impl(comm, &in_value, 1, out_values, root, - is_mpi_datatype<T>()); - else - detail::gather_impl(comm, &in_value, 1, root, is_mpi_datatype<T>()); + BOOST_ASSERT(out_values || (comm.rank() != root)); + detail::gather_impl(comm, &in_value, 1, out_values, root, is_mpi_datatype<T>()); } template<typename T> void gather(const communicator& comm, const T& in_value, int root) { BOOST_ASSERT(comm.rank() != root); - detail::gather_impl(comm, &in_value, 1, root, is_mpi_datatype<T>()); + detail::gather_impl(comm, &in_value, 1, (T*)0, root, is_mpi_datatype<T>()); } template<typename T> @@ -106,12 +136,11 @@ void gather(const communicator& comm, const T& in_value, std::vector<T>& out_values, int root) { + using detail::c_data; if (comm.rank() == root) { out_values.resize(comm.size()); - ::boost::mpi::gather(comm, in_value, &out_values[0], root); - } else { - ::boost::mpi::gather(comm, in_value, root); } + ::boost::mpi::gather(comm, in_value, c_data(out_values), root); } template<typename T> @@ -119,11 +148,8 @@ void gather(const communicator& comm, const T* in_values, int n, T* out_values, int root) { - if (comm.rank() == root) - detail::gather_impl(comm, in_values, n, out_values, root, - is_mpi_datatype<T>()); - else - detail::gather_impl(comm, in_values, n, root, is_mpi_datatype<T>()); + detail::gather_impl(comm, in_values, n, out_values, root, + is_mpi_datatype<T>()); } template<typename T> @@ -133,10 +159,8 @@ gather(const communicator& comm, const T* in_values, int n, { if (comm.rank() == root) { out_values.resize(comm.size() * n); - ::boost::mpi::gather(comm, in_values, n, &out_values[0], root); - } - else - ::boost::mpi::gather(comm, in_values, n, root); + } + ::boost::mpi::gather(comm, in_values, n, out_values.data(), root); } template<typename T> diff --git a/boost/mpi/collectives/gatherv.hpp b/boost/mpi/collectives/gatherv.hpp index eb5f9c16dc..6b8d706fc6 100644 --- a/boost/mpi/collectives/gatherv.hpp +++ b/boost/mpi/collectives/gatherv.hpp @@ -8,15 +8,18 @@ #ifndef BOOST_MPI_GATHERV_HPP #define BOOST_MPI_GATHERV_HPP +#include <vector> + #include <boost/mpi/exception.hpp> #include <boost/mpi/datatype.hpp> -#include <vector> #include <boost/mpi/packed_oarchive.hpp> #include <boost/mpi/packed_iarchive.hpp> #include <boost/mpi/detail/point_to_point.hpp> #include <boost/mpi/communicator.hpp> #include <boost/mpi/environment.hpp> +#include <boost/mpi/detail/offsets.hpp> #include <boost/assert.hpp> +#include <boost/scoped_array.hpp> namespace boost { namespace mpi { @@ -58,41 +61,21 @@ namespace detail { gatherv_impl(const communicator& comm, const T* in_values, int in_size, T* out_values, const int* sizes, const int* displs, int root, mpl::false_) { - int tag = environment::collectives_tag(); - int nprocs = comm.size(); - - for (int src = 0; src < nprocs; ++src) { - if (src == root) - // Our own values will never be transmitted: just copy them. - std::copy(in_values, in_values + in_size, out_values + displs[src]); - else { -// comm.recv(src, tag, out_values + displs[src], sizes[src]); - // Receive archive - packed_iarchive ia(comm); - MPI_Status status; - detail::packed_archive_recv(comm, src, tag, ia, status); - for (int i = 0; i < sizes[src]; ++i) - ia >> out_values[ displs[src] + i ]; - } - } + // convert displacement to offsets to skip + scoped_array<int> skipped(make_skipped_slots(comm, sizes, displs, root)); + gather_impl(comm, in_values, in_size, out_values, sizes, skipped.get(), root, mpl::false_()); } // We're gathering at a non-root for a type that does not have an // associated MPI datatype, so we'll need to serialize - // it. Unfortunately, this means that we cannot use MPI_Gatherv, so - // we'll just have all of the non-root nodes send individual - // messages to the root. + // it. template<typename T> void gatherv_impl(const communicator& comm, const T* in_values, int in_size, int root, mpl::false_) { - int tag = environment::collectives_tag(); -// comm.send(root, tag, in_values, in_size); - packed_oarchive oa(comm); - for (int i = 0; i < in_size; ++i) - oa << in_values[i]; - detail::packed_archive_send(comm, root, tag, oa); + gather_impl(comm, in_values, in_size, (T*)0,(int const*)0,(int const*)0, root, + mpl::false_()); } } // end namespace detail diff --git a/boost/mpi/collectives/scatter.hpp b/boost/mpi/collectives/scatter.hpp index 196682dd59..0c91b1e6aa 100644 --- a/boost/mpi/collectives/scatter.hpp +++ b/boost/mpi/collectives/scatter.hpp @@ -16,94 +16,147 @@ #include <boost/mpi/detail/point_to_point.hpp> #include <boost/mpi/communicator.hpp> #include <boost/mpi/environment.hpp> +#include <boost/mpi/detail/offsets.hpp> +#include <boost/mpi/detail/antiques.hpp> #include <boost/assert.hpp> namespace boost { namespace mpi { namespace detail { - // We're scattering from the root for a type that has an associated MPI - // datatype, so we'll use MPI_Scatter to do all of the work. - template<typename T> - void - scatter_impl(const communicator& comm, const T* in_values, T* out_values, - int n, int root, mpl::true_) - { - MPI_Datatype type = get_mpi_datatype<T>(*in_values); - BOOST_MPI_CHECK_RESULT(MPI_Scatter, - (const_cast<T*>(in_values), n, type, - out_values, n, type, root, comm)); - } +// We're scattering from the root for a type that has an associated MPI +// datatype, so we'll use MPI_Scatter to do all of the work. +template<typename T> +void +scatter_impl(const communicator& comm, const T* in_values, T* out_values, + int n, int root, mpl::true_) +{ + MPI_Datatype type = get_mpi_datatype<T>(*in_values); + BOOST_MPI_CHECK_RESULT(MPI_Scatter, + (const_cast<T*>(in_values), n, type, + out_values, n, type, root, comm)); +} - // We're scattering from a non-root for a type that has an associated MPI - // datatype, so we'll use MPI_Scatter to do all of the work. - template<typename T> - void - scatter_impl(const communicator& comm, T* out_values, int n, int root, - mpl::true_) - { - MPI_Datatype type = get_mpi_datatype<T>(*out_values); - BOOST_MPI_CHECK_RESULT(MPI_Scatter, - (0, n, type, - out_values, n, type, - root, comm)); +// We're scattering from a non-root for a type that has an associated MPI +// datatype, so we'll use MPI_Scatter to do all of the work. +template<typename T> +void +scatter_impl(const communicator& comm, T* out_values, int n, int root, + mpl::true_) +{ + MPI_Datatype type = get_mpi_datatype<T>(*out_values); + BOOST_MPI_CHECK_RESULT(MPI_Scatter, + (0, n, type, + out_values, n, type, + root, comm)); +} + +// Fill the sendbuf while keeping trac of the slot's footprints +// Used in the first steps of both scatter and scatterv +// Nslots contains the number of slots being sent +// to each process (identical values for scatter). +// skiped_slots, if present, is deduced from the +// displacement array authorised be the MPI API, +// for some yet to be determined reason. +template<typename T> +void +fill_scatter_sendbuf(const communicator& comm, T const* values, + int const* nslots, int const* skipped_slots, + packed_oarchive::buffer_type& sendbuf, std::vector<int>& archsizes) { + int nproc = comm.size(); + archsizes.resize(nproc); + + for (int dest = 0; dest < nproc; ++dest) { + if (skipped_slots) { // wee need to keep this for backward compatibility + for(int k= 0; k < skipped_slots[dest]; ++k) ++values; + } + packed_oarchive procarchive(comm); + for (int i = 0; i < nslots[dest]; ++i) { + procarchive << *values++; + } + int archsize = procarchive.size(); + sendbuf.resize(sendbuf.size() + archsize); + archsizes[dest] = archsize; + char const* aptr = static_cast<char const*>(procarchive.address()); + std::copy(aptr, aptr+archsize, sendbuf.end()-archsize); } +} - // We're scattering from the root for a type that does not have an - // associated MPI datatype, so we'll need to serialize - // it. Unfortunately, this means that we cannot use MPI_Scatter, so - // we'll just have the root send individual messages to the other - // processes. - template<typename T> - void - scatter_impl(const communicator& comm, const T* in_values, T* out_values, - int n, int root, mpl::false_) - { - int tag = environment::collectives_tag(); - int size = comm.size(); - - for (int dest = 0; dest < size; ++dest) { - if (dest == root) { - // Our own values will never be transmitted: just copy them. - std::copy(in_values + dest * n, in_values + (dest + 1) * n, out_values); - } else { - // Send archive - packed_oarchive oa(comm); - for (int i = 0; i < n; ++i) - oa << in_values[dest * n + i]; - detail::packed_archive_send(comm, dest, tag, oa); - } +template<typename T, class A> +T* +non_const_data(std::vector<T,A> const& v) { + using detail::c_data; + return const_cast<T*>(c_data(v)); +} + +// Dispatch the sendbuf among proc. +// Used in the second steps of both scatter and scatterv +// in_value is only provide in the non variadic case. +template<typename T> +void +dispatch_scatter_sendbuf(const communicator& comm, + packed_oarchive::buffer_type const& sendbuf, std::vector<int> const& archsizes, + T const* in_values, + T* out_values, int n, int root) { + // Distribute the sizes + int myarchsize; + BOOST_MPI_CHECK_RESULT(MPI_Scatter, + (non_const_data(archsizes), 1, MPI_INTEGER, + &myarchsize, 1, MPI_INTEGER, root, comm)); + std::vector<int> offsets; + if (root == comm.rank()) { + sizes2offsets(archsizes, offsets); + } + // Get my proc archive + packed_iarchive::buffer_type recvbuf; + recvbuf.resize(myarchsize); + BOOST_MPI_CHECK_RESULT(MPI_Scatterv, + (non_const_data(sendbuf), non_const_data(archsizes), c_data(offsets), MPI_BYTE, + c_data(recvbuf), recvbuf.size(), MPI_BYTE, + root, MPI_Comm(comm))); + // Unserialize + if ( in_values != 0 && root == comm.rank()) { + // Our own local values are already here: just copy them. + std::copy(in_values + root * n, in_values + (root + 1) * n, out_values); + } else { + // Otherwise deserialize: + packed_iarchive iarchv(comm, recvbuf); + for (int i = 0; i < n; ++i) { + iarchv >> out_values[i]; } } +} - // We're scattering to a non-root for a type that does not have an - // associated MPI datatype, so we'll need to de-serialize - // it. Unfortunately, this means that we cannot use MPI_Scatter, so - // we'll just have all of the non-root nodes send individual - // messages to the root. - template<typename T> - void - scatter_impl(const communicator& comm, T* out_values, int n, int root, - mpl::false_) - { - int tag = environment::collectives_tag(); - - packed_iarchive ia(comm); - MPI_Status status; - detail::packed_archive_recv(comm, root, tag, ia, status); - for (int i = 0; i < n; ++i) - ia >> out_values[i]; +// We're scattering from the root for a type that does not have an +// associated MPI datatype, so we'll need to serialize it. +template<typename T> +void +scatter_impl(const communicator& comm, const T* in_values, T* out_values, + int n, int root, mpl::false_) +{ + packed_oarchive::buffer_type sendbuf; + std::vector<int> archsizes; + + if (root == comm.rank()) { + std::vector<int> nslots(comm.size(), n); + fill_scatter_sendbuf(comm, in_values, c_data(nslots), (int const*)0, sendbuf, archsizes); } + dispatch_scatter_sendbuf(comm, sendbuf, archsizes, in_values, out_values, n, root); +} + +template<typename T> +void +scatter_impl(const communicator& comm, T* out_values, int n, int root, + mpl::false_ is_mpi_type) +{ + scatter_impl(comm, (T const*)0, out_values, n, root, is_mpi_type); +} } // end namespace detail template<typename T> void scatter(const communicator& comm, const T* in_values, T& out_value, int root) { - if (comm.rank() == root) - detail::scatter_impl(comm, in_values, &out_value, 1, root, - is_mpi_datatype<T>()); - else - detail::scatter_impl(comm, &out_value, 1, root, is_mpi_datatype<T>()); + detail::scatter_impl(comm, in_values, &out_value, 1, root, is_mpi_datatype<T>()); } template<typename T> @@ -111,11 +164,8 @@ void scatter(const communicator& comm, const std::vector<T>& in_values, T& out_value, int root) { - if (comm.rank() == root) - ::boost::mpi::scatter<T>(comm, &in_values[0], out_value, root); - else - ::boost::mpi::scatter<T>(comm, static_cast<const T*>(0), out_value, - root); + using detail::c_data; + ::boost::mpi::scatter<T>(comm, c_data(in_values), out_value, root); } template<typename T> @@ -130,11 +180,7 @@ void scatter(const communicator& comm, const T* in_values, T* out_values, int n, int root) { - if (comm.rank() == root) - detail::scatter_impl(comm, in_values, out_values, n, root, - is_mpi_datatype<T>()); - else - detail::scatter_impl(comm, out_values, n, root, is_mpi_datatype<T>()); + detail::scatter_impl(comm, in_values, out_values, n, root, is_mpi_datatype<T>()); } template<typename T> @@ -142,11 +188,7 @@ void scatter(const communicator& comm, const std::vector<T>& in_values, T* out_values, int n, int root) { - if (comm.rank() == root) - ::boost::mpi::scatter(comm, &in_values[0], out_values, n, root); - else - ::boost::mpi::scatter(comm, static_cast<const T*>(0), out_values, - n, root); + ::boost::mpi::scatter(comm, &in_values[0], out_values, n, root); } template<typename T> diff --git a/boost/mpi/collectives/scatterv.hpp b/boost/mpi/collectives/scatterv.hpp index 6e6f27002b..57e073c81f 100644 --- a/boost/mpi/collectives/scatterv.hpp +++ b/boost/mpi/collectives/scatterv.hpp @@ -8,93 +8,90 @@ #ifndef BOOST_MPI_SCATTERV_HPP #define BOOST_MPI_SCATTERV_HPP -#include <boost/mpi/exception.hpp> -#include <boost/mpi/datatype.hpp> -#include <vector> -#include <boost/mpi/packed_oarchive.hpp> -#include <boost/mpi/packed_iarchive.hpp> -#include <boost/mpi/detail/point_to_point.hpp> -#include <boost/mpi/communicator.hpp> -#include <boost/mpi/environment.hpp> -#include <boost/assert.hpp> +#include <boost/scoped_array.hpp> +#include <boost/mpi/collectives/scatter.hpp> +#include <boost/mpi/detail/offsets.hpp> +#include <boost/mpi/detail/antiques.hpp> namespace boost { namespace mpi { namespace detail { - // We're scattering from the root for a type that has an associated MPI - // datatype, so we'll use MPI_Scatterv to do all of the work. - template<typename T> - void - scatterv_impl(const communicator& comm, const T* in_values, const int* sizes, - const int* displs, T* out_values, int out_size, int root, mpl::true_) - { - MPI_Datatype type = get_mpi_datatype<T>(*in_values); - BOOST_MPI_CHECK_RESULT(MPI_Scatterv, - (const_cast<T*>(in_values), const_cast<int*>(sizes), - const_cast<int*>(displs), type, - out_values, out_size, type, root, comm)); - } - // We're scattering from a non-root for a type that has an associated MPI - // datatype, so we'll use MPI_Scatterv to do all of the work. - template<typename T> - void - scatterv_impl(const communicator& comm, T* out_values, int out_size, int root, - mpl::true_) - { - MPI_Datatype type = get_mpi_datatype<T>(*out_values); - BOOST_MPI_CHECK_RESULT(MPI_Scatterv, - (0, 0, 0, type, - out_values, out_size, type, - root, comm)); - } +////////////////////////////////////////////// +/// Implementation for MPI primitive types /// +////////////////////////////////////////////// + +// We're scattering from the root for a type that has an associated MPI +// datatype, so we'll use MPI_Scatterv to do all of the work. +template<typename T> +void +scatterv_impl(const communicator& comm, const T* in_values, T* out_values, int out_size, + const int* sizes, const int* displs, int root, mpl::true_) +{ + assert(!sizes || out_size == sizes[comm.rank()]); + assert(bool(sizes) == bool(in_values)); + + scoped_array<int> new_offsets_mem(make_offsets(comm, sizes, displs, root)); + if (new_offsets_mem) displs = new_offsets_mem.get(); + MPI_Datatype type = get_mpi_datatype<T>(*in_values); + BOOST_MPI_CHECK_RESULT(MPI_Scatterv, + (const_cast<T*>(in_values), const_cast<int*>(sizes), + const_cast<int*>(displs), type, + out_values, out_size, type, root, comm)); +} - // We're scattering from the root for a type that does not have an - // associated MPI datatype, so we'll need to serialize - // it. Unfortunately, this means that we cannot use MPI_Scatterv, so - // we'll just have the root send individual messages to the other - // processes. - template<typename T> - void - scatterv_impl(const communicator& comm, const T* in_values, const int* sizes, - const int* displs, T* out_values, int out_size, int root, mpl::false_) - { - int tag = environment::collectives_tag(); - int nprocs = comm.size(); - - for (int dest = 0; dest < nprocs; ++dest) { - if (dest == root) { - // Our own values will never be transmitted: just copy them. - std::copy(in_values + displs[dest], - in_values + displs[dest] + out_size, out_values); - } else { - // Send archive - packed_oarchive oa(comm); - for (int i = 0; i < sizes[dest]; ++i) - oa << in_values[ displs[dest] + i ]; - detail::packed_archive_send(comm, dest, tag, oa); - } +// We're scattering from a non-root for a type that has an associated MPI +// datatype, so we'll use MPI_Scatterv to do all of the work. +template<typename T> +void +scatterv_impl(const communicator& comm, T* out_values, int out_size, int root, + mpl::true_ is_mpi_type) +{ + scatterv_impl(comm, (T const*)0, out_values, out_size, + (const int*)0, (const int*)0, root, is_mpi_type); +} + +////////////////////////////////////////////////// +/// Implementation for non MPI primitive types /// +////////////////////////////////////////////////// + +// We're scattering from the root for a type that does not have an +// associated MPI datatype, so we'll need to serialize it. +template<typename T> +void +scatterv_impl(const communicator& comm, const T* in_values, T* out_values, int out_size, + int const* sizes, int const* displs, int root, mpl::false_) +{ + packed_oarchive::buffer_type sendbuf; + bool is_root = comm.rank() == root; + int nproc = comm.size(); + std::vector<int> archsizes; + if (is_root) { + assert(out_size == sizes[comm.rank()]); + archsizes.resize(nproc); + std::vector<int> skipped; + if (displs) { + skipped.resize(nproc); + offsets2skipped(sizes, displs, c_data(skipped), nproc); + displs = c_data(skipped); } + fill_scatter_sendbuf(comm, in_values, sizes, (int const*)0, sendbuf, archsizes); } + dispatch_scatter_sendbuf(comm, sendbuf, archsizes, (T const*)0, out_values, out_size, root); +} + +// We're scattering to a non-root for a type that does not have an +// associated MPI datatype. input data not needed. +// it. +template<typename T> +void +scatterv_impl(const communicator& comm, T* out_values, int n, int root, + mpl::false_ isnt_mpi_type) +{ + assert(root != comm.rank()); + scatterv_impl(comm, (T const*)0, out_values, n, (int const*)0, (int const*)0, root, isnt_mpi_type); +} - // We're scattering to a non-root for a type that does not have an - // associated MPI datatype, so we'll need to de-serialize - // it. Unfortunately, this means that we cannot use MPI_Scatterv, so - // we'll just have all of the non-root nodes send individual - // messages to the root. - template<typename T> - void - scatterv_impl(const communicator& comm, T* out_values, int out_size, int root, - mpl::false_) - { - int tag = environment::collectives_tag(); - - packed_iarchive ia(comm); - MPI_Status status; - detail::packed_archive_recv(comm, root, tag, ia, status); - for (int i = 0; i < out_size; ++i) - ia >> out_values[i]; - } } // end namespace detail template<typename T> @@ -103,13 +100,9 @@ scatterv(const communicator& comm, const T* in_values, const std::vector<int>& sizes, const std::vector<int>& displs, T* out_values, int out_size, int root) { - int rank = comm.rank(); - if (rank == root) - detail::scatterv_impl(comm, in_values, &sizes[0], &displs[0], - out_values, out_size, root, is_mpi_datatype<T>()); - else - detail::scatterv_impl(comm, out_values, out_size, root, - is_mpi_datatype<T>()); + using detail::c_data; + scatterv_impl(comm, in_values, out_values, out_size, c_data(sizes), c_data(displs), + root, is_mpi_datatype<T>()); } template<typename T> @@ -118,12 +111,9 @@ scatterv(const communicator& comm, const std::vector<T>& in_values, const std::vector<int>& sizes, const std::vector<int>& displs, T* out_values, int out_size, int root) { - if (comm.rank() == root) - ::boost::mpi::scatterv(comm, &in_values[0], sizes, displs, - out_values, out_size, root); - else - ::boost::mpi::scatterv(comm, static_cast<const T*>(0), sizes, displs, - out_values, out_size, root); + using detail::c_data; + ::boost::mpi::scatterv(comm, c_data(in_values), sizes, displs, + out_values, out_size, root); } template<typename T> @@ -141,16 +131,10 @@ void scatterv(const communicator& comm, const T* in_values, const std::vector<int>& sizes, T* out_values, int root) { - int nprocs = comm.size(); - int myrank = comm.rank(); - - std::vector<int> displs(nprocs); - for (int rank = 0, aux = 0; rank < nprocs; ++rank) { - displs[rank] = aux; - aux += sizes[rank]; - } - ::boost::mpi::scatterv(comm, in_values, sizes, displs, out_values, - sizes[myrank], root); + using detail::c_data; + detail::scatterv_impl(comm, in_values, out_values, sizes[comm.rank()], + c_data(sizes), (int const*)0, + root, is_mpi_datatype<T>()); } template<typename T> @@ -161,6 +145,23 @@ scatterv(const communicator& comm, const std::vector<T>& in_values, ::boost::mpi::scatterv(comm, &in_values[0], sizes, out_values, root); } +template<typename T> +void +scatterv(const communicator& comm, const T* in_values, + T* out_values, int n, int root) +{ + detail::scatterv_impl(comm, in_values, out_values, n, (int const*)0, (int const*)0, + root, is_mpi_datatype<T>()); +} + +template<typename T> +void +scatterv(const communicator& comm, const std::vector<T>& in_values, + T* out_values, int out_size, int root) +{ + ::boost::mpi::scatterv(comm, &in_values[0], out_values, out_size, root); +} + } } // end namespace boost::mpi #endif // BOOST_MPI_SCATTERV_HPP diff --git a/boost/mpi/communicator.hpp b/boost/mpi/communicator.hpp index a491086ad5..af29d1c6ff 100644 --- a/boost/mpi/communicator.hpp +++ b/boost/mpi/communicator.hpp @@ -116,6 +116,14 @@ class intercommunicator; class graph_communicator; /** + * INTERNAL ONLY + * + * Forward declaration of @c cartesian_communicator needed for the "cast" + * from a communicator to a cartesian communicator. + */ +class cartesian_communicator; + +/** * @brief A communicator that permits communication and * synchronization among a set of processes. * @@ -850,30 +858,28 @@ class BOOST_MPI_DECL communicator optional<graph_communicator> as_graph_communicator() const; /** + * Determines whether this communicator has a Graph topology. + */ + bool has_graph_topology() const; + + /** + * Determine if the communicator has a cartesian topology and, if so, + * return that @c cartesian_communicator. Even though the communicators + * have different types, they refer to the same underlying + * communication space and can be used interchangeably for + * communication. + * + * @returns an @c optional containing the cartesian communicator, if this + * communicator does in fact have a cartesian topology. Otherwise, returns + * an empty @c optional. + */ + optional<cartesian_communicator> as_cartesian_communicator() const; + + /** * Determines whether this communicator has a Cartesian topology. */ bool has_cartesian_topology() const; -#if 0 - template<typename Extents> - communicator - with_cartesian_topology(const Extents& extents, - bool periodic = false, - bool reorder = false) const; - - template<typename DimInputIterator, typename PeriodicInputIterator> - communicator - with_cartesian_topology(DimInputIterator first_dim, - DimInputIterator last_dim, - PeriodicInputIterator first_periodic, - bool reorder = false); - - template<typename Allocator, std::size_t NumDims> - communicator - with_cartesian_topology(const multi_array<bool, NumDims, Allocator>& periods, - bool reorder = false); -#endif - /** Abort all tasks in the group of this communicator. * * Makes a "best attempt" to abort all of the tasks in the group of @@ -1122,6 +1128,115 @@ inline bool operator!=(const communicator& comm1, const communicator& comm2) /************************************************************************ * Implementation details * ************************************************************************/ + +/** + * INTERNAL ONLY (using the same 'end' name might be considerd unfortunate + */ +template<> +BOOST_MPI_DECL void +communicator::send<packed_oarchive>(int dest, int tag, + const packed_oarchive& ar) const; + +/** + * INTERNAL ONLY + */ +template<> +BOOST_MPI_DECL void +communicator::send<packed_skeleton_oarchive> + (int dest, int tag, const packed_skeleton_oarchive& ar) const; + +/** + * INTERNAL ONLY + */ +template<> +BOOST_MPI_DECL void +communicator::send<content>(int dest, int tag, const content& c) const; + +/** + * INTERNAL ONLY + */ +template<> +BOOST_MPI_DECL status +communicator::recv<packed_iarchive>(int source, int tag, + packed_iarchive& ar) const; + +/** + * INTERNAL ONLY + */ +template<> +BOOST_MPI_DECL status +communicator::recv<packed_skeleton_iarchive> + (int source, int tag, packed_skeleton_iarchive& ar) const; + +/** + * INTERNAL ONLY + */ +template<> +BOOST_MPI_DECL status +communicator::recv<const content>(int source, int tag, + const content& c) const; + +/** + * INTERNAL ONLY + */ +template<> +inline status +communicator::recv<content>(int source, int tag, + content& c) const +{ + return recv<const content>(source,tag,c); +} + +/** + * INTERNAL ONLY + */ +template<> +BOOST_MPI_DECL request +communicator::isend<packed_oarchive>(int dest, int tag, + const packed_oarchive& ar) const; + +/** + * INTERNAL ONLY + */ +template<> +BOOST_MPI_DECL request +communicator::isend<packed_skeleton_oarchive> + (int dest, int tag, const packed_skeleton_oarchive& ar) const; + +/** + * INTERNAL ONLY + */ +template<> +BOOST_MPI_DECL request +communicator::isend<content>(int dest, int tag, const content& c) const; + +/** + * INTERNAL ONLY + */ +template<> +BOOST_MPI_DECL request +communicator::irecv<packed_skeleton_iarchive> + (int source, int tag, packed_skeleton_iarchive& ar) const; + +/** + * INTERNAL ONLY + */ +template<> +BOOST_MPI_DECL request +communicator::irecv<const content>(int source, int tag, + const content& c) const; + +/** + * INTERNAL ONLY + */ +template<> +inline request +communicator::irecv<content>(int source, int tag, + content& c) const +{ + return irecv<const content>(source, tag, c); +} + // Count elements in a message template<typename T> inline optional<int> status::count() const @@ -1742,115 +1857,6 @@ request communicator::irecv(int source, int tag, T* values, int n) const return this->array_irecv_impl(source, tag, values, n, is_mpi_datatype<T>()); } -/** - * INTERNAL ONLY - */ -template<> -BOOST_MPI_DECL void -communicator::send<packed_oarchive>(int dest, int tag, - const packed_oarchive& ar) const; - -/** - * INTERNAL ONLY - */ -template<> -BOOST_MPI_DECL void -communicator::send<packed_skeleton_oarchive> - (int dest, int tag, const packed_skeleton_oarchive& ar) const; - -/** - * INTERNAL ONLY - */ -template<> -BOOST_MPI_DECL void -communicator::send<content>(int dest, int tag, const content& c) const; - -/** - * INTERNAL ONLY - */ -template<> -BOOST_MPI_DECL status -communicator::recv<packed_iarchive>(int source, int tag, - packed_iarchive& ar) const; - -/** - * INTERNAL ONLY - */ -template<> -BOOST_MPI_DECL status -communicator::recv<packed_skeleton_iarchive> - (int source, int tag, packed_skeleton_iarchive& ar) const; - -/** - * INTERNAL ONLY - */ -template<> -BOOST_MPI_DECL status -communicator::recv<const content>(int source, int tag, - const content& c) const; - -/** - * INTERNAL ONLY - */ -template<> -inline status -communicator::recv<content>(int source, int tag, - content& c) const -{ - return recv<const content>(source,tag,c); -} - -/** - * INTERNAL ONLY - */ -template<> -BOOST_MPI_DECL request -communicator::isend<packed_oarchive>(int dest, int tag, - const packed_oarchive& ar) const; - -/** - * INTERNAL ONLY - */ -template<> -BOOST_MPI_DECL request -communicator::isend<packed_skeleton_oarchive> - (int dest, int tag, const packed_skeleton_oarchive& ar) const; - -/** - * INTERNAL ONLY - */ -template<> -BOOST_MPI_DECL request -communicator::isend<content>(int dest, int tag, const content& c) const; - -/** - * INTERNAL ONLY - */ -template<> -BOOST_MPI_DECL request -communicator::irecv<packed_skeleton_iarchive> - (int source, int tag, packed_skeleton_iarchive& ar) const; - -/** - * INTERNAL ONLY - */ -template<> -BOOST_MPI_DECL request -communicator::irecv<const content>(int source, int tag, - const content& c) const; - -/** - * INTERNAL ONLY - */ -template<> -inline request -communicator::irecv<content>(int source, int tag, - content& c) const -{ - return irecv<const content>(source, tag, c); -} - - } } // end namespace boost::mpi // If the user has already included skeleton_and_content.hpp, include diff --git a/boost/mpi/detail/antiques.hpp b/boost/mpi/detail/antiques.hpp index 6ece779777..0bd235b2c1 100644 --- a/boost/mpi/detail/antiques.hpp +++ b/boost/mpi/detail/antiques.hpp @@ -13,17 +13,28 @@ // Support for some obsolette compilers namespace boost { namespace mpi { - namespace detail { - // Some old gnu compiler have no support for vector<>::data - // Use this in the mean time, the cumbersome syntax should - // serve as an incentive to get rid of this when those compilers - // are dropped. - template <typename T, typename A> - T* c_data(std::vector<T,A>& v) { return &(v[0]); } - - template <typename T, typename A> - T const* c_data(std::vector<T,A> const& v) { return &(v[0]); } - +namespace detail { + // Some old gnu compiler have no support for vector<>::data + // Use this in the mean time, the cumbersome syntax should + // serve as an incentive to get rid of this when those compilers + // are dropped. + template <typename T, typename A> + T* c_data(std::vector<T,A>& v) { return &(v[0]); } + + template <typename T, typename A> + T const* c_data(std::vector<T,A> const& v) { return &(v[0]); } + + // Some old MPI implementation (OpenMPI 1.6 for example) have non + // conforming API w.r.t. constness. + // We choose to fix this trhough this converter in order to + // explain/remember why we're doing this and remove it easilly + // when support for those MPI is dropped. + // The fix is as specific (un templatized, for one) as possible + // in order to encourage it usage for the probleme at hand. + // Problematic API include MPI_Send + inline + void *unconst(void const* addr) { return const_cast<void*>(addr); } + } } } #endif diff --git a/boost/mpi/detail/binary_buffer_oprimitive.hpp b/boost/mpi/detail/binary_buffer_oprimitive.hpp index 1de441d26b..313097b795 100644 --- a/boost/mpi/detail/binary_buffer_oprimitive.hpp +++ b/boost/mpi/detail/binary_buffer_oprimitive.hpp @@ -47,7 +47,12 @@ public: { return size_ = buffer_.size(); } - + + const std::size_t* size_ptr() const + { + return &size(); + } + void save_binary(void const *address, std::size_t count) { save_impl(address,count); diff --git a/boost/mpi/detail/mpi_datatype_primitive.hpp b/boost/mpi/detail/mpi_datatype_primitive.hpp index b2263fac4c..6a82624e43 100644 --- a/boost/mpi/detail/mpi_datatype_primitive.hpp +++ b/boost/mpi/detail/mpi_datatype_primitive.hpp @@ -21,6 +21,7 @@ namespace std{ #include <boost/mpi/datatype_fwd.hpp> #include <boost/mpi/exception.hpp> +#include <boost/mpi/detail/antiques.hpp> #include <boost/throw_exception.hpp> #include <boost/assert.hpp> #include <boost/mpl/placeholders.hpp> @@ -129,6 +130,12 @@ private: lengths.push_back(l); } + template <class T> + static T* get_data(std::vector<T>& v) + { + return v.empty() ? 0 : &(v[0]); + } + std::vector<MPI_Aint> addresses; std::vector<MPI_Datatype> types; std::vector<int> lengths; diff --git a/boost/mpi/detail/offsets.hpp b/boost/mpi/detail/offsets.hpp new file mode 100644 index 0000000000..7e5ab7dff6 --- /dev/null +++ b/boost/mpi/detail/offsets.hpp @@ -0,0 +1,47 @@ +// Copyright Alain Miniussi 2014. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// Authors: Alain Miniussi + +#ifndef BOOST_MPI_OFFSETS_HPP +#define BOOST_MPI_OFFSETS_HPP + +#include <vector> +#include <boost/mpi/communicator.hpp> + +namespace boost { namespace mpi { +namespace detail { + +// Convert a sequence of sizes [S0..Sn] to a sequence displacement +// [O0..On] where O[0] = 0 and O[k+1] = O[k]+S[k]. +void sizes2offsets(int const* sizes, int* offsets, int n); + +// Same as size2offset(sizes.data(), offsets.data(), sizes.size()) +void sizes2offsets(std::vector<int> const& sizes, std::vector<int>& offsets); + +// Given a sequence of sizes (typically the number of records dispatched +// to each process in a scater) and a sequence of displacements (typically the +// slot index at with those record starts), convert the later to a number +// of skipped slots. +void offsets2skipped(int const* sizes, int const* offsets, int* skipped, int n); + +// Reconstruct offsets from sizes assuming no padding. +// Only takes place if on the root process and if +// displs are not already provided. +// If memory was allocated, returns a pointer to it +// otherwise null. +int* make_offsets(communicator const& comm, int const* sizes, int const* displs, int root = -1); + +// Reconstruct skip slots from sizes and offsets. +// Only takes place if on the root process and if +// displs are provided. +// If memory was allocated, returns a pointer to it +// otherwise null. +int* make_skipped_slots(communicator const& comm, int const* sizes, int const* displs, int root = -1); + +} +}}// end namespace boost::mpi + +#endif // BOOST_MPI_OFFSETS_HPP diff --git a/boost/mpi/detail/packed_iprimitive.hpp b/boost/mpi/detail/packed_iprimitive.hpp index 69d2c73a2b..85a4010fea 100644 --- a/boost/mpi/detail/packed_iprimitive.hpp +++ b/boost/mpi/detail/packed_iprimitive.hpp @@ -14,7 +14,7 @@ #include <boost/config.hpp> #include <boost/mpi/datatype.hpp> #include <boost/mpi/exception.hpp> -#include <boost/assert.hpp> +#include <boost/mpi/detail/antiques.hpp> #include <boost/serialization/array.hpp> #include <vector> #include <boost/mpi/detail/antiques.hpp> diff --git a/boost/mpi/detail/packed_oprimitive.hpp b/boost/mpi/detail/packed_oprimitive.hpp index 1cb4ba0c26..4ca8e07240 100644 --- a/boost/mpi/detail/packed_oprimitive.hpp +++ b/boost/mpi/detail/packed_oprimitive.hpp @@ -12,7 +12,6 @@ #include <boost/mpi/config.hpp> #include <cstddef> // size_t #include <boost/config.hpp> - #include <boost/mpi/datatype.hpp> #include <boost/mpi/exception.hpp> #include <boost/mpi/detail/antiques.hpp> @@ -47,6 +46,11 @@ public: return size_ = buffer_.size(); } + const std::size_t* size_ptr() const + { + return &size(); + } + void save_binary(void const *address, std::size_t count) { save_impl(address,MPI_BYTE,count); @@ -108,6 +112,11 @@ private: buffer_.resize(position); } + static buffer_type::value_type* get_data(buffer_type& b) + { + return b.empty() ? 0 : &(b[0]); + } + buffer_type& buffer_; mutable std::size_t size_; MPI_Comm comm; diff --git a/boost/mpi/environment.hpp b/boost/mpi/environment.hpp index 92af129f38..cb90b6d046 100644 --- a/boost/mpi/environment.hpp +++ b/boost/mpi/environment.hpp @@ -265,6 +265,12 @@ public: */ static bool is_main_thread(); + /** @brief MPI version. + * + * Returns a pair with the version and sub-version number. + */ + static std::pair<int, int> version(); + private: /// Whether this environment object called MPI_Init bool i_initialized; diff --git a/boost/mpi/exception.hpp b/boost/mpi/exception.hpp index 12523077cc..154a4317c6 100644 --- a/boost/mpi/exception.hpp +++ b/boost/mpi/exception.hpp @@ -15,6 +15,7 @@ #include <boost/mpi/config.hpp> #include <exception> +#include <cassert> #include <string> #include <boost/config.hpp> #include <boost/throw_exception.hpp> @@ -94,6 +95,7 @@ class BOOST_MPI_DECL exception : public std::exception #define BOOST_MPI_CHECK_RESULT( MPIFunc, Args ) \ { \ int _check_result = MPIFunc Args; \ + assert(_check_result == MPI_SUCCESS); \ if (_check_result != MPI_SUCCESS) \ boost::throw_exception(boost::mpi::exception(#MPIFunc, \ _check_result)); \ diff --git a/boost/mpi/operations.hpp b/boost/mpi/operations.hpp index c1189e4364..b72b13d79a 100644 --- a/boost/mpi/operations.hpp +++ b/boost/mpi/operations.hpp @@ -55,8 +55,11 @@ struct is_commutative : public mpl::false_ { }; * associated, built-in MPI data type, translates to @c MPI_MAX. */ template<typename T> -struct maximum : public std::binary_function<T, T, T> +struct maximum { + typedef T first_argument_type; + typedef T second_argument_type; + typedef T result_type; /** @returns the maximum of x and y. */ const T& operator()(const T& x, const T& y) const { @@ -72,8 +75,11 @@ struct maximum : public std::binary_function<T, T, T> * associated, built-in MPI data type, translates to @c MPI_MIN. */ template<typename T> -struct minimum : public std::binary_function<T, T, T> +struct minimum { + typedef T first_argument_type; + typedef T second_argument_type; + typedef T result_type; /** @returns the minimum of x and y. */ const T& operator()(const T& x, const T& y) const { @@ -90,8 +96,11 @@ struct minimum : public std::binary_function<T, T, T> * associated, built-in MPI data type, translates to @c MPI_BAND. */ template<typename T> -struct bitwise_and : public std::binary_function<T, T, T> +struct bitwise_and { + typedef T first_argument_type; + typedef T second_argument_type; + typedef T result_type; /** @returns @c x & y. */ T operator()(const T& x, const T& y) const { @@ -107,8 +116,11 @@ struct bitwise_and : public std::binary_function<T, T, T> * associated, built-in MPI data type, translates to @c MPI_BOR. */ template<typename T> -struct bitwise_or : public std::binary_function<T, T, T> +struct bitwise_or { + typedef T first_argument_type; + typedef T second_argument_type; + typedef T result_type; /** @returns the @c x | y. */ T operator()(const T& x, const T& y) const { @@ -124,8 +136,11 @@ struct bitwise_or : public std::binary_function<T, T, T> * an associated, built-in MPI data type, translates to @c MPI_LXOR. */ template<typename T> -struct logical_xor : public std::binary_function<T, T, T> +struct logical_xor { + typedef T first_argument_type; + typedef T second_argument_type; + typedef T result_type; /** @returns the logical exclusive OR of x and y. */ T operator()(const T& x, const T& y) const { @@ -142,8 +157,11 @@ struct logical_xor : public std::binary_function<T, T, T> * MPI_BXOR. */ template<typename T> -struct bitwise_xor : public std::binary_function<T, T, T> +struct bitwise_xor { + typedef T first_argument_type; + typedef T second_argument_type; + typedef T result_type; /** @returns @c x ^ y. */ T operator()(const T& x, const T& y) const { diff --git a/boost/mpi/python/serialize.hpp b/boost/mpi/python/serialize.hpp index 8933b3405f..feb703d836 100644 --- a/boost/mpi/python/serialize.hpp +++ b/boost/mpi/python/serialize.hpp @@ -26,7 +26,6 @@ #include <boost/python/str.hpp> #include <boost/python/extract.hpp> -#include <memory> #include <map> #include <boost/function/function3.hpp> @@ -37,6 +36,7 @@ #include <boost/serialization/split_free.hpp> #include <boost/serialization/array.hpp> #include <boost/serialization/array_wrapper.hpp> +#include <boost/smart_ptr/scoped_array.hpp> #include <boost/assert.hpp> @@ -442,7 +442,7 @@ load_impl(Archiver& ar, boost::python::object& obj, int len; ar >> len; - std::auto_ptr<char> string(new char[len]); + boost::scoped_array<char> string(new char[len]); ar >> boost::serialization::make_array(string.get(), len); boost::python::str py_string(string.get(), len); obj = boost::python::pickle::loads(py_string); |