// (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_HPP | |
#define BOOST_MPI_SKELETON_AND_CONTENT_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_; | |
}; | |
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; | |
} | |
} } // end namespace boost::mpi | |
#include <boost/mpi/detail/content_oarchive.hpp> | |
// For any headers that have provided declarations based on forward | |
// declarations of the contents of this header, include definitions | |
// for those declarations. This means that the inclusion of | |
// skeleton_and_content.hpp enables the use of skeleton/content | |
// transmission throughout the library. | |
#ifdef BOOST_MPI_BROADCAST_HPP | |
# include <boost/mpi/detail/broadcast_sc.hpp> | |
#endif | |
#ifdef BOOST_MPI_COMMUNICATOR_HPP | |
# include <boost/mpi/detail/communicator_sc.hpp> | |
#endif | |
// required by export | |
BOOST_SERIALIZATION_REGISTER_ARCHIVE(boost::mpi::packed_skeleton_oarchive) | |
BOOST_SERIALIZATION_REGISTER_ARCHIVE(boost::mpi::packed_skeleton_iarchive) | |
BOOST_SERIALIZATION_REGISTER_ARCHIVE(boost::mpi::detail::type1) | |
BOOST_SERIALIZATION_REGISTER_ARCHIVE(boost::mpi::detail::type2) | |
BOOST_SERIALIZATION_USE_ARRAY_OPTIMIZATION(boost::mpi::packed_skeleton_oarchive) | |
BOOST_SERIALIZATION_USE_ARRAY_OPTIMIZATION(boost::mpi::packed_skeleton_iarchive) | |
#endif // BOOST_MPI_SKELETON_AND_CONTENT_HPP |