update boost on linux

This commit is contained in:
Bassem Girgis
2019-08-10 16:06:25 -05:00
parent 76ad52be58
commit 861b918727
5363 changed files with 483306 additions and 116507 deletions

View File

@@ -0,0 +1,383 @@
// 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.
#if !defined(BOOST_NO_CXX11_DEFAULTED_MOVES)
cartesian_topology(cartesian_topology&& other) : super(other) {}
cartesian_topology& operator=(cartesian_topology&& other) {
stl().swap(other.stl());
return *this;
}
#endif
~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

View File

@@ -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

View File

@@ -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

View File

@@ -48,10 +48,10 @@ namespace detail {
template<typename T, typename Op>
void
all_reduce_impl(const communicator& comm, const T* in_values, int n,
T* out_values, Op op, mpl::false_ /*is_mpi_op*/,
T* out_values, Op /* op */, mpl::false_ /*is_mpi_op*/,
mpl::true_ /*is_mpi_datatype*/)
{
user_op<Op, T> mpi_op(op);
user_op<Op, T> mpi_op;
BOOST_MPI_CHECK_RESULT(MPI_Allreduce,
(const_cast<T*>(in_values), out_values, n,
boost::mpi::get_mpi_datatype<T>(*in_values),

View File

@@ -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,

View File

@@ -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];
}

View File

@@ -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_ 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.
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];
}
// 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 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);
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>

View File

@@ -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

View File

@@ -81,7 +81,7 @@ namespace detail {
T* out_values, Op op, int root, mpl::false_ /*is_mpi_op*/,
mpl::true_/*is_mpi_datatype*/)
{
user_op<Op, T> mpi_op(op);
user_op<Op, T> mpi_op;
BOOST_MPI_CHECK_RESULT(MPI_Reduce,
(const_cast<T*>(in_values), out_values, n,
boost::mpi::get_mpi_datatype<T>(*in_values),
@@ -96,7 +96,7 @@ namespace detail {
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);
user_op<Op, T> mpi_op;
BOOST_MPI_CHECK_RESULT(MPI_Reduce,
(const_cast<T*>(in_values), 0, n,
boost::mpi::get_mpi_datatype<T>(*in_values),

View File

@@ -67,7 +67,7 @@ namespace detail {
scan_impl(const communicator& comm, const T* in_values, int n, T* out_values,
Op op, mpl::false_ /*is_mpi_op*/, mpl::true_ /*is_mpi_datatype*/)
{
user_op<Op, T> mpi_op(op);
user_op<Op, T> mpi_op;
BOOST_MPI_CHECK_RESULT(MPI_Scan,
(const_cast<T*>(in_values), out_values, n,
boost::mpi::get_mpi_datatype<T>(*in_values),

View File

@@ -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));
}
// 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 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));
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);
}
// 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);
}
// 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>

View File

@@ -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 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();
// 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));
}
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, 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();
// 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);
}
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

View File

@@ -21,6 +21,7 @@
#include <boost/shared_ptr.hpp>
#include <boost/mpi/datatype.hpp>
#include <boost/mpi/nonblocking.hpp>
#include <boost/static_assert.hpp>
#include <utility>
#include <iterator>
#include <stdexcept> // for std::range_error
@@ -115,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.
@@ -256,9 +265,17 @@ class BOOST_MPI_DECL communicator
* a single MPI_Send call. For variable-length data, e.g.,
* serialized types and packed archives, two messages will be sent
* via MPI_Send: one containing the length of the data and the
* second containing the data itself. Note that the transmission
* mode for variable-length data is an implementation detail that
* is subject to change.
* second containing the data itself.
*
* Std::vectors of MPI data type
* are considered variable size, e.g. their number of elements is
* unknown and must be transmited (although the serialization process
* is skipped). You can use the array specialized versions of
* communication methods is both sender and receiver know the vector
* size.
*
* Note that the transmission mode for variable-length data is an
* implementation detail that is subject to change.
*
* @param dest The rank of the remote process to which the data
* will be sent.
@@ -269,7 +286,7 @@ class BOOST_MPI_DECL communicator
*
* @param value The value that will be transmitted to the
* receiver. The type @c T of this value must meet the aforementioned
* criteria for transmission.
* criteria for transmission.
*/
template<typename T>
void send(int dest, int tag, const T& value) const;
@@ -277,14 +294,6 @@ class BOOST_MPI_DECL communicator
template<typename T, typename A>
void send(int dest, int tag, const std::vector<T,A>& value) const;
template<typename T, typename A>
void send_vector(int dest, int tag, const std::vector<T,A>& value,
mpl::true_) const;
template<typename T, typename A>
void send_vector(int dest, int tag, const std::vector<T,A>& value,
mpl::false_) const;
/**
* @brief Send the skeleton of an object.
*
@@ -400,14 +409,6 @@ class BOOST_MPI_DECL communicator
template<typename T, typename A>
status recv(int source, int tag, std::vector<T,A>& value) const;
template<typename T, typename A>
status recv_vector(int source, int tag, std::vector<T,A>& value,
mpl::true_) const;
template<typename T, typename A>
status recv_vector(int source, int tag, std::vector<T,A>& value,
mpl::false_) const;
/**
* @brief Receive a skeleton from a remote process.
*
@@ -536,7 +537,8 @@ class BOOST_MPI_DECL communicator
*
* @param value The value that will be transmitted to the
* receiver. The type @c T of this value must meet the aforementioned
* criteria for transmission.
* criteria for transmission. If modified before transmited, the
* modification may or may not be transmited.
*
* @returns a @c request object that describes this communication.
*/
@@ -601,6 +603,9 @@ class BOOST_MPI_DECL communicator
template<typename T>
request isend(int dest, int tag, const T* values, int n) const;
template<typename T, class A>
request isend(int dest, int tag, const std::vector<T,A>& values) const;
/**
* @brief Send a message to another process without any data
* without blocking.
@@ -685,6 +690,9 @@ class BOOST_MPI_DECL communicator
template<typename T>
request irecv(int source, int tag, T* values, int n) const;
template<typename T, typename A>
request irecv(int source, int tag, std::vector<T,A>& values) const;
/**
* @brief Initiate receipt of a message from a remote process that
* carries no data.
@@ -852,28 +860,26 @@ class BOOST_MPI_DECL communicator
/**
* 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
@@ -1094,6 +1100,39 @@ class BOOST_MPI_DECL communicator
request
array_irecv_impl(int source, int tag, T* values, int n, mpl::false_) const;
// We're sending/receivig a vector with associated MPI datatype.
// We need to send/recv the size and then the data and make sure
// blocking and non blocking method agrees on the format.
template<typename T, typename A>
request irecv_vector(int source, int tag, std::vector<T,A>& values,
mpl::true_) const;
template<typename T, class A>
request isend_vector(int dest, int tag, const std::vector<T,A>& values,
mpl::true_) const;
template<typename T, typename A>
void send_vector(int dest, int tag, const std::vector<T,A>& value,
mpl::true_) const;
template<typename T, typename A>
status recv_vector(int source, int tag, std::vector<T,A>& value,
mpl::true_) const;
// We're sending/receivig a vector with no associated MPI datatype.
// We need to send/recv it as an archive and make sure
// blocking and non blocking method agrees on the format.
template<typename T, typename A>
request irecv_vector(int source, int tag, std::vector<T,A>& values,
mpl::false_) const;
template<typename T, class A>
request isend_vector(int dest, int tag, const std::vector<T,A>& values,
mpl::false_) const;
template<typename T, typename A>
void send_vector(int dest, int tag, const std::vector<T,A>& value,
mpl::false_) const;
template<typename T, typename A>
status recv_vector(int source, int tag, std::vector<T,A>& value,
mpl::false_) const;
protected:
shared_ptr<MPI_Comm> comm_ptr;
};
@@ -1122,6 +1161,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
@@ -1424,6 +1572,35 @@ request communicator::isend(int dest, int tag, const T& value) const
return this->isend_impl(dest, tag, value, is_mpi_datatype<T>());
}
template<typename T, class A>
request communicator::isend(int dest, int tag, const std::vector<T,A>& values) const
{
return this->isend_vector(dest, tag, values, is_mpi_datatype<T>());
}
template<typename T, class A>
request
communicator::isend_vector(int dest, int tag, const std::vector<T,A>& values,
mpl::true_) const
{
std::size_t size = values.size();
request req = this->isend_impl(dest, tag, size, mpl::true_());
BOOST_MPI_CHECK_RESULT(MPI_Isend,
(const_cast<T*>(values.data()), size,
get_mpi_datatype<T>(),
dest, tag, MPI_Comm(*this), &req.m_requests[1]));
return req;
}
template<typename T, class A>
request
communicator::isend_vector(int dest, int tag, const std::vector<T,A>& values,
mpl::false_ no) const
{
return this->isend_impl(dest, tag, values, no);
}
template<typename T>
request
communicator::array_isend_impl(int dest, int tag, const T* values, int n,
@@ -1543,6 +1720,31 @@ namespace detail {
stat.m_count = count;
}
/**
* Internal data structure that stores everything required to manage
* the receipt of an array of primitive data but unknown size.
* Such an array can have been send with blocking operation and so must
* be compatible with the (size_t,raw_data[]) format.
*/
template<typename T, class A>
struct dynamic_array_irecv_data
{
BOOST_STATIC_ASSERT_MSG(is_mpi_datatype<T>::value, "Can only be specialized for MPI datatypes.");
dynamic_array_irecv_data(const communicator& comm, int source, int tag,
std::vector<T,A>& values)
: comm(comm), source(source), tag(tag), count(-1), values(values)
{
}
communicator comm;
int source;
int tag;
std::size_t count;
std::vector<T,A>& values;
};
}
template<typename T>
@@ -1663,6 +1865,62 @@ request::handle_serialized_array_irecv(request* self, request_action action)
}
}
template<typename T, class A>
optional<status>
request::handle_dynamic_primitive_array_irecv(request* self, request_action action)
{
typedef detail::dynamic_array_irecv_data<T,A> data_t;
shared_ptr<data_t> data = static_pointer_cast<data_t>(self->m_data);
if (action == ra_wait) {
status stat;
if (self->m_requests[1] == MPI_REQUEST_NULL) {
// Wait for the count message to complete
BOOST_MPI_CHECK_RESULT(MPI_Wait,
(self->m_requests, &stat.m_status));
// Resize our buffer and get ready to receive its data
data->values.resize(data->count);
BOOST_MPI_CHECK_RESULT(MPI_Irecv,
(&(data->values[0]), data->values.size(), get_mpi_datatype<T>(),
stat.source(), stat.tag(),
MPI_Comm(data->comm), self->m_requests + 1));
}
// Wait until we have received the entire message
BOOST_MPI_CHECK_RESULT(MPI_Wait,
(self->m_requests + 1, &stat.m_status));
return stat;
} else if (action == ra_test) {
status stat;
int flag = 0;
if (self->m_requests[1] == MPI_REQUEST_NULL) {
// Check if the count message has completed
BOOST_MPI_CHECK_RESULT(MPI_Test,
(self->m_requests, &flag, &stat.m_status));
if (flag) {
// Resize our buffer and get ready to receive its data
data->values.resize(data->count);
BOOST_MPI_CHECK_RESULT(MPI_Irecv,
(&(data->values[0]), data->values.size(),MPI_PACKED,
stat.source(), stat.tag(),
MPI_Comm(data->comm), self->m_requests + 1));
} else
return optional<status>(); // We have not finished yet
}
// Check if we have received the message data
BOOST_MPI_CHECK_RESULT(MPI_Test,
(self->m_requests + 1, &flag, &stat.m_status));
if (flag) {
return stat;
} else
return optional<status>();
} else {
return optional<status>();
}
}
// We're receiving a type that has an associated MPI datatype, so we
// map directly to that datatype.
template<typename T>
@@ -1734,6 +1992,39 @@ communicator::array_irecv_impl(int source, int tag, T* values, int n,
return req;
}
template<typename T, class A>
request
communicator::irecv_vector(int source, int tag, std::vector<T,A>& values,
mpl::true_) const
{
typedef detail::dynamic_array_irecv_data<T,A> data_t;
shared_ptr<data_t> data(new data_t(*this, source, tag, values));
request req;
req.m_data = data;
req.m_handler = request::handle_dynamic_primitive_array_irecv<T,A>;
BOOST_MPI_CHECK_RESULT(MPI_Irecv,
(&data->count, 1,
get_mpi_datatype<std::size_t>(data->count),
source, tag, MPI_Comm(*this), &req.m_requests[0]));
return req;
}
template<typename T, class A>
request
communicator::irecv_vector(int source, int tag, std::vector<T,A>& values,
mpl::false_ no) const
{
return irecv_impl(source, tag, values, no);
}
template<typename T, typename A>
request
communicator::irecv(int source, int tag, std::vector<T,A>& values) const
{
return irecv_vector(source, tag, values, is_mpi_datatype<T>());
}
// Array receive must receive the elements directly into a buffer.
template<typename T>
@@ -1742,115 +2033,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

View File

@@ -0,0 +1,40 @@
// 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_ANTIQUES_HPP
#define BOOST_MPI_ANTIQUES_HPP
#include <vector>
// 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]); }
// 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

View File

@@ -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);

View File

@@ -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>
@@ -28,6 +29,7 @@ namespace std{
#include <stdexcept>
#include <iostream>
#include <vector>
#include <boost/mpi/detail/antiques.hpp>
namespace boost { namespace mpi { namespace detail {
@@ -79,18 +81,18 @@ public:
BOOST_MPI_CHECK_RESULT(MPI_Type_create_struct,
(
addresses.size(),
get_data(lengths),
get_data(addresses),
get_data(types),
c_data(lengths),
c_data(addresses),
c_data(types),
&datatype_
));
#else
BOOST_MPI_CHECK_RESULT(MPI_Type_struct,
(
addresses.size(),
get_data(lengths),
get_data(addresses),
get_data(types),
c_data(lengths),
c_data(addresses),
c_data(types),
&datatype_
));
#endif

View File

@@ -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

View File

@@ -14,9 +14,10 @@
#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>
#include <boost/mpi/allocator.hpp>
namespace boost { namespace mpi {
@@ -103,12 +104,7 @@ private:
void load_impl(void * p, MPI_Datatype t, int l)
{
BOOST_MPI_CHECK_RESULT(MPI_Unpack,
(get_data(buffer_), buffer_.size(), &position, p, l, t, comm));
}
static buffer_type::value_type* get_data(buffer_type& b)
{
return b.empty() ? 0 : &(b[0]);
(const_cast<char*>(detail::c_data(buffer_)), buffer_.size(), &position, p, l, t, comm));
}
buffer_type & buffer_;

View File

@@ -12,9 +12,9 @@
#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>
#include <boost/serialization/array.hpp>
#include <boost/assert.hpp>
#include <vector>
@@ -46,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);
@@ -97,7 +102,10 @@ private:
// pack the data into the buffer
BOOST_MPI_CHECK_RESULT(MPI_Pack,
(const_cast<void*>(p), l, t, get_data(buffer_), buffer_.size(), &position, comm));
(const_cast<void*>(p),l,t,
detail::c_data(buffer_),
buffer_.size(),
&position,comm));
// reduce the buffer size if needed
BOOST_ASSERT(std::size_t(position) <= buffer_.size());
if (std::size_t(position) < buffer_.size())

View File

@@ -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;

View File

@@ -0,0 +1,26 @@
// Copyright (C) 2018 Alain Miniussi <alain.miniussi -at- oca.eu>.
// 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)
/** @file error_string.hpp
*
* Error code to string convertion.
*/
#ifndef BOOST_MPI_ERROR_STRING_HPP
#define BOOST_MPI_ERROR_STRING_HPP
#include <boost/mpi/config.hpp>
#include <string>
namespace boost { namespace mpi {
/**
* @brief Convert a MPI error code to an error string.
*/
std::string error_string(int err_code);
} } // end namespace boost::mpi
#endif // BOOST_MPI_ERROR_STRING_HPP

View File

@@ -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)); \
@@ -102,3 +104,4 @@ class BOOST_MPI_DECL exception : public std::exception
} } // end namespace boost::mpi
#endif // BOOST_MPI_EXCEPTION_HPP

View File

@@ -59,20 +59,26 @@ wait_any(ForwardIterator first, ForwardIterator last)
ForwardIterator current = first;
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_handler)) {
if (optional<status> result = current->test())
bool current_is_active =
( current->m_requests[0] != MPI_REQUEST_NULL ||
current->m_requests[1] != MPI_REQUEST_NULL) ;
if (current_is_active) {
optional<status> result = current->test();
if (bool(result)) {
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
// MPI_Request.
all_trivial_requests =
all_trivial_requests
&& !current->m_handler
&& current->m_requests[1] == MPI_REQUEST_NULL;
// We could probably ignore non trivial request that are inactive,
// but we can assume that a mix of trivial and non trivial requests
// is unlikely enough not to care.
bool current_trivial_request =
( !bool(current->m_handler) &&
current->m_requests[1] == MPI_REQUEST_NULL);
all_trivial_requests = all_trivial_requests && current_trivial_request;
// Move to the next request.
++n;

View File

@@ -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
{
@@ -274,14 +292,12 @@ namespace detail {
class user_op
{
public:
explicit user_op(Op& op)
user_op()
{
BOOST_MPI_CHECK_RESULT(MPI_Op_create,
(&user_op<Op, T>::perform,
is_commutative<Op, T>::value,
&mpi_op));
op_ptr = &op;
}
~user_op()
@@ -303,18 +319,16 @@ namespace detail {
private:
MPI_Op mpi_op;
static Op* op_ptr;
static void BOOST_MPI_CALLING_CONVENTION perform(void* vinvec, void* voutvec, int* plen, MPI_Datatype*)
{
T* invec = static_cast<T*>(vinvec);
T* outvec = static_cast<T*>(voutvec);
std::transform(invec, invec + *plen, outvec, outvec, *op_ptr);
Op op;
std::transform(invec, invec + *plen, outvec, outvec, op);
}
};
template<typename Op, typename T> Op* user_op<Op, T>::op_ptr = 0;
} // end namespace detail
} } // end namespace boost::mpi

View File

@@ -36,7 +36,6 @@
#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>

View File

@@ -83,6 +83,15 @@ class BOOST_MPI_DECL request
static optional<status>
handle_serialized_array_irecv(request* self, request_action action);
/**
* INTERNAL ONLY
*
* Handles the non-blocking receive of a dynamic array of primitive values.
*/
template<typename T, class A>
static optional<status>
handle_dynamic_primitive_array_irecv(request* self, request_action action);
public: // template friends are not portable
/// INTERNAL ONLY