/Src/Dependencies/Boost/boost/graph/distributed/mpi_process_group.hpp

http://hadesmem.googlecode.com/ · C++ Header · 809 lines · 385 code · 147 blank · 277 comment · 4 complexity · cadef62753c9a51f268c43c6c757a79e MD5 · raw file

  1. // Copyright (C) 2004-2008 The Trustees of Indiana University.
  2. // Copyright (C) 2007 Douglas Gregor
  3. // Copyright (C) 2007 Matthias Troyer <troyer@boost-consulting.com>
  4. // Use, modification and distribution is subject to the Boost Software
  5. // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt)
  7. // Authors: Douglas Gregor
  8. // Matthias Troyer
  9. // Andrew Lumsdaine
  10. #ifndef BOOST_GRAPH_DISTRIBUTED_MPI_PROCESS_GROUP
  11. #define BOOST_GRAPH_DISTRIBUTED_MPI_PROCESS_GROUP
  12. #ifndef BOOST_GRAPH_USE_MPI
  13. #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
  14. #endif
  15. //#define NO_SPLIT_BATCHES
  16. #define SEND_OOB_BSEND
  17. #include <boost/optional.hpp>
  18. #include <boost/shared_ptr.hpp>
  19. #include <boost/weak_ptr.hpp>
  20. #include <utility>
  21. #include <memory>
  22. #include <boost/function/function1.hpp>
  23. #include <boost/function/function2.hpp>
  24. #include <boost/function/function0.hpp>
  25. #include <boost/mpi.hpp>
  26. #include <boost/graph/parallel/process_group.hpp>
  27. #include <boost/utility/enable_if.hpp>
  28. namespace boost { namespace graph { namespace distributed {
  29. // Process group tags
  30. struct mpi_process_group_tag : virtual parallel::linear_process_group_tag { };
  31. class mpi_process_group
  32. {
  33. struct impl;
  34. public:
  35. /// Number of tags available to each data structure.
  36. static const int max_tags = 256;
  37. /**
  38. * The type of a "receive" handler, that will be provided with
  39. * (source, tag) pairs when a message is received. Users can provide a
  40. * receive handler for a distributed data structure, for example, to
  41. * automatically pick up and respond to messages as needed.
  42. */
  43. typedef function<void(int source, int tag)> receiver_type;
  44. /**
  45. * The type of a handler for the on-synchronize event, which will be
  46. * executed at the beginning of synchronize().
  47. */
  48. typedef function0<void> on_synchronize_event_type;
  49. /// Used as a tag to help create an "empty" process group.
  50. struct create_empty {};
  51. /// The type used to buffer message data
  52. typedef boost::mpi::packed_oprimitive::buffer_type buffer_type;
  53. /// The type used to identify a process
  54. typedef int process_id_type;
  55. /// The type used to count the number of processes
  56. typedef int process_size_type;
  57. /// The type of communicator used to transmit data via MPI
  58. typedef boost::mpi::communicator communicator_type;
  59. /// Classification of the capabilities of this process group
  60. struct communication_category
  61. : virtual parallel::bsp_process_group_tag,
  62. virtual mpi_process_group_tag { };
  63. // TBD: We can eliminate the "source" field and possibly the
  64. // "offset" field.
  65. struct message_header {
  66. /// The process that sent the message
  67. process_id_type source;
  68. /// The message tag
  69. int tag;
  70. /// The offset of the message into the buffer
  71. std::size_t offset;
  72. /// The length of the message in the buffer, in bytes
  73. std::size_t bytes;
  74. template <class Archive>
  75. void serialize(Archive& ar, int)
  76. {
  77. ar & source & tag & offset & bytes;
  78. }
  79. };
  80. /**
  81. * Stores the outgoing messages for a particular processor.
  82. *
  83. * @todo Evaluate whether we should use a deque instance, which
  84. * would reduce could reduce the cost of "sending" messages but
  85. * increases the time spent in the synchronization step.
  86. */
  87. struct outgoing_messages {
  88. outgoing_messages() {}
  89. ~outgoing_messages() {}
  90. std::vector<message_header> headers;
  91. buffer_type buffer;
  92. template <class Archive>
  93. void serialize(Archive& ar, int)
  94. {
  95. ar & headers & buffer;
  96. }
  97. void swap(outgoing_messages& x)
  98. {
  99. headers.swap(x.headers);
  100. buffer.swap(x.buffer);
  101. }
  102. };
  103. private:
  104. /**
  105. * Virtual base from which every trigger will be launched. See @c
  106. * trigger_launcher for more information.
  107. */
  108. class trigger_base : boost::noncopyable
  109. {
  110. public:
  111. explicit trigger_base(int tag) : tag_(tag) { }
  112. /// Retrieve the tag associated with this trigger
  113. int tag() const { return tag_; }
  114. virtual ~trigger_base() { }
  115. /**
  116. * Invoked to receive a message that matches a particular trigger.
  117. *
  118. * @param source the source of the message
  119. * @param tag the (local) tag of the message
  120. * @param context the context under which the trigger is being
  121. * invoked
  122. */
  123. virtual void
  124. receive(mpi_process_group const& pg, int source, int tag,
  125. trigger_receive_context context, int block=-1) const = 0;
  126. protected:
  127. // The message tag associated with this trigger
  128. int tag_;
  129. };
  130. /**
  131. * Launches a specific handler in response to a trigger. This
  132. * function object wraps up the handler function object and a buffer
  133. * for incoming data.
  134. */
  135. template<typename Type, typename Handler>
  136. class trigger_launcher : public trigger_base
  137. {
  138. public:
  139. explicit trigger_launcher(mpi_process_group& self, int tag,
  140. const Handler& handler)
  141. : trigger_base(tag), self(self), handler(handler)
  142. {}
  143. void
  144. receive(mpi_process_group const& pg, int source, int tag,
  145. trigger_receive_context context, int block=-1) const;
  146. private:
  147. mpi_process_group& self;
  148. mutable Handler handler;
  149. };
  150. /**
  151. * Launches a specific handler with a message reply in response to a
  152. * trigger. This function object wraps up the handler function
  153. * object and a buffer for incoming data.
  154. */
  155. template<typename Type, typename Handler>
  156. class reply_trigger_launcher : public trigger_base
  157. {
  158. public:
  159. explicit reply_trigger_launcher(mpi_process_group& self, int tag,
  160. const Handler& handler)
  161. : trigger_base(tag), self(self), handler(handler)
  162. {}
  163. void
  164. receive(mpi_process_group const& pg, int source, int tag,
  165. trigger_receive_context context, int block=-1) const;
  166. private:
  167. mpi_process_group& self;
  168. mutable Handler handler;
  169. };
  170. template<typename Type, typename Handler>
  171. class global_trigger_launcher : public trigger_base
  172. {
  173. public:
  174. explicit global_trigger_launcher(mpi_process_group& self, int tag,
  175. const Handler& handler)
  176. : trigger_base(tag), handler(handler)
  177. {
  178. }
  179. void
  180. receive(mpi_process_group const& pg, int source, int tag,
  181. trigger_receive_context context, int block=-1) const;
  182. private:
  183. mutable Handler handler;
  184. // TBD: do not forget to cancel any outstanding Irecv when deleted,
  185. // if we decide to use Irecv
  186. };
  187. template<typename Type, typename Handler>
  188. class global_irecv_trigger_launcher : public trigger_base
  189. {
  190. public:
  191. explicit global_irecv_trigger_launcher(mpi_process_group& self, int tag,
  192. const Handler& handler, int sz)
  193. : trigger_base(tag), handler(handler), buffer_size(sz)
  194. {
  195. prepare_receive(self,tag);
  196. }
  197. void
  198. receive(mpi_process_group const& pg, int source, int tag,
  199. trigger_receive_context context, int block=-1) const;
  200. private:
  201. void prepare_receive(mpi_process_group const& pg, int tag, bool force=false) const;
  202. Handler handler;
  203. int buffer_size;
  204. // TBD: do not forget to cancel any outstanding Irecv when deleted,
  205. // if we decide to use Irecv
  206. };
  207. public:
  208. /**
  209. * Construct a new BSP process group from an MPI communicator. The
  210. * MPI communicator will be duplicated to create a new communicator
  211. * for this process group to use.
  212. */
  213. mpi_process_group(communicator_type parent_comm = communicator_type());
  214. /**
  215. * Construct a new BSP process group from an MPI communicator. The
  216. * MPI communicator will be duplicated to create a new communicator
  217. * for this process group to use. This constructor allows to tune the
  218. * size of message batches.
  219. *
  220. * @param num_headers The maximum number of headers in a message batch
  221. *
  222. * @param buffer_size The maximum size of the message buffer in a batch.
  223. *
  224. */
  225. mpi_process_group( std::size_t num_headers, std::size_t buffer_size,
  226. communicator_type parent_comm = communicator_type());
  227. /**
  228. * Construct a copy of the BSP process group for a new distributed
  229. * data structure. This data structure will synchronize with all
  230. * other members of the process group's equivalence class (including
  231. * @p other), but will have its own set of tags.
  232. *
  233. * @param other The process group that this new process group will
  234. * be based on, using a different set of tags within the same
  235. * communication and synchronization space.
  236. *
  237. * @param handler A message handler that will be passed (source,
  238. * tag) pairs for each message received by this data
  239. * structure. The handler is expected to receive the messages
  240. * immediately. The handler can be changed after-the-fact by
  241. * calling @c replace_handler.
  242. *
  243. * @param out_of_band_receive An anachronism. TODO: remove this.
  244. */
  245. mpi_process_group(const mpi_process_group& other,
  246. const receiver_type& handler,
  247. bool out_of_band_receive = false);
  248. /**
  249. * Construct a copy of the BSP process group for a new distributed
  250. * data structure. This data structure will synchronize with all
  251. * other members of the process group's equivalence class (including
  252. * @p other), but will have its own set of tags.
  253. */
  254. mpi_process_group(const mpi_process_group& other,
  255. attach_distributed_object,
  256. bool out_of_band_receive = false);
  257. /**
  258. * Create an "empty" process group, with no information. This is an
  259. * internal routine that users should never need.
  260. */
  261. explicit mpi_process_group(create_empty) {}
  262. /**
  263. * Destroys this copy of the process group.
  264. */
  265. ~mpi_process_group();
  266. /**
  267. * Replace the current message handler with a new message handler.
  268. *
  269. * @param handle The new message handler.
  270. * @param out_of_band_receive An anachronism: remove this
  271. */
  272. void replace_handler(const receiver_type& handler,
  273. bool out_of_band_receive = false);
  274. /**
  275. * Turns this process group into the process group for a new
  276. * distributed data structure or object, allocating its own tag
  277. * block.
  278. */
  279. void make_distributed_object();
  280. /**
  281. * Replace the handler to be invoked at the beginning of synchronize.
  282. */
  283. void
  284. replace_on_synchronize_handler(const on_synchronize_event_type& handler = 0);
  285. /**
  286. * Return the block number of the current data structure. A value of
  287. * 0 indicates that this particular instance of the process group is
  288. * not associated with any distributed data structure.
  289. */
  290. int my_block_number() const { return block_num? *block_num : 0; }
  291. /**
  292. * Encode a block number/tag pair into a single encoded tag for
  293. * transmission.
  294. */
  295. int encode_tag(int block_num, int tag) const
  296. { return block_num * max_tags + tag; }
  297. /**
  298. * Decode an encoded tag into a block number/tag pair.
  299. */
  300. std::pair<int, int> decode_tag(int encoded_tag) const
  301. { return std::make_pair(encoded_tag / max_tags, encoded_tag % max_tags); }
  302. // @todo Actually write up the friend declarations so these could be
  303. // private.
  304. // private:
  305. /** Allocate a block of tags for this instance. The block should not
  306. * have been allocated already, e.g., my_block_number() ==
  307. * 0. Returns the newly-allocated block number.
  308. */
  309. int allocate_block(bool out_of_band_receive = false);
  310. /** Potentially emit a receive event out of band. Returns true if an event
  311. * was actually sent, false otherwise.
  312. */
  313. bool maybe_emit_receive(int process, int encoded_tag) const;
  314. /** Emit a receive event. Returns true if an event was actually
  315. * sent, false otherwise.
  316. */
  317. bool emit_receive(int process, int encoded_tag) const;
  318. /** Emit an on-synchronize event to all block handlers. */
  319. void emit_on_synchronize() const;
  320. /** Retrieve a reference to the stored receiver in this block. */
  321. template<typename Receiver>
  322. Receiver* get_receiver();
  323. template<typename T>
  324. void
  325. send_impl(int dest, int tag, const T& value,
  326. mpl::true_ /*is_mpi_datatype*/) const;
  327. template<typename T>
  328. void
  329. send_impl(int dest, int tag, const T& value,
  330. mpl::false_ /*is_mpi_datatype*/) const;
  331. template<typename T>
  332. typename disable_if<boost::mpi::is_mpi_datatype<T>, void>::type
  333. array_send_impl(int dest, int tag, const T values[], std::size_t n) const;
  334. template<typename T>
  335. bool
  336. receive_impl(int source, int tag, T& value,
  337. mpl::true_ /*is_mpi_datatype*/) const;
  338. template<typename T>
  339. bool
  340. receive_impl(int source, int tag, T& value,
  341. mpl::false_ /*is_mpi_datatype*/) const;
  342. // Receive an array of values
  343. template<typename T>
  344. typename disable_if<boost::mpi::is_mpi_datatype<T>, bool>::type
  345. array_receive_impl(int source, int tag, T* values, std::size_t& n) const;
  346. optional<std::pair<mpi_process_group::process_id_type, int> > probe() const;
  347. void synchronize() const;
  348. operator bool() { return impl_; }
  349. mpi_process_group base() const;
  350. /**
  351. * Create a new trigger for a specific message tag. Triggers handle
  352. * out-of-band messaging, and the handler itself will be called
  353. * whenever a message is available. The handler itself accepts four
  354. * arguments: the source of the message, the message tag (which will
  355. * be the same as @p tag), the message data (of type @c Type), and a
  356. * boolean flag that states whether the message was received
  357. * out-of-band. The last will be @c true for out-of-band receives,
  358. * or @c false for receives at the end of a synchronization step.
  359. */
  360. template<typename Type, typename Handler>
  361. void trigger(int tag, const Handler& handler);
  362. /**
  363. * Create a new trigger for a specific message tag, along with a way
  364. * to send a reply with data back to the sender. Triggers handle
  365. * out-of-band messaging, and the handler itself will be called
  366. * whenever a message is available. The handler itself accepts four
  367. * arguments: the source of the message, the message tag (which will
  368. * be the same as @p tag), the message data (of type @c Type), and a
  369. * boolean flag that states whether the message was received
  370. * out-of-band. The last will be @c true for out-of-band receives,
  371. * or @c false for receives at the end of a synchronization
  372. * step. The handler also returns a value, which will be routed back
  373. * to the sender.
  374. */
  375. template<typename Type, typename Handler>
  376. void trigger_with_reply(int tag, const Handler& handler);
  377. template<typename Type, typename Handler>
  378. void global_trigger(int tag, const Handler& handler, std::size_t buffer_size=0);
  379. /**
  380. * Poll for any out-of-band messages. This routine will check if any
  381. * out-of-band messages are available. Those that are available will
  382. * be handled immediately, if possible.
  383. *
  384. * @returns if an out-of-band message has been received, but we are
  385. * unable to actually receive the message, a (source, tag) pair will
  386. * be returned. Otherwise, returns an empty optional.
  387. *
  388. * @param wait When true, we should block until a message comes in.
  389. *
  390. * @param synchronizing whether we are currently synchronizing the
  391. * process group
  392. */
  393. optional<std::pair<int, int> >
  394. poll(bool wait = false, int block = -1, bool synchronizing = false) const;
  395. /**
  396. * Determines the context of the trigger currently executing. If
  397. * multiple triggers are executing (recursively), then the context
  398. * for the most deeply nested trigger will be returned. If no
  399. * triggers are executing, returns @c trc_none. This might be used,
  400. * for example, to determine whether a reply to a message should
  401. * itself be sent out-of-band or whether it can go via the normal,
  402. * slower communication route.
  403. */
  404. trigger_receive_context trigger_context() const;
  405. /// INTERNAL ONLY
  406. void receive_batch(process_id_type source, outgoing_messages& batch) const;
  407. /// INTERNAL ONLY
  408. ///
  409. /// Determine the actual communicator and tag will be used for a
  410. /// transmission with the given tag.
  411. std::pair<boost::mpi::communicator, int>
  412. actual_communicator_and_tag(int tag, int block) const;
  413. /// set the size of the message buffer used for buffered oob sends
  414. static void set_message_buffer_size(std::size_t s);
  415. /// get the size of the message buffer used for buffered oob sends
  416. static std::size_t message_buffer_size();
  417. static int old_buffer_size;
  418. static void* old_buffer;
  419. private:
  420. void install_trigger(int tag, int block,
  421. shared_ptr<trigger_base> const& launcher);
  422. void poll_requests(int block=-1) const;
  423. // send a batch if the buffer is full now or would get full
  424. void maybe_send_batch(process_id_type dest) const;
  425. // actually send a batch
  426. void send_batch(process_id_type dest, outgoing_messages& batch) const;
  427. void send_batch(process_id_type dest) const;
  428. void pack_headers() const;
  429. /**
  430. * Process a batch of incoming messages immediately.
  431. *
  432. * @param source the source of these messages
  433. */
  434. void process_batch(process_id_type source) const;
  435. void receive_batch(boost::mpi::status& status) const;
  436. //void free_finished_sends() const;
  437. /// Status messages used internally by the process group
  438. enum status_messages {
  439. /// the first of the reserved message tags
  440. msg_reserved_first = 126,
  441. /// Sent from a processor when sending batched messages
  442. msg_batch = 126,
  443. /// Sent from a processor when sending large batched messages, larger than
  444. /// the maximum buffer size for messages to be received by MPI_Irecv
  445. msg_large_batch = 127,
  446. /// Sent from a source processor to everyone else when that
  447. /// processor has entered the synchronize() function.
  448. msg_synchronizing = 128,
  449. /// the last of the reserved message tags
  450. msg_reserved_last = 128
  451. };
  452. /**
  453. * Description of a block of tags associated to a particular
  454. * distributed data structure. This structure will live as long as
  455. * the distributed data structure is around, and will be used to
  456. * help send messages to the data structure.
  457. */
  458. struct block_type
  459. {
  460. block_type() { }
  461. /// Handler for receive events
  462. receiver_type on_receive;
  463. /// Handler executed at the start of synchronization
  464. on_synchronize_event_type on_synchronize;
  465. /// Individual message triggers. Note: at present, this vector is
  466. /// indexed by the (local) tag of the trigger. Any tags that
  467. /// don't have triggers will have NULL pointers in that spot.
  468. std::vector<shared_ptr<trigger_base> > triggers;
  469. };
  470. /**
  471. * Data structure containing all of the blocks for the distributed
  472. * data structures attached to a process group.
  473. */
  474. typedef std::vector<block_type*> blocks_type;
  475. /// Iterator into @c blocks_type.
  476. typedef blocks_type::iterator block_iterator;
  477. /**
  478. * Deleter used to deallocate a block when its distributed data
  479. * structure is destroyed. This type will be used as the deleter for
  480. * @c block_num.
  481. */
  482. struct deallocate_block;
  483. static std::vector<char> message_buffer;
  484. public:
  485. /**
  486. * Data associated with the process group and all of its attached
  487. * distributed data structures.
  488. */
  489. shared_ptr<impl> impl_;
  490. /**
  491. * When non-null, indicates that this copy of the process group is
  492. * associated with a particular distributed data structure. The
  493. * integer value contains the block number (a value > 0) associated
  494. * with that data structure. The deleter for this @c shared_ptr is a
  495. * @c deallocate_block object that will deallocate the associated
  496. * block in @c impl_->blocks.
  497. */
  498. shared_ptr<int> block_num;
  499. /**
  500. * Rank of this process, to avoid having to call rank() repeatedly.
  501. */
  502. int rank;
  503. /**
  504. * Number of processes in this process group, to avoid having to
  505. * call communicator::size() repeatedly.
  506. */
  507. int size;
  508. };
  509. inline mpi_process_group::process_id_type
  510. process_id(const mpi_process_group& pg)
  511. { return pg.rank; }
  512. inline mpi_process_group::process_size_type
  513. num_processes(const mpi_process_group& pg)
  514. { return pg.size; }
  515. mpi_process_group::communicator_type communicator(const mpi_process_group& pg);
  516. template<typename T>
  517. void
  518. send(const mpi_process_group& pg, mpi_process_group::process_id_type dest,
  519. int tag, const T& value);
  520. template<typename InputIterator>
  521. void
  522. send(const mpi_process_group& pg, mpi_process_group::process_id_type dest,
  523. int tag, InputIterator first, InputIterator last);
  524. template<typename T>
  525. inline void
  526. send(const mpi_process_group& pg, mpi_process_group::process_id_type dest,
  527. int tag, T* first, T* last)
  528. { send(pg, dest, tag, first, last - first); }
  529. template<typename T>
  530. inline void
  531. send(const mpi_process_group& pg, mpi_process_group::process_id_type dest,
  532. int tag, const T* first, const T* last)
  533. { send(pg, dest, tag, first, last - first); }
  534. template<typename T>
  535. mpi_process_group::process_id_type
  536. receive(const mpi_process_group& pg, int tag, T& value);
  537. template<typename T>
  538. mpi_process_group::process_id_type
  539. receive(const mpi_process_group& pg,
  540. mpi_process_group::process_id_type source, int tag, T& value);
  541. optional<std::pair<mpi_process_group::process_id_type, int> >
  542. probe(const mpi_process_group& pg);
  543. void synchronize(const mpi_process_group& pg);
  544. template<typename T, typename BinaryOperation>
  545. T*
  546. all_reduce(const mpi_process_group& pg, T* first, T* last, T* out,
  547. BinaryOperation bin_op);
  548. template<typename T, typename BinaryOperation>
  549. T*
  550. scan(const mpi_process_group& pg, T* first, T* last, T* out,
  551. BinaryOperation bin_op);
  552. template<typename InputIterator, typename T>
  553. void
  554. all_gather(const mpi_process_group& pg,
  555. InputIterator first, InputIterator last, std::vector<T>& out);
  556. template<typename InputIterator>
  557. mpi_process_group
  558. process_subgroup(const mpi_process_group& pg,
  559. InputIterator first, InputIterator last);
  560. template<typename T>
  561. void
  562. broadcast(const mpi_process_group& pg, T& val,
  563. mpi_process_group::process_id_type root);
  564. /*******************************************************************
  565. * Out-of-band communication *
  566. *******************************************************************/
  567. template<typename T>
  568. typename enable_if<boost::mpi::is_mpi_datatype<T> >::type
  569. send_oob(const mpi_process_group& pg, mpi_process_group::process_id_type dest,
  570. int tag, const T& value, int block=-1)
  571. {
  572. using boost::mpi::get_mpi_datatype;
  573. // Determine the actual message tag we will use for the send, and which
  574. // communicator we will use.
  575. std::pair<boost::mpi::communicator, int> actual
  576. = pg.actual_communicator_and_tag(tag, block);
  577. #ifdef SEND_OOB_BSEND
  578. if (mpi_process_group::message_buffer_size()) {
  579. MPI_Bsend(const_cast<T*>(&value), 1, get_mpi_datatype<T>(value), dest,
  580. actual.second, actual.first);
  581. return;
  582. }
  583. #endif
  584. MPI_Request request;
  585. MPI_Isend(const_cast<T*>(&value), 1, get_mpi_datatype<T>(value), dest,
  586. actual.second, actual.first, &request);
  587. int done=0;
  588. do {
  589. pg.poll();
  590. MPI_Test(&request,&done,MPI_STATUS_IGNORE);
  591. } while (!done);
  592. }
  593. template<typename T>
  594. typename disable_if<boost::mpi::is_mpi_datatype<T> >::type
  595. send_oob(const mpi_process_group& pg, mpi_process_group::process_id_type dest,
  596. int tag, const T& value, int block=-1)
  597. {
  598. using boost::mpi::packed_oarchive;
  599. // Determine the actual message tag we will use for the send, and which
  600. // communicator we will use.
  601. std::pair<boost::mpi::communicator, int> actual
  602. = pg.actual_communicator_and_tag(tag, block);
  603. // Serialize the data into a buffer
  604. packed_oarchive out(actual.first);
  605. out << value;
  606. std::size_t size = out.size();
  607. // Send the actual message data
  608. #ifdef SEND_OOB_BSEND
  609. if (mpi_process_group::message_buffer_size()) {
  610. MPI_Bsend(const_cast<void*>(out.address()), size, MPI_PACKED,
  611. dest, actual.second, actual.first);
  612. return;
  613. }
  614. #endif
  615. MPI_Request request;
  616. MPI_Isend(const_cast<void*>(out.address()), size, MPI_PACKED,
  617. dest, actual.second, actual.first, &request);
  618. int done=0;
  619. do {
  620. pg.poll();
  621. MPI_Test(&request,&done,MPI_STATUS_IGNORE);
  622. } while (!done);
  623. }
  624. template<typename T>
  625. typename enable_if<boost::mpi::is_mpi_datatype<T> >::type
  626. receive_oob(const mpi_process_group& pg,
  627. mpi_process_group::process_id_type source, int tag, T& value, int block=-1);
  628. template<typename T>
  629. typename disable_if<boost::mpi::is_mpi_datatype<T> >::type
  630. receive_oob(const mpi_process_group& pg,
  631. mpi_process_group::process_id_type source, int tag, T& value, int block=-1);
  632. template<typename SendT, typename ReplyT>
  633. typename enable_if<boost::mpi::is_mpi_datatype<ReplyT> >::type
  634. send_oob_with_reply(const mpi_process_group& pg,
  635. mpi_process_group::process_id_type dest,
  636. int tag, const SendT& send_value, ReplyT& reply_value,
  637. int block = -1);
  638. template<typename SendT, typename ReplyT>
  639. typename disable_if<boost::mpi::is_mpi_datatype<ReplyT> >::type
  640. send_oob_with_reply(const mpi_process_group& pg,
  641. mpi_process_group::process_id_type dest,
  642. int tag, const SendT& send_value, ReplyT& reply_value,
  643. int block = -1);
  644. } } } // end namespace boost::graph::distributed
  645. BOOST_IS_BITWISE_SERIALIZABLE(boost::graph::distributed::mpi_process_group::message_header)
  646. namespace boost { namespace mpi {
  647. template<>
  648. struct is_mpi_datatype<boost::graph::distributed::mpi_process_group::message_header> : mpl::true_ { };
  649. } } // end namespace boost::mpi
  650. namespace std {
  651. /// optimized swap for outgoing messages
  652. inline void
  653. swap(boost::graph::distributed::mpi_process_group::outgoing_messages& x,
  654. boost::graph::distributed::mpi_process_group::outgoing_messages& y)
  655. {
  656. x.swap(y);
  657. }
  658. }
  659. BOOST_CLASS_IMPLEMENTATION(boost::graph::distributed::mpi_process_group::outgoing_messages,object_serializable)
  660. BOOST_CLASS_TRACKING(boost::graph::distributed::mpi_process_group::outgoing_messages,track_never)
  661. #include <boost/graph/distributed/detail/mpi_process_group.ipp>
  662. #endif // BOOST_PARALLEL_MPI_MPI_PROCESS_GROUP_HPP