summaryrefslogtreecommitdiff
path: root/boost/mpi
diff options
context:
space:
mode:
Diffstat (limited to 'boost/mpi')
-rw-r--r--boost/mpi/collectives.hpp138
-rw-r--r--boost/mpi/collectives/gatherv.hpp164
-rw-r--r--boost/mpi/collectives/reduce.hpp44
-rw-r--r--boost/mpi/collectives/scatterv.hpp166
-rw-r--r--boost/mpi/communicator.hpp64
-rw-r--r--boost/mpi/config.hpp25
-rw-r--r--boost/mpi/datatype.hpp12
-rw-r--r--boost/mpi/detail/forward_skeleton_iarchive.hpp17
-rw-r--r--boost/mpi/detail/forward_skeleton_oarchive.hpp17
-rw-r--r--boost/mpi/detail/ignore_skeleton_oarchive.hpp18
-rw-r--r--boost/mpi/detail/mpi_datatype_oarchive.hpp9
-rw-r--r--boost/mpi/nonblocking.hpp12
-rw-r--r--boost/mpi/packed_iarchive.hpp22
-rw-r--r--boost/mpi/packed_oarchive.hpp20
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;
}