update boost
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 *
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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
|
||||
|
||||
631
linx64/include/boost/mpi/detail/request_handlers.hpp
Normal file
631
linx64/include/boost/mpi/detail/request_handlers.hpp
Normal 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
|
||||
@@ -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;
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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>());
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
363
linx64/include/boost/mpi/skeleton_and_content_types.hpp
Normal file
363
linx64/include/boost/mpi/skeleton_and_content_types.hpp
Normal 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
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user