nonblocking_test.cpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. // Copyright (C) 2006 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 nonblocking point-to-point operations.
  6. #include <boost/mpi/nonblocking.hpp>
  7. #include <boost/mpi/communicator.hpp>
  8. #include <boost/mpi/environment.hpp>
  9. #include "gps_position.hpp"
  10. #include <boost/lexical_cast.hpp>
  11. #include <boost/serialization/string.hpp>
  12. #include <boost/serialization/list.hpp>
  13. #include <iterator>
  14. #include <algorithm>
  15. //#include "debugger.cpp"
  16. #define BOOST_TEST_MODULE mpi_non_blockin_test
  17. #include <boost/test/included/unit_test.hpp>
  18. using boost::mpi::communicator;
  19. using boost::mpi::request;
  20. using boost::mpi::status;
  21. enum method_kind {
  22. mk_wait_any, mk_test_any, mk_wait_all, mk_wait_all_keep,
  23. mk_test_all, mk_test_all_keep, mk_wait_some, mk_wait_some_keep,
  24. mk_test_some, mk_test_some_keep,
  25. mk_test_size
  26. };
  27. static const char* method_kind_names[mk_test_size] = {
  28. "wait_any",
  29. "test_any",
  30. "wait_all",
  31. "wait_all (keep results)",
  32. "test_all",
  33. "test_all (keep results)",
  34. "wait_some",
  35. "wait_some (keep results)",
  36. "test_some",
  37. "test_some (keep results)"
  38. };
  39. template<typename T>
  40. void
  41. nonblocking_tests( const communicator& comm, const T* values, int num_values,
  42. const char* kind, bool composite)
  43. {
  44. nonblocking_test(comm, values, num_values, kind, mk_wait_any);
  45. nonblocking_test(comm, values, num_values, kind, mk_test_any);
  46. //wait_for_debugger(comm);
  47. nonblocking_test(comm, values, num_values, kind, mk_wait_all);
  48. nonblocking_test(comm, values, num_values, kind, mk_wait_all_keep);
  49. if (!composite) {
  50. nonblocking_test(comm, values, num_values, kind, mk_test_all);
  51. nonblocking_test(comm, values, num_values, kind, mk_test_all_keep);
  52. }
  53. nonblocking_test(comm, values, num_values, kind, mk_wait_some);
  54. nonblocking_test(comm, values, num_values, kind, mk_wait_some_keep);
  55. nonblocking_test(comm, values, num_values, kind, mk_test_some);
  56. nonblocking_test(comm, values, num_values, kind, mk_test_some_keep);
  57. }
  58. template<typename T>
  59. void
  60. nonblocking_test(const communicator& comm, const T* values, int num_values,
  61. const char* kind, method_kind method)
  62. {
  63. using boost::mpi::wait_any;
  64. using boost::mpi::test_any;
  65. using boost::mpi::wait_all;
  66. using boost::mpi::test_all;
  67. using boost::mpi::wait_some;
  68. using boost::mpi::test_some;
  69. int next = (comm.rank() + 1) % comm.size();
  70. int prev = (comm.rank() + comm.size() - 1) % comm.size();
  71. if (comm.rank() == 0) {
  72. std::cout << "Testing " << method_kind_names[method]
  73. << " with " << kind << "...";
  74. std::cout.flush();
  75. }
  76. typedef std::pair<status, std::vector<request>::iterator>
  77. status_iterator_pair;
  78. T incoming_value;
  79. std::vector<T> incoming_values(num_values);
  80. std::vector<request> reqs;
  81. // Send/receive the first value
  82. reqs.push_back(comm.isend(next, 0, values[0]));
  83. reqs.push_back(comm.irecv(prev, 0, incoming_value));
  84. if (method != mk_wait_any && method != mk_test_any) {
  85. #ifndef LAM_MPI
  86. // We've run into problems here (with 0-length messages) with
  87. // LAM/MPI on Mac OS X and x86-86 Linux. Will investigate
  88. // further at a later time, but the problem only seems to occur
  89. // when using shared memory, not TCP.
  90. // Send/receive an empty message
  91. reqs.push_back(comm.isend(next, 1));
  92. reqs.push_back(comm.irecv(prev, 1));
  93. #endif
  94. // Send/receive an array
  95. reqs.push_back(comm.isend(next, 2, values, num_values));
  96. reqs.push_back(comm.irecv(prev, 2, &incoming_values.front(), num_values));
  97. }
  98. switch (method) {
  99. case mk_wait_any:
  100. if (wait_any(reqs.begin(), reqs.end()).second == reqs.begin())
  101. reqs[1].wait();
  102. else
  103. reqs[0].wait();
  104. break;
  105. case mk_test_any:
  106. {
  107. boost::optional<status_iterator_pair> result;
  108. do {
  109. result = test_any(reqs.begin(), reqs.end());
  110. } while (!result);
  111. if (result->second == reqs.begin())
  112. reqs[1].wait();
  113. else
  114. reqs[0].wait();
  115. break;
  116. }
  117. case mk_wait_all:
  118. wait_all(reqs.begin(), reqs.end());
  119. break;
  120. case mk_wait_all_keep:
  121. {
  122. std::vector<status> stats;
  123. wait_all(reqs.begin(), reqs.end(), std::back_inserter(stats));
  124. }
  125. break;
  126. case mk_test_all:
  127. while (!test_all(reqs.begin(), reqs.end())) { /* Busy wait */ }
  128. break;
  129. case mk_test_all_keep:
  130. {
  131. std::vector<status> stats;
  132. while (!test_all(reqs.begin(), reqs.end(), std::back_inserter(stats)))
  133. /* Busy wait */;
  134. }
  135. break;
  136. case mk_wait_some:
  137. {
  138. std::vector<request>::iterator pos = reqs.end();
  139. do {
  140. pos = wait_some(reqs.begin(), pos);
  141. } while (pos != reqs.begin());
  142. }
  143. break;
  144. case mk_wait_some_keep:
  145. {
  146. std::vector<status> stats;
  147. std::vector<request>::iterator pos = reqs.end();
  148. do {
  149. pos = wait_some(reqs.begin(), pos, std::back_inserter(stats)).second;
  150. } while (pos != reqs.begin());
  151. }
  152. break;
  153. case mk_test_some:
  154. {
  155. std::vector<request>::iterator pos = reqs.end();
  156. do {
  157. pos = test_some(reqs.begin(), pos);
  158. } while (pos != reqs.begin());
  159. }
  160. break;
  161. case mk_test_some_keep:
  162. {
  163. std::vector<status> stats;
  164. std::vector<request>::iterator pos = reqs.end();
  165. do {
  166. pos = test_some(reqs.begin(), pos, std::back_inserter(stats)).second;
  167. } while (pos != reqs.begin());
  168. }
  169. break;
  170. default:
  171. BOOST_CHECK(false);
  172. }
  173. if (comm.rank() == 0) {
  174. bool okay = true;
  175. if (!((incoming_value == values[0])))
  176. okay = false;
  177. if (method != mk_wait_any && method != mk_test_any
  178. && !std::equal(incoming_values.begin(), incoming_values.end(),
  179. values))
  180. okay = false;
  181. if (okay)
  182. std::cout << "OK." << std::endl;
  183. else
  184. std::cerr << "ERROR!" << std::endl;
  185. }
  186. BOOST_CHECK(incoming_value == values[0]);
  187. if (method != mk_wait_any && method != mk_test_any)
  188. BOOST_CHECK(std::equal(incoming_values.begin(), incoming_values.end(),
  189. values));
  190. }
  191. BOOST_AUTO_TEST_CASE(nonblocking)
  192. {
  193. boost::mpi::environment env;
  194. communicator comm;
  195. int int_array[3] = {17, 42, 256};
  196. nonblocking_tests(comm, int_array, 3, "integers", false);
  197. gps_position gps_array[2] = {
  198. gps_position(17, 42, .06),
  199. gps_position(42, 17, .06)
  200. };
  201. nonblocking_tests(comm, gps_array, 2, "gps positions", false);
  202. std::string string_array[2] = { "Hello", "World" };
  203. nonblocking_tests(comm, string_array, 2, "strings", true);
  204. std::list<std::string> lst_of_strings;
  205. for (int i = 0; i < comm.size(); ++i)
  206. lst_of_strings.push_back(boost::lexical_cast<std::string>(i));
  207. nonblocking_tests(comm, &lst_of_strings, 1, "list of strings", true);
  208. }