| // (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 |