skeleton_content_test.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. // Copyright 2005 Douglas Gregor.
  2. // Use, modification and distribution is subject to the Boost Software
  3. // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  4. // http://www.boost.org/LICENSE_1_0.txt)
  5. // A test of the communicator that transmits skeletons and
  6. // content for data types.
  7. #include <boost/mpi/communicator.hpp>
  8. #include <boost/mpi/environment.hpp>
  9. #include <boost/serialization/list.hpp>
  10. #include <boost/mpi/skeleton_and_content.hpp>
  11. #include <boost/mpi/nonblocking.hpp>
  12. #include <algorithm>
  13. #include <boost/iterator/counting_iterator.hpp>
  14. #include <boost/mpi/collectives/broadcast.hpp>
  15. #define BOOST_TEST_MODULE mpi_skeleton_content
  16. #include <boost/test/included/unit_test.hpp>
  17. using boost::mpi::communicator;
  18. using boost::mpi::packed_skeleton_iarchive;
  19. using boost::mpi::packed_skeleton_oarchive;
  20. void
  21. test_skeleton_and_content(const communicator& comm, int root,
  22. bool manual_broadcast)
  23. {
  24. using boost::mpi::skeleton;
  25. using boost::mpi::content;
  26. using boost::mpi::get_content;
  27. using boost::make_counting_iterator;
  28. using boost::mpi::broadcast;
  29. int list_size = comm.size() + 7;
  30. if (comm.rank() == root) {
  31. // Fill in the seed data
  32. std::list<int> original_list;
  33. for (int i = 0; i < list_size; ++i)
  34. original_list.push_back(i);
  35. std::cout << "Broadcasting integer list skeleton from root " << root
  36. << "...";
  37. if (manual_broadcast) {
  38. // Broadcast the skeleton (manually)
  39. for (int p = 0; p < comm.size(); ++p)
  40. if (p != root) comm.send(p, 0, skeleton(original_list));
  41. } else {
  42. broadcast(comm, skeleton(original_list), root);
  43. }
  44. std::cout << "OK." << std::endl;
  45. // Broadcast the content (manually)
  46. std::cout << "Broadcasting integer list content from root " << root
  47. << "...";
  48. {
  49. content c = get_content(original_list);
  50. for (int p = 0; p < comm.size(); ++p)
  51. if (p != root) comm.send(p, 1, c);
  52. }
  53. std::cout << "OK." << std::endl;
  54. // Reverse the list, broadcast the content again
  55. std::reverse(original_list.begin(), original_list.end());
  56. std::cout << "Broadcasting reversed integer list content from root "
  57. << root << "...";
  58. {
  59. content c = get_content(original_list);
  60. for (int p = 0; p < comm.size(); ++p)
  61. if (p != root) comm.send(p, 2, c);
  62. }
  63. std::cout << "OK." << std::endl;
  64. } else {
  65. // Allocate some useless data, to try to get the addresses of the
  66. // list<int>'s used later to be different across processes.
  67. std::list<int> junk_list(comm.rank() * 3 + 1, 17);
  68. // Receive the skeleton to build up the transferred list
  69. std::list<int> transferred_list;
  70. if (manual_broadcast) {
  71. comm.recv(root, 0, skeleton(transferred_list));
  72. } else {
  73. broadcast(comm, skeleton(transferred_list), root);
  74. }
  75. BOOST_CHECK((int)transferred_list.size() == list_size);
  76. // Receive the content and check it
  77. comm.recv(root, 1, get_content(transferred_list));
  78. BOOST_CHECK(std::equal(make_counting_iterator(0),
  79. make_counting_iterator(list_size),
  80. transferred_list.begin()));
  81. // Receive the reversed content and check it
  82. comm.recv(root, 2, get_content(transferred_list));
  83. BOOST_CHECK(std::equal(make_counting_iterator(0),
  84. make_counting_iterator(list_size),
  85. transferred_list.rbegin()));
  86. }
  87. (comm.barrier)();
  88. }
  89. void
  90. test_skeleton_and_content_nonblocking(const communicator& comm, int root)
  91. {
  92. using boost::mpi::skeleton;
  93. using boost::mpi::content;
  94. using boost::mpi::get_content;
  95. using boost::make_counting_iterator;
  96. using boost::mpi::broadcast;
  97. using boost::mpi::request;
  98. using boost::mpi::wait_all;
  99. int list_size = comm.size() + 7;
  100. if (comm.rank() == root) {
  101. // Fill in the seed data
  102. std::list<int> original_list;
  103. for (int i = 0; i < list_size; ++i)
  104. original_list.push_back(i);
  105. std::cout << "Non-blocking broadcast of integer list skeleton from root " << root
  106. << "...";
  107. // Broadcast the skeleton (manually)
  108. {
  109. std::vector<request> reqs;
  110. for (int p = 0; p < comm.size(); ++p)
  111. if (p != root)
  112. reqs.push_back(comm.isend(p, 0, skeleton(original_list)));
  113. wait_all(reqs.begin(), reqs.end());
  114. }
  115. std::cout << "OK." << std::endl;
  116. // Broadcast the content (manually)
  117. std::cout << "Non-blocking broadcast of integer list content from root " << root
  118. << "...";
  119. {
  120. content c = get_content(original_list);
  121. std::vector<request> reqs;
  122. for (int p = 0; p < comm.size(); ++p)
  123. if (p != root) reqs.push_back(comm.isend(p, 1, c));
  124. wait_all(reqs.begin(), reqs.end());
  125. }
  126. std::cout << "OK." << std::endl;
  127. // Reverse the list, broadcast the content again
  128. std::reverse(original_list.begin(), original_list.end());
  129. std::cout << "Non-blocking broadcast of reversed integer list content from root "
  130. << root << "...";
  131. {
  132. std::vector<request> reqs;
  133. content c = get_content(original_list);
  134. for (int p = 0; p < comm.size(); ++p)
  135. if (p != root) reqs.push_back(comm.isend(p, 2, c));
  136. wait_all(reqs.begin(), reqs.end());
  137. }
  138. std::cout << "OK." << std::endl;
  139. } else {
  140. // Allocate some useless data, to try to get the addresses of the
  141. // list<int>'s used later to be different across processes.
  142. std::list<int> junk_list(comm.rank() * 3 + 1, 17);
  143. // Receive the skeleton to build up the transferred list
  144. std::list<int> transferred_list;
  145. request req = comm.irecv(root, 0, skeleton(transferred_list));
  146. req.wait();
  147. BOOST_CHECK((int)transferred_list.size() == list_size);
  148. // Receive the content and check it
  149. req = comm.irecv(root, 1, get_content(transferred_list));
  150. req.wait();
  151. BOOST_CHECK(std::equal(make_counting_iterator(0),
  152. make_counting_iterator(list_size),
  153. transferred_list.begin()));
  154. // Receive the reversed content and check it
  155. req = comm.irecv(root, 2, get_content(transferred_list));
  156. req.wait();
  157. BOOST_CHECK(std::equal(make_counting_iterator(0),
  158. make_counting_iterator(list_size),
  159. transferred_list.rbegin()));
  160. }
  161. (comm.barrier)();
  162. }
  163. BOOST_AUTO_TEST_CASE(sendrecv)
  164. {
  165. boost::mpi::environment env;
  166. communicator comm;
  167. BOOST_TEST_REQUIRE(comm.size() > 1);
  168. test_skeleton_and_content(comm, 0, true);
  169. test_skeleton_and_content(comm, 0, false);
  170. test_skeleton_and_content(comm, 1, true);
  171. test_skeleton_and_content(comm, 1, false);
  172. test_skeleton_and_content_nonblocking(comm, 0);
  173. test_skeleton_and_content_nonblocking(comm, 1);
  174. }