update boost on linux
This commit is contained in:
383
linx64/include/boost/mpi/cartesian_communicator.hpp
Normal file
383
linx64/include/boost/mpi/cartesian_communicator.hpp
Normal 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
|
||||
@@ -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
|
||||
|
||||
140
linx64/include/boost/mpi/collectives/all_gatherv.hpp
Normal file
140
linx64/include/boost/mpi/collectives/all_gatherv.hpp
Normal 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
|
||||
@@ -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),
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
40
linx64/include/boost/mpi/detail/antiques.hpp
Normal file
40
linx64/include/boost/mpi/detail/antiques.hpp
Normal 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
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
47
linx64/include/boost/mpi/detail/offsets.hpp
Normal file
47
linx64/include/boost/mpi/detail/offsets.hpp
Normal 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
|
||||
@@ -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_;
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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;
|
||||
|
||||
26
linx64/include/boost/mpi/error_string.hpp
Normal file
26
linx64/include/boost/mpi/error_string.hpp
Normal 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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user