update boost

This commit is contained in:
2023-11-24 12:56:13 -06:00
parent cfc99971af
commit 19d727037a
9260 changed files with 849256 additions and 299957 deletions

View File

@@ -74,6 +74,54 @@ template<typename T>
void
all_gather(const communicator& comm, const T* in_values, int n, T* out_values);
/**
* \overload
*/
template<typename T>
void
all_gatherv(const communicator& comm, const T& in_value, T* out_values,
const std::vector<int>& sizes);
/**
* \overload
*/
template<typename T>
void
all_gatherv(const communicator& comm, const T* in_values, T* out_values,
const std::vector<int>& sizes);
/**
* \overload
*/
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);
/**
* \overload
*/
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);
/**
* \overload
*/
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);
/**
* \overload
*/
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);
/**
* @brief Combine the values stored by each process into a single
* value available to all processes.
@@ -684,6 +732,7 @@ scan(const communicator& comm, const T* in_values, int n, T* out_values, Op op);
#ifndef BOOST_MPI_COLLECTIVES_FORWARD_ONLY
// Include implementations of each of the collectives
# include <boost/mpi/collectives/all_gather.hpp>
# include <boost/mpi/collectives/all_gatherv.hpp>
# include <boost/mpi/collectives/all_reduce.hpp>
# include <boost/mpi/collectives/all_to_all.hpp>
# include <boost/mpi/collectives/broadcast.hpp>

View File

@@ -57,8 +57,8 @@ all_gather_impl(const communicator& comm, const T* in_values, int n,
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,
(&oasize, 1, MPI_INT,
c_data(oasizes), 1, MPI_INT,
MPI_Comm(comm)));
// Gather the archives, which can be of different sizes, so
// we need to use allgatherv.

View File

@@ -77,7 +77,7 @@ namespace detail {
// implementation in this case.
// it's not clear how/if we can avoid the copy.
std::vector<T> tmp_in( out_values, out_values + n);
reduce(comm, &(tmp_in[0]), n, out_values, op, 0);
reduce(comm, detail::c_data(tmp_in), n, out_values, op, 0);
} else {
reduce(comm, in_values, n, out_values, op, 0);
}

View File

@@ -91,10 +91,10 @@ namespace detail {
// Transmit the actual data
BOOST_MPI_CHECK_RESULT(MPI_Alltoallv,
(&outgoing[0], &send_sizes[0],
&send_disps[0], MPI_PACKED,
&incoming[0], &recv_sizes[0],
&recv_disps[0], MPI_PACKED,
(detail::c_data(outgoing), detail::c_data(send_sizes),
detail::c_data(send_disps), MPI_PACKED,
detail::c_data(incoming), detail::c_data(recv_sizes),
detail::c_data(recv_disps), MPI_PACKED,
comm));
// Deserialize data from the iarchive
@@ -126,7 +126,7 @@ all_to_all(const communicator& comm, const std::vector<T>& in_values,
{
BOOST_ASSERT((int)in_values.size() == comm.size());
out_values.resize(comm.size());
::boost::mpi::all_to_all(comm, &in_values[0], &out_values[0]);
::boost::mpi::all_to_all(comm, detail::c_data(in_values), detail::c_data(out_values));
}
template<typename T>
@@ -143,7 +143,7 @@ all_to_all(const communicator& comm, const std::vector<T>& in_values, int n,
{
BOOST_ASSERT((int)in_values.size() == comm.size() * n);
out_values.resize(comm.size() * n);
::boost::mpi::all_to_all(comm, &in_values[0], n, &out_values[0]);
::boost::mpi::all_to_all(comm, detail::c_data(in_values), n, detail::c_data(out_values));
}
} } // end namespace boost::mpi

View File

@@ -69,8 +69,8 @@ gather_impl(const communicator& comm, const T* in_values, int n, T* out_values,
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,
(&oasize, 1, MPI_INT,
c_data(oasizes), 1, MPI_INT,
root, MPI_Comm(comm)));
// Gather the archives, which can be of different sizes, so
// we need to use gatherv.

View File

@@ -87,7 +87,7 @@ gatherv(const communicator& comm, const T* in_values, int in_size,
{
if (comm.rank() == root)
detail::gatherv_impl(comm, in_values, in_size,
out_values, &sizes[0], &displs[0],
out_values, detail::c_data(sizes), detail::c_data(displs),
root, is_mpi_datatype<T>());
else
detail::gatherv_impl(comm, in_values, in_size, root, is_mpi_datatype<T>());
@@ -99,7 +99,7 @@ gatherv(const communicator& comm, const std::vector<T>& in_values,
T* out_values, const std::vector<int>& sizes, const std::vector<int>& displs,
int root)
{
::boost::mpi::gatherv(comm, &in_values[0], in_values.size(), out_values, sizes, displs, root);
::boost::mpi::gatherv(comm, detail::c_data(in_values), in_values.size(), out_values, sizes, displs, root);
}
template<typename T>
@@ -113,7 +113,7 @@ template<typename T>
void gatherv(const communicator& comm, const std::vector<T>& in_values, int root)
{
BOOST_ASSERT(comm.rank() != root);
detail::gatherv_impl(comm, &in_values[0], in_values.size(), root, is_mpi_datatype<T>());
detail::gatherv_impl(comm, detail::c_data(in_values), in_values.size(), root, is_mpi_datatype<T>());
}
///////////////////////
@@ -139,7 +139,7 @@ void
gatherv(const communicator& comm, const std::vector<T>& in_values,
T* out_values, const std::vector<int>& sizes, int root)
{
::boost::mpi::gatherv(comm, &in_values[0], in_values.size(), out_values, sizes, root);
::boost::mpi::gatherv(comm, detail::c_data(in_values), in_values.size(), out_values, sizes, root);
}
} } // end namespace boost::mpi

View File

@@ -335,7 +335,7 @@ void
reduce(const communicator & comm, std::vector<T> const & in_values, Op op,
int root)
{
reduce(comm, &in_values.front(), in_values.size(), op, root);
reduce(comm, detail::c_data(in_values), in_values.size(), op, root);
}
template<typename T, typename Op>
@@ -344,7 +344,7 @@ reduce(const communicator & comm, std::vector<T> const & in_values,
std::vector<T> & out_values, Op op, int root)
{
if (root == comm.rank()) out_values.resize(in_values.size());
reduce(comm, &in_values.front(), in_values.size(), &out_values.front(), op,
reduce(comm, detail::c_data(in_values), in_values.size(), detail::c_data(out_values), op,
root);
}

View File

@@ -100,8 +100,8 @@ dispatch_scatter_sendbuf(const communicator& comm,
// Distribute the sizes
int myarchsize;
BOOST_MPI_CHECK_RESULT(MPI_Scatter,
(non_const_data(archsizes), 1, MPI_INTEGER,
&myarchsize, 1, MPI_INTEGER, root, comm));
(non_const_data(archsizes), 1, MPI_INT,
&myarchsize, 1, MPI_INT, root, comm));
std::vector<int> offsets;
if (root == comm.rank()) {
sizes2offsets(archsizes, offsets);
@@ -188,7 +188,7 @@ void
scatter(const communicator& comm, const std::vector<T>& in_values,
T* out_values, int n, int root)
{
::boost::mpi::scatter(comm, &in_values[0], out_values, n, root);
::boost::mpi::scatter(comm, detail::c_data(in_values), out_values, n, root);
}
template<typename T>

View File

@@ -101,7 +101,7 @@ scatterv(const communicator& comm, const T* in_values,
T* out_values, int out_size, int root)
{
using detail::c_data;
scatterv_impl(comm, in_values, out_values, out_size, c_data(sizes), c_data(displs),
detail::scatterv_impl(comm, in_values, out_values, out_size, c_data(sizes), c_data(displs),
root, is_mpi_datatype<T>());
}
@@ -142,7 +142,7 @@ void
scatterv(const communicator& comm, const std::vector<T>& in_values,
const std::vector<int>& sizes, T* out_values, int root)
{
::boost::mpi::scatterv(comm, &in_values[0], sizes, out_values, root);
::boost::mpi::scatterv(comm, detail::c_data(in_values), sizes, out_values, root);
}
template<typename T>
@@ -159,7 +159,7 @@ 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);
::boost::mpi::scatterv(comm, detail::c_data(in_values), out_values, out_size, root);
}
} } // end namespace boost::mpi

View File

@@ -34,9 +34,6 @@
// For (de-)serializing skeletons and content
#include <boost/mpi/skeleton_and_content_fwd.hpp>
// For (de-)serializing arrays
#include <boost/serialization/array.hpp>
#include <boost/mpi/detail/point_to_point.hpp>
#include <boost/mpi/status.hpp>
#include <boost/mpi/request.hpp>
@@ -512,7 +509,7 @@ class BOOST_MPI_DECL communicator
*/
status recv(int source, int tag) const;
/** @brief Send a message to remote process nd receive another message
/** @brief Send a message to remote process and receive another message
* from another process.
*/
template<typename T>
@@ -802,23 +799,7 @@ class BOOST_MPI_DECL communicator
* Split the communicator into multiple, disjoint communicators
* each of which is based on a particular color. This is a
* collective operation that returns a new communicator that is a
* subgroup of @p this. This routine is functionally equivalent to
* @c MPI_Comm_split.
*
* @param color The color of this process. All processes with the
* same @p color value will be placed into the same group.
*
* @returns A new communicator containing all of the processes in
* @p this that have the same @p color.
*/
communicator split(int color) const;
/**
* Split the communicator into multiple, disjoint communicators
* each of which is based on a particular color. This is a
* collective operation that returns a new communicator that is a
* subgroup of @p this. This routine is functionally equivalent to
* @c MPI_Comm_split.
* subgroup of @p this.
*
* @param color The color of this process. All processes with the
* same @p color value will be placed into the same group.
@@ -833,6 +814,7 @@ class BOOST_MPI_DECL communicator
* @p this that have the same @p color.
*/
communicator split(int color, int key) const;
communicator split(int color) const;
/**
* Determine if the communicator is in fact an intercommunicator
@@ -1157,11 +1139,15 @@ inline bool operator!=(const communicator& comm1, const communicator& comm2)
return !(comm1 == comm2);
}
}} // boost::mpi
/************************************************************************
* Implementation details *
************************************************************************/
#include <boost/mpi/detail/request_handlers.hpp>
namespace boost { namespace mpi {
/**
* INTERNAL ONLY (using the same 'end' name might be considerd unfortunate
*/
@@ -1270,44 +1256,13 @@ communicator::irecv<content>(int source, int tag,
return irecv<const content>(source, tag, c);
}
// Count elements in a message
template<typename T>
inline optional<int> status::count() const
{
return count_impl<T>(is_mpi_datatype<T>());
}
template<typename T>
optional<int> status::count_impl(mpl::true_) const
{
if (m_count != -1)
return m_count;
int return_value;
BOOST_MPI_CHECK_RESULT(MPI_Get_count,
(&m_status, get_mpi_datatype<T>(T()), &return_value));
if (return_value == MPI_UNDEFINED)
return optional<int>();
else
/* Cache the result. */
return m_count = return_value;
}
template<typename T>
inline optional<int> status::count_impl(mpl::false_) const
{
if (m_count == -1)
return optional<int>();
else
return m_count;
}
// We're sending a type that has an associated MPI datatype, so we
// map directly to that datatype.
template<typename T>
void
communicator::send_impl(int dest, int tag, const T& value, mpl::true_) const
{
// received by recv or trivial handler.
BOOST_MPI_CHECK_RESULT(MPI_Send,
(const_cast<T*>(&value), 1, get_mpi_datatype<T>(value),
dest, tag, MPI_Comm(*this)));
@@ -1355,26 +1310,37 @@ communicator::array_send_impl(int dest, int tag, const T* values, int n,
mpl::false_) const
{
packed_oarchive oa(*this);
oa << n << boost::serialization::make_array(values, n);
T const* v = values;
while (v < values+n) {
oa << *v++;
}
send(dest, tag, oa);
}
template<typename T, typename A>
void communicator::send_vector(int dest, int tag,
const std::vector<T,A>& value, mpl::true_ true_type) const
const std::vector<T,A>& values, mpl::true_ primitive) const
{
// send the vector size
typename std::vector<T,A>::size_type size = value.size();
send(dest, tag, size);
// send the data
this->array_send_impl(dest, tag, value.data(), size, true_type);
#if defined(BOOST_MPI_USE_IMPROBE)
array_send_impl(dest, tag, values.data(), values.size(), primitive);
#else
{
// non blocking recv by legacy_dynamic_primitive_array_handler
// blocking recv by recv_vector(source,tag,value,primitive)
// send the vector size
typename std::vector<T,A>::size_type size = values.size();
send(dest, tag, size);
// send the data
this->array_send_impl(dest, tag, values.data(), size, primitive);
}
#endif
}
template<typename T, typename A>
void communicator::send_vector(int dest, int tag,
const std::vector<T,A>& value, mpl::false_ false_type) const
const std::vector<T,A>& value, mpl::false_ primitive) const
{
this->send_impl(dest, tag, value, false_type);
this->send_impl(dest, tag, value, primitive);
}
template<typename T, typename A>
@@ -1396,7 +1362,6 @@ template<typename T>
status communicator::recv_impl(int source, int tag, T& value, mpl::true_) const
{
status stat;
BOOST_MPI_CHECK_RESULT(MPI_Recv,
(const_cast<T*>(&value), 1,
get_mpi_datatype<T>(value),
@@ -1444,38 +1409,42 @@ status
communicator::array_recv_impl(int source, int tag, T* values, int n,
mpl::false_) const
{
// Receive the message
packed_iarchive ia(*this);
status stat = recv(source, tag, ia);
// Determine how much data we are going to receive
int count;
ia >> count;
// Deserialize the data in the message
boost::serialization::array_wrapper<T> arr(values, count > n? n : count);
ia >> arr;
if (count > n) {
boost::throw_exception(
std::range_error("communicator::recv: message receive overflow"));
T* v = values;
while (v != values+n) {
ia >> *v++;
}
stat.m_count = count;
stat.m_count = n;
return stat;
}
template<typename T, typename A>
status communicator::recv_vector(int source, int tag,
std::vector<T,A>& value, mpl::true_ true_type) const
std::vector<T,A>& values, mpl::true_ primitive) const
{
// receive the vector size
typename std::vector<T,A>::size_type size = 0;
recv(source, tag, size);
// size the vector
value.resize(size);
// receive the data
return this->array_recv_impl(source, tag, value.data(), size, true_type);
#if defined(BOOST_MPI_USE_IMPROBE)
{
MPI_Message msg;
status stat;
BOOST_MPI_CHECK_RESULT(MPI_Mprobe, (source,tag,*this,&msg,&stat.m_status));
int count;
BOOST_MPI_CHECK_RESULT(MPI_Get_count, (&stat.m_status,get_mpi_datatype<T>(),&count));
values.resize(count);
BOOST_MPI_CHECK_RESULT(MPI_Mrecv, (values.data(), count, get_mpi_datatype<T>(), &msg, &stat.m_status));
return stat;
}
#else
{
// receive the vector size
typename std::vector<T,A>::size_type size = 0;
recv(source, tag, size);
// size the vector
values.resize(size);
// receive the data
return this->array_recv_impl(source, tag, values.data(), size, primitive);
}
#endif
}
template<typename T, typename A>
@@ -1542,12 +1511,7 @@ template<typename T>
request
communicator::isend_impl(int dest, int tag, const T& value, mpl::true_) const
{
request req;
BOOST_MPI_CHECK_RESULT(MPI_Isend,
(const_cast<T*>(&value), 1,
get_mpi_datatype<T>(value),
dest, tag, MPI_Comm(*this), &req.m_requests[0]));
return req;
return request::make_trivial_send(*this, dest, tag, value);
}
// We're sending a type that does not have an associated MPI
@@ -1560,7 +1524,7 @@ communicator::isend_impl(int dest, int tag, const T& value, mpl::false_) const
shared_ptr<packed_oarchive> archive(new packed_oarchive(*this));
*archive << value;
request result = isend(dest, tag, *archive);
result.m_data = archive;
result.preserve(archive);
return result;
}
@@ -1581,16 +1545,9 @@ request communicator::isend(int dest, int tag, const std::vector<T,A>& values) c
template<typename T, class A>
request
communicator::isend_vector(int dest, int tag, const std::vector<T,A>& values,
mpl::true_) const
mpl::true_ primitive) 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;
return request::make_dynamic_primitive_array_send(*this, dest, tag, values);
}
template<typename T, class A>
@@ -1606,12 +1563,7 @@ request
communicator::array_isend_impl(int dest, int tag, const T* values, int n,
mpl::true_) const
{
request req;
BOOST_MPI_CHECK_RESULT(MPI_Isend,
(const_cast<T*>(values), n,
get_mpi_datatype<T>(*values),
dest, tag, MPI_Comm(*this), &req.m_requests[0]));
return req;
return request::make_trivial_send(*this, dest, tag, values, n);
}
template<typename T>
@@ -1620,9 +1572,12 @@ communicator::array_isend_impl(int dest, int tag, const T* values, int n,
mpl::false_) const
{
shared_ptr<packed_oarchive> archive(new packed_oarchive(*this));
*archive << n << boost::serialization::make_array(values, n);
T const* v = values;
while (v < values+n) {
*archive << *v++;
}
request result = isend(dest, tag, *archive);
result.m_data = archive;
result.preserve(archive);
return result;
}
@@ -1634,323 +1589,20 @@ request communicator::isend(int dest, int tag, const T* values, int n) const
return array_isend_impl(dest, tag, values, n, is_mpi_datatype<T>());
}
namespace detail {
/**
* Internal data structure that stores everything required to manage
* the receipt of serialized data via a request object.
*/
template<typename T>
struct serialized_irecv_data
{
serialized_irecv_data(const communicator& comm, int source, int tag,
T& value)
: comm(comm), source(source), tag(tag), ia(comm), value(value)
{
}
void deserialize(status& stat)
{
ia >> value;
stat.m_count = 1;
}
communicator comm;
int source;
int tag;
std::size_t count;
packed_iarchive ia;
T& value;
};
template<>
struct serialized_irecv_data<packed_iarchive>
{
serialized_irecv_data(const communicator& comm, int source, int tag,
packed_iarchive& ia)
: comm(comm), source(source), tag(tag), ia(ia) { }
void deserialize(status&) { /* Do nothing. */ }
communicator comm;
int source;
int tag;
std::size_t count;
packed_iarchive& ia;
};
/**
* Internal data structure that stores everything required to manage
* the receipt of an array of serialized data via a request object.
*/
template<typename T>
struct serialized_array_irecv_data
{
serialized_array_irecv_data(const communicator& comm, int source, int tag,
T* values, int n)
: comm(comm), source(source), tag(tag), ia(comm), values(values), n(n)
{
}
void deserialize(status& stat);
communicator comm;
int source;
int tag;
std::size_t count;
packed_iarchive ia;
T* values;
int n;
};
template<typename T>
void serialized_array_irecv_data<T>::deserialize(status& stat)
{
// Determine how much data we are going to receive
int count;
ia >> count;
// Deserialize the data in the message
boost::serialization::array_wrapper<T> arr(values, count > n? n : count);
ia >> arr;
if (count > n) {
boost::throw_exception(
std::range_error("communicator::recv: message receive overflow"));
}
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>
optional<status>
request::handle_serialized_irecv(request* self, request_action action)
{
typedef detail::serialized_irecv_data<T> 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->ia.resize(data->count);
BOOST_MPI_CHECK_RESULT(MPI_Irecv,
(data->ia.address(), data->ia.size(), MPI_PACKED,
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));
data->deserialize(stat);
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->ia.resize(data->count);
BOOST_MPI_CHECK_RESULT(MPI_Irecv,
(data->ia.address(), data->ia.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) {
data->deserialize(stat);
return stat;
} else
return optional<status>();
} else {
return optional<status>();
}
}
template<typename T>
optional<status>
request::handle_serialized_array_irecv(request* self, request_action action)
{
typedef detail::serialized_array_irecv_data<T> 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->ia.resize(data->count);
BOOST_MPI_CHECK_RESULT(MPI_Irecv,
(data->ia.address(), data->ia.size(), MPI_PACKED,
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));
data->deserialize(stat);
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->ia.resize(data->count);
BOOST_MPI_CHECK_RESULT(MPI_Irecv,
(data->ia.address(), data->ia.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) {
data->deserialize(stat);
return stat;
} else
return optional<status>();
} else {
return optional<status>();
}
}
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>
request
communicator::irecv_impl(int source, int tag, T& value, mpl::true_) const
{
request req;
BOOST_MPI_CHECK_RESULT(MPI_Irecv,
(const_cast<T*>(&value), 1,
get_mpi_datatype<T>(value),
source, tag, MPI_Comm(*this), &req.m_requests[0]));
return req;
return request::make_trivial_recv(*this, source, tag, value);
}
template<typename T>
request
communicator::irecv_impl(int source, int tag, T& value, mpl::false_) const
{
typedef detail::serialized_irecv_data<T> data_t;
shared_ptr<data_t> data(new data_t(*this, source, tag, value));
request req;
req.m_data = data;
req.m_handler = request::handle_serialized_irecv<T>;
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;
return request::make_serialized(*this, source, tag, value);
}
template<typename T>
@@ -1965,12 +1617,7 @@ request
communicator::array_irecv_impl(int source, int tag, T* values, int n,
mpl::true_) const
{
request req;
BOOST_MPI_CHECK_RESULT(MPI_Irecv,
(const_cast<T*>(values), n,
get_mpi_datatype<T>(*values),
source, tag, MPI_Comm(*this), &req.m_requests[0]));
return req;
return request::make_trivial_recv(*this, source, tag, values, n);
}
template<typename T>
@@ -1978,37 +1625,15 @@ request
communicator::array_irecv_impl(int source, int tag, T* values, int n,
mpl::false_) const
{
typedef detail::serialized_array_irecv_data<T> data_t;
shared_ptr<data_t> data(new data_t(*this, source, tag, values, n));
request req;
req.m_data = data;
req.m_handler = request::handle_serialized_array_irecv<T>;
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;
return request::make_serialized_array(*this, source, tag, values, n);
}
template<typename T, class A>
request
communicator::irecv_vector(int source, int tag, std::vector<T,A>& values,
mpl::true_) const
mpl::true_ primitive) 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;
return request::make_dynamic_primitive_array_recv(*this, source, tag, values);
}
template<typename T, class A>

View File

@@ -16,6 +16,8 @@
/* Force MPICH not to define SEEK_SET, SEEK_CUR, and SEEK_END, which
conflict with the versions in <stdio.h> and <cstdio>. */
#define MPICH_IGNORE_CXX_SEEK 1
/* We do not want to link in the OpenMPI CXX stuff */
#define OMPI_SKIP_MPICXX
#include <mpi.h>
#include <boost/config.hpp>
@@ -32,9 +34,33 @@
*/
#define BOOST_MPI_HOMOGENEOUS
#if defined MPI_VERSION
/** @brief Major version of the underlying MPI implementation supproted standard.
*
* If, for some reason, MPI_VERSION is not supported, you should probably set that
* according to your MPI documentation
*/
# define BOOST_MPI_VERSION MPI_VERSION
#else
// assume a safe default
# define BOOST_MPI_VERSION 2
#endif
#if defined MPI_SUBVERSION
/** @brief Major version of the underlying MPI implementation supported standard.
*
* If, for some reason, MPI_SUBVERSION is not supported, you should probably set that
* according to your MPI documentation
*/
# define BOOST_MPI_SUBVERSION MPI_SUBVERSION
#else
// assume a safe default
# define BOOST_MPI_SUBVERSION 2
#endif
// If this is an MPI-2 implementation, define configuration macros for
// the features we are interested in.
#if defined(MPI_VERSION) && MPI_VERSION >= 2
#if BOOST_MPI_VERSION >= 2
/** @brief Determine if the MPI implementation has support for memory
* allocation.
*
@@ -92,10 +118,29 @@
# define BOOST_MPI_HAS_MEMORY_ALLOCATION
# define BOOST_MPI_HAS_NOARG_INITIALIZATION
# undef BOOST_MPI_BCAST_BOTTOM_WORKS_FINE
#elif defined(MPICH_NAME)
#endif
#if defined(MPICH_NAME)
// Configuration for MPICH
#endif
#if defined(OPEN_MPI)
// Configuration for Open MPI
#endif
#if BOOST_MPI_VERSION >= 3
// MPI_Probe an friends should work
# if defined(I_MPI_NUMVERSION)
// Excepted for some Intel versions.
// Note that I_MPI_NUMVERSION is not always defined with Intel.
# if I_MPI_NUMVERSION > 20190004000
# define BOOST_MPI_USE_IMPROBE 1
# endif
# else
# define BOOST_MPI_USE_IMPROBE 1
# endif
#endif
/*****************************************************************************
* *
* DLL import/export options *

View File

@@ -27,6 +27,7 @@
#include <boost/mpi/detail/mpi_datatype_cache.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/archive/basic_archive.hpp>
#include <boost/serialization/library_version_type.hpp>
#include <boost/serialization/item_version_type.hpp>
#include <utility> // for std::pair
@@ -80,7 +81,7 @@ struct is_mpi_logical_datatype
* complex MPI data type for a given C++ type.
*
* This type trait determines when there is a direct mapping from a
* C++ type to an MPI data type that is classified as an complex data
* C++ type to an MPI data type that is classified as a complex data
* type. See @c is_mpi_builtin_datatype for general information about
* built-in MPI data types.
*/
@@ -140,7 +141,7 @@ struct is_mpi_builtin_datatype
* be accessible via @c get_mpi_datatype.
* For any C++ type that maps to a built-in MPI data type (see @c
* is_mpi_builtin_datatype), @c is_mpi_data_type is trivially
* is_mpi_builtin_datatype), @c is_mpi_datatype is trivially
* true. However, any POD ("Plain Old Data") type containing types
* that themselves can be represented by MPI data types can itself be
* represented as an MPI data type. For instance, a @c point3d class
@@ -280,16 +281,16 @@ struct is_mpi_datatype<std::array<T, N> >
// Define wchar_t specialization of is_mpi_datatype, if possible.
#if !defined(BOOST_NO_INTRINSIC_WCHAR_T) && \
(defined(MPI_WCHAR) || (defined(MPI_VERSION) && MPI_VERSION >= 2))
(defined(MPI_WCHAR) || (BOOST_MPI_VERSION >= 2))
BOOST_MPI_DATATYPE(wchar_t, MPI_WCHAR, builtin);
#endif
// Define long long or __int64 specialization of is_mpi_datatype, if possible.
#if defined(BOOST_HAS_LONG_LONG) && \
(defined(MPI_LONG_LONG_INT) || (defined(MPI_VERSION) && MPI_VERSION >= 2))
(defined(MPI_LONG_LONG_INT) || (BOOST_MPI_VERSION >= 2))
BOOST_MPI_DATATYPE(long long, MPI_LONG_LONG_INT, builtin);
#elif defined(BOOST_HAS_MS_INT64) && \
(defined(MPI_LONG_LONG_INT) || (defined(MPI_VERSION) && MPI_VERSION >= 2))
(defined(MPI_LONG_LONG_INT) || (BOOST_MPI_VERSION >= 2))
BOOST_MPI_DATATYPE(__int64, MPI_LONG_LONG_INT, builtin);
#endif
@@ -300,16 +301,16 @@ BOOST_MPI_DATATYPE(__int64, MPI_LONG_LONG_INT, builtin);
// MPI_UNSIGNED_LONG_LONG.
#if defined(BOOST_HAS_LONG_LONG) && \
(defined(MPI_UNSIGNED_LONG_LONG) \
|| (defined(MPI_VERSION) && MPI_VERSION >= 2))
|| (BOOST_MPI_VERSION >= 2))
BOOST_MPI_DATATYPE(unsigned long long, MPI_UNSIGNED_LONG_LONG, builtin);
#elif defined(BOOST_HAS_MS_INT64) && \
(defined(MPI_UNSIGNED_LONG_LONG) \
|| (defined(MPI_VERSION) && MPI_VERSION >= 2))
|| (BOOST_MPI_VERSION >= 2))
BOOST_MPI_DATATYPE(unsigned __int64, MPI_UNSIGNED_LONG_LONG, builtin);
#endif
// Define signed char specialization of is_mpi_datatype, if possible.
#if defined(MPI_SIGNED_CHAR) || (defined(MPI_VERSION) && MPI_VERSION >= 2)
#if defined(MPI_SIGNED_CHAR) || (BOOST_MPI_VERSION >= 2)
BOOST_MPI_DATATYPE(signed char, MPI_SIGNED_CHAR, builtin);
#endif
@@ -344,7 +345,7 @@ struct is_mpi_datatype<bool>
#ifndef BOOST_MPI_DOXYGEN
// direct support for special primitive data types of the serialization library
BOOST_MPI_DATATYPE(boost::archive::library_version_type, get_mpi_datatype(uint_least16_t()), integer);
BOOST_MPI_DATATYPE(boost::serialization::library_version_type, get_mpi_datatype(uint_least16_t()), integer);
BOOST_MPI_DATATYPE(boost::archive::version_type, get_mpi_datatype(uint_least8_t()), integer);
BOOST_MPI_DATATYPE(boost::archive::class_id_type, get_mpi_datatype(int_least16_t()), integer);
BOOST_MPI_DATATYPE(boost::archive::class_id_reference_type, get_mpi_datatype(int_least16_t()), integer);

View File

@@ -19,10 +19,10 @@ namespace detail {
// 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]); }
T* c_data(std::vector<T,A>& v) { return v.empty() ? static_cast<T*>(0) : &(v[0]); }
template <typename T, typename A>
T const* c_data(std::vector<T,A> const& v) { return &(v[0]); }
T const* c_data(std::vector<T,A> const& v) { return v.empty() ? static_cast<T const*>(0) : &(v[0]); }
// Some old MPI implementation (OpenMPI 1.6 for example) have non
// conforming API w.r.t. constness.

View File

@@ -41,12 +41,12 @@ public:
void* address ()
{
return &buffer_.front();
return detail::c_data(buffer_);
}
void const* address () const
{
return &buffer_.front();
return detail::c_data(buffer_);
}
const std::size_t& size() const
@@ -100,7 +100,7 @@ public:
#endif
s.resize(l);
// note breaking a rule here - could be a problem on some platform
load_impl(const_cast<char *>(s.data()),l);
load_impl(const_cast<CharType *>(s.data()), l*sizeof(CharType));
}
private:

View File

@@ -40,7 +40,7 @@ public:
void const * address() const
{
return &buffer_.front();
return detail::c_data(buffer_);
}
const std::size_t& size() const
@@ -89,7 +89,7 @@ public:
{
unsigned int l = static_cast<unsigned int>(s.size());
save(l);
save_impl(s.data(),s.size());
save_impl(s.data(),s.size()*sizeof(CharType));
}
private:

View File

@@ -13,14 +13,6 @@
namespace boost { namespace mpi {
template<typename T>
inline void
broadcast(const communicator& comm, skeleton_proxy<T>& proxy, int root)
{
const skeleton_proxy<T>& const_proxy(proxy);
broadcast(comm, const_proxy, root);
}
template<typename T>
void
broadcast(const communicator& comm, const skeleton_proxy<T>& proxy, int root)
@@ -36,6 +28,15 @@ broadcast(const communicator& comm, const skeleton_proxy<T>& proxy, int root)
}
}
template<typename T>
inline void
broadcast(const communicator& comm, skeleton_proxy<T>& proxy, int root)
{
const skeleton_proxy<T>& const_proxy(proxy);
broadcast(comm, const_proxy, root);
}
} } // end namespace boost::mpi
#endif // BOOST_MPI_BROADCAST_SC_HPP

View File

@@ -50,46 +50,10 @@ communicator::isend(int dest, int tag, const skeleton_proxy<T>& proxy) const
*archive << proxy.object;
request result = isend(dest, tag, *archive);
result.m_data = archive;
result.preserve(archive);
return result;
}
namespace detail {
template<typename T>
struct serialized_irecv_data<const skeleton_proxy<T> >
{
serialized_irecv_data(const communicator& comm, int source, int tag,
skeleton_proxy<T> proxy)
: comm(comm), source(source), tag(tag), isa(comm),
ia(isa.get_skeleton()), proxy(proxy) { }
void deserialize(status& stat)
{
isa >> proxy.object;
stat.m_count = 1;
}
communicator comm;
int source;
int tag;
std::size_t count;
packed_skeleton_iarchive isa;
packed_iarchive& ia;
skeleton_proxy<T> proxy;
};
template<typename T>
struct serialized_irecv_data<skeleton_proxy<T> >
: public serialized_irecv_data<const skeleton_proxy<T> >
{
typedef serialized_irecv_data<const skeleton_proxy<T> > inherited;
serialized_irecv_data(const communicator& comm, int source, int tag,
const skeleton_proxy<T>& proxy)
: inherited(comm, source, tag, proxy) { }
};
}
} } // end namespace boost::mpi
#endif // BOOST_MPI_COMMUNICATOR_SC_HPP

View File

@@ -15,6 +15,7 @@
#include <boost/archive/detail/oserializer.hpp>
#include <boost/serialization/collection_size_type.hpp>
#include <boost/serialization/array.hpp>
#include <boost/serialization/library_version_type.hpp>
#include <boost/serialization/item_version_type.hpp>
namespace boost { namespace mpi { namespace detail {
@@ -48,7 +49,6 @@ protected:
BOOST_ARCHIVE_IGNORE_IMPLEMENTATION(archive::class_id_optional_type)
BOOST_ARCHIVE_IGNORE_IMPLEMENTATION(archive::version_type)
BOOST_ARCHIVE_IGNORE_IMPLEMENTATION(archive::library_version_type)
BOOST_ARCHIVE_IGNORE_IMPLEMENTATION(archive::class_id_type)
BOOST_ARCHIVE_IGNORE_IMPLEMENTATION(archive::class_id_reference_type)
BOOST_ARCHIVE_IGNORE_IMPLEMENTATION(archive::object_id_type)
@@ -56,6 +56,7 @@ BOOST_ARCHIVE_IGNORE_IMPLEMENTATION(archive::object_reference_type)
BOOST_ARCHIVE_IGNORE_IMPLEMENTATION(archive::tracking_type)
BOOST_ARCHIVE_IGNORE_IMPLEMENTATION(archive::class_name_type)
BOOST_ARCHIVE_IGNORE_IMPLEMENTATION(serialization::collection_size_type)
BOOST_ARCHIVE_IGNORE_IMPLEMENTATION(serialization::library_version_type)
BOOST_ARCHIVE_IGNORE_IMPLEMENTATION(serialization::item_version_type)
void save_override(std::string const & s)

View File

@@ -50,7 +50,7 @@ public:
: is_committed(false),
origin()
{
#if defined(MPI_VERSION) && MPI_VERSION >= 2
#if BOOST_MPI_VERSION >= 2
BOOST_MPI_CHECK_RESULT(MPI_Get_address,(const_cast<void*>(orig), &origin));
#else
BOOST_MPI_CHECK_RESULT(MPI_Address,(const_cast<void*>(orig), &origin));
@@ -77,7 +77,7 @@ public:
{
if (!is_committed)
{
#if defined(MPI_VERSION) && MPI_VERSION >= 2
#if BOOST_MPI_VERSION >= 2
BOOST_MPI_CHECK_RESULT(MPI_Type_create_struct,
(
addresses.size(),
@@ -120,7 +120,7 @@ private:
// store address, type and length
MPI_Aint a;
#if defined(MPI_VERSION) && MPI_VERSION >= 2
#if BOOST_MPI_VERSION >= 2
BOOST_MPI_CHECK_RESULT(MPI_Get_address,(const_cast<void*>(p), &a));
#else
BOOST_MPI_CHECK_RESULT(MPI_Address,(const_cast<void*>(p), &a));
@@ -133,7 +133,7 @@ private:
template <class T>
static T* get_data(std::vector<T>& v)
{
return v.empty() ? 0 : &(v[0]);
return detail::c_data(v);
}
std::vector<MPI_Aint> addresses;

View File

@@ -9,6 +9,7 @@
#define BOOST_MPI_OFFSETS_HPP
#include <vector>
#include <boost/mpi/config.hpp>
#include <boost/mpi/communicator.hpp>
namespace boost { namespace mpi {
@@ -16,10 +17,10 @@ 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);
void BOOST_MPI_DECL 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);
void BOOST_MPI_DECL 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
@@ -32,7 +33,7 @@ void offsets2skipped(int const* sizes, int const* offsets, int* skipped, int n);
// 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);
int* BOOST_MPI_DECL 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

View File

@@ -39,12 +39,12 @@ public:
void* address ()
{
return &buffer_[0];
return detail::c_data(buffer_);
}
void const* address () const
{
return &buffer_[0];
return detail::c_data(buffer_);
}
const std::size_t& size() const

View File

@@ -38,7 +38,7 @@ public:
void const * address() const
{
return &buffer_[0];
return detail::c_data(buffer_);
}
const std::size_t& size() const
@@ -114,7 +114,7 @@ private:
static buffer_type::value_type* get_data(buffer_type& b)
{
return b.empty() ? 0 : &(b[0]);
return detail::c_data(b);
}
buffer_type& buffer_;

View File

@@ -13,11 +13,16 @@
#include <boost/mpi/packed_oarchive.hpp>
#include <boost/mpi/packed_iarchive.hpp>
namespace boost { namespace mpi { namespace detail {
namespace boost { namespace mpi {
class request;
class communicator;
namespace detail {
/** Sends a packed archive using MPI_Send. */
BOOST_MPI_DECL void
packed_archive_send(MPI_Comm comm, int dest, int tag,
packed_archive_send(communicator const& comm, int dest, int tag,
const packed_oarchive& ar);
/** Sends a packed archive using MPI_Isend.
@@ -26,25 +31,21 @@ packed_archive_send(MPI_Comm comm, int dest, int tag,
* for each packet will be placed into the out_requests array, up to
* num_out_requests packets. The number of packets sent will be
* returned from the function.
*
* @pre num_out_requests >= 2
*/
BOOST_MPI_DECL int
packed_archive_isend(MPI_Comm comm, int dest, int tag,
const packed_oarchive& ar,
MPI_Request* out_requests, int num_out_requests);
BOOST_MPI_DECL request
packed_archive_isend(communicator const& comm, int dest, int tag,
const packed_oarchive& ar);
/**
* \overload
*/
BOOST_MPI_DECL int
packed_archive_isend(MPI_Comm comm, int dest, int tag,
const packed_iarchive& ar,
MPI_Request* out_requests, int num_out_requests);
BOOST_MPI_DECL request
packed_archive_isend(communicator const& comm, int dest, int tag,
const packed_iarchive& ar);
/** Receives a packed archive using MPI_Recv. */
BOOST_MPI_DECL void
packed_archive_recv(MPI_Comm comm, int source, int tag, packed_iarchive& ar,
packed_archive_recv(communicator const& comm, int source, int tag, packed_iarchive& ar,
MPI_Status& status);
} } } // end namespace boost::mpi::detail

View File

@@ -0,0 +1,631 @@
// Copyright (C) 2018 Alain Miniussi <alain.miniussi@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)
// Request implementation dtails
// This header should be included only after the communicator and request
// classes has been defined.
#ifndef BOOST_MPI_REQUEST_HANDLERS_HPP
#define BOOST_MPI_REQUEST_HANDLERS_HPP
#include <boost/mpi/skeleton_and_content_types.hpp>
namespace boost { namespace mpi {
namespace detail {
/**
* Internal data structure that stores everything required to manage
* the receipt of serialized data via a request object.
*/
template<typename T>
struct serialized_irecv_data {
serialized_irecv_data(const communicator& comm, T& value)
: m_ia(comm), m_value(value) {}
void deserialize(status& stat)
{
m_ia >> m_value;
stat.m_count = 1;
}
std::size_t m_count;
packed_iarchive m_ia;
T& m_value;
};
template<>
struct serialized_irecv_data<packed_iarchive>
{
serialized_irecv_data(communicator const&, packed_iarchive& ia) : m_ia(ia) { }
void deserialize(status&) { /* Do nothing. */ }
std::size_t m_count;
packed_iarchive& m_ia;
};
/**
* Internal data structure that stores everything required to manage
* the receipt of an array of serialized data via a request object.
*/
template<typename T>
struct serialized_array_irecv_data
{
serialized_array_irecv_data(const communicator& comm, T* values, int n)
: m_count(0), m_ia(comm), m_values(values), m_nb(n) {}
void deserialize(status& stat);
std::size_t m_count;
packed_iarchive m_ia;
T* m_values;
int m_nb;
};
template<typename T>
void serialized_array_irecv_data<T>::deserialize(status& stat)
{
T* v = m_values;
T* end = m_values+m_nb;
while (v < end) {
m_ia >> *v++;
}
stat.m_count = m_nb;
}
/**
* 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(std::vector<T,A>& values)
: m_count(-1), m_values(values) {}
std::size_t m_count;
std::vector<T,A>& m_values;
};
template<typename T>
struct serialized_irecv_data<const skeleton_proxy<T> >
{
serialized_irecv_data(const communicator& comm, skeleton_proxy<T> proxy)
: m_isa(comm), m_ia(m_isa.get_skeleton()), m_proxy(proxy) { }
void deserialize(status& stat)
{
m_isa >> m_proxy.object;
stat.m_count = 1;
}
std::size_t m_count;
packed_skeleton_iarchive m_isa;
packed_iarchive& m_ia;
skeleton_proxy<T> m_proxy;
};
template<typename T>
struct serialized_irecv_data<skeleton_proxy<T> >
: public serialized_irecv_data<const skeleton_proxy<T> >
{
typedef serialized_irecv_data<const skeleton_proxy<T> > inherited;
serialized_irecv_data(const communicator& comm, const skeleton_proxy<T>& proxy)
: inherited(comm, proxy) { }
};
}
#if BOOST_MPI_VERSION >= 3
template<class Data>
class request::probe_handler
: public request::handler,
protected Data {
protected:
template<typename I1>
probe_handler(communicator const& comm, int source, int tag, I1& i1)
: Data(comm, i1),
m_comm(comm),
m_source(source),
m_tag(tag) {}
// no variadic template for now
template<typename I1, typename I2>
probe_handler(communicator const& comm, int source, int tag, I1& i1, I2& i2)
: Data(comm, i1, i2),
m_comm(comm),
m_source(source),
m_tag(tag) {}
public:
bool active() const { return m_source != MPI_PROC_NULL; }
optional<MPI_Request&> trivial() { return boost::none; }
void cancel() { m_source = MPI_PROC_NULL; }
status wait() {
MPI_Message msg;
status stat;
BOOST_MPI_CHECK_RESULT(MPI_Mprobe, (m_source,m_tag,m_comm,&msg,&stat.m_status));
return unpack(msg, stat);
}
optional<status> test() {
status stat;
int flag = 0;
MPI_Message msg;
BOOST_MPI_CHECK_RESULT(MPI_Improbe, (m_source,m_tag,m_comm,&flag,&msg,&stat.m_status));
if (flag) {
return unpack(msg, stat);
} else {
return optional<status>();
}
}
protected:
friend class request;
status unpack(MPI_Message& msg, status& stat) {
int count;
MPI_Datatype datatype = this->Data::datatype();
BOOST_MPI_CHECK_RESULT(MPI_Get_count, (&stat.m_status, datatype, &count));
this->Data::resize(count);
BOOST_MPI_CHECK_RESULT(MPI_Mrecv, (this->Data::buffer(), count, datatype, &msg, &stat.m_status));
this->Data::deserialize();
m_source = MPI_PROC_NULL;
stat.m_count = 1;
return stat;
}
communicator const& m_comm;
int m_source;
int m_tag;
};
#endif // BOOST_MPI_VERSION >= 3
namespace detail {
template<class A>
struct dynamic_primitive_array_data {
dynamic_primitive_array_data(communicator const&, A& arr) : m_buffer(arr) {}
void* buffer() { return m_buffer.data(); }
void resize(std::size_t sz) { m_buffer.resize(sz); }
void deserialize() {}
MPI_Datatype datatype() { return get_mpi_datatype<typename A::value_type>(); }
A& m_buffer;
};
template<typename T>
struct serialized_data {
serialized_data(communicator const& comm, T& value) : m_archive(comm), m_value(value) {}
void* buffer() { return m_archive.address(); }
void resize(std::size_t sz) { m_archive.resize(sz); }
void deserialize() { m_archive >> m_value; }
MPI_Datatype datatype() { return MPI_PACKED; }
packed_iarchive m_archive;
T& m_value;
};
template<>
struct serialized_data<packed_iarchive> {
serialized_data(communicator const& comm, packed_iarchive& ar) : m_archive(ar) {}
void* buffer() { return m_archive.address(); }
void resize(std::size_t sz) { m_archive.resize(sz); }
void deserialize() {}
MPI_Datatype datatype() { return MPI_PACKED; }
packed_iarchive& m_archive;
};
template<typename T>
struct serialized_data<const skeleton_proxy<T> > {
serialized_data(communicator const& comm, skeleton_proxy<T> skel)
: m_proxy(skel),
m_archive(comm) {}
void* buffer() { return m_archive.get_skeleton().address(); }
void resize(std::size_t sz) { m_archive.get_skeleton().resize(sz); }
void deserialize() { m_archive >> m_proxy.object; }
MPI_Datatype datatype() { return MPI_PACKED; }
skeleton_proxy<T> m_proxy;
packed_skeleton_iarchive m_archive;
};
template<typename T>
struct serialized_data<skeleton_proxy<T> >
: public serialized_data<const skeleton_proxy<T> > {
typedef serialized_data<const skeleton_proxy<T> > super;
serialized_data(communicator const& comm, skeleton_proxy<T> skel)
: super(comm, skel) {}
};
template<typename T>
struct serialized_array_data {
serialized_array_data(communicator const& comm, T* values, int nb)
: m_archive(comm), m_values(values), m_nb(nb) {}
void* buffer() { return m_archive.address(); }
void resize(std::size_t sz) { m_archive.resize(sz); }
void deserialize() {
T* end = m_values + m_nb;
T* v = m_values;
while (v != end) {
m_archive >> *v++;
}
}
MPI_Datatype datatype() { return MPI_PACKED; }
packed_iarchive m_archive;
T* m_values;
int m_nb;
};
}
class BOOST_MPI_DECL request::legacy_handler : public request::handler {
public:
legacy_handler(communicator const& comm, int source, int tag);
void cancel() {
for (int i = 0; i < 2; ++i) {
if (m_requests[i] != MPI_REQUEST_NULL) {
BOOST_MPI_CHECK_RESULT(MPI_Cancel, (m_requests+i));
}
}
}
bool active() const;
optional<MPI_Request&> trivial();
MPI_Request m_requests[2];
communicator m_comm;
int m_source;
int m_tag;
};
template<typename T>
class request::legacy_serialized_handler
: public request::legacy_handler,
protected detail::serialized_irecv_data<T> {
public:
typedef detail::serialized_irecv_data<T> extra;
legacy_serialized_handler(communicator const& comm, int source, int tag, T& value)
: legacy_handler(comm, source, tag),
extra(comm, value) {
BOOST_MPI_CHECK_RESULT(MPI_Irecv,
(&this->extra::m_count, 1,
get_mpi_datatype(this->extra::m_count),
source, tag, comm, m_requests+0));
}
status wait() {
status stat;
if (m_requests[1] == MPI_REQUEST_NULL) {
// Wait for the count message to complete
BOOST_MPI_CHECK_RESULT(MPI_Wait,
(m_requests, &stat.m_status));
// Resize our buffer and get ready to receive its data
this->extra::m_ia.resize(this->extra::m_count);
BOOST_MPI_CHECK_RESULT(MPI_Irecv,
(this->extra::m_ia.address(), this->extra::m_ia.size(), MPI_PACKED,
stat.source(), stat.tag(),
MPI_Comm(m_comm), m_requests + 1));
}
// Wait until we have received the entire message
BOOST_MPI_CHECK_RESULT(MPI_Wait,
(m_requests + 1, &stat.m_status));
this->deserialize(stat);
return stat;
}
optional<status> test() {
status stat;
int flag = 0;
if (m_requests[1] == MPI_REQUEST_NULL) {
// Check if the count message has completed
BOOST_MPI_CHECK_RESULT(MPI_Test,
(m_requests, &flag, &stat.m_status));
if (flag) {
// Resize our buffer and get ready to receive its data
this->extra::m_ia.resize(this->extra::m_count);
BOOST_MPI_CHECK_RESULT(MPI_Irecv,
(this->extra::m_ia.address(), this->extra::m_ia.size(),MPI_PACKED,
stat.source(), stat.tag(),
MPI_Comm(m_comm), 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,
(m_requests + 1, &flag, &stat.m_status));
if (flag) {
this->deserialize(stat);
return stat;
} else
return optional<status>();
}
};
template<typename T>
class request::legacy_serialized_array_handler
: public request::legacy_handler,
protected detail::serialized_array_irecv_data<T> {
typedef detail::serialized_array_irecv_data<T> extra;
public:
legacy_serialized_array_handler(communicator const& comm, int source, int tag, T* values, int n)
: legacy_handler(comm, source, tag),
extra(comm, values, n) {
BOOST_MPI_CHECK_RESULT(MPI_Irecv,
(&this->extra::m_count, 1,
get_mpi_datatype(this->extra::m_count),
source, tag, comm, m_requests+0));
}
status wait() {
status stat;
if (m_requests[1] == MPI_REQUEST_NULL) {
// Wait for the count message to complete
BOOST_MPI_CHECK_RESULT(MPI_Wait,
(m_requests, &stat.m_status));
// Resize our buffer and get ready to receive its data
this->extra::m_ia.resize(this->extra::m_count);
BOOST_MPI_CHECK_RESULT(MPI_Irecv,
(this->extra::m_ia.address(), this->extra::m_ia.size(), MPI_PACKED,
stat.source(), stat.tag(),
MPI_Comm(m_comm), m_requests + 1));
}
// Wait until we have received the entire message
BOOST_MPI_CHECK_RESULT(MPI_Wait,
(m_requests + 1, &stat.m_status));
this->deserialize(stat);
return stat;
}
optional<status> test() {
status stat;
int flag = 0;
if (m_requests[1] == MPI_REQUEST_NULL) {
// Check if the count message has completed
BOOST_MPI_CHECK_RESULT(MPI_Test,
(m_requests, &flag, &stat.m_status));
if (flag) {
// Resize our buffer and get ready to receive its data
this->extra::m_ia.resize(this->extra::m_count);
BOOST_MPI_CHECK_RESULT(MPI_Irecv,
(this->extra::m_ia.address(), this->extra::m_ia.size(),MPI_PACKED,
stat.source(), stat.tag(),
MPI_Comm(m_comm), 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,
(m_requests + 1, &flag, &stat.m_status));
if (flag) {
this->deserialize(stat);
return stat;
} else
return optional<status>();
}
};
template<typename T, class A>
class request::legacy_dynamic_primitive_array_handler
: public request::legacy_handler,
protected detail::dynamic_array_irecv_data<T,A>
{
typedef detail::dynamic_array_irecv_data<T,A> extra;
public:
legacy_dynamic_primitive_array_handler(communicator const& comm, int source, int tag, std::vector<T,A>& values)
: legacy_handler(comm, source, tag),
extra(values) {
BOOST_MPI_CHECK_RESULT(MPI_Irecv,
(&this->extra::m_count, 1,
get_mpi_datatype(this->extra::m_count),
source, tag, comm, m_requests+0));
}
status wait() {
status stat;
if (m_requests[1] == MPI_REQUEST_NULL) {
// Wait for the count message to complete
BOOST_MPI_CHECK_RESULT(MPI_Wait,
(m_requests, &stat.m_status));
// Resize our buffer and get ready to receive its data
this->extra::m_values.resize(this->extra::m_count);
BOOST_MPI_CHECK_RESULT(MPI_Irecv,
(detail::c_data(this->extra::m_values), this->extra::m_values.size(), get_mpi_datatype<T>(),
stat.source(), stat.tag(),
MPI_Comm(m_comm), m_requests + 1));
}
// Wait until we have received the entire message
BOOST_MPI_CHECK_RESULT(MPI_Wait,
(m_requests + 1, &stat.m_status));
return stat;
}
optional<status> test() {
status stat;
int flag = 0;
if (m_requests[1] == MPI_REQUEST_NULL) {
// Check if the count message has completed
BOOST_MPI_CHECK_RESULT(MPI_Test,
(m_requests, &flag, &stat.m_status));
if (flag) {
// Resize our buffer and get ready to receive its data
this->extra::m_values.resize(this->extra::m_count);
BOOST_MPI_CHECK_RESULT(MPI_Irecv,
(detail::c_data(this->extra::m_values), this->extra::m_values.size(), get_mpi_datatype<T>(),
stat.source(), stat.tag(),
MPI_Comm(m_comm), 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,
(m_requests + 1, &flag, &stat.m_status));
if (flag) {
return stat;
} else
return optional<status>();
}
};
class BOOST_MPI_DECL request::trivial_handler : public request::handler {
public:
trivial_handler();
status wait();
optional<status> test();
void cancel();
bool active() const;
optional<MPI_Request&> trivial();
private:
friend class request;
MPI_Request m_request;
};
class request::dynamic_handler : public request::handler {
dynamic_handler();
status wait();
optional<status> test();
void cancel();
bool active() const;
optional<MPI_Request&> trivial();
private:
friend class request;
MPI_Request m_requests[2];
};
template<typename T>
request request::make_serialized(communicator const& comm, int source, int tag, T& value) {
#if defined(BOOST_MPI_USE_IMPROBE)
return request(new probe_handler<detail::serialized_data<T> >(comm, source, tag, value));
#else
return request(new legacy_serialized_handler<T>(comm, source, tag, value));
#endif
}
template<typename T>
request request::make_serialized_array(communicator const& comm, int source, int tag, T* values, int n) {
#if defined(BOOST_MPI_USE_IMPROBE)
return request(new probe_handler<detail::serialized_array_data<T> >(comm, source, tag, values, n));
#else
return request(new legacy_serialized_array_handler<T>(comm, source, tag, values, n));
#endif
}
template<typename T, class A>
request request::make_dynamic_primitive_array_recv(communicator const& comm, int source, int tag,
std::vector<T,A>& values) {
#if defined(BOOST_MPI_USE_IMPROBE)
return request(new probe_handler<detail::dynamic_primitive_array_data<std::vector<T,A> > >(comm,source,tag,values));
#else
return request(new legacy_dynamic_primitive_array_handler<T,A>(comm, source, tag, values));
#endif
}
template<typename T>
request
request::make_trivial_send(communicator const& comm, int dest, int tag, T const* values, int n) {
trivial_handler* handler = new trivial_handler;
BOOST_MPI_CHECK_RESULT(MPI_Isend,
(const_cast<T*>(values), n,
get_mpi_datatype<T>(),
dest, tag, comm, &handler->m_request));
return request(handler);
}
template<typename T>
request
request::make_trivial_send(communicator const& comm, int dest, int tag, T const& value) {
return make_trivial_send(comm, dest, tag, &value, 1);
}
template<typename T>
request
request::make_trivial_recv(communicator const& comm, int dest, int tag, T* values, int n) {
trivial_handler* handler = new trivial_handler;
BOOST_MPI_CHECK_RESULT(MPI_Irecv,
(values, n,
get_mpi_datatype<T>(),
dest, tag, comm, &handler->m_request));
return request(handler);
}
template<typename T>
request
request::make_trivial_recv(communicator const& comm, int dest, int tag, T& value) {
return make_trivial_recv(comm, dest, tag, &value, 1);
}
template<typename T, class A>
request request::make_dynamic_primitive_array_send(communicator const& comm, int dest, int tag,
std::vector<T,A> const& values) {
#if defined(BOOST_MPI_USE_IMPROBE)
return make_trivial_send(comm, dest, tag, values.data(), values.size());
#else
{
// non blocking recv by legacy_dynamic_primitive_array_handler
// blocking recv by status recv_vector(source,tag,value,primitive)
boost::shared_ptr<std::size_t> size(new std::size_t(values.size()));
dynamic_handler* handler = new dynamic_handler;
request req(handler);
req.preserve(size);
BOOST_MPI_CHECK_RESULT(MPI_Isend,
(size.get(), 1,
get_mpi_datatype(*size),
dest, tag, comm, handler->m_requests+0));
BOOST_MPI_CHECK_RESULT(MPI_Isend,
(const_cast<T*>(values.data()), *size,
get_mpi_datatype<T>(),
dest, tag, comm, handler->m_requests+1));
return req;
}
#endif
}
inline
request::legacy_handler::legacy_handler(communicator const& comm, int source, int tag)
: m_comm(comm),
m_source(source),
m_tag(tag)
{
m_requests[0] = MPI_REQUEST_NULL;
m_requests[1] = MPI_REQUEST_NULL;
}
}}
#endif // BOOST_MPI_REQUEST_HANDLERS_HPP

View File

@@ -28,14 +28,14 @@ namespace threading {
enum level {
/** Only one thread will execute.
*/
single = MPI_THREAD_SINGLE,
single,
/** Only main thread will do MPI calls.
*
* The process may be multi-threaded, but only the main
* thread will make MPI calls (all MPI calls are ``funneled''
* to the main thread).
*/
funneled = MPI_THREAD_FUNNELED,
funneled,
/** Only one thread at the time do MPI calls.
*
* The process may be multi-threaded, and multiple
@@ -43,12 +43,12 @@ enum level {
* MPI calls are not made concurrently from two distinct
* threads (all MPI calls are ``serialized'').
*/
serialized = MPI_THREAD_SERIALIZED,
serialized,
/** Multiple thread may do MPI calls.
*
* Multiple threads may call MPI, with no restrictions.
*/
multiple = MPI_THREAD_MULTIPLE
multiple
};
/** Formated output for threading level. */
@@ -271,6 +271,17 @@ public:
*/
static std::pair<int, int> version();
/** @brief MPI library implementation version string.
*
* This routine returns a string with an additional library version
* information. The actual form of this version string is unspecified,
* but may be documented by the underlying MPI implementation.
* This routine is implemented as a call to @c MPI_Get_library_version,
* which is available from MPI-3. On older implementations the empty
* string will be returned.
*/
static std::string library_version();
private:
/// Whether this environment object called MPI_Init
bool i_initialized;

View File

@@ -28,7 +28,6 @@
// Headers required to implement graph topologies
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/properties.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/iterator/counting_iterator.hpp>
#include <boost/graph/iteration_macros.hpp>
#include <boost/shared_array.hpp>
@@ -236,8 +235,8 @@ graph_communicator::setup_graph(const communicator& comm, const Graph& graph,
BOOST_MPI_CHECK_RESULT(MPI_Graph_create,
((MPI_Comm)comm,
nvertices,
&indices[0],
edges.empty()? (int*)0 : &edges[0],
detail::c_data(indices),
detail::c_data(edges),
reorder,
&newcomm));
this->comm_ptr.reset(new MPI_Comm(newcomm), comm_free());

View File

@@ -16,6 +16,7 @@
#define BOOST_MPI_GROUP_HPP
#include <boost/mpi/exception.hpp>
#include <boost/mpi/detail/antiques.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/optional.hpp>
#include <vector>
@@ -272,9 +273,9 @@ group::translate_ranks(InputIterator first, InputIterator last,
BOOST_MPI_CHECK_RESULT(MPI_Group_translate_ranks,
((MPI_Group)*this,
in_array.size(),
&in_array[0],
detail::c_data(in_array),
(MPI_Group)to_group,
&out_array[0]));
detail::c_data(out_array)));
for (std::vector<int>::size_type i = 0, n = out_array.size(); i < n; ++i)
*out++ = out_array[i];
@@ -300,7 +301,7 @@ group group::include(InputIterator first, InputIterator last)
std::vector<int> ranks(first, last);
MPI_Group result;
BOOST_MPI_CHECK_RESULT(MPI_Group_incl,
((MPI_Group)*this, ranks.size(), &ranks[0], &result));
((MPI_Group)*this, ranks.size(), detail::c_data(ranks), &result));
return group(result, /*adopt=*/true);
}
@@ -322,7 +323,7 @@ group group::exclude(InputIterator first, InputIterator last)
std::vector<int> ranks(first, last);
MPI_Group result;
BOOST_MPI_CHECK_RESULT(MPI_Group_excl,
((MPI_Group)*this, ranks.size(), &ranks[0], &result));
((MPI_Group)*this, ranks.size(), detail::c_data(ranks), &result));
return group(result, /*adopt=*/true);
}

View File

@@ -59,10 +59,7 @@ wait_any(ForwardIterator first, ForwardIterator last)
ForwardIterator current = first;
while (true) {
// Check if we have found a completed request. If so, return it.
bool current_is_active =
( current->m_requests[0] != MPI_REQUEST_NULL ||
current->m_requests[1] != MPI_REQUEST_NULL) ;
if (current_is_active) {
if (current->active()) {
optional<status> result = current->test();
if (bool(result)) {
return std::make_pair(*result, current);
@@ -75,10 +72,7 @@ wait_any(ForwardIterator first, ForwardIterator last)
// 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;
all_trivial_requests = all_trivial_requests && current->trivial();
// Move to the next request.
++n;
@@ -89,14 +83,15 @@ wait_any(ForwardIterator first, ForwardIterator last)
if (all_trivial_requests) {
std::vector<MPI_Request> requests;
requests.reserve(n);
for (current = first; current != last; ++current)
requests.push_back(current->m_requests[0]);
for (current = first; current != last; ++current) {
requests.push_back(*current->trivial());
}
// Let MPI wait until one of these operations completes.
int index;
status stat;
BOOST_MPI_CHECK_RESULT(MPI_Waitany,
(n, &requests[0], &index, &stat.m_status));
(n, detail::c_data(requests), &index, &stat.m_status));
// We don't have a notion of empty requests or status objects,
// so this is an error.
@@ -106,7 +101,7 @@ wait_any(ForwardIterator first, ForwardIterator last)
// Find the iterator corresponding to the completed request.
current = first;
advance(current, index);
current->m_requests[0] = requests[index];
*current->trivial() = requests[index];
return std::make_pair(stat, current);
}
@@ -199,7 +194,10 @@ wait_all(ForwardIterator first, ForwardIterator last, OutputIterator out)
difference_type idx = 0;
for (ForwardIterator current = first; current != last; ++current, ++idx) {
if (!completed[idx]) {
if (optional<status> stat = current->test()) {
if (!current->active()) {
completed[idx] = true;
--num_outstanding_requests;
} else if (optional<status> stat = current->test()) {
// This outstanding request has been completed. We're done.
results[idx] = *stat;
completed[idx] = true;
@@ -209,10 +207,7 @@ wait_all(ForwardIterator first, ForwardIterator last, OutputIterator out)
// 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;
all_trivial_requests = all_trivial_requests && current->trivial();
}
}
}
@@ -225,13 +220,13 @@ wait_all(ForwardIterator first, ForwardIterator last, OutputIterator out)
std::vector<MPI_Request> requests;
requests.reserve(num_outstanding_requests);
for (ForwardIterator current = first; current != last; ++current)
requests.push_back(current->m_requests[0]);
requests.push_back(*current->trivial());
// Let MPI wait until all of these operations completes.
std::vector<MPI_Status> stats(num_outstanding_requests);
BOOST_MPI_CHECK_RESULT(MPI_Waitall,
(num_outstanding_requests, &requests[0],
&stats[0]));
(num_outstanding_requests, detail::c_data(requests),
detail::c_data(stats)));
for (std::vector<MPI_Status>::iterator i = stats.begin();
i != stats.end(); ++i, ++out) {
@@ -263,7 +258,7 @@ wait_all(ForwardIterator first, ForwardIterator last)
difference_type num_outstanding_requests = distance(first, last);
std::vector<bool> completed(num_outstanding_requests);
std::vector<bool> completed(num_outstanding_requests, false);
while (num_outstanding_requests > 0) {
bool all_trivial_requests = true;
@@ -271,7 +266,10 @@ wait_all(ForwardIterator first, ForwardIterator last)
difference_type idx = 0;
for (ForwardIterator current = first; current != last; ++current, ++idx) {
if (!completed[idx]) {
if (optional<status> stat = current->test()) {
if (!current->active()) {
completed[idx] = true;
--num_outstanding_requests;
} else if (optional<status> stat = current->test()) {
// This outstanding request has been completed.
completed[idx] = true;
--num_outstanding_requests;
@@ -280,10 +278,7 @@ wait_all(ForwardIterator first, ForwardIterator last)
// 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;
all_trivial_requests = all_trivial_requests && current->trivial();
}
}
}
@@ -296,11 +291,11 @@ wait_all(ForwardIterator first, ForwardIterator last)
std::vector<MPI_Request> requests;
requests.reserve(num_outstanding_requests);
for (ForwardIterator current = first; current != last; ++current)
requests.push_back(current->m_requests[0]);
requests.push_back(*current->trivial());
// Let MPI wait until all of these operations completes.
BOOST_MPI_CHECK_RESULT(MPI_Waitall,
(num_outstanding_requests, &requests[0],
(num_outstanding_requests, detail::c_data(requests),
MPI_STATUSES_IGNORE));
// Signal completion
@@ -348,16 +343,16 @@ test_all(ForwardIterator first, ForwardIterator last, OutputIterator out)
for (; first != last; ++first) {
// If we have a non-trivial request, then no requests can be
// completed.
if (first->m_handler || first->m_requests[1] != MPI_REQUEST_NULL)
if (!first->trivial()) {
return optional<OutputIterator>();
requests.push_back(first->m_requests[0]);
}
requests.push_back(*first->trivial());
}
int flag = 0;
int n = requests.size();
std::vector<MPI_Status> stats(n);
BOOST_MPI_CHECK_RESULT(MPI_Testall, (n, &requests[0], &flag, &stats[0]));
BOOST_MPI_CHECK_RESULT(MPI_Testall, (n, detail::c_data(requests), &flag, detail::c_data(stats)));
if (flag) {
for (int i = 0; i < n; ++i, ++out) {
status stat;
@@ -381,16 +376,16 @@ test_all(ForwardIterator first, ForwardIterator last)
for (; first != last; ++first) {
// If we have a non-trivial request, then no requests can be
// completed.
if (first->m_handler || first->m_requests[1] != MPI_REQUEST_NULL)
if (!first->trivial()) {
return false;
requests.push_back(first->m_requests[0]);
}
requests.push_back(*first->trivial());
}
int flag = 0;
int n = requests.size();
BOOST_MPI_CHECK_RESULT(MPI_Testall,
(n, &requests[0], &flag, MPI_STATUSES_IGNORE));
(n, detail::c_data(requests), &flag, MPI_STATUSES_IGNORE));
return flag != 0;
}
@@ -467,10 +462,7 @@ wait_some(BidirectionalIterator first, BidirectionalIterator last,
// 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;
all_trivial_requests = all_trivial_requests && current->trivial();
// Move to the next request.
++n;
@@ -492,13 +484,13 @@ wait_some(BidirectionalIterator first, BidirectionalIterator last,
std::vector<MPI_Status> stats(n);
requests.reserve(n);
for (current = first; current != last; ++current)
requests.push_back(current->m_requests[0]);
requests.push_back(*current->trivial());
// Let MPI wait until some of these operations complete.
int num_completed;
BOOST_MPI_CHECK_RESULT(MPI_Waitsome,
(n, &requests[0], &num_completed, &indices[0],
&stats[0]));
(n, detail::c_data(requests), &num_completed, detail::c_data(indices),
detail::c_data(stats)));
// Translate the index-based result of MPI_Waitsome into a
// partitioning on the requests.
@@ -518,7 +510,7 @@ wait_some(BidirectionalIterator first, BidirectionalIterator last,
// Finish up the request and swap it into the "completed
// requests" partition.
current->m_requests[0] = requests[indices[index]];
*current->trivial() = requests[indices[index]];
--start_of_completed;
iter_swap(current, start_of_completed);
}
@@ -583,10 +575,7 @@ wait_some(BidirectionalIterator first, BidirectionalIterator last)
// 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;
all_trivial_requests = all_trivial_requests && current->trivial();
// Move to the next request.
++n;
@@ -603,12 +592,12 @@ wait_some(BidirectionalIterator first, BidirectionalIterator last)
std::vector<int> indices(n);
requests.reserve(n);
for (current = first; current != last; ++current)
requests.push_back(current->m_requests[0]);
requests.push_back(*current->trivial());
// Let MPI wait until some of these operations complete.
int num_completed;
BOOST_MPI_CHECK_RESULT(MPI_Waitsome,
(n, &requests[0], &num_completed, &indices[0],
(n, detail::c_data(requests), &num_completed, detail::c_data(indices),
MPI_STATUSES_IGNORE));
// Translate the index-based result of MPI_Waitsome into a
@@ -624,7 +613,7 @@ wait_some(BidirectionalIterator first, BidirectionalIterator last)
// Finish up the request and swap it into the "completed
// requests" partition.
current->m_requests[0] = requests[indices[index]];
*current->trivial() = requests[indices[index]];
--start_of_completed;
iter_swap(current, start_of_completed);
}

View File

@@ -23,7 +23,8 @@
#include <boost/mpl/if.hpp>
#include <boost/mpl/and.hpp>
#include <boost/mpi/datatype.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/core/enable_if.hpp>
#include <boost/core/uncaught_exceptions.hpp>
#include <functional>
namespace boost { namespace mpi {
@@ -302,7 +303,7 @@ namespace detail {
~user_op()
{
if (std::uncaught_exception()) {
if (boost::core::uncaught_exceptions() > 0) {
// Ignore failure cases: there are obviously other problems
// already, and we don't want to cause program termination if
// MPI_Op_free fails.

View File

@@ -45,6 +45,8 @@
#define BOOST_MPI_PYTHON_FORWARD_ONLY
#include <boost/mpi/python.hpp>
#include "bytesobject.h"
/************************************************************************
* Boost.Python Serialization Section *
************************************************************************/
@@ -140,8 +142,8 @@ class BOOST_MPI_PYTHON_DECL pickle {
struct data_t;
public:
static str dumps(object obj, int protocol = -1);
static object loads(str s);
static object dumps(object obj, int protocol = -1);
static object loads(object s);
private:
static void initialize_data();
@@ -399,10 +401,10 @@ save_impl(Archiver& ar, const boost::python::object& obj,
const unsigned int /*version*/,
mpl::false_ /*has_direct_serialization*/)
{
boost::python::str py_string = boost::python::pickle::dumps(obj);
int len = boost::python::extract<int>(py_string.attr("__len__")());
const char* string = boost::python::extract<const char*>(py_string);
ar << len << boost::serialization::make_array(string, len);
boost::python::object bytes = boost::python::pickle::dumps(obj);
int sz = PyBytes_Size(bytes.ptr());
char *data = PyBytes_AsString(bytes.ptr());
ar << sz << boost::serialization::make_array(data, sz);
}
/// Try to save a Python object by directly serializing it; fall back
@@ -441,11 +443,10 @@ load_impl(Archiver& ar, boost::python::object& obj,
{
int len;
ar >> len;
boost::scoped_array<char> string(new char[len]);
ar >> boost::serialization::make_array(string.get(), len);
boost::python::str py_string(string.get(), len);
obj = boost::python::pickle::loads(py_string);
boost::scoped_array<char> data(new char[len]);
ar >> boost::serialization::make_array(data.get(), len);
boost::python::object bytes(boost::python::handle<>(PyBytes_FromStringAndSize(data.get(), len)));
obj = boost::python::pickle::loads(bytes);
}
/// Try to load a Python object by directly deserializing it; fall back
@@ -487,7 +488,6 @@ save(Archiver& ar, const boost::python::object& obj,
{
typedef Archiver OArchiver;
typedef typename input_archiver<OArchiver>::type IArchiver;
detail::save_impl(ar, obj, version,
has_direct_serialization<IArchiver, OArchiver>());
}
@@ -499,7 +499,6 @@ load(Archiver& ar, boost::python::object& obj,
{
typedef Archiver IArchiver;
typedef typename output_archiver<IArchiver>::type OArchiver;
detail::load_impl(ar, obj, version,
has_direct_serialization<IArchiver, OArchiver>());
}

View File

@@ -13,6 +13,7 @@
#define BOOST_MPI_REQUEST_HPP
#include <boost/mpi/config.hpp>
#include <boost/mpi/status.hpp>
#include <boost/optional.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/mpi/packed_iarchive.hpp>
@@ -37,12 +38,61 @@ class BOOST_MPI_DECL request
*/
request();
/**
* Send a known number of primitive objects in one MPI request.
*/
template<typename T>
static request make_trivial_send(communicator const& comm, int dest, int tag, T const& value);
template<typename T>
static request make_trivial_send(communicator const& comm, int dest, int tag, T const* values, int n);
static request make_packed_send(communicator const& comm, int dest, int tag, void const* values, std::size_t n);
static request make_bottom_send(communicator const& comm, int dest, int tag, MPI_Datatype tp);
static request make_empty_send(communicator const& comm, int dest, int tag);
/**
* Receive a known number of primitive objects in one MPI request.
*/
template<typename T>
static request make_trivial_recv(communicator const& comm, int dest, int tag, T& value);
template<typename T>
static request make_trivial_recv(communicator const& comm, int dest, int tag, T* values, int n);
static request make_bottom_recv(communicator const& comm, int dest, int tag, MPI_Datatype tp);
static request make_empty_recv(communicator const& comm, int dest, int tag);
/**
* Construct request for simple data of unknown size.
*/
static request make_dynamic();
/**
* Constructs request for serialized data.
*/
template<typename T>
static request make_serialized(communicator const& comm, int source, int tag, T& value);
/**
* Constructs request for array of complex data.
*/
template<typename T>
static request make_serialized_array(communicator const& comm, int source, int tag, T* values, int n);
/**
* Request to recv array of primitive data.
*/
template<typename T, class A>
static request
make_dynamic_primitive_array_recv(communicator const& comm, int source, int tag,
std::vector<T,A>& values);
/**
* Request to send array of primitive data.
*/
template<typename T, class A>
static request
make_dynamic_primitive_array_send(communicator const& comm, int source, int tag,
std::vector<T,A> const& values);
/**
* Wait until the communication associated with this request has
* completed, then return a @c status object describing the
* communication.
*/
status wait();
status wait() { return m_handler ? m_handler->wait() : status(); }
/**
* Determine whether the communication associated with this request
@@ -52,58 +102,58 @@ class BOOST_MPI_DECL request
* yet. Note that once @c test() returns a @c status object, the
* request has completed and @c wait() should not be called.
*/
optional<status> test();
optional<status> test() { return active() ? m_handler->test() : optional<status>(); }
/**
* Cancel a pending communication, assuming it has not already been
* completed.
*/
void cancel();
void cancel() { if (m_handler) { m_handler->cancel(); } m_preserved.reset(); }
/**
* The trivial MPI requet implenting this request, provided it's trivial.
* Probably irrelevant to most users.
*/
optional<MPI_Request&> trivial() { return (m_handler
? m_handler->trivial()
: optional<MPI_Request&>()); }
/**
* Is this request potentialy pending ?
*/
bool active() const { return bool(m_handler) && m_handler->active(); }
// Some data might need protection while the reqest is processed.
void preserve(boost::shared_ptr<void> d);
class handler {
public:
virtual BOOST_MPI_DECL ~handler() = 0;
virtual status wait() = 0;
virtual optional<status> test() = 0;
virtual void cancel() = 0;
virtual bool active() const = 0;
virtual optional<MPI_Request&> trivial() = 0;
};
private:
enum request_action { ra_wait, ra_test, ra_cancel };
typedef optional<status> (*handler_type)(request* self,
request_action action);
request(handler *h) : m_handler(h) {};
/**
* INTERNAL ONLY
*
* Handles the non-blocking receive of a serialized value.
*/
template<typename T>
static optional<status>
handle_serialized_irecv(request* self, request_action action);
/**
* INTERNAL ONLY
*
* Handles the non-blocking receive of an array of serialized values.
*/
template<typename T>
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
MPI_Request m_requests[2];
/// INTERNAL ONLY
handler_type m_handler;
/// INTERNAL ONLY
shared_ptr<void> m_data;
friend class communicator;
// specific implementations
class legacy_handler;
class trivial_handler;
class dynamic_handler;
template<typename T> class legacy_serialized_handler;
template<typename T> class legacy_serialized_array_handler;
template<typename T, class A> class legacy_dynamic_primitive_array_handler;
#if BOOST_MPI_VERSION >= 3
template<class Data> class probe_handler;
#endif
private:
shared_ptr<handler> m_handler;
shared_ptr<void> m_preserved;
};
} } // end namespace boost::mpi

View File

@@ -25,338 +25,10 @@
#include <boost/mpi/config.hpp>
#include <boost/archive/detail/auto_link_archive.hpp>
#include <boost/mpi/packed_iarchive.hpp>
#include <boost/mpi/packed_oarchive.hpp>
#include <boost/mpi/detail/forward_skeleton_iarchive.hpp>
#include <boost/mpi/detail/forward_skeleton_oarchive.hpp>
#include <boost/mpi/detail/ignore_iprimitive.hpp>
#include <boost/mpi/detail/ignore_oprimitive.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/archive/detail/register_archive.hpp>
#include <boost/mpi/skeleton_and_content_types.hpp>
namespace boost { namespace mpi {
/**
* @brief A proxy that requests that the skeleton of an object be
* transmitted.
*
* The @c skeleton_proxy is a lightweight proxy object used to
* indicate that the skeleton of an object, not the object itself,
* should be transmitted. It can be used with the @c send and @c recv
* operations of communicators or the @c broadcast collective. When a
* @c skeleton_proxy is sent, Boost.MPI generates a description
* containing the structure of the stored object. When that skeleton
* is received, the receiving object is reshaped to match the
* structure. Once the skeleton of an object as been transmitted, its
* @c content can be transmitted separately (often several times)
* without changing the structure of the object.
*/
template <class T>
struct BOOST_MPI_DECL skeleton_proxy
{
/**
* Constructs a @c skeleton_proxy that references object @p x.
*
* @param x the object whose structure will be transmitted or
* altered.
*/
skeleton_proxy(T& x)
: object(x)
{}
T& object;
};
/**
* @brief Create a skeleton proxy object.
*
* This routine creates an instance of the skeleton_proxy class. It
* will typically be used when calling @c send, @c recv, or @c
* broadcast, to indicate that only the skeleton (structure) of an
* object should be transmitted and not its contents.
*
* @param x the object whose structure will be transmitted.
*
* @returns a skeleton_proxy object referencing @p x
*/
template <class T>
inline const skeleton_proxy<T> skeleton(T& x)
{
return skeleton_proxy<T>(x);
}
namespace detail {
/// @brief a class holding an MPI datatype
/// INTERNAL ONLY
/// the type is freed upon destruction
class BOOST_MPI_DECL mpi_datatype_holder : public boost::noncopyable
{
public:
mpi_datatype_holder()
: is_committed(false)
{}
mpi_datatype_holder(MPI_Datatype t, bool committed = true)
: d(t)
, is_committed(committed)
{}
void commit()
{
BOOST_MPI_CHECK_RESULT(MPI_Type_commit,(&d));
is_committed=true;
}
MPI_Datatype get_mpi_datatype() const
{
return d;
}
~mpi_datatype_holder()
{
int finalized=0;
BOOST_MPI_CHECK_RESULT(MPI_Finalized,(&finalized));
if (!finalized && is_committed)
BOOST_MPI_CHECK_RESULT(MPI_Type_free,(&d));
}
private:
MPI_Datatype d;
bool is_committed;
};
} // end namespace detail
/** @brief A proxy object that transfers the content of an object
* without its structure.
*
* The @c content class indicates that Boost.MPI should transmit or
* receive the content of an object, but without any information
* about the structure of the object. It is only meaningful to
* transmit the content of an object after the receiver has already
* received the skeleton for the same object.
*
* Most users will not use @c content objects directly. Rather, they
* will invoke @c send, @c recv, or @c broadcast operations using @c
* get_content().
*/
class BOOST_MPI_DECL content
{
public:
/**
* Constructs an empty @c content object. This object will not be
* useful for any Boost.MPI operations until it is reassigned.
*/
content() {}
/**
* This routine initializes the @c content object with an MPI data
* type that refers to the content of an object without its structure.
*
* @param d the MPI data type referring to the content of the object.
*
* @param committed @c true indicates that @c MPI_Type_commit has
* already been excuted for the data type @p d.
*/
content(MPI_Datatype d, bool committed=true)
: holder(new detail::mpi_datatype_holder(d,committed))
{}
/**
* Replace the MPI data type referencing the content of an object.
*
* @param d the new MPI data type referring to the content of the
* object.
*
* @returns *this
*/
const content& operator=(MPI_Datatype d)
{
holder.reset(new detail::mpi_datatype_holder(d));
return *this;
}
/**
* Retrieve the MPI data type that refers to the content of the
* object.
*
* @returns the MPI data type, which should only be transmitted or
* received using @c MPI_BOTTOM as the address.
*/
MPI_Datatype get_mpi_datatype() const
{
return holder->get_mpi_datatype();
}
/**
* Commit the MPI data type referring to the content of the
* object.
*/
void commit()
{
holder->commit();
}
private:
boost::shared_ptr<detail::mpi_datatype_holder> holder;
};
/** @brief Returns the content of an object, suitable for transmission
* via Boost.MPI.
*
* The function creates an absolute MPI datatype for the object,
* where all offsets are counted from the address 0 (a.k.a. @c
* MPI_BOTTOM) instead of the address @c &x of the object. This
* allows the creation of MPI data types for complex data structures
* containing pointers, such as linked lists or trees.
*
* The disadvantage, compared to relative MPI data types is that for
* each object a new MPI data type has to be created.
*
* The contents of an object can only be transmitted when the
* receiver already has an object with the same structure or shape as
* the sender. To accomplish this, first transmit the skeleton of the
* object using, e.g., @c skeleton() or @c skeleton_proxy.
*
* The type @c T has to allow creation of an absolute MPI data type
* (content).
*
* @param x the object for which the content will be transmitted.
*
* @returns the content of the object @p x, which can be used for
* transmission via @c send, @c recv, or @c broadcast.
*/
template <class T> const content get_content(const T& x);
/** @brief An archiver that reconstructs a data structure based on the
* binary skeleton stored in a buffer.
*
* The @c packed_skeleton_iarchive class is an Archiver (as in the
* Boost.Serialization library) that can construct the the shape of a
* data structure based on a binary skeleton stored in a buffer. The
* @c packed_skeleton_iarchive is typically used by the receiver of a
* skeleton, to prepare a data structure that will eventually receive
* content separately.
*
* Users will not generally need to use @c packed_skeleton_iarchive
* directly. Instead, use @c skeleton or @c get_skeleton.
*/
class BOOST_MPI_DECL packed_skeleton_iarchive
: public detail::ignore_iprimitive,
public detail::forward_skeleton_iarchive<packed_skeleton_iarchive,packed_iarchive>
{
public:
/**
* Construct a @c packed_skeleton_iarchive for the given
* communicator.
*
* @param comm The communicator over which this archive will be
* transmitted.
*
* @param flags Control the serialization of the skeleton. Refer to
* the Boost.Serialization documentation before changing the
* default flags.
*/
packed_skeleton_iarchive(MPI_Comm const & comm,
unsigned int flags = boost::archive::no_header)
: detail::forward_skeleton_iarchive<packed_skeleton_iarchive,packed_iarchive>(skeleton_archive_)
, skeleton_archive_(comm,flags)
{}
/**
* Construct a @c packed_skeleton_iarchive that unpacks a skeleton
* from the given @p archive.
*
* @param archive the archive from which the skeleton will be
* unpacked.
*
*/
explicit packed_skeleton_iarchive(packed_iarchive & archive)
: detail::forward_skeleton_iarchive<packed_skeleton_iarchive,packed_iarchive>(archive)
, skeleton_archive_(MPI_COMM_WORLD, boost::archive::no_header)
{}
/**
* Retrieve the archive corresponding to this skeleton.
*/
const packed_iarchive& get_skeleton() const
{
return this->implementation_archive;
}
/**
* Retrieve the archive corresponding to this skeleton.
*/
packed_iarchive& get_skeleton()
{
return this->implementation_archive;
}
private:
/// Store the actual archive that holds the structure, unless the
/// user overrides this with their own archive.
packed_iarchive skeleton_archive_;
};
/** @brief An archiver that records the binary skeleton of a data
* structure into a buffer.
*
* The @c packed_skeleton_oarchive class is an Archiver (as in the
* Boost.Serialization library) that can record the shape of a data
* structure (called the "skeleton") into a binary representation
* stored in a buffer. The @c packed_skeleton_oarchive is typically
* used by the send of a skeleton, to pack the skeleton of a data
* structure for transmission separately from the content.
*
* Users will not generally need to use @c packed_skeleton_oarchive
* directly. Instead, use @c skeleton or @c get_skeleton.
*/
class BOOST_MPI_DECL packed_skeleton_oarchive
: public detail::ignore_oprimitive,
public detail::forward_skeleton_oarchive<packed_skeleton_oarchive,packed_oarchive>
{
public:
/**
* Construct a @c packed_skeleton_oarchive for the given
* communicator.
*
* @param comm The communicator over which this archive will be
* transmitted.
*
* @param flags Control the serialization of the skeleton. Refer to
* the Boost.Serialization documentation before changing the
* default flags.
*/
packed_skeleton_oarchive(MPI_Comm const & comm,
unsigned int flags = boost::archive::no_header)
: detail::forward_skeleton_oarchive<packed_skeleton_oarchive,packed_oarchive>(skeleton_archive_)
, skeleton_archive_(comm,flags)
{}
/**
* Construct a @c packed_skeleton_oarchive that packs a skeleton
* into the given @p archive.
*
* @param archive the archive to which the skeleton will be packed.
*
*/
explicit packed_skeleton_oarchive(packed_oarchive & archive)
: detail::forward_skeleton_oarchive<packed_skeleton_oarchive,packed_oarchive>(archive)
, skeleton_archive_(MPI_COMM_WORLD, boost::archive::no_header)
{}
/**
* Retrieve the archive corresponding to this skeleton.
*/
const packed_oarchive& get_skeleton() const
{
return this->implementation_archive;
}
private:
/// Store the actual archive that holds the structure.
packed_oarchive skeleton_archive_;
};
namespace detail {
typedef boost::mpi::detail::forward_skeleton_oarchive<boost::mpi::packed_skeleton_oarchive,boost::mpi::packed_oarchive> type1;
typedef boost::mpi::detail::forward_skeleton_iarchive<boost::mpi::packed_skeleton_iarchive,boost::mpi::packed_iarchive> type2;

View File

@@ -0,0 +1,363 @@
// (C) Copyright 2005 Matthias Troyer
// (C) Copyright 2006 Douglas Gregor <doug.gregor -at gmail.com>
// 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)
// Authors: Matthias Troyer
// Douglas Gregor
/** @file skeleton_and_content.hpp
*
* This header provides facilities that allow the structure of data
* types (called the "skeleton") to be transmitted and received
* separately from the content stored in those data types. These
* facilities are useful when the data in a stable data structure
* (e.g., a mesh or a graph) will need to be transmitted
* repeatedly. In this case, transmitting the skeleton only once
* saves both communication effort (it need not be sent again) and
* local computation (serialization need only be performed once for
* the content).
*/
#ifndef BOOST_MPI_SKELETON_AND_CONTENT_TYPES_HPP
#define BOOST_MPI_SKELETON_AND_CONTENT_TYPES_HPP
#include <boost/mpi/config.hpp>
#include <boost/archive/detail/auto_link_archive.hpp>
#include <boost/mpi/packed_iarchive.hpp>
#include <boost/mpi/packed_oarchive.hpp>
#include <boost/mpi/detail/forward_skeleton_iarchive.hpp>
#include <boost/mpi/detail/forward_skeleton_oarchive.hpp>
#include <boost/mpi/detail/ignore_iprimitive.hpp>
#include <boost/mpi/detail/ignore_oprimitive.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/archive/detail/register_archive.hpp>
namespace boost { namespace mpi {
/**
* @brief A proxy that requests that the skeleton of an object be
* transmitted.
*
* The @c skeleton_proxy is a lightweight proxy object used to
* indicate that the skeleton of an object, not the object itself,
* should be transmitted. It can be used with the @c send and @c recv
* operations of communicators or the @c broadcast collective. When a
* @c skeleton_proxy is sent, Boost.MPI generates a description
* containing the structure of the stored object. When that skeleton
* is received, the receiving object is reshaped to match the
* structure. Once the skeleton of an object as been transmitted, its
* @c content can be transmitted separately (often several times)
* without changing the structure of the object.
*/
template <class T>
struct BOOST_MPI_DECL skeleton_proxy
{
/**
* Constructs a @c skeleton_proxy that references object @p x.
*
* @param x the object whose structure will be transmitted or
* altered.
*/
skeleton_proxy(T& x)
: object(x)
{}
T& object;
};
/**
* @brief Create a skeleton proxy object.
*
* This routine creates an instance of the skeleton_proxy class. It
* will typically be used when calling @c send, @c recv, or @c
* broadcast, to indicate that only the skeleton (structure) of an
* object should be transmitted and not its contents.
*
* @param x the object whose structure will be transmitted.
*
* @returns a skeleton_proxy object referencing @p x
*/
template <class T>
inline const skeleton_proxy<T> skeleton(T& x)
{
return skeleton_proxy<T>(x);
}
namespace detail {
/// @brief a class holding an MPI datatype
/// INTERNAL ONLY
/// the type is freed upon destruction
class BOOST_MPI_DECL mpi_datatype_holder : public boost::noncopyable
{
public:
mpi_datatype_holder()
: is_committed(false)
{}
mpi_datatype_holder(MPI_Datatype t, bool committed = true)
: d(t)
, is_committed(committed)
{}
void commit()
{
BOOST_MPI_CHECK_RESULT(MPI_Type_commit,(&d));
is_committed=true;
}
MPI_Datatype get_mpi_datatype() const
{
return d;
}
~mpi_datatype_holder()
{
int finalized=0;
BOOST_MPI_CHECK_RESULT(MPI_Finalized,(&finalized));
if (!finalized && is_committed)
BOOST_MPI_CHECK_RESULT(MPI_Type_free,(&d));
}
private:
MPI_Datatype d;
bool is_committed;
};
} // end namespace detail
/** @brief A proxy object that transfers the content of an object
* without its structure.
*
* The @c content class indicates that Boost.MPI should transmit or
* receive the content of an object, but without any information
* about the structure of the object. It is only meaningful to
* transmit the content of an object after the receiver has already
* received the skeleton for the same object.
*
* Most users will not use @c content objects directly. Rather, they
* will invoke @c send, @c recv, or @c broadcast operations using @c
* get_content().
*/
class BOOST_MPI_DECL content
{
public:
/**
* Constructs an empty @c content object. This object will not be
* useful for any Boost.MPI operations until it is reassigned.
*/
content() {}
/**
* This routine initializes the @c content object with an MPI data
* type that refers to the content of an object without its structure.
*
* @param d the MPI data type referring to the content of the object.
*
* @param committed @c true indicates that @c MPI_Type_commit has
* already been excuted for the data type @p d.
*/
content(MPI_Datatype d, bool committed=true)
: holder(new detail::mpi_datatype_holder(d,committed))
{}
/**
* Replace the MPI data type referencing the content of an object.
*
* @param d the new MPI data type referring to the content of the
* object.
*
* @returns *this
*/
const content& operator=(MPI_Datatype d)
{
holder.reset(new detail::mpi_datatype_holder(d));
return *this;
}
/**
* Retrieve the MPI data type that refers to the content of the
* object.
*
* @returns the MPI data type, which should only be transmitted or
* received using @c MPI_BOTTOM as the address.
*/
MPI_Datatype get_mpi_datatype() const
{
return holder->get_mpi_datatype();
}
/**
* Commit the MPI data type referring to the content of the
* object.
*/
void commit()
{
holder->commit();
}
private:
boost::shared_ptr<detail::mpi_datatype_holder> holder;
};
/** @brief Returns the content of an object, suitable for transmission
* via Boost.MPI.
*
* The function creates an absolute MPI datatype for the object,
* where all offsets are counted from the address 0 (a.k.a. @c
* MPI_BOTTOM) instead of the address @c &x of the object. This
* allows the creation of MPI data types for complex data structures
* containing pointers, such as linked lists or trees.
*
* The disadvantage, compared to relative MPI data types is that for
* each object a new MPI data type has to be created.
*
* The contents of an object can only be transmitted when the
* receiver already has an object with the same structure or shape as
* the sender. To accomplish this, first transmit the skeleton of the
* object using, e.g., @c skeleton() or @c skeleton_proxy.
*
* The type @c T has to allow creation of an absolute MPI data type
* (content).
*
* @param x the object for which the content will be transmitted.
*
* @returns the content of the object @p x, which can be used for
* transmission via @c send, @c recv, or @c broadcast.
*/
template <class T> const content get_content(const T& x);
/** @brief An archiver that reconstructs a data structure based on the
* binary skeleton stored in a buffer.
*
* The @c packed_skeleton_iarchive class is an Archiver (as in the
* Boost.Serialization library) that can construct the the shape of a
* data structure based on a binary skeleton stored in a buffer. The
* @c packed_skeleton_iarchive is typically used by the receiver of a
* skeleton, to prepare a data structure that will eventually receive
* content separately.
*
* Users will not generally need to use @c packed_skeleton_iarchive
* directly. Instead, use @c skeleton or @c get_skeleton.
*/
class BOOST_MPI_DECL packed_skeleton_iarchive
: public detail::ignore_iprimitive,
public detail::forward_skeleton_iarchive<packed_skeleton_iarchive,packed_iarchive>
{
public:
/**
* Construct a @c packed_skeleton_iarchive for the given
* communicator.
*
* @param comm The communicator over which this archive will be
* transmitted.
*
* @param flags Control the serialization of the skeleton. Refer to
* the Boost.Serialization documentation before changing the
* default flags.
*/
packed_skeleton_iarchive(MPI_Comm const & comm,
unsigned int flags = boost::archive::no_header)
: detail::forward_skeleton_iarchive<packed_skeleton_iarchive,packed_iarchive>(skeleton_archive_)
, skeleton_archive_(comm,flags)
{}
/**
* Construct a @c packed_skeleton_iarchive that unpacks a skeleton
* from the given @p archive.
*
* @param archive the archive from which the skeleton will be
* unpacked.
*
*/
explicit packed_skeleton_iarchive(packed_iarchive & archive)
: detail::forward_skeleton_iarchive<packed_skeleton_iarchive,packed_iarchive>(archive)
, skeleton_archive_(MPI_COMM_WORLD, boost::archive::no_header)
{}
/**
* Retrieve the archive corresponding to this skeleton.
*/
const packed_iarchive& get_skeleton() const
{
return this->implementation_archive;
}
/**
* Retrieve the archive corresponding to this skeleton.
*/
packed_iarchive& get_skeleton()
{
return this->implementation_archive;
}
private:
/// Store the actual archive that holds the structure, unless the
/// user overrides this with their own archive.
packed_iarchive skeleton_archive_;
};
/** @brief An archiver that records the binary skeleton of a data
* structure into a buffer.
*
* The @c packed_skeleton_oarchive class is an Archiver (as in the
* Boost.Serialization library) that can record the shape of a data
* structure (called the "skeleton") into a binary representation
* stored in a buffer. The @c packed_skeleton_oarchive is typically
* used by the send of a skeleton, to pack the skeleton of a data
* structure for transmission separately from the content.
*
* Users will not generally need to use @c packed_skeleton_oarchive
* directly. Instead, use @c skeleton or @c get_skeleton.
*/
class BOOST_MPI_DECL packed_skeleton_oarchive
: public detail::ignore_oprimitive,
public detail::forward_skeleton_oarchive<packed_skeleton_oarchive,packed_oarchive>
{
public:
/**
* Construct a @c packed_skeleton_oarchive for the given
* communicator.
*
* @param comm The communicator over which this archive will be
* transmitted.
*
* @param flags Control the serialization of the skeleton. Refer to
* the Boost.Serialization documentation before changing the
* default flags.
*/
packed_skeleton_oarchive(MPI_Comm const & comm,
unsigned int flags = boost::archive::no_header)
: detail::forward_skeleton_oarchive<packed_skeleton_oarchive,packed_oarchive>(skeleton_archive_)
, skeleton_archive_(comm,flags)
{}
/**
* Construct a @c packed_skeleton_oarchive that packs a skeleton
* into the given @p archive.
*
* @param archive the archive to which the skeleton will be packed.
*
*/
explicit packed_skeleton_oarchive(packed_oarchive & archive)
: detail::forward_skeleton_oarchive<packed_skeleton_oarchive,packed_oarchive>(archive)
, skeleton_archive_(MPI_COMM_WORLD, boost::archive::no_header)
{}
/**
* Retrieve the archive corresponding to this skeleton.
*/
const packed_oarchive& get_skeleton() const
{
return this->implementation_archive;
}
private:
/// Store the actual archive that holds the structure.
packed_oarchive skeleton_archive_;
};
} } // end namespace boost::mpi
#endif // BOOST_MPI_SKELETON_AND_CONTENT_TYPES_HPP

View File

@@ -13,7 +13,9 @@
#define BOOST_MPI_STATUS_HPP
#include <boost/mpi/config.hpp>
#include <boost/mpi/datatype.hpp>
#include <boost/optional.hpp>
#include <boost/mpl/bool.hpp>
namespace boost { namespace mpi {
@@ -68,7 +70,7 @@ class BOOST_MPI_DECL status
* @returns the number of @c T elements in the message, if it can be
* determined.
*/
template<typename T> optional<int> count() const;
template<typename T> optional<int> count() const { return count_impl<T>(is_mpi_datatype<T>()); }
/**
* References the underlying @c MPI_Status
@@ -101,6 +103,31 @@ class BOOST_MPI_DECL status
friend class request;
};
template<typename T>
inline optional<int> status::count_impl(mpl::true_) const
{
if (m_count != -1)
return m_count;
int return_value;
BOOST_MPI_CHECK_RESULT(MPI_Get_count,
(&m_status, get_mpi_datatype<T>(T()), &return_value));
if (return_value == MPI_UNDEFINED)
return optional<int>();
else
/* Cache the result. */
return m_count = return_value;
}
template<typename T>
inline optional<int> status::count_impl(mpl::false_) const
{
if (m_count == -1)
return optional<int>();
else
return m_count;
}
} } // end namespace boost::mpi