blob: c1e145ca18bf3671bd581472a04b1db85c6bc2af [file] [log] [blame]
// Copyright (C) 2005, 2006 Douglas Gregor.
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/mpi/communicator.hpp>
#include <boost/mpi/group.hpp>
#include <boost/mpi/intercommunicator.hpp>
#include <boost/mpi/graph_communicator.hpp>
#include <boost/mpi/skeleton_and_content.hpp>
#include <boost/mpi/detail/point_to_point.hpp>
namespace boost { namespace mpi {
/***************************************************************************
* status *
***************************************************************************/
bool status::cancelled() const
{
int flag = 0;
BOOST_MPI_CHECK_RESULT(MPI_Test_cancelled, (&m_status, &flag));
return flag != 0;
}
/***************************************************************************
* communicator *
***************************************************************************/
communicator::communicator()
{
comm_ptr.reset(new MPI_Comm(MPI_COMM_WORLD));
}
communicator::communicator(const MPI_Comm& comm, comm_create_kind kind)
{
if (comm == MPI_COMM_NULL)
/* MPI_COMM_NULL indicates that the communicator is not usable. */
return;
switch (kind) {
case comm_duplicate:
{
MPI_Comm newcomm;
BOOST_MPI_CHECK_RESULT(MPI_Comm_dup, (comm, &newcomm));
comm_ptr.reset(new MPI_Comm(newcomm), comm_free());
MPI_Errhandler_set(newcomm, MPI_ERRORS_RETURN);
break;
}
case comm_take_ownership:
comm_ptr.reset(new MPI_Comm(comm), comm_free());
break;
case comm_attach:
comm_ptr.reset(new MPI_Comm(comm));
break;
}
}
communicator::communicator(const communicator& comm,
const boost::mpi::group& subgroup)
{
MPI_Comm newcomm;
BOOST_MPI_CHECK_RESULT(MPI_Comm_create,
((MPI_Comm)comm, (MPI_Group)subgroup, &newcomm));
comm_ptr.reset(new MPI_Comm(newcomm), comm_free());
}
int communicator::size() const
{
int size_;
BOOST_MPI_CHECK_RESULT(MPI_Comm_size, (MPI_Comm(*this), &size_));
return size_;
}
int communicator::rank() const
{
int rank_;
BOOST_MPI_CHECK_RESULT(MPI_Comm_rank, (MPI_Comm(*this), &rank_));
return rank_;
}
boost::mpi::group communicator::group() const
{
MPI_Group gr;
BOOST_MPI_CHECK_RESULT(MPI_Comm_group, ((MPI_Comm)*this, &gr));
return boost::mpi::group(gr, /*adopt=*/true);
}
void communicator::send(int dest, int tag) const
{
BOOST_MPI_CHECK_RESULT(MPI_Send,
(MPI_BOTTOM, 0, MPI_PACKED,
dest, tag, MPI_Comm(*this)));
}
status communicator::recv(int source, int tag) const
{
status stat;
BOOST_MPI_CHECK_RESULT(MPI_Recv,
(MPI_BOTTOM, 0, MPI_PACKED,
source, tag, MPI_Comm(*this), &stat.m_status));
return stat;
}
optional<status> communicator::iprobe(int source, int tag) const
{
typedef optional<status> result_type;
status stat;
int flag;
BOOST_MPI_CHECK_RESULT(MPI_Iprobe,
(source, tag, MPI_Comm(*this), &flag,
&stat.m_status));
if (flag) return stat;
else return result_type();
}
status communicator::probe(int source, int tag) const
{
typedef optional<status> result_type;
status stat;
BOOST_MPI_CHECK_RESULT(MPI_Probe,
(source, tag, MPI_Comm(*this), &stat.m_status));
return stat;
}
void (communicator::barrier)() const
{
BOOST_MPI_CHECK_RESULT(MPI_Barrier, (MPI_Comm(*this)));
}
communicator::operator MPI_Comm() const
{
if (comm_ptr) return *comm_ptr;
else return MPI_COMM_NULL;
}
communicator communicator::split(int color) const
{
return split(color, rank());
}
communicator communicator::split(int color, int key) const
{
MPI_Comm newcomm;
BOOST_MPI_CHECK_RESULT(MPI_Comm_split,
(MPI_Comm(*this), color, key, &newcomm));
return communicator(newcomm, comm_take_ownership);
}
optional<intercommunicator> communicator::as_intercommunicator() const
{
int flag;
BOOST_MPI_CHECK_RESULT(MPI_Comm_test_inter, ((MPI_Comm)*this, &flag));
if (flag)
return intercommunicator(comm_ptr);
else
return optional<intercommunicator>();
}
optional<graph_communicator> communicator::as_graph_communicator() const
{
int status;
BOOST_MPI_CHECK_RESULT(MPI_Topo_test, ((MPI_Comm)*this, &status));
if (status == MPI_GRAPH)
return graph_communicator(comm_ptr);
else
return optional<graph_communicator>();
}
bool communicator::has_cartesian_topology() const
{
int status;
BOOST_MPI_CHECK_RESULT(MPI_Topo_test, ((MPI_Comm)*this, &status));
return status == MPI_CART;
}
void communicator::abort(int errcode) const
{
BOOST_MPI_CHECK_RESULT(MPI_Abort, (MPI_Comm(*this), errcode));
}
/*************************************************************
* archived send/recv *
*************************************************************/
template<>
void
communicator::send<packed_oarchive>(int dest, int tag,
const packed_oarchive& ar) const
{
detail::packed_archive_send(MPI_Comm(*this), dest, tag, ar);
}
template<>
void
communicator::send<packed_skeleton_oarchive>
(int dest, int tag, const packed_skeleton_oarchive& ar) const
{
this->send(dest, tag, ar.get_skeleton());
}
template<>
void communicator::send<content>(int dest, int tag, const content& c) const
{
BOOST_MPI_CHECK_RESULT(MPI_Send,
(MPI_BOTTOM, 1, c.get_mpi_datatype(),
dest, tag, MPI_Comm(*this)));
}
template<>
status
communicator::recv<packed_iarchive>(int source, int tag,
packed_iarchive& ar) const
{
status stat;
detail::packed_archive_recv(MPI_Comm(*this), source, tag, ar,
stat.m_status);
return stat;
}
template<>
status
communicator::recv<packed_skeleton_iarchive>
(int source, int tag, packed_skeleton_iarchive& ar) const
{
return this->recv(source, tag, ar.get_skeleton());
}
template<>
status
communicator::recv<const content>(int source, int tag, const content& c) const
{
status stat;
BOOST_MPI_CHECK_RESULT(MPI_Recv,
(MPI_BOTTOM, 1, c.get_mpi_datatype(),
source, tag, MPI_Comm(*this), &stat.m_status));
return stat;
}
/*************************************************************
* non-blocking send/recv *
*************************************************************/
template<>
request
communicator::isend<packed_oarchive>(int dest, int tag,
const packed_oarchive& ar) const
{
request req;
detail::packed_archive_isend(MPI_Comm(*this), dest, tag, ar,
&req.m_requests[0] ,2);
return req;
}
template<>
request
communicator::isend<packed_skeleton_oarchive>
(int dest, int tag, const packed_skeleton_oarchive& ar) const
{
return this->isend(dest, tag, ar.get_skeleton());
}
template<>
request communicator::isend<content>(int dest, int tag, const content& c) const
{
request req;
BOOST_MPI_CHECK_RESULT(MPI_Isend,
(MPI_BOTTOM, 1, c.get_mpi_datatype(),
dest, tag, MPI_Comm(*this), &req.m_requests[0]));
return req;
}
request communicator::isend(int dest, int tag) const
{
request req;
BOOST_MPI_CHECK_RESULT(MPI_Isend,
(MPI_BOTTOM, 0, MPI_PACKED,
dest, tag, MPI_Comm(*this), &req.m_requests[0]));
return req;
}
template<>
request
communicator::irecv<packed_skeleton_iarchive>
(int source, int tag, packed_skeleton_iarchive& ar) const
{
return this->irecv(source, tag, ar.get_skeleton());
}
template<>
request
communicator::irecv<const content>(int source, int tag,
const content& c) const
{
request req;
BOOST_MPI_CHECK_RESULT(MPI_Irecv,
(MPI_BOTTOM, 1, c.get_mpi_datatype(),
source, tag, MPI_Comm(*this), &req.m_requests[0]));
return req;
}
request communicator::irecv(int source, int tag) const
{
request req;
BOOST_MPI_CHECK_RESULT(MPI_Irecv,
(MPI_BOTTOM, 0, MPI_PACKED,
source, tag, MPI_Comm(*this), &req.m_requests[0]));
return req;
}
bool operator==(const communicator& comm1, const communicator& comm2)
{
int result;
BOOST_MPI_CHECK_RESULT(MPI_Comm_compare,
((MPI_Comm)comm1, (MPI_Comm)comm2, &result));
return result == MPI_IDENT;
}
} } // end namespace boost::mpi