diff options
Diffstat (limited to 'boost/mpi')
-rw-r--r-- | boost/mpi/collectives.hpp | 138 | ||||
-rw-r--r-- | boost/mpi/collectives/gatherv.hpp | 164 | ||||
-rw-r--r-- | boost/mpi/collectives/reduce.hpp | 44 | ||||
-rw-r--r-- | boost/mpi/collectives/scatterv.hpp | 166 | ||||
-rw-r--r-- | boost/mpi/communicator.hpp | 64 | ||||
-rw-r--r-- | boost/mpi/config.hpp | 25 | ||||
-rw-r--r-- | boost/mpi/datatype.hpp | 12 | ||||
-rw-r--r-- | boost/mpi/detail/forward_skeleton_iarchive.hpp | 17 | ||||
-rw-r--r-- | boost/mpi/detail/forward_skeleton_oarchive.hpp | 17 | ||||
-rw-r--r-- | boost/mpi/detail/ignore_skeleton_oarchive.hpp | 18 | ||||
-rw-r--r-- | boost/mpi/detail/mpi_datatype_oarchive.hpp | 9 | ||||
-rw-r--r-- | boost/mpi/nonblocking.hpp | 12 | ||||
-rw-r--r-- | boost/mpi/packed_iarchive.hpp | 22 | ||||
-rw-r--r-- | boost/mpi/packed_oarchive.hpp | 20 |
14 files changed, 630 insertions, 98 deletions
diff --git a/boost/mpi/collectives.hpp b/boost/mpi/collectives.hpp index e74fd72bb0..72c4294606 100644 --- a/boost/mpi/collectives.hpp +++ b/boost/mpi/collectives.hpp @@ -333,6 +333,75 @@ template<typename T> void gather(const communicator& comm, const T* in_values, int n, int root); /** + * @brief Similar to boost::mpi::gather with the difference that the number + * of values to be send by non-root processes can vary. + * + * @param comm The communicator over which the gather will occur. + * + * @param in_values The array of values to be transmitted by each process. + * + * @param in_size For each non-root process this specifies the size + * of @p in_values. + * + * @param out_values A pointer to storage that will be populated with + * the values from each process. For non-root processes, this parameter + * may be omitted. If it is still provided, however, it will be unchanged. + * + * @param sizes A vector containing the number of elements each non-root + * process will send. + * + * @param displs A vector such that the i-th entry specifies the + * displacement (relative to @p out_values) from which to take the ingoing + * data at the @p root process. Overloaded versions for which @p displs is + * omitted assume that the data is to be placed contiguously at the root process. + * + * @param root The process ID number that will collect the + * values. This value must be the same on all processes. + */ +template<typename T> +void +gatherv(const communicator& comm, const std::vector<T>& in_values, + T* out_values, const std::vector<int>& sizes, const std::vector<int>& displs, + int root); + +/** + * \overload + */ +template<typename T> +void +gatherv(const communicator& comm, const T* in_values, int in_size, + T* out_values, const std::vector<int>& sizes, const std::vector<int>& displs, + int root); + +/** + * \overload + */ +template<typename T> +void gatherv(const communicator& comm, const std::vector<T>& in_values, int root); + +/** + * \overload + */ +template<typename T> +void gatherv(const communicator& comm, const T* in_values, int in_size, int root); + +/** + * \overload + */ +template<typename T> +void +gatherv(const communicator& comm, const T* in_values, int in_size, + T* out_values, const std::vector<int>& sizes, int root); + +/** + * \overload + */ +template<typename T> +void +gatherv(const communicator& comm, const std::vector<T>& in_values, + T* out_values, const std::vector<int>& sizes, int root); + +/** * @brief Scatter the values stored at the root to all processes * within the communicator. * @@ -347,7 +416,7 @@ void gather(const communicator& comm, const T* in_values, int n, int root); * When the type @c T has an associated MPI data type, this routine * invokes @c MPI_Scatter to scatter the values. * - * @param comm The communicator over which the gather will occur. + * @param comm The communicator over which the scatter will occur. * * @param in_values A vector or pointer to storage that will contain * the values to send to each process, indexed by the process rank. @@ -402,6 +471,71 @@ template<typename T> void scatter(const communicator& comm, T* out_values, int n, int root); /** + * @brief Similar to boost::mpi::scatter with the difference that the number + * of values stored at the root process does not need to be a multiple of + * the communicator's size. + * + * @param comm The communicator over which the scatter will occur. + * + * @param in_values A vector or pointer to storage that will contain + * the values to send to each process, indexed by the process rank. + * For non-root processes, this parameter may be omitted. If it is + * still provided, however, it will be unchanged. + * + * @param sizes A vector containing the number of elements each non-root + * process will receive. + * + * @param displs A vector such that the i-th entry specifies the + * displacement (relative to @p in_values) from which to take the outgoing + * data to process i. Overloaded versions for which @p displs is omitted + * assume that the data is contiguous at the @p root process. + * + * @param out_values The array of values received by each process. + * + * @param out_size For each non-root process this will contain the size + * of @p out_values. + * + * @param root The process ID number that will scatter the + * values. This value must be the same on all processes. + */ +template<typename T> +void +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); + +/** + * \overload + */ +template<typename T> +void +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); + +/** + * \overload + */ +template<typename T> +void scatterv(const communicator& comm, T* out_values, int out_size, int root); + +/** + * \overload + */ +template<typename T> +void +scatterv(const communicator& comm, const T* in_values, + const std::vector<int>& sizes, T* out_values, int root); + +/** + * \overload + */ +template<typename T> +void +scatterv(const communicator& comm, const std::vector<T>& in_values, + const std::vector<int>& sizes, T* out_values, int root); + +/** * @brief Combine the values stored by each process into a single * value at the root. * @@ -554,7 +688,9 @@ scan(const communicator& comm, const T* in_values, int n, T* out_values, Op op); # include <boost/mpi/collectives/all_to_all.hpp> # include <boost/mpi/collectives/broadcast.hpp> # include <boost/mpi/collectives/gather.hpp> +# include <boost/mpi/collectives/gatherv.hpp> # include <boost/mpi/collectives/scatter.hpp> +# include <boost/mpi/collectives/scatterv.hpp> # include <boost/mpi/collectives/reduce.hpp> # include <boost/mpi/collectives/scan.hpp> #endif diff --git a/boost/mpi/collectives/gatherv.hpp b/boost/mpi/collectives/gatherv.hpp new file mode 100644 index 0000000000..eb5f9c16dc --- /dev/null +++ b/boost/mpi/collectives/gatherv.hpp @@ -0,0 +1,164 @@ +// Copyright (C) 2011 Júlio Hoffimann. + +// 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_GATHERV_HPP +#define BOOST_MPI_GATHERV_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> + +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_Gatherv to do all of the work. + template<typename T> + void + gatherv_impl(const communicator& comm, const T* in_values, int in_size, + T* out_values, const int* sizes, const int* displs, int root, mpl::true_) + { + MPI_Datatype type = get_mpi_datatype<T>(*in_values); + BOOST_MPI_CHECK_RESULT(MPI_Gatherv, + (const_cast<T*>(in_values), in_size, type, + out_values, const_cast<int*>(sizes), const_cast<int*>(displs), + type, root, comm)); + } + + // We're gathering from a non-root for a type that has an associated MPI + // datatype, so we'll use MPI_Gatherv to do all of the work. + template<typename T> + void + gatherv_impl(const communicator& comm, const T* in_values, int in_size, int root, + mpl::true_) + { + MPI_Datatype type = get_mpi_datatype<T>(*in_values); + BOOST_MPI_CHECK_RESULT(MPI_Gatherv, + (const_cast<T*>(in_values), in_size, type, + 0, 0, 0, type, root, comm)); + } + + // 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_Gatherv, so + // we'll just have all of the non-root nodes send individual + // messages to the root. + template<typename T> + void + 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 ]; + } + } + } + + // 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. + 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); + } +} // end namespace detail + +template<typename T> +void +gatherv(const communicator& comm, const T* in_values, int in_size, + T* out_values, const std::vector<int>& sizes, const std::vector<int>& displs, + int root) +{ + if (comm.rank() == root) + detail::gatherv_impl(comm, in_values, in_size, + out_values, &sizes[0], &displs[0], + root, is_mpi_datatype<T>()); + else + detail::gatherv_impl(comm, in_values, in_size, root, is_mpi_datatype<T>()); +} + +template<typename T> +void +gatherv(const communicator& comm, const std::vector<T>& in_values, + T* out_values, const std::vector<int>& sizes, const std::vector<int>& displs, + int root) +{ + ::boost::mpi::gatherv(comm, &in_values[0], in_values.size(), out_values, sizes, displs, root); +} + +template<typename T> +void gatherv(const communicator& comm, const T* in_values, int in_size, int root) +{ + BOOST_ASSERT(comm.rank() != root); + detail::gatherv_impl(comm, in_values, in_size, root, is_mpi_datatype<T>()); +} + +template<typename T> +void gatherv(const communicator& comm, const std::vector<T>& in_values, int root) +{ + BOOST_ASSERT(comm.rank() != root); + detail::gatherv_impl(comm, &in_values[0], in_values.size(), root, is_mpi_datatype<T>()); +} + +/////////////////////// +// common use versions +/////////////////////// +template<typename T> +void +gatherv(const communicator& comm, const T* in_values, int in_size, + T* out_values, const std::vector<int>& sizes, int root) +{ + int nprocs = comm.size(); + + std::vector<int> displs( nprocs ); + for (int rank = 0, aux = 0; rank < nprocs; ++rank) { + displs[rank] = aux; + aux += sizes[rank]; + } + ::boost::mpi::gatherv(comm, in_values, in_size, out_values, sizes, displs, root); +} + +template<typename T> +void +gatherv(const communicator& comm, const std::vector<T>& in_values, + T* out_values, const std::vector<int>& sizes, int root) +{ + ::boost::mpi::gatherv(comm, &in_values[0], in_values.size(), out_values, sizes, root); +} + +} } // end namespace boost::mpi + +#endif // BOOST_MPI_GATHERV_HPP diff --git a/boost/mpi/collectives/reduce.hpp b/boost/mpi/collectives/reduce.hpp index 8fc2fe6eb6..4a94d71c12 100644 --- a/boost/mpi/collectives/reduce.hpp +++ b/boost/mpi/collectives/reduce.hpp @@ -45,7 +45,7 @@ namespace detail { // datatype and operation, so we'll use MPI_Reduce directly. template<typename T, typename Op> void - reduce_impl(const communicator& comm, const T* in_values, int n, + reduce_impl(const communicator& comm, const T* in_values, int n, T* out_values, Op op, int root, mpl::true_ /*is_mpi_op*/, mpl::true_/*is_mpi_datatype*/) { @@ -59,7 +59,7 @@ namespace detail { // datatype and operation, so we'll use MPI_Reduce directly. template<typename T, typename Op> void - reduce_impl(const communicator& comm, const T* in_values, int n, Op op, + reduce_impl(const communicator& comm, const T* in_values, int n, Op op, int root, mpl::true_ /*is_mpi_op*/, mpl::true_/*is_mpi_datatype*/) { BOOST_MPI_CHECK_RESULT(MPI_Reduce, @@ -77,7 +77,7 @@ namespace detail { // directly, but we'll need to create an MPI_Op manually. template<typename T, typename Op> void - reduce_impl(const communicator& comm, const T* in_values, int n, + reduce_impl(const communicator& comm, const T* in_values, int n, T* out_values, Op op, int root, mpl::false_ /*is_mpi_op*/, mpl::true_/*is_mpi_datatype*/) { @@ -93,7 +93,7 @@ namespace detail { // directly, but we'll need to create an MPI_Op manually. template<typename T, typename Op> void - reduce_impl(const communicator& comm, const T* in_values, int n, Op op, + reduce_impl(const communicator& comm, const T* in_values, int n, Op op, int root, mpl::false_/*is_mpi_op*/, mpl::true_/*is_mpi_datatype*/) { user_op<Op, T> mpi_op(op); @@ -111,7 +111,7 @@ namespace detail { template<typename T, typename Op> void tree_reduce_impl(const communicator& comm, const T* in_values, int n, - T* out_values, Op op, int root, + T* out_values, Op op, int root, mpl::true_ /*is_commutative*/) { std::copy(in_values, in_values + n, out_values); @@ -156,7 +156,7 @@ namespace detail { int root, mpl::true_ /*is_commutative*/) { scoped_array<T> results(new T[n]); - detail::tree_reduce_impl(comm, in_values, n, results.get(), op, root, + detail::tree_reduce_impl(comm, in_values, n, results.get(), op, root, mpl::true_()); } @@ -164,7 +164,7 @@ namespace detail { template<typename T, typename Op> void tree_reduce_impl(const communicator& comm, const T* in_values, int n, - T* out_values, Op op, int root, + T* out_values, Op op, int root, mpl::false_ /*is_commutative*/) { int tag = environment::collectives_tag(); @@ -285,7 +285,7 @@ namespace detail { // algorithm. template<typename T, typename Op> void - reduce_impl(const communicator& comm, const T* in_values, int n, + reduce_impl(const communicator& comm, const T* in_values, int n, T* out_values, Op op, int root, mpl::false_ /*is_mpi_op*/, mpl::false_ /*is_mpi_datatype*/) { @@ -298,8 +298,8 @@ namespace detail { // algorithm. template<typename T, typename Op> void - reduce_impl(const communicator& comm, const T* in_values, int n, Op op, - int root, mpl::false_ /*is_mpi_op*/, + reduce_impl(const communicator& comm, const T* in_values, int n, Op op, + int root, mpl::false_ /*is_mpi_op*/, mpl::false_ /*is_mpi_datatype*/) { detail::tree_reduce_impl(comm, in_values, n, op, root, @@ -309,7 +309,7 @@ namespace detail { template<typename T, typename Op> void -reduce(const communicator& comm, const T* in_values, int n, T* out_values, +reduce(const communicator& comm, const T* in_values, int n, T* out_values, Op op, int root) { if (comm.rank() == root) @@ -321,7 +321,7 @@ reduce(const communicator& comm, const T* in_values, int n, T* out_values, } template<typename T, typename Op> -void +void reduce(const communicator& comm, const T* in_values, int n, Op op, int root) { BOOST_ASSERT(comm.rank() != root); @@ -330,21 +330,21 @@ reduce(const communicator& comm, const T* in_values, int n, Op op, int root) is_mpi_op<Op, T>(), is_mpi_datatype<T>()); } -template<typename T, typename Op> -void -reduce(const communicator & comm, std::vector<T> const & in_values, Op op, - int root) +template<typename T, typename Op> +void +reduce(const communicator & comm, std::vector<T> const & in_values, Op op, + int root) { reduce(comm, &in_values.front(), in_values.size(), op, root); } -template<typename T, typename Op> -void -reduce(const communicator & comm, std::vector<T> const & in_values, - std::vector<T> & out_values, Op op, int root) +template<typename T, typename Op> +void +reduce(const communicator & comm, std::vector<T> const & in_values, + std::vector<T> & out_values, Op op, int root) { - out_values.resize(in_values.size()); - reduce(comm, &in_values.front(), in_values.size(), &out_values.front(), op, + if (root == comm.rank()) out_values.resize(in_values.size()); + reduce(comm, &in_values.front(), in_values.size(), &out_values.front(), op, root); } diff --git a/boost/mpi/collectives/scatterv.hpp b/boost/mpi/collectives/scatterv.hpp new file mode 100644 index 0000000000..6e6f27002b --- /dev/null +++ b/boost/mpi/collectives/scatterv.hpp @@ -0,0 +1,166 @@ +// Copyright (C) 2011 Júlio Hoffimann. + +// 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.6. Scatterv +#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> + +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)); + } + + // 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 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> +void +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>()); +} + +template<typename T> +void +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); +} + +template<typename T> +void scatterv(const communicator& comm, T* out_values, int out_size, int root) +{ + BOOST_ASSERT(comm.rank() != root); + detail::scatterv_impl(comm, out_values, out_size, root, is_mpi_datatype<T>()); +} + +/////////////////////// +// common use versions +/////////////////////// +template<typename T> +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); +} + +template<typename T> +void +scatterv(const communicator& comm, const std::vector<T>& in_values, + const std::vector<int>& sizes, T* out_values, int root) +{ + ::boost::mpi::scatterv(comm, &in_values[0], sizes, out_values, root); +} + +} } // end namespace boost::mpi + +#endif // BOOST_MPI_SCATTERV_HPP diff --git a/boost/mpi/communicator.hpp b/boost/mpi/communicator.hpp index 65de3a47f2..fcef0866a9 100644 --- a/boost/mpi/communicator.hpp +++ b/boost/mpi/communicator.hpp @@ -19,6 +19,7 @@ #include <boost/optional.hpp> #include <boost/shared_ptr.hpp> #include <boost/mpi/datatype.hpp> +#include <boost/mpi/nonblocking.hpp> #include <utility> #include <iterator> #include <stdexcept> // for std::range_error @@ -486,6 +487,12 @@ class BOOST_MPI_DECL communicator */ status recv(int source, int tag) const; + /** @brief Send a message to remote process nd receive another message + * from another process. + */ + template<typename T> + status sendrecv(int dest, int stag, const T& sval, int src, int rtag, T& rval) const; + /** * @brief Send a message to a remote process without blocking. * @@ -859,6 +866,25 @@ class BOOST_MPI_DECL communicator void abort(int errcode) const; protected: + + /** + * INTERNAL ONLY + * + * Implementation of sendrecv for mpi type. + */ + template<typename T> + status sendrecv_impl(int dest, int stag, const T& sval, int src, int rtag, T& rval, + mpl::true_) const; + + /** + * INTERNAL ONLY + * + * Implementation of sendrecv for complex types, which must be passed as archives. + */ + template<typename T> + status sendrecv_impl(int dest, int stag, const T& sval, int src, int rtag, T& rval, + mpl::false_) const; + /** * INTERNAL ONLY * @@ -1250,6 +1276,44 @@ status communicator::recv(int source, int tag, T* values, int n) const return this->array_recv_impl(source, tag, values, n, is_mpi_datatype<T>()); } + +template<typename T> +status communicator::sendrecv_impl(int dest, int stag, const T& sval, int src, int rtag, T& rval, + mpl::true_) const +{ + status stat; + BOOST_MPI_CHECK_RESULT(MPI_Sendrecv, + (const_cast<T*>(&sval), 1, + get_mpi_datatype<T>(sval), + dest, stag, + &rval, 1, + get_mpi_datatype<T>(rval), + src, rtag, + MPI_Comm(*this), &stat.m_status)); + return stat; +} + +template<typename T> +status communicator::sendrecv_impl(int dest, int stag, const T& sval, int src, int rtag, T& rval, + mpl::false_) const +{ + int const SEND = 0; + int const RECV = 1; + request srrequests[2]; + srrequests[SEND] = this->isend_impl(dest, stag, sval, mpl::false_()); + srrequests[RECV] = this->irecv_impl(src, rtag, rval, mpl::false_()); + status srstatuses[2]; + wait_all(srrequests, srrequests + 2, srstatuses); + return srstatuses[RECV]; +} + +template<typename T> +status communicator::sendrecv(int dest, int stag, const T& sval, int src, int rtag, T& rval) const +{ + return this->sendrecv_impl(dest, stag, sval, src, rtag, rval, is_mpi_datatype<T>()); +} + + // We're sending a type that has an associated MPI datatype, so we // map directly to that datatype. template<typename T> diff --git a/boost/mpi/config.hpp b/boost/mpi/config.hpp index acbdc78daa..ff91b17c35 100644 --- a/boost/mpi/config.hpp +++ b/boost/mpi/config.hpp @@ -20,10 +20,17 @@ #include <mpi.h> #include <boost/config.hpp> -/** @brief Define this macro to avoid expensice MPI_Pack/Unpack calls on - * homogeneous machines. -*/ -//#define BOOST_MPI_HOMOGENEOUS +/** @brief Comment this macro is you are running in an heterogeneous environement. + * + * When this flags is enabled, we assume some simple, POD like, type can be + * transmited without paying the cost of portable serialization. + * + * Comment this if your platform is not homogeneous and that portable + * serialization/deserialization must be performed. + * + * It you do so, check that you MPI implementation supports thats kind of environement. + */ +#define BOOST_MPI_HOMOGENEOUS // If this is an MPI-2 implementation, define configuration macros for // the features we are interested in. @@ -71,10 +78,20 @@ # define BOOST_MPI_CALLING_CONVENTION #endif +/** @brief Indicates that MPI_Bcast supports MPI_BOTTOM. + * + * Some implementations have a broken MPI_Bcast wrt to MPI_BOTTOM. + * BullX MPI and LAM seems to be among them, at least for some versions. + * The `broacast_test.cpp` test `test_skeleton_and_content` can be used to + * detect that. + */ +#define BOOST_MPI_BCAST_BOTTOM_WORKS_FINE + #if defined(LAM_MPI) // Configuration for LAM/MPI # define BOOST_MPI_HAS_MEMORY_ALLOCATION # define BOOST_MPI_HAS_NOARG_INITIALIZATION +# undef BOOST_MPI_BCAST_BOTTOM_WORKS_FINE #elif defined(MPICH_NAME) // Configuration for MPICH #endif diff --git a/boost/mpi/datatype.hpp b/boost/mpi/datatype.hpp index 7fa7e1c3d0..c26dfdfc3b 100644 --- a/boost/mpi/datatype.hpp +++ b/boost/mpi/datatype.hpp @@ -36,7 +36,7 @@ namespace boost { namespace mpi { * @brief Type trait that determines if there exists a built-in * integer MPI data type for a given C++ type. * - * This ytpe trait determines when there is a direct mapping from a + * This type trait determines when there is a direct mapping from a * C++ type to an MPI data type that is classified as an integer data * type. See @c is_mpi_builtin_datatype for general information about * built-in MPI data types. @@ -49,7 +49,7 @@ struct is_mpi_integer_datatype * @brief Type trait that determines if there exists a built-in * floating point MPI data type for a given C++ type. * - * This ytpe trait determines when there is a direct mapping from a + * This type trait determines when there is a direct mapping from a * C++ type to an MPI data type that is classified as a floating * point data type. See @c is_mpi_builtin_datatype for general * information about built-in MPI data types. @@ -62,7 +62,7 @@ struct is_mpi_floating_point_datatype * @brief Type trait that determines if there exists a built-in * logical MPI data type for a given C++ type. * - * This ytpe trait determines when there is a direct mapping from a + * This type trait determines when there is a direct mapping from a * C++ type to an MPI data type that is classified as an logical data * type. See @c is_mpi_builtin_datatype for general information about * built-in MPI data types. @@ -75,7 +75,7 @@ struct is_mpi_logical_datatype * @brief Type trait that determines if there exists a built-in * complex MPI data type for a given C++ type. * - * This ytpe trait determines when there is a direct mapping from a + * This type trait determines when there is a direct mapping from a * C++ type to an MPI data type that is classified as an complex data * type. See @c is_mpi_builtin_datatype for general information about * built-in MPI data types. @@ -88,7 +88,7 @@ struct is_mpi_complex_datatype * @brief Type trait that determines if there exists a built-in * byte MPI data type for a given C++ type. * - * This ytpe trait determines when there is a direct mapping from a + * This type trait determines when there is a direct mapping from a * C++ type to an MPI data type that is classified as an byte data * type. See @c is_mpi_builtin_datatype for general information about * built-in MPI data types. @@ -198,7 +198,7 @@ get_mpi_datatype< CppType >(const CppType&) { return MPIType; } \ \ template<> \ struct BOOST_JOIN(is_mpi_,BOOST_JOIN(Kind,_datatype))< CppType > \ -: boost::mpl::bool_<true> \ +: boost::mpl::true_ \ {} /// INTERNAL ONLY diff --git a/boost/mpi/detail/forward_skeleton_iarchive.hpp b/boost/mpi/detail/forward_skeleton_iarchive.hpp index 6e1181981d..c4b9e0f2a8 100644 --- a/boost/mpi/detail/forward_skeleton_iarchive.hpp +++ b/boost/mpi/detail/forward_skeleton_iarchive.hpp @@ -9,8 +9,6 @@ #ifndef BOOST_MPI_DETAIL_FORWARD_SKELETON_IARCHIVE_HPP #define BOOST_MPI_DETAIL_FORWARD_SKELETON_IARCHIVE_HPP -#include <boost/serialization/pfto.hpp> - #include <boost/archive/detail/auto_link_archive.hpp> #include <boost/archive/detail/iserializer.hpp> #include <boost/archive/detail/interface_iarchive.hpp> @@ -41,17 +39,14 @@ public: protected: #endif - // intermediate level to support override of operators - // for templates in the absence of partial function - // template ordering - template<class T> - void load_override(T & t, BOOST_PFTO int) - { - archive::load(* this->This(), t); - } + template<class T> + void load_override(T & t) + { + archive::load(* this->This(), t); + } #define BOOST_ARCHIVE_FORWARD_IMPLEMENTATION(T) \ - void load_override(T & t , int) \ + void load_override(T & t) \ { \ implementation_archive >> t; \ } diff --git a/boost/mpi/detail/forward_skeleton_oarchive.hpp b/boost/mpi/detail/forward_skeleton_oarchive.hpp index 6aab0538ab..4b0e057266 100644 --- a/boost/mpi/detail/forward_skeleton_oarchive.hpp +++ b/boost/mpi/detail/forward_skeleton_oarchive.hpp @@ -9,8 +9,6 @@ #ifndef BOOST_MPI_DETAIL_FORWARD_SKELETON_OARCHIVE_HPP #define BOOST_MPI_DETAIL_FORWARD_SKELETON_OARCHIVE_HPP -#include <boost/serialization/pfto.hpp> - #include <boost/archive/detail/auto_link_archive.hpp> #include <boost/archive/detail/oserializer.hpp> #include <boost/archive/detail/interface_oarchive.hpp> @@ -41,17 +39,14 @@ public: protected: #endif - // intermediate level to support override of operators - // for templates in the absence of partial function - // template ordering - template<class T> - void save_override(T const& t, BOOST_PFTO int) - { - archive::save(* this->This(), t); - } + template<class T> + void save_override(T const& t) + { + archive::save(* this->This(), t); + } #define BOOST_ARCHIVE_FORWARD_IMPLEMENTATION(T) \ - void save_override(T const & t , int) \ + void save_override(T const & t) \ { \ implementation_archive << t; \ } diff --git a/boost/mpi/detail/ignore_skeleton_oarchive.hpp b/boost/mpi/detail/ignore_skeleton_oarchive.hpp index 06a6bd59ca..29248f993d 100644 --- a/boost/mpi/detail/ignore_skeleton_oarchive.hpp +++ b/boost/mpi/detail/ignore_skeleton_oarchive.hpp @@ -9,8 +9,6 @@ #ifndef BOOST_MPI_DETAIL_IGNORE_SKELETON_OARCHIVE_HPP #define BOOST_MPI_DETAIL_IGNORE_SKELETON_OARCHIVE_HPP -#include <boost/serialization/pfto.hpp> - #include <boost/archive/detail/auto_link_archive.hpp> #include <boost/archive/detail/common_oarchive.hpp> #include <boost/archive/basic_archive.hpp> @@ -38,18 +36,14 @@ public: friend class archive::save_access; protected: #endif - - // intermediate level to support override of operators - // for templates in the absence of partial function - // template ordering - template<class T> - void save_override(T const& t, BOOST_PFTO int) - { - archive::save(* this->This(), t); - } + template<class T> + void save_override(T const& t) + { + archive::save(* this->This(), t); + } #define BOOST_ARCHIVE_IGNORE_IMPLEMENTATION(T) \ - void save_override(T const & , int) \ + void save_override(T const &) \ {} BOOST_ARCHIVE_IGNORE_IMPLEMENTATION(archive::class_id_optional_type) diff --git a/boost/mpi/detail/mpi_datatype_oarchive.hpp b/boost/mpi/detail/mpi_datatype_oarchive.hpp index 7079f21a21..68f9abb6b5 100644 --- a/boost/mpi/detail/mpi_datatype_oarchive.hpp +++ b/boost/mpi/detail/mpi_datatype_oarchive.hpp @@ -41,12 +41,9 @@ public: BOOST_MPL_ASSERT((is_mpi_datatype<T>)); *this << x; // serialize the object } - - // intermediate level to support override of operators - // for templates in the absence of partial function - // template ordering + template<class T> - void save_override(T const& t, BOOST_PFTO int) + void save_override(T const& t) { save_enum(t,boost::is_enum<T>()); } @@ -54,7 +51,7 @@ public: template<class T> void save_enum(T const& t, mpl::false_) { - ignore_skeleton_oarchive<mpi_datatype_oarchive>::save_override(t, 0); + ignore_skeleton_oarchive<mpi_datatype_oarchive>::save_override(t); } template<class T> diff --git a/boost/mpi/nonblocking.hpp b/boost/mpi/nonblocking.hpp index a2d2e34313..1fc1ecd038 100644 --- a/boost/mpi/nonblocking.hpp +++ b/boost/mpi/nonblocking.hpp @@ -60,9 +60,11 @@ wait_any(ForwardIterator first, ForwardIterator last) while (true) { // Check if we have found a completed request. If so, return it. if (current->m_requests[0] != MPI_REQUEST_NULL && - current->m_requests[1] != MPI_REQUEST_NULL) + (current->m_requests[1] != MPI_REQUEST_NULL || + current->m_handler)) { if (optional<status> result = current->test()) return std::make_pair(*result, current); + } // Check if this request (and all others before it) are "trivial" // requests, e.g., they can be represented with a single @@ -138,10 +140,12 @@ template<typename ForwardIterator> optional<std::pair<status, ForwardIterator> > test_any(ForwardIterator first, ForwardIterator last) { - for (ForwardIterator current = first; first != last; ++first) { + while (first != last) { // Check if we have found a completed request. If so, return it. - if (optional<status> result = current->test()) - return std::make_pair(*result, current); + if (optional<status> result = first->test()) { + return std::make_pair(*result, first); + } + ++first; } // We found nothing diff --git a/boost/mpi/packed_iarchive.hpp b/boost/mpi/packed_iarchive.hpp index 23d6468c55..bb8094b41c 100644 --- a/boost/mpi/packed_iarchive.hpp +++ b/boost/mpi/packed_iarchive.hpp @@ -94,48 +94,48 @@ public: // Load everything else in the usual way, forwarding on to the Base class template<class T> - void load_override(T& x, int version, mpl::false_) + void load_override(T& x, mpl::false_) { - archive::detail::common_iarchive<packed_iarchive>::load_override(x,version); + archive::detail::common_iarchive<packed_iarchive>::load_override(x); } // Load it directly using the primnivites template<class T> - void load_override(T& x, int /*version*/, mpl::true_) + void load_override(T& x, mpl::true_) { iprimitive::load(x); } // Load all supported datatypes directly template<class T> - void load_override(T& x, int version) + void load_override(T& x) { typedef typename mpl::apply1<use_array_optimization , BOOST_DEDUCED_TYPENAME remove_const<T>::type >::type use_optimized; - load_override(x, version, use_optimized()); + load_override(x, use_optimized()); } // input archives need to ignore the optional information - void load_override(archive::class_id_optional_type & /*t*/, int){} + void load_override(archive::class_id_optional_type & /*t*/){} - void load_override(archive::class_id_type & t, int version){ + void load_override(archive::class_id_type & t){ int_least16_t x=0; * this->This() >> x; t = boost::archive::class_id_type(x); } - void load_override(archive::version_type & t, int version){ + void load_override(archive::version_type & t){ int_least8_t x=0; * this->This() >> x; t = boost::archive::version_type(x); } - void load_override(archive::class_id_reference_type & t, int version){ - load_override(static_cast<archive::class_id_type &>(t), version); + void load_override(archive::class_id_reference_type & t){ + load_override(static_cast<archive::class_id_type &>(t)); } - void load_override(archive::class_name_type & t, int) + void load_override(archive::class_name_type & t) { std::string cn; cn.reserve(BOOST_SERIALIZATION_MAX_KEY_SIZE); diff --git a/boost/mpi/packed_oarchive.hpp b/boost/mpi/packed_oarchive.hpp index 887aeac6e3..c6c0173ae6 100644 --- a/boost/mpi/packed_oarchive.hpp +++ b/boost/mpi/packed_oarchive.hpp @@ -92,41 +92,41 @@ public: // Save everything else in the usual way, forwarding on to the Base class template<class T> - void save_override(T const& x, int version, mpl::false_) + void save_override(T const& x, mpl::false_) { - archive::detail::common_oarchive<packed_oarchive>::save_override(x,version); + archive::detail::common_oarchive<packed_oarchive>::save_override(x); } // Save it directly using the primitives template<class T> - void save_override(T const& x, int /*version*/, mpl::true_) + void save_override(T const& x, mpl::true_) { oprimitive::save(x); } // Save all supported datatypes directly template<class T> - void save_override(T const& x, int version) + void save_override(T const& x) { typedef typename mpl::apply1<use_array_optimization,T>::type use_optimized; - save_override(x, version, use_optimized()); + save_override(x, use_optimized()); } - // input archives need to ignore the optional information - void save_override(const archive::class_id_optional_type & /*t*/, int){} + // output archives need to ignore the optional information + void save_override(const archive::class_id_optional_type & ){} // explicitly convert to char * to avoid compile ambiguities - void save_override(const archive::class_name_type & t, int){ + void save_override(const archive::class_name_type & t){ const std::string s(t); * this->This() << s; } - void save_override(archive::class_id_type & t, int version){ + void save_override(const archive::class_id_type & t){ const boost::int_least16_t x = t; * this->This() << x; } - void save_override(archive::version_type & t, int version){ + void save_override(const archive::version_type & t){ const boost::int_least8_t x = t; * this->This() << x; } |