distributed_property_map_test.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. // Copyright (C) 2004-2008 The Trustees of Indiana University.
  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. // Authors: Douglas Gregor
  6. // Andrew Lumsdaine
  7. #include <boost/graph/use_mpi.hpp>
  8. #include <boost/config.hpp>
  9. #include <boost/throw_exception.hpp>
  10. #include <boost/graph/distributed/mpi_process_group.hpp>
  11. #include <boost/property_map/property_map.hpp>
  12. #include <boost/test/minimal.hpp>
  13. #include <vector>
  14. #include <string>
  15. #include <boost/serialization/vector.hpp>
  16. #include <boost/serialization/string.hpp>
  17. #include <boost/serialization/utility.hpp>
  18. #include <boost/lexical_cast.hpp>
  19. #include <boost/graph/parallel/basic_reduce.hpp>
  20. #ifdef BOOST_NO_EXCEPTIONS
  21. void
  22. boost::throw_exception(std::exception const& ex)
  23. {
  24. std::cout << ex.what() << std::endl;
  25. abort();
  26. }
  27. #endif
  28. using namespace boost;
  29. using boost::graph::distributed::mpi_process_group;
  30. enum color_t { red, blue };
  31. struct remote_key
  32. {
  33. remote_key(int p = -1, std::size_t l = 0) : processor(p), local_key(l) {}
  34. int processor;
  35. std::size_t local_key;
  36. template<typename Archiver>
  37. void serialize(Archiver& ar, const unsigned int /*version*/)
  38. {
  39. ar & processor & local_key;
  40. }
  41. };
  42. namespace boost { namespace mpi {
  43. template<> struct is_mpi_datatype<remote_key> : mpl::true_ { };
  44. } }
  45. BOOST_IS_BITWISE_SERIALIZABLE(remote_key)
  46. BOOST_CLASS_IMPLEMENTATION(remote_key,object_serializable)
  47. BOOST_CLASS_TRACKING(remote_key,track_never)
  48. namespace boost {
  49. template<>
  50. struct hash<remote_key>
  51. {
  52. std::size_t operator()(const remote_key& key) const
  53. {
  54. std::size_t hash = hash_value(key.processor);
  55. hash_combine(hash, key.local_key);
  56. return hash;
  57. }
  58. };
  59. }
  60. inline bool operator==(const remote_key& x, const remote_key& y)
  61. { return x.processor == y.processor && x.local_key == y.local_key; }
  62. struct remote_key_to_global
  63. {
  64. typedef readable_property_map_tag category;
  65. typedef remote_key key_type;
  66. typedef std::pair<int, std::size_t> value_type;
  67. typedef value_type reference;
  68. };
  69. inline std::pair<int, std::size_t>
  70. get(remote_key_to_global, const remote_key& key)
  71. {
  72. return std::make_pair(key.processor, key.local_key);
  73. }
  74. template<typename T>
  75. struct my_reduce : boost::parallel::basic_reduce<T> {
  76. BOOST_STATIC_CONSTANT(bool, non_default_resolver = true);
  77. };
  78. void colored_test()
  79. {
  80. mpi_process_group pg;
  81. const int n = 500;
  82. color_t my_start_color = process_id(pg) % 2 == 0? ::red : ::blue;
  83. int next_processor = (process_id(pg) + 1) % num_processes(pg);
  84. color_t next_start_color = next_processor % 2 == 0? ::red : ::blue;
  85. // Initial color map: even-numbered processes are all red,
  86. // odd-numbered processes are all blue.
  87. std::vector<color_t> color_vec(n, my_start_color);
  88. typedef iterator_property_map<std::vector<color_t>::iterator,
  89. identity_property_map> LocalPropertyMap;
  90. LocalPropertyMap local_colors(color_vec.begin(), identity_property_map());
  91. synchronize(pg);
  92. // Create the distributed property map
  93. typedef boost::parallel::distributed_property_map<mpi_process_group,
  94. remote_key_to_global,
  95. LocalPropertyMap> ColorMap;
  96. ColorMap colors(pg, remote_key_to_global(), local_colors);
  97. colors.set_reduce(my_reduce<color_t>());
  98. if (process_id(pg) == 0) std::cerr << "Checking local colors...";
  99. // check local processor colors
  100. for (int i = 0; i < n; ++i) {
  101. remote_key k(process_id(pg), i);
  102. BOOST_CHECK(get(colors, k) == my_start_color);
  103. }
  104. colors.set_consistency_model(boost::parallel::cm_bidirectional);
  105. if (process_id(pg) == 0) std::cerr << "OK.\nChecking next processor's default colors...";
  106. // check next processor's colors
  107. for (int i = 0; i < n; ++i) {
  108. remote_key k(next_processor, i);
  109. BOOST_CHECK(get(colors, k) == color_t());
  110. }
  111. if (process_id(pg) == 0) std::cerr << "OK.\nSynchronizing...";
  112. synchronize(pg);
  113. if (process_id(pg) == 0) std::cerr << "OK.\nChecking next processor's colors...";
  114. // check next processor's colors
  115. for (int i = 0; i < n; ++i) {
  116. remote_key k(next_processor, i);
  117. BOOST_CHECK(get(colors, k) == next_start_color);
  118. }
  119. if (process_id(pg) == 0) std::cerr << "OK.\nSynchronizing...";
  120. synchronize(pg);
  121. if (process_id(pg) == 0) std::cerr << "OK.\nChanging next processor's colors...";
  122. // change the next processor's colors
  123. color_t next_finish_color = next_processor % 2 == 0? ::blue : ::red;
  124. for (int i = 0; i < n; ++i) {
  125. remote_key k(next_processor, i);
  126. put(colors, k, next_finish_color);
  127. }
  128. if (process_id(pg) == 0) std::cerr << "OK.\nSynchronizing...";
  129. synchronize(pg);
  130. if (process_id(pg) == 0) std::cerr << "OK.\nChecking changed colors...";
  131. // check our own colors
  132. color_t my_finish_color = process_id(pg) % 2 == 0? ::blue : ::red;
  133. for (int i = 0; i < n; ++i) {
  134. remote_key k(process_id(pg), i);
  135. BOOST_CHECK(get(colors, k) == my_finish_color);
  136. }
  137. // check our neighbor's colors
  138. if (process_id(pg) == 0) std::cerr << "OK.\nChecking changed colors on neighbor...";
  139. for (int i = 0; i < n; ++i) {
  140. remote_key k(next_processor, i);
  141. BOOST_CHECK(get(colors, k) == next_finish_color);
  142. }
  143. synchronize(pg);
  144. if (process_id(pg) == 0) std::cerr << "OK.\n";
  145. }
  146. void bool_test()
  147. {
  148. mpi_process_group pg;
  149. const int n = 500;
  150. bool my_start_value = process_id(pg) % 2;
  151. int next_processor = (process_id(pg) + 1) % num_processes(pg);
  152. bool next_start_value = ((process_id(pg) + 1) % num_processes(pg)) % 2;
  153. // Initial color map: even-numbered processes are false,
  154. // odd-numbered processes are true
  155. std::vector<bool> bool_vec(n, my_start_value);
  156. typedef iterator_property_map<std::vector<bool>::iterator,
  157. identity_property_map> LocalPropertyMap;
  158. LocalPropertyMap local_values(bool_vec.begin(), identity_property_map());
  159. synchronize(pg);
  160. // Create the distributed property map
  161. typedef boost::parallel::distributed_property_map<mpi_process_group,
  162. remote_key_to_global,
  163. LocalPropertyMap> ValueMap;
  164. ValueMap values(pg, remote_key_to_global(), local_values);
  165. values.set_reduce(my_reduce<bool>());
  166. if (process_id(pg) == 0) std::cerr << "Checking local values...";
  167. // check local processor values
  168. for (int i = 0; i < n; ++i) {
  169. remote_key k(process_id(pg), i);
  170. BOOST_CHECK(get(values, k) == my_start_value);
  171. }
  172. values.set_consistency_model(boost::parallel::cm_bidirectional);
  173. if (process_id(pg) == 0) std::cerr << "OK.\nChecking next processor's default values...";
  174. // check next processor's values
  175. for (int i = 0; i < n; ++i) {
  176. remote_key k(next_processor, i);
  177. BOOST_CHECK(get(values, k) == false);
  178. }
  179. if (process_id(pg) == 0) std::cerr << "OK.\nSynchronizing...";
  180. synchronize(pg);
  181. if (process_id(pg) == 0) std::cerr << "OK.\nChecking next processor's values...";
  182. // check next processor's values
  183. for (int i = 0; i < n; ++i) {
  184. remote_key k(next_processor, i);
  185. BOOST_CHECK(get(values, k) == next_start_value);
  186. }
  187. if (process_id(pg) == 0) std::cerr << "OK.\nSynchronizing...";
  188. synchronize(pg);
  189. if (process_id(pg) == 0) std::cerr << "OK.\nChanging next processor's values...";
  190. // change the next processor's values
  191. bool next_finish_value = next_processor % 2 == 0;
  192. for (int i = 0; i < n; ++i) {
  193. remote_key k(next_processor, i);
  194. put(values, k, next_finish_value);
  195. }
  196. if (process_id(pg) == 0) std::cerr << "OK.\nSynchronizing...";
  197. synchronize(pg);
  198. if (process_id(pg) == 0) std::cerr << "OK.\nChecking changed values...";
  199. // check our own values
  200. bool my_finish_value = process_id(pg) % 2 == 0;
  201. for (int i = 0; i < n; ++i) {
  202. remote_key k(process_id(pg), i);
  203. BOOST_CHECK(get(values, k) == my_finish_value);
  204. }
  205. // check our neighbor's values
  206. if (process_id(pg) == 0) std::cerr << "OK.\nChecking changed values on neighbor...";
  207. for (int i = 0; i < n; ++i) {
  208. remote_key k(next_processor, i);
  209. BOOST_CHECK(get(values, k) == next_finish_value);
  210. }
  211. synchronize(pg);
  212. if (process_id(pg) == 0) std::cerr << "OK.\n";
  213. }
  214. void string_test()
  215. {
  216. mpi_process_group pg;
  217. const int n = 500;
  218. std::string my_start_string = lexical_cast<std::string>(process_id(pg));
  219. int next_processor = (process_id(pg) + 1) % num_processes(pg);
  220. std::string next_start_string = lexical_cast<std::string>(next_processor);
  221. // Initial color map: even-numbered processes are false,
  222. // odd-numbered processes are true
  223. std::vector<std::string> string_vec(n, my_start_string);
  224. typedef iterator_property_map<std::vector<std::string>::iterator,
  225. identity_property_map> LocalPropertyMap;
  226. LocalPropertyMap local_strings(string_vec.begin(), identity_property_map());
  227. synchronize(pg);
  228. // Create the distributed property map
  229. typedef boost::parallel::distributed_property_map<mpi_process_group,
  230. remote_key_to_global,
  231. LocalPropertyMap> StringMap;
  232. StringMap strings(pg, remote_key_to_global(), local_strings);
  233. strings.set_reduce(my_reduce<std::string>());
  234. if (process_id(pg) == 0) std::cerr << "Checking local strings...";
  235. // check local processor strings
  236. for (int i = 0; i < n; ++i) {
  237. remote_key k(process_id(pg), i);
  238. BOOST_CHECK(get(strings, k) == my_start_string);
  239. }
  240. strings.set_consistency_model(boost::parallel::cm_bidirectional);
  241. if (process_id(pg) == 0) std::cerr << "OK.\nChecking next processor's default strings...";
  242. // check next processor's strings
  243. for (int i = 0; i < n; ++i) {
  244. remote_key k(next_processor, i);
  245. BOOST_CHECK(get(strings, k) == (num_processes(pg) == 1 ? my_start_string : std::string()));
  246. }
  247. if (process_id(pg) == 0) std::cerr << "OK.\nSynchronizing...";
  248. synchronize(pg);
  249. if (process_id(pg) == 0) std::cerr << "OK.\nChecking next processor's strings...";
  250. // check next processor's strings
  251. for (int i = 0; i < n; ++i) {
  252. remote_key k(next_processor, i);
  253. BOOST_CHECK(get(strings, k) == next_start_string);
  254. }
  255. if (process_id(pg) == 0) std::cerr << "OK.\nSynchronizing...";
  256. synchronize(pg);
  257. if (process_id(pg) == 0) std::cerr << "OK.\nChanging next processor's strings...";
  258. // change the next processor's strings
  259. std::string next_finish_string = next_start_string + next_start_string;
  260. for (int i = 0; i < n; ++i) {
  261. remote_key k(next_processor, i);
  262. put(strings, k, next_finish_string);
  263. }
  264. if (process_id(pg) == 0) std::cerr << "OK.\nSynchronizing...";
  265. synchronize(pg);
  266. if (process_id(pg) == 0) std::cerr << "OK.\nChecking changed strings...";
  267. // check our own strings
  268. std::string my_finish_string = my_start_string + my_start_string;
  269. for (int i = 0; i < n; ++i) {
  270. remote_key k(process_id(pg), i);
  271. BOOST_CHECK(get(strings, k) == my_finish_string);
  272. }
  273. // check our neighbor's strings
  274. if (process_id(pg) == 0) std::cerr << "OK.\nChecking changed strings on neighbor...";
  275. for (int i = 0; i < n; ++i) {
  276. remote_key k(next_processor, i);
  277. BOOST_CHECK(get(strings, k) == next_finish_string);
  278. }
  279. synchronize(pg);
  280. if (process_id(pg) == 0) std::cerr << "OK.\n";
  281. }
  282. int test_main(int argc, char** argv)
  283. {
  284. boost::mpi::environment env(argc, argv);
  285. colored_test();
  286. bool_test();
  287. string_test();
  288. return 0;
  289. }