algorithm_performance.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887
  1. // Copyright 2004 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: Nick Edmonds
  6. // Andrew Lumsdaine
  7. // #define PBGL_ACCOUNTING
  8. #include <boost/graph/use_mpi.hpp>
  9. #include <boost/graph/distributed/compressed_sparse_row_graph.hpp>
  10. #include <boost/graph/distributed/adjacency_list.hpp>
  11. #include <boost/graph/distributed/mpi_process_group.hpp>
  12. #include <boost/test/minimal.hpp>
  13. #include <boost/random.hpp>
  14. #include <boost/property_map/parallel/distributed_property_map.hpp>
  15. #include <boost/graph/distributed/graphviz.hpp>
  16. #include <boost/graph/iteration_macros.hpp>
  17. #include <boost/graph/properties.hpp>
  18. #include <boost/graph/rmat_graph_generator.hpp>
  19. #include <boost/graph/small_world_generator.hpp>
  20. #include <boost/graph/erdos_renyi_generator.hpp>
  21. #include <boost/graph/distributed/connected_components.hpp>
  22. #include <boost/graph/distributed/connected_components_parallel_search.hpp>
  23. #include <boost/graph/distributed/betweenness_centrality.hpp>
  24. #include <boost/graph/distributed/delta_stepping_shortest_paths.hpp>
  25. #include <time.h>
  26. #include <sys/time.h>
  27. #include <iostream>
  28. #include <iomanip>
  29. #include <vector>
  30. #include <stdint.h>
  31. // Edge distribution tags select a generator
  32. struct rmat_edge_distribution_tag { };
  33. struct rmat_unique_edge_distribution_tag { };
  34. using namespace boost;
  35. using boost::graph::distributed::mpi_process_group;
  36. /****************************************************************************
  37. * Timing
  38. ****************************************************************************/
  39. #ifndef PBGL_ACCOUNTING
  40. typedef double time_type;
  41. inline time_type get_time()
  42. {
  43. timeval tp;
  44. gettimeofday(&tp, 0);
  45. return tp.tv_sec + tp.tv_usec / 1000000.0;
  46. }
  47. std::string print_time(time_type t)
  48. {
  49. std::ostringstream out;
  50. out << std::setiosflags(std::ios::fixed) << std::setprecision(2) << t;
  51. return out.str();
  52. }
  53. #endif // PBGL_ACCOUNTING
  54. /****************************************************************************
  55. * Edge weight generator iterator *
  56. ****************************************************************************/
  57. template<typename F, typename RandomGenerator>
  58. class generator_iterator
  59. {
  60. public:
  61. typedef std::input_iterator_tag iterator_category;
  62. typedef typename F::result_type value_type;
  63. typedef const value_type& reference;
  64. typedef const value_type* pointer;
  65. typedef void difference_type;
  66. explicit
  67. generator_iterator(RandomGenerator& gen, const F& f = F())
  68. : f(f), gen(&gen)
  69. {
  70. value = this->f(gen);
  71. }
  72. reference operator*() const { return value; }
  73. pointer operator->() const { return &value; }
  74. generator_iterator& operator++()
  75. {
  76. value = f(*gen);
  77. return *this;
  78. }
  79. generator_iterator operator++(int)
  80. {
  81. generator_iterator temp(*this);
  82. ++(*this);
  83. return temp;
  84. }
  85. bool operator==(const generator_iterator& other) const
  86. { return f == other.f; }
  87. bool operator!=(const generator_iterator& other) const
  88. { return !(*this == other); }
  89. private:
  90. F f;
  91. RandomGenerator* gen;
  92. value_type value;
  93. };
  94. template<typename F, typename RandomGenerator>
  95. inline generator_iterator<F, RandomGenerator>
  96. make_generator_iterator( RandomGenerator& gen, const F& f)
  97. { return generator_iterator<F, RandomGenerator>(gen, f); }
  98. /****************************************************************************
  99. * Edge Property *
  100. ****************************************************************************/
  101. typedef int weight_type;
  102. struct WeightedEdge {
  103. WeightedEdge(weight_type weight = 0) : weight(weight) { }
  104. weight_type weight;
  105. template<typename Archiver>
  106. void serialize(Archiver& ar, const unsigned int /*version*/)
  107. {
  108. ar & weight;
  109. }
  110. };
  111. /****************************************************************************
  112. * Algorithm Tests *
  113. ****************************************************************************/
  114. template <typename Graph>
  115. void test_directed_sequential_algorithms(const Graph& g)
  116. { }
  117. template <typename Graph>
  118. void test_undirected_sequential_algorithms(const Graph& g)
  119. {
  120. std::vector<unsigned int> componentS(num_vertices(g));
  121. typedef iterator_property_map<
  122. std::vector<unsigned int>::iterator,
  123. typename property_map<Graph, vertex_index_t>::type>
  124. ComponentMap;
  125. ComponentMap component(componentS.begin(), get(vertex_index, g));
  126. time_type start = get_time();
  127. unsigned int num_components = connected_components(g, component);
  128. time_type end = get_time();
  129. std::cerr << " Sequential connected Components time = "
  130. << print_time(end - start) << " seconds.\n"
  131. << " " << num_components << " components identified\n";
  132. }
  133. template <typename Graph, typename EdgeWeightMap>
  134. void test_directed_csr_only_algorithms(const Graph& g, EdgeWeightMap weight,
  135. typename graph_traits<Graph>::vertices_size_type num_sources,
  136. typename property_traits<EdgeWeightMap>::value_type C)
  137. {
  138. typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
  139. typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
  140. typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type;
  141. typedef typename graph_traits<Graph>::edges_size_type edges_size_type;
  142. typedef typename boost::graph::parallel::process_group_type<Graph>::type
  143. process_group_type;
  144. process_group_type pg = process_group(g);
  145. typename process_group_type::process_id_type id = process_id(pg);
  146. typename process_group_type::process_size_type p = num_processes(pg);
  147. vertices_size_type n = num_vertices(g);
  148. n = boost::parallel::all_reduce(pg, n, std::plus<vertices_size_type>());
  149. edges_size_type m = num_edges(g);
  150. m = boost::parallel::all_reduce(pg, m, std::plus<edges_size_type>());
  151. //
  152. // Betweenness Centrality (Approximate)
  153. //
  154. queue<vertex_descriptor> delta_stepping_vertices;
  155. {
  156. // Distributed Centrality Map
  157. typedef typename property_map<Graph, vertex_index_t>::const_type IndexMap;
  158. typedef iterator_property_map<std::vector<int>::iterator, IndexMap> CentralityMap;
  159. std::vector<int> centralityS(num_vertices(g), 0);
  160. CentralityMap centrality(centralityS.begin(), get(vertex_index, g));
  161. // Calculate number of vertices of degree 0
  162. vertices_size_type n0 = 0;
  163. BGL_FORALL_VERTICES_T(v, g, Graph) {
  164. if (out_degree(v, g) == 0) n0++;
  165. }
  166. n0 = boost::parallel::all_reduce(pg, n0, std::plus<vertices_size_type>());
  167. queue<vertex_descriptor> sources;
  168. {
  169. assert(num_sources >= p); // Don't feel like adding a special case for num_sources < p
  170. minstd_rand gen;
  171. uniform_int<vertices_size_type> rand_vertex(0, num_vertices(g) - 1);
  172. std::vector<vertex_descriptor> all_sources, local_sources;
  173. vertices_size_type local_vertices = vertices_size_type(floor((double)num_sources / p));
  174. local_vertices += (id < (num_sources - (p * local_vertices)) ? 1 : 0);
  175. while (local_vertices > 0) {
  176. vertex_iterator iter = vertices(g).first;
  177. std::advance(iter, rand_vertex(gen));
  178. if (out_degree(*iter, g) != 0
  179. && std::find(local_sources.begin(), local_sources.end(), *iter) == local_sources.end()) {
  180. local_sources.push_back(*iter);
  181. --local_vertices;
  182. }
  183. }
  184. all_gather(pg, local_sources.begin(), local_sources.end(), all_sources);
  185. std::sort(all_sources.begin(), all_sources.end());
  186. for (typename std::vector<vertex_descriptor>::iterator iter = all_sources.begin();
  187. iter != all_sources.end(); ++iter) {
  188. sources.push(*iter);
  189. delta_stepping_vertices.push(*iter);
  190. }
  191. }
  192. // NOTE: The delta below assumes uniform edge weight distribution
  193. time_type start = get_time();
  194. brandes_betweenness_centrality(g, buffer(sources).weight_map(weight).
  195. centrality_map(centrality).lookahead((m / n) * (C / 2)));
  196. time_type end = get_time();
  197. edges_size_type exactTEPs = edges_size_type(floor(7 * n* (n - n0) / (end - start)));
  198. if (id == 0)
  199. std::cerr << " Betweenness Centrality Approximate (" << num_sources << " sources) = "
  200. << print_time(end - start) << " (" << exactTEPs << " TEPs)\n";
  201. }
  202. //
  203. // Delta stepping performance (to compare to SSSP inside BC
  204. //
  205. if (false) {
  206. typedef typename property_map<Graph, vertex_index_t>::const_type IndexMap;
  207. typedef iterator_property_map<std::vector<int>::iterator, IndexMap> DistanceMap;
  208. std::vector<int> distanceS(num_vertices(g), 0);
  209. DistanceMap distance(distanceS.begin(), get(vertex_index, g));
  210. while(!delta_stepping_vertices.empty()) {
  211. time_type start = get_time();
  212. delta_stepping_shortest_paths(g, delta_stepping_vertices.top(), dummy_property_map(),
  213. distance, weight);
  214. time_type end = get_time();
  215. delta_stepping_vertices.pop();
  216. distance.reset();
  217. if (id == 0)
  218. std::cerr << " Delta-stepping shortest paths = " << print_time(end - start)
  219. << std::endl;
  220. }
  221. }
  222. }
  223. template <typename Graph>
  224. void test_directed_algorithms(const Graph& g)
  225. {
  226. }
  227. template <typename Graph>
  228. void test_undirected_algorithms(const Graph& g)
  229. {
  230. typedef typename boost::graph::parallel::process_group_type<Graph>::type
  231. process_group_type;
  232. process_group_type pg = process_group(g);
  233. typename process_group_type::process_id_type id = process_id(pg);
  234. typename process_group_type::process_size_type p = num_processes(pg);
  235. // Connected Components
  236. std::vector<unsigned int> local_components_vec(num_vertices(g));
  237. typedef iterator_property_map<
  238. std::vector<unsigned int>::iterator,
  239. typename property_map<Graph, vertex_index_t>::type>
  240. ComponentMap;
  241. ComponentMap component(local_components_vec.begin(), get(vertex_index, g));
  242. int num_components;
  243. time_type start = get_time();
  244. num_components = connected_components(g, component);
  245. time_type end = get_time();
  246. if (id == 0)
  247. std::cerr << " Connected Components time = " << print_time(end - start)
  248. << " seconds.\n"
  249. << " " << num_components << " components identified\n";
  250. start = get_time();
  251. num_components = boost::graph::distributed::connected_components_ps(g, component);
  252. end = get_time();
  253. if (id == 0)
  254. std::cerr << " Connected Components (parallel search) time = "
  255. << print_time(end - start) << " seconds.\n"
  256. << " " << num_components << " components identified\n";
  257. }
  258. /****************************************************************************
  259. * Graph Type Tests *
  260. ****************************************************************************/
  261. // TODO: Re-seed PRNG before sequential tests to get the same graph as the
  262. // distributed case?
  263. //
  264. // Compressed Sparse Row
  265. //
  266. // R-MAT
  267. template <typename ProcessGroup, typename RandomGenerator, typename Distribution>
  268. void test_csr(const ProcessGroup& pg, RandomGenerator& gen, Distribution& distrib,
  269. bool sequential_tests, size_t N, size_t M, size_t C,
  270. double a, double b, double c, double d, size_t num_sources,
  271. rmat_edge_distribution_tag)
  272. {
  273. if (process_id(pg) == 0)
  274. std::cerr << " R-MAT\n";
  275. typedef compressed_sparse_row_graph<directedS, no_property, WeightedEdge, no_property,
  276. distributedS<mpi_process_group> > Graph;
  277. Graph g(sorted_rmat_iterator<RandomGenerator, Graph>(gen, N, M, a, b, c, d),
  278. sorted_rmat_iterator<RandomGenerator, Graph>(),
  279. make_generator_iterator(gen, uniform_int<int>(1, C)),
  280. N, pg, distrib);
  281. test_directed_algorithms(g);
  282. test_directed_csr_only_algorithms(g, get(&WeightedEdge::weight, g), num_sources, C);
  283. if (sequential_tests && process_id(pg) == 0) {
  284. typedef compressed_sparse_row_graph<directedS, no_property, WeightedEdge>
  285. seqGraph;
  286. seqGraph sg(edges_are_sorted,
  287. sorted_rmat_iterator<RandomGenerator, seqGraph>(gen, N, M, a, b, c, d),
  288. sorted_rmat_iterator<RandomGenerator, seqGraph>(),
  289. make_generator_iterator(gen, uniform_int<int>(1, C)),
  290. N);
  291. test_directed_sequential_algorithms(sg);
  292. }
  293. }
  294. // R-MAT with unique edges
  295. template <typename ProcessGroup, typename RandomGenerator, typename Distribution>
  296. void test_csr(const ProcessGroup& pg, RandomGenerator& gen, Distribution& distrib,
  297. bool sequential_tests, size_t N, size_t M, size_t C,
  298. double a, double b, double c, double d, size_t num_sources,
  299. rmat_unique_edge_distribution_tag)
  300. {
  301. if (process_id(pg) == 0)
  302. std::cerr << " R-MAT - unique\n";
  303. typedef compressed_sparse_row_graph<directedS, no_property, WeightedEdge, no_property,
  304. distributedS<mpi_process_group> > Graph;
  305. // Last boolean parameter makes R-MAT bidirectional
  306. Graph g(sorted_unique_rmat_iterator<RandomGenerator, Graph>(gen, N, M, a, b, c, d),
  307. sorted_unique_rmat_iterator<RandomGenerator, Graph>(),
  308. make_generator_iterator(gen, uniform_int<int>(1, C)),
  309. N, pg, distrib);
  310. test_directed_algorithms(g);
  311. test_directed_csr_only_algorithms(g, get(&WeightedEdge::weight, g), num_sources, C);
  312. if (sequential_tests && process_id(pg) == 0) {
  313. typedef compressed_sparse_row_graph<directedS, no_property, WeightedEdge>
  314. seqGraph;
  315. seqGraph sg(edges_are_sorted,
  316. sorted_unique_rmat_iterator<RandomGenerator, seqGraph>(gen, N, M, a, b, c, d),
  317. sorted_unique_rmat_iterator<RandomGenerator, seqGraph>(),
  318. make_generator_iterator(gen, uniform_int<int>(1, C)),
  319. N);
  320. test_directed_sequential_algorithms(sg);
  321. }
  322. }
  323. // Erdos-Renyi
  324. template <typename ProcessGroup, typename RandomGenerator, typename Distribution>
  325. void test_csr(const ProcessGroup& pg, RandomGenerator& gen, Distribution& distrib,
  326. bool sequential_tests, size_t N, size_t M, size_t C, size_t num_sources)
  327. {
  328. if (process_id(pg) == 0)
  329. std::cerr << " Erdos-Renyi\n";
  330. double _p = static_cast<double>(M) / (N*N);
  331. typedef compressed_sparse_row_graph<directedS, no_property, WeightedEdge, no_property,
  332. distributedS<mpi_process_group> > Graph;
  333. Graph g(sorted_erdos_renyi_iterator<RandomGenerator, Graph>(gen, N, _p/2),
  334. sorted_erdos_renyi_iterator<RandomGenerator, Graph>(),
  335. make_generator_iterator(gen, uniform_int<int>(1, C)),
  336. N, pg, distrib);
  337. test_directed_algorithms(g);
  338. test_directed_csr_only_algorithms(g, get(&WeightedEdge::weight, g), num_sources, C);
  339. if (sequential_tests && process_id(pg) == 0) {
  340. typedef compressed_sparse_row_graph<directedS, no_property, WeightedEdge>
  341. seqGraph;
  342. seqGraph sg(edges_are_sorted,
  343. sorted_erdos_renyi_iterator<RandomGenerator, seqGraph>(gen, N, _p/2),
  344. sorted_erdos_renyi_iterator<RandomGenerator, seqGraph>(),
  345. make_generator_iterator(gen, uniform_int<int>(1, C)),
  346. N);
  347. test_directed_sequential_algorithms(sg);
  348. }
  349. }
  350. // Small World
  351. template <typename ProcessGroup, typename RandomGenerator, typename Distribution>
  352. void test_csr(const ProcessGroup& pg, RandomGenerator& gen, Distribution& distrib,
  353. bool sequential_tests, size_t N, size_t M, size_t C, double p,
  354. size_t num_sources)
  355. {
  356. if (process_id(pg) == 0)
  357. std::cerr << " Small-World\n";
  358. int k = M / N;
  359. typedef compressed_sparse_row_graph<directedS, no_property, WeightedEdge, no_property,
  360. distributedS<mpi_process_group> > Graph;
  361. Graph g(small_world_iterator<RandomGenerator, Graph>(gen, N, k, p),
  362. small_world_iterator<RandomGenerator, Graph>(),
  363. make_generator_iterator(gen, uniform_int<int>(1, C)),
  364. N, pg, distrib);
  365. test_directed_algorithms(g);
  366. test_directed_csr_only_algorithms(g, get(&WeightedEdge::weight, g), num_sources, C);
  367. if (sequential_tests && process_id(pg) == 0) {
  368. typedef compressed_sparse_row_graph<directedS, no_property, WeightedEdge>
  369. seqGraph;
  370. seqGraph sg(edges_are_sorted,
  371. small_world_iterator<RandomGenerator, seqGraph>(gen, N, k, p),
  372. small_world_iterator<RandomGenerator, seqGraph>(),
  373. make_generator_iterator(gen, uniform_int<int>(1, C)),
  374. N);
  375. test_directed_sequential_algorithms(sg);
  376. }
  377. }
  378. //
  379. // Adjacency List
  380. //
  381. // R-MAT
  382. template <typename ProcessGroup, typename RandomGenerator, typename Distribution>
  383. void test_adjacency_list(const ProcessGroup& pg, RandomGenerator& gen, Distribution& distrib,
  384. bool sequential_tests, size_t N, size_t M, size_t C,
  385. double a, double b, double c, double d,
  386. rmat_edge_distribution_tag)
  387. {
  388. if (process_id(pg) == 0)
  389. std::cerr << "R-MAT\n";
  390. {
  391. typedef adjacency_list<vecS, distributedS<mpi_process_group, vecS>,
  392. directedS, no_property, WeightedEdge> Graph;
  393. Graph g(rmat_iterator<RandomGenerator, Graph>(gen, N, M, a, b, c, d),
  394. rmat_iterator<RandomGenerator, Graph>(),
  395. make_generator_iterator(gen, uniform_int<int>(1, C)),
  396. N, pg, distrib);
  397. test_directed_algorithms(g);
  398. }
  399. {
  400. typedef adjacency_list<vecS, distributedS<mpi_process_group, vecS>,
  401. undirectedS, no_property, WeightedEdge> Graph;
  402. Graph g(rmat_iterator<RandomGenerator, Graph>(gen, N, M, a, b, c, d),
  403. rmat_iterator<RandomGenerator, Graph>(),
  404. make_generator_iterator(gen, uniform_int<int>(1, C)),
  405. N, pg, distrib);
  406. test_undirected_algorithms(g);
  407. }
  408. if (sequential_tests && process_id(pg) == 0) {
  409. {
  410. typedef adjacency_list<vecS, vecS, directedS, no_property, property<edge_weight_t, int> >
  411. seqGraph;
  412. seqGraph sg(rmat_iterator<RandomGenerator, seqGraph>(gen, N, M, a, b, c, d),
  413. rmat_iterator<RandomGenerator, seqGraph>(),
  414. make_generator_iterator(gen, uniform_int<int>(1, C)),
  415. N);
  416. test_directed_sequential_algorithms(sg);
  417. }
  418. {
  419. typedef adjacency_list<vecS, vecS, undirectedS, no_property, property<edge_weight_t, int> >
  420. seqGraph;
  421. seqGraph sg(rmat_iterator<RandomGenerator, seqGraph>(gen, N, M, a, b, c, d),
  422. rmat_iterator<RandomGenerator, seqGraph>(),
  423. make_generator_iterator(gen, uniform_int<int>(1, C)),
  424. N);
  425. test_undirected_sequential_algorithms(sg);
  426. }
  427. }
  428. }
  429. // R-MAT with unique edges
  430. template <typename ProcessGroup, typename RandomGenerator, typename Distribution>
  431. void test_adjacency_list(const ProcessGroup& pg, RandomGenerator& gen, Distribution& distrib,
  432. bool sequential_tests, size_t N, size_t M, size_t C,
  433. double a, double b, double c, double d,
  434. rmat_unique_edge_distribution_tag)
  435. {
  436. if (process_id(pg) == 0)
  437. std::cerr << " R-MAT - unique\n";
  438. {
  439. typedef adjacency_list<vecS, distributedS<mpi_process_group, vecS>,
  440. directedS, no_property, WeightedEdge> Graph;
  441. Graph g(sorted_unique_rmat_iterator<RandomGenerator, Graph>(gen, N, M, a, b, c, d),
  442. sorted_unique_rmat_iterator<RandomGenerator, Graph>(),
  443. make_generator_iterator(gen, uniform_int<int>(1, C)),
  444. N, pg, distrib);
  445. test_directed_algorithms(g);
  446. }
  447. {
  448. typedef adjacency_list<vecS, distributedS<mpi_process_group, vecS>,
  449. undirectedS, no_property, WeightedEdge> Graph;
  450. Graph g(sorted_unique_rmat_iterator<RandomGenerator, Graph>(gen, N, M, a, b, c, d),
  451. sorted_unique_rmat_iterator<RandomGenerator, Graph>(),
  452. make_generator_iterator(gen, uniform_int<int>(1, C)),
  453. N, pg, distrib);
  454. test_undirected_algorithms(g);
  455. }
  456. if (sequential_tests && process_id(pg) == 0) {
  457. {
  458. typedef adjacency_list<vecS, vecS, directedS, no_property, property<edge_weight_t, int> >
  459. seqGraph;
  460. seqGraph sg(sorted_unique_rmat_iterator<RandomGenerator, seqGraph>(gen, N, M, a, b, c, d),
  461. sorted_unique_rmat_iterator<RandomGenerator, seqGraph>(),
  462. make_generator_iterator(gen, uniform_int<int>(1, C)),
  463. N);
  464. test_directed_sequential_algorithms(sg);
  465. }
  466. {
  467. typedef adjacency_list<vecS, vecS, undirectedS, no_property, property<edge_weight_t, int> >
  468. seqGraph;
  469. seqGraph sg(sorted_unique_rmat_iterator<RandomGenerator, seqGraph>(gen, N, M, a, b, c, d),
  470. sorted_unique_rmat_iterator<RandomGenerator, seqGraph>(),
  471. make_generator_iterator(gen, uniform_int<int>(1, C)),
  472. N);
  473. test_undirected_sequential_algorithms(sg);
  474. }
  475. }
  476. }
  477. // Erdos-Renyi
  478. template <typename ProcessGroup, typename RandomGenerator, typename Distribution>
  479. void test_adjacency_list(const ProcessGroup& pg, RandomGenerator& gen, Distribution& distrib,
  480. bool sequential_tests, size_t N, size_t M, size_t C)
  481. {
  482. if (process_id(pg) == 0)
  483. std::cerr << " Erdos-Renyi\n";
  484. double _p = static_cast<double>(M) / N*N;
  485. {
  486. typedef adjacency_list<vecS, distributedS<mpi_process_group, vecS>,
  487. directedS, no_property, WeightedEdge> Graph;
  488. Graph g(erdos_renyi_iterator<RandomGenerator, Graph>(gen, N, _p/2),
  489. erdos_renyi_iterator<RandomGenerator, Graph>(),
  490. make_generator_iterator(gen, uniform_int<int>(1, C)),
  491. N, pg, distrib);
  492. test_directed_algorithms(g);
  493. }
  494. {
  495. typedef adjacency_list<vecS, distributedS<mpi_process_group, vecS>,
  496. undirectedS, no_property, WeightedEdge> Graph;
  497. Graph g(erdos_renyi_iterator<RandomGenerator, Graph>(gen, N, _p/2),
  498. erdos_renyi_iterator<RandomGenerator, Graph>(),
  499. make_generator_iterator(gen, uniform_int<int>(1, C)),
  500. N, pg, distrib);
  501. test_undirected_algorithms(g);
  502. }
  503. if (sequential_tests && process_id(pg) == 0) {
  504. {
  505. typedef adjacency_list<vecS, vecS, directedS, no_property, property<edge_weight_t, int> >
  506. seqGraph;
  507. seqGraph sg(erdos_renyi_iterator<RandomGenerator, seqGraph>(gen, N, _p/2),
  508. erdos_renyi_iterator<RandomGenerator, seqGraph>(),
  509. make_generator_iterator(gen, uniform_int<int>(1, C)),
  510. N);
  511. test_directed_sequential_algorithms(sg);
  512. }
  513. {
  514. typedef adjacency_list<vecS, vecS, undirectedS, no_property, property<edge_weight_t, int> >
  515. seqGraph;
  516. seqGraph sg(erdos_renyi_iterator<RandomGenerator, seqGraph>(gen, N, _p/2),
  517. erdos_renyi_iterator<RandomGenerator, seqGraph>(),
  518. make_generator_iterator(gen, uniform_int<int>(1, C)),
  519. N);
  520. test_undirected_sequential_algorithms(sg);
  521. }
  522. }
  523. }
  524. // Small World
  525. template <typename ProcessGroup, typename RandomGenerator, typename Distribution>
  526. void test_adjacency_list(const ProcessGroup& pg, RandomGenerator& gen, Distribution& distrib,
  527. bool sequential_tests, size_t N, size_t M, size_t C, double p)
  528. {
  529. if (process_id(pg) == 0)
  530. std::cerr << " Small-World\n";
  531. int k = M / N;
  532. {
  533. typedef adjacency_list<vecS, distributedS<mpi_process_group, vecS>,
  534. directedS, no_property, WeightedEdge> Graph;
  535. Graph g(small_world_iterator<RandomGenerator, Graph>(gen, N, k, p),
  536. small_world_iterator<RandomGenerator, Graph>(),
  537. make_generator_iterator(gen, uniform_int<int>(1, C)),
  538. N, pg, distrib);
  539. test_directed_algorithms(g);
  540. }
  541. {
  542. typedef adjacency_list<vecS, distributedS<mpi_process_group, vecS>,
  543. undirectedS, no_property, WeightedEdge> Graph;
  544. Graph g(small_world_iterator<RandomGenerator, Graph>(gen, N, k, p),
  545. small_world_iterator<RandomGenerator, Graph>(),
  546. make_generator_iterator(gen, uniform_int<int>(1, C)),
  547. N, pg, distrib);
  548. test_undirected_algorithms(g);
  549. }
  550. if (sequential_tests && process_id(pg) == 0) {
  551. {
  552. typedef adjacency_list<vecS, vecS, directedS, no_property, property<edge_weight_t, int> >
  553. seqGraph;
  554. seqGraph sg(small_world_iterator<RandomGenerator, seqGraph>(gen, N, k, p),
  555. small_world_iterator<RandomGenerator, seqGraph>(),
  556. make_generator_iterator(gen, uniform_int<int>(1, C)),
  557. N);
  558. test_directed_sequential_algorithms(sg);
  559. }
  560. {
  561. typedef adjacency_list<vecS, vecS, undirectedS, no_property, property<edge_weight_t, int> >
  562. seqGraph;
  563. seqGraph sg(small_world_iterator<RandomGenerator, seqGraph>(gen, N, k, p),
  564. small_world_iterator<RandomGenerator, seqGraph>(),
  565. make_generator_iterator(gen, uniform_int<int>(1, C)),
  566. N);
  567. test_undirected_sequential_algorithms(sg);
  568. }
  569. }
  570. }
  571. void usage()
  572. {
  573. std::cerr << "Algorithm Performance Test\n"
  574. << "Usage : algorithm_performance [options]\n\n"
  575. << "Options are:\n"
  576. << "\t--vertices v\t\t\tNumber of vertices in the graph\n"
  577. << "\t--edges v\t\t\tNumber of edges in the graph\n"
  578. << "\t--seed s\t\t\tSeed for synchronized random number generator\n"
  579. << "\t--max-weight miw\t\tMaximum integer edge weight\n"
  580. << "\t--rewire-probability\t\tRewire-probabitility (p) for small-world graphs\n"
  581. << "\t--dot\t\t\t\tEmit a dot file containing the graph\n"
  582. << "\t--verify\t\t\tVerify result\n"
  583. << "\t--degree-dist\t\t\tOutput degree distribution of graph\n"
  584. << "\t--sequential-graph\t\tRun sequential graph tests\n"
  585. << "\t--erdos-renyi\t\t\tRun tests on Erdos-Renyi graphs\n"
  586. << "\t--small-world\t\t\tRun tests on Small World graphs\n"
  587. << "\t--rmat\t\t\t\tRun tests on R-MAT graphs\n"
  588. << "\t--rmat-unique\t\t\tRun tests on R-MAT graphs with no duplicate edges\n"
  589. << "\t--csr <bool>\t\t\tRun tests using CSR graphs\n"
  590. << "\t--adjacency-list <bool>\t\tRun tests using Adjacency List graphs\n";
  591. }
  592. int test_main(int argc, char* argv[])
  593. {
  594. mpi::environment env(argc, argv);
  595. rand48 gen;
  596. // Default args
  597. size_t n = 100,
  598. m = 8*n,
  599. c = 100,
  600. num_sources = 32,
  601. num_headers = 16 * 1024,
  602. batch_buffer_size = 1024 * 1024;
  603. uint64_t seed = 1;
  604. bool emit_dot_file = false,
  605. verify = false,
  606. sequential_graph = false,
  607. show_degree_dist = false,
  608. erdos_renyi = false,
  609. small_world = false,
  610. rmat = false,
  611. rmat_unique = false,
  612. csr = false,
  613. adj_list = false;
  614. double p = 0.1,
  615. rmat_a = 0.5,
  616. rmat_b = 0.25,
  617. rmat_c = 0.1,
  618. rmat_d = 0.15;
  619. // Parse args
  620. for (int i = 1; i < argc; ++i) {
  621. std::string arg = argv[i];
  622. if (arg == "--vertices")
  623. n = boost::lexical_cast<size_t>( argv[i+1] );
  624. if (arg == "--seed")
  625. seed = boost::lexical_cast<uint64_t>( argv[i+1] );
  626. if (arg == "--edges")
  627. m = boost::lexical_cast<size_t>( argv[i+1] );
  628. if (arg == "--max-weight")
  629. c = boost::lexical_cast<int>( argv[i+1] );
  630. if (arg == "--batch-buffer-size") {
  631. batch_buffer_size = boost::lexical_cast<size_t>( argv[i+1] );
  632. num_headers = batch_buffer_size / 16;
  633. num_headers = num_headers > 0 ? num_headers : 1;
  634. }
  635. if (arg == "--rewire-probability")
  636. p = boost::lexical_cast<double>( argv[i+1] );
  637. if (arg == "--num-sources")
  638. num_sources = boost::lexical_cast<size_t>( argv[i + 1] );
  639. if (arg == "--erdos-renyi")
  640. erdos_renyi = true;
  641. if (arg == "--small-world")
  642. small_world = true;
  643. if (arg == "--rmat")
  644. rmat = true;
  645. if (arg == "--rmat-unique")
  646. rmat_unique = true;
  647. if (arg == "--dot")
  648. emit_dot_file = true;
  649. if (arg == "--verify")
  650. verify = true;
  651. if (arg == "--degree-dist")
  652. show_degree_dist = true;
  653. if (arg == "--sequential-graph")
  654. sequential_graph = true;
  655. if (arg == "--csr")
  656. csr = std::string(argv[i+1]) == "true";
  657. if (arg == "--adjacency-list")
  658. adj_list = std::string(argv[i+1]) == "true";
  659. }
  660. mpi_process_group pg(num_headers, batch_buffer_size);
  661. if (argc == 1) {
  662. if (process_id(pg) == 0)
  663. usage();
  664. exit(-1);
  665. }
  666. gen.seed(seed);
  667. parallel::variant_distribution<mpi_process_group> distrib
  668. = parallel::block(pg, n);
  669. if (csr) {
  670. if (process_id(pg) == 0)
  671. std::cerr << "CSR Graph Tests\n";
  672. if (erdos_renyi)
  673. test_csr(pg, gen, distrib, sequential_graph, n, m, c, num_sources);
  674. if (small_world)
  675. test_csr(pg, gen, distrib, sequential_graph, n, m, c, p, num_sources);
  676. if (rmat)
  677. test_csr(pg, gen, distrib, sequential_graph, n, m, c,
  678. rmat_a, rmat_b, rmat_c, rmat_d, num_sources, rmat_edge_distribution_tag());
  679. if (rmat_unique)
  680. test_csr(pg, gen, distrib, sequential_graph, n, m, c,
  681. rmat_a, rmat_b, rmat_c, rmat_d, num_sources, rmat_unique_edge_distribution_tag());
  682. }
  683. gen.seed(seed); // DEBUG
  684. if (adj_list) {
  685. if (process_id(pg) == 0)
  686. std::cerr << "Adjacency List Graph Tests\n";
  687. if (erdos_renyi)
  688. test_adjacency_list(pg, gen, distrib, sequential_graph, n, m, c);
  689. if (small_world)
  690. test_adjacency_list(pg, gen, distrib, sequential_graph, n, m, c, p);
  691. if (rmat)
  692. test_adjacency_list(pg, gen, distrib, sequential_graph, n, m, c,
  693. rmat_a, rmat_b, rmat_c, rmat_d, rmat_edge_distribution_tag());
  694. if (rmat_unique)
  695. test_adjacency_list(pg, gen, distrib, sequential_graph, n, m, c,
  696. rmat_a, rmat_b, rmat_c, rmat_d, rmat_unique_edge_distribution_tag());
  697. }
  698. return 0;
  699. }