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