skeleton_and_content_types.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. // (C) Copyright 2005 Matthias Troyer
  2. // (C) Copyright 2006 Douglas Gregor <doug.gregor -at gmail.com>
  3. // Use, modification and distribution is subject to the Boost Software
  4. // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  5. // http://www.boost.org/LICENSE_1_0.txt)
  6. // Authors: Matthias Troyer
  7. // Douglas Gregor
  8. /** @file skeleton_and_content.hpp
  9. *
  10. * This header provides facilities that allow the structure of data
  11. * types (called the "skeleton") to be transmitted and received
  12. * separately from the content stored in those data types. These
  13. * facilities are useful when the data in a stable data structure
  14. * (e.g., a mesh or a graph) will need to be transmitted
  15. * repeatedly. In this case, transmitting the skeleton only once
  16. * saves both communication effort (it need not be sent again) and
  17. * local computation (serialization need only be performed once for
  18. * the content).
  19. */
  20. #ifndef BOOST_MPI_SKELETON_AND_CONTENT_TYPES_HPP
  21. #define BOOST_MPI_SKELETON_AND_CONTENT_TYPES_HPP
  22. #include <boost/mpi/config.hpp>
  23. #include <boost/archive/detail/auto_link_archive.hpp>
  24. #include <boost/mpi/packed_iarchive.hpp>
  25. #include <boost/mpi/packed_oarchive.hpp>
  26. #include <boost/mpi/detail/forward_skeleton_iarchive.hpp>
  27. #include <boost/mpi/detail/forward_skeleton_oarchive.hpp>
  28. #include <boost/mpi/detail/ignore_iprimitive.hpp>
  29. #include <boost/mpi/detail/ignore_oprimitive.hpp>
  30. #include <boost/shared_ptr.hpp>
  31. #include <boost/archive/detail/register_archive.hpp>
  32. namespace boost { namespace mpi {
  33. /**
  34. * @brief A proxy that requests that the skeleton of an object be
  35. * transmitted.
  36. *
  37. * The @c skeleton_proxy is a lightweight proxy object used to
  38. * indicate that the skeleton of an object, not the object itself,
  39. * should be transmitted. It can be used with the @c send and @c recv
  40. * operations of communicators or the @c broadcast collective. When a
  41. * @c skeleton_proxy is sent, Boost.MPI generates a description
  42. * containing the structure of the stored object. When that skeleton
  43. * is received, the receiving object is reshaped to match the
  44. * structure. Once the skeleton of an object as been transmitted, its
  45. * @c content can be transmitted separately (often several times)
  46. * without changing the structure of the object.
  47. */
  48. template <class T>
  49. struct BOOST_MPI_DECL skeleton_proxy
  50. {
  51. /**
  52. * Constructs a @c skeleton_proxy that references object @p x.
  53. *
  54. * @param x the object whose structure will be transmitted or
  55. * altered.
  56. */
  57. skeleton_proxy(T& x)
  58. : object(x)
  59. {}
  60. T& object;
  61. };
  62. /**
  63. * @brief Create a skeleton proxy object.
  64. *
  65. * This routine creates an instance of the skeleton_proxy class. It
  66. * will typically be used when calling @c send, @c recv, or @c
  67. * broadcast, to indicate that only the skeleton (structure) of an
  68. * object should be transmitted and not its contents.
  69. *
  70. * @param x the object whose structure will be transmitted.
  71. *
  72. * @returns a skeleton_proxy object referencing @p x
  73. */
  74. template <class T>
  75. inline const skeleton_proxy<T> skeleton(T& x)
  76. {
  77. return skeleton_proxy<T>(x);
  78. }
  79. namespace detail {
  80. /// @brief a class holding an MPI datatype
  81. /// INTERNAL ONLY
  82. /// the type is freed upon destruction
  83. class BOOST_MPI_DECL mpi_datatype_holder : public boost::noncopyable
  84. {
  85. public:
  86. mpi_datatype_holder()
  87. : is_committed(false)
  88. {}
  89. mpi_datatype_holder(MPI_Datatype t, bool committed = true)
  90. : d(t)
  91. , is_committed(committed)
  92. {}
  93. void commit()
  94. {
  95. BOOST_MPI_CHECK_RESULT(MPI_Type_commit,(&d));
  96. is_committed=true;
  97. }
  98. MPI_Datatype get_mpi_datatype() const
  99. {
  100. return d;
  101. }
  102. ~mpi_datatype_holder()
  103. {
  104. int finalized=0;
  105. BOOST_MPI_CHECK_RESULT(MPI_Finalized,(&finalized));
  106. if (!finalized && is_committed)
  107. BOOST_MPI_CHECK_RESULT(MPI_Type_free,(&d));
  108. }
  109. private:
  110. MPI_Datatype d;
  111. bool is_committed;
  112. };
  113. } // end namespace detail
  114. /** @brief A proxy object that transfers the content of an object
  115. * without its structure.
  116. *
  117. * The @c content class indicates that Boost.MPI should transmit or
  118. * receive the content of an object, but without any information
  119. * about the structure of the object. It is only meaningful to
  120. * transmit the content of an object after the receiver has already
  121. * received the skeleton for the same object.
  122. *
  123. * Most users will not use @c content objects directly. Rather, they
  124. * will invoke @c send, @c recv, or @c broadcast operations using @c
  125. * get_content().
  126. */
  127. class BOOST_MPI_DECL content
  128. {
  129. public:
  130. /**
  131. * Constructs an empty @c content object. This object will not be
  132. * useful for any Boost.MPI operations until it is reassigned.
  133. */
  134. content() {}
  135. /**
  136. * This routine initializes the @c content object with an MPI data
  137. * type that refers to the content of an object without its structure.
  138. *
  139. * @param d the MPI data type referring to the content of the object.
  140. *
  141. * @param committed @c true indicates that @c MPI_Type_commit has
  142. * already been excuted for the data type @p d.
  143. */
  144. content(MPI_Datatype d, bool committed=true)
  145. : holder(new detail::mpi_datatype_holder(d,committed))
  146. {}
  147. /**
  148. * Replace the MPI data type referencing the content of an object.
  149. *
  150. * @param d the new MPI data type referring to the content of the
  151. * object.
  152. *
  153. * @returns *this
  154. */
  155. const content& operator=(MPI_Datatype d)
  156. {
  157. holder.reset(new detail::mpi_datatype_holder(d));
  158. return *this;
  159. }
  160. /**
  161. * Retrieve the MPI data type that refers to the content of the
  162. * object.
  163. *
  164. * @returns the MPI data type, which should only be transmitted or
  165. * received using @c MPI_BOTTOM as the address.
  166. */
  167. MPI_Datatype get_mpi_datatype() const
  168. {
  169. return holder->get_mpi_datatype();
  170. }
  171. /**
  172. * Commit the MPI data type referring to the content of the
  173. * object.
  174. */
  175. void commit()
  176. {
  177. holder->commit();
  178. }
  179. private:
  180. boost::shared_ptr<detail::mpi_datatype_holder> holder;
  181. };
  182. /** @brief Returns the content of an object, suitable for transmission
  183. * via Boost.MPI.
  184. *
  185. * The function creates an absolute MPI datatype for the object,
  186. * where all offsets are counted from the address 0 (a.k.a. @c
  187. * MPI_BOTTOM) instead of the address @c &x of the object. This
  188. * allows the creation of MPI data types for complex data structures
  189. * containing pointers, such as linked lists or trees.
  190. *
  191. * The disadvantage, compared to relative MPI data types is that for
  192. * each object a new MPI data type has to be created.
  193. *
  194. * The contents of an object can only be transmitted when the
  195. * receiver already has an object with the same structure or shape as
  196. * the sender. To accomplish this, first transmit the skeleton of the
  197. * object using, e.g., @c skeleton() or @c skeleton_proxy.
  198. *
  199. * The type @c T has to allow creation of an absolute MPI data type
  200. * (content).
  201. *
  202. * @param x the object for which the content will be transmitted.
  203. *
  204. * @returns the content of the object @p x, which can be used for
  205. * transmission via @c send, @c recv, or @c broadcast.
  206. */
  207. template <class T> const content get_content(const T& x);
  208. /** @brief An archiver that reconstructs a data structure based on the
  209. * binary skeleton stored in a buffer.
  210. *
  211. * The @c packed_skeleton_iarchive class is an Archiver (as in the
  212. * Boost.Serialization library) that can construct the the shape of a
  213. * data structure based on a binary skeleton stored in a buffer. The
  214. * @c packed_skeleton_iarchive is typically used by the receiver of a
  215. * skeleton, to prepare a data structure that will eventually receive
  216. * content separately.
  217. *
  218. * Users will not generally need to use @c packed_skeleton_iarchive
  219. * directly. Instead, use @c skeleton or @c get_skeleton.
  220. */
  221. class BOOST_MPI_DECL packed_skeleton_iarchive
  222. : public detail::ignore_iprimitive,
  223. public detail::forward_skeleton_iarchive<packed_skeleton_iarchive,packed_iarchive>
  224. {
  225. public:
  226. /**
  227. * Construct a @c packed_skeleton_iarchive for the given
  228. * communicator.
  229. *
  230. * @param comm The communicator over which this archive will be
  231. * transmitted.
  232. *
  233. * @param flags Control the serialization of the skeleton. Refer to
  234. * the Boost.Serialization documentation before changing the
  235. * default flags.
  236. */
  237. packed_skeleton_iarchive(MPI_Comm const & comm,
  238. unsigned int flags = boost::archive::no_header)
  239. : detail::forward_skeleton_iarchive<packed_skeleton_iarchive,packed_iarchive>(skeleton_archive_)
  240. , skeleton_archive_(comm,flags)
  241. {}
  242. /**
  243. * Construct a @c packed_skeleton_iarchive that unpacks a skeleton
  244. * from the given @p archive.
  245. *
  246. * @param archive the archive from which the skeleton will be
  247. * unpacked.
  248. *
  249. */
  250. explicit packed_skeleton_iarchive(packed_iarchive & archive)
  251. : detail::forward_skeleton_iarchive<packed_skeleton_iarchive,packed_iarchive>(archive)
  252. , skeleton_archive_(MPI_COMM_WORLD, boost::archive::no_header)
  253. {}
  254. /**
  255. * Retrieve the archive corresponding to this skeleton.
  256. */
  257. const packed_iarchive& get_skeleton() const
  258. {
  259. return this->implementation_archive;
  260. }
  261. /**
  262. * Retrieve the archive corresponding to this skeleton.
  263. */
  264. packed_iarchive& get_skeleton()
  265. {
  266. return this->implementation_archive;
  267. }
  268. private:
  269. /// Store the actual archive that holds the structure, unless the
  270. /// user overrides this with their own archive.
  271. packed_iarchive skeleton_archive_;
  272. };
  273. /** @brief An archiver that records the binary skeleton of a data
  274. * structure into a buffer.
  275. *
  276. * The @c packed_skeleton_oarchive class is an Archiver (as in the
  277. * Boost.Serialization library) that can record the shape of a data
  278. * structure (called the "skeleton") into a binary representation
  279. * stored in a buffer. The @c packed_skeleton_oarchive is typically
  280. * used by the send of a skeleton, to pack the skeleton of a data
  281. * structure for transmission separately from the content.
  282. *
  283. * Users will not generally need to use @c packed_skeleton_oarchive
  284. * directly. Instead, use @c skeleton or @c get_skeleton.
  285. */
  286. class BOOST_MPI_DECL packed_skeleton_oarchive
  287. : public detail::ignore_oprimitive,
  288. public detail::forward_skeleton_oarchive<packed_skeleton_oarchive,packed_oarchive>
  289. {
  290. public:
  291. /**
  292. * Construct a @c packed_skeleton_oarchive for the given
  293. * communicator.
  294. *
  295. * @param comm The communicator over which this archive will be
  296. * transmitted.
  297. *
  298. * @param flags Control the serialization of the skeleton. Refer to
  299. * the Boost.Serialization documentation before changing the
  300. * default flags.
  301. */
  302. packed_skeleton_oarchive(MPI_Comm const & comm,
  303. unsigned int flags = boost::archive::no_header)
  304. : detail::forward_skeleton_oarchive<packed_skeleton_oarchive,packed_oarchive>(skeleton_archive_)
  305. , skeleton_archive_(comm,flags)
  306. {}
  307. /**
  308. * Construct a @c packed_skeleton_oarchive that packs a skeleton
  309. * into the given @p archive.
  310. *
  311. * @param archive the archive to which the skeleton will be packed.
  312. *
  313. */
  314. explicit packed_skeleton_oarchive(packed_oarchive & archive)
  315. : detail::forward_skeleton_oarchive<packed_skeleton_oarchive,packed_oarchive>(archive)
  316. , skeleton_archive_(MPI_COMM_WORLD, boost::archive::no_header)
  317. {}
  318. /**
  319. * Retrieve the archive corresponding to this skeleton.
  320. */
  321. const packed_oarchive& get_skeleton() const
  322. {
  323. return this->implementation_archive;
  324. }
  325. private:
  326. /// Store the actual archive that holds the structure.
  327. packed_oarchive skeleton_archive_;
  328. };
  329. } } // end namespace boost::mpi
  330. #endif // BOOST_MPI_SKELETON_AND_CONTENT_TYPES_HPP