graph_parallel/test/algorithm_performance.cpp

888 lines
30 KiB
C++

// Copyright 2004 The Trustees of Indiana University.
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// Authors: Nick Edmonds
// Andrew Lumsdaine
// #define PBGL_ACCOUNTING
#include <boost/graph/use_mpi.hpp>
#include <boost/graph/distributed/compressed_sparse_row_graph.hpp>
#include <boost/graph/distributed/adjacency_list.hpp>
#include <boost/graph/distributed/mpi_process_group.hpp>
#include <boost/test/minimal.hpp>
#include <boost/random.hpp>
#include <boost/property_map/parallel/distributed_property_map.hpp>
#include <boost/graph/distributed/graphviz.hpp>
#include <boost/graph/iteration_macros.hpp>
#include <boost/graph/properties.hpp>
#include <boost/graph/rmat_graph_generator.hpp>
#include <boost/graph/small_world_generator.hpp>
#include <boost/graph/erdos_renyi_generator.hpp>
#include <boost/graph/distributed/connected_components.hpp>
#include <boost/graph/distributed/connected_components_parallel_search.hpp>
#include <boost/graph/distributed/betweenness_centrality.hpp>
#include <boost/graph/distributed/delta_stepping_shortest_paths.hpp>
#include <time.h>
#include <sys/time.h>
#include <iostream>
#include <iomanip>
#include <vector>
#include <stdint.h>
// Edge distribution tags select a generator
struct rmat_edge_distribution_tag { };
struct rmat_unique_edge_distribution_tag { };
using namespace boost;
using boost::graph::distributed::mpi_process_group;
/****************************************************************************
* Timing
****************************************************************************/
#ifndef PBGL_ACCOUNTING
typedef double time_type;
inline time_type get_time()
{
timeval tp;
gettimeofday(&tp, 0);
return tp.tv_sec + tp.tv_usec / 1000000.0;
}
std::string print_time(time_type t)
{
std::ostringstream out;
out << std::setiosflags(std::ios::fixed) << std::setprecision(2) << t;
return out.str();
}
#endif // PBGL_ACCOUNTING
/****************************************************************************
* Edge weight generator iterator *
****************************************************************************/
template<typename F, typename RandomGenerator>
class generator_iterator
{
public:
typedef std::input_iterator_tag iterator_category;
typedef typename F::result_type value_type;
typedef const value_type& reference;
typedef const value_type* pointer;
typedef void difference_type;
explicit
generator_iterator(RandomGenerator& gen, const F& f = F())
: f(f), gen(&gen)
{
value = this->f(gen);
}
reference operator*() const { return value; }
pointer operator->() const { return &value; }
generator_iterator& operator++()
{
value = f(*gen);
return *this;
}
generator_iterator operator++(int)
{
generator_iterator temp(*this);
++(*this);
return temp;
}
bool operator==(const generator_iterator& other) const
{ return f == other.f; }
bool operator!=(const generator_iterator& other) const
{ return !(*this == other); }
private:
F f;
RandomGenerator* gen;
value_type value;
};
template<typename F, typename RandomGenerator>
inline generator_iterator<F, RandomGenerator>
make_generator_iterator( RandomGenerator& gen, const F& f)
{ return generator_iterator<F, RandomGenerator>(gen, f); }
/****************************************************************************
* Edge Property *
****************************************************************************/
typedef int weight_type;
struct WeightedEdge {
WeightedEdge(weight_type weight = 0) : weight(weight) { }
weight_type weight;
template<typename Archiver>
void serialize(Archiver& ar, const unsigned int /*version*/)
{
ar & weight;
}
};
/****************************************************************************
* Algorithm Tests *
****************************************************************************/
template <typename Graph>
void test_directed_sequential_algorithms(const Graph& g)
{ }
template <typename Graph>
void test_undirected_sequential_algorithms(const Graph& g)
{
std::vector<unsigned int> componentS(num_vertices(g));
typedef iterator_property_map<
std::vector<unsigned int>::iterator,
typename property_map<Graph, vertex_index_t>::type>
ComponentMap;
ComponentMap component(componentS.begin(), get(vertex_index, g));
time_type start = get_time();
unsigned int num_components = connected_components(g, component);
time_type end = get_time();
std::cerr << " Sequential connected Components time = "
<< print_time(end - start) << " seconds.\n"
<< " " << num_components << " components identified\n";
}
template <typename Graph, typename EdgeWeightMap>
void test_directed_csr_only_algorithms(const Graph& g, EdgeWeightMap weight,
typename graph_traits<Graph>::vertices_size_type num_sources,
typename property_traits<EdgeWeightMap>::value_type C)
{
typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type;
typedef typename graph_traits<Graph>::edges_size_type edges_size_type;
typedef typename boost::graph::parallel::process_group_type<Graph>::type
process_group_type;
process_group_type pg = process_group(g);
typename process_group_type::process_id_type id = process_id(pg);
typename process_group_type::process_size_type p = num_processes(pg);
vertices_size_type n = num_vertices(g);
n = boost::parallel::all_reduce(pg, n, std::plus<vertices_size_type>());
edges_size_type m = num_edges(g);
m = boost::parallel::all_reduce(pg, m, std::plus<edges_size_type>());
//
// Betweenness Centrality (Approximate)
//
queue<vertex_descriptor> delta_stepping_vertices;
{
// Distributed Centrality Map
typedef typename property_map<Graph, vertex_index_t>::const_type IndexMap;
typedef iterator_property_map<std::vector<int>::iterator, IndexMap> CentralityMap;
std::vector<int> centralityS(num_vertices(g), 0);
CentralityMap centrality(centralityS.begin(), get(vertex_index, g));
// Calculate number of vertices of degree 0
vertices_size_type n0 = 0;
BGL_FORALL_VERTICES_T(v, g, Graph) {
if (out_degree(v, g) == 0) n0++;
}
n0 = boost::parallel::all_reduce(pg, n0, std::plus<vertices_size_type>());
queue<vertex_descriptor> sources;
{
assert(num_sources >= p); // Don't feel like adding a special case for num_sources < p
minstd_rand gen;
uniform_int<vertices_size_type> rand_vertex(0, num_vertices(g) - 1);
std::vector<vertex_descriptor> all_sources, local_sources;
vertices_size_type local_vertices = vertices_size_type(floor((double)num_sources / p));
local_vertices += (id < (num_sources - (p * local_vertices)) ? 1 : 0);
while (local_vertices > 0) {
vertex_iterator iter = vertices(g).first;
std::advance(iter, rand_vertex(gen));
if (out_degree(*iter, g) != 0
&& std::find(local_sources.begin(), local_sources.end(), *iter) == local_sources.end()) {
local_sources.push_back(*iter);
--local_vertices;
}
}
all_gather(pg, local_sources.begin(), local_sources.end(), all_sources);
std::sort(all_sources.begin(), all_sources.end());
for (typename std::vector<vertex_descriptor>::iterator iter = all_sources.begin();
iter != all_sources.end(); ++iter) {
sources.push(*iter);
delta_stepping_vertices.push(*iter);
}
}
// NOTE: The delta below assumes uniform edge weight distribution
time_type start = get_time();
brandes_betweenness_centrality(g, buffer(sources).weight_map(weight).
centrality_map(centrality).lookahead((m / n) * (C / 2)));
time_type end = get_time();
edges_size_type exactTEPs = edges_size_type(floor(7 * n* (n - n0) / (end - start)));
if (id == 0)
std::cerr << " Betweenness Centrality Approximate (" << num_sources << " sources) = "
<< print_time(end - start) << " (" << exactTEPs << " TEPs)\n";
}
//
// Delta stepping performance (to compare to SSSP inside BC
//
if (false) {
typedef typename property_map<Graph, vertex_index_t>::const_type IndexMap;
typedef iterator_property_map<std::vector<int>::iterator, IndexMap> DistanceMap;
std::vector<int> distanceS(num_vertices(g), 0);
DistanceMap distance(distanceS.begin(), get(vertex_index, g));
while(!delta_stepping_vertices.empty()) {
time_type start = get_time();
delta_stepping_shortest_paths(g, delta_stepping_vertices.top(), dummy_property_map(),
distance, weight);
time_type end = get_time();
delta_stepping_vertices.pop();
distance.reset();
if (id == 0)
std::cerr << " Delta-stepping shortest paths = " << print_time(end - start)
<< std::endl;
}
}
}
template <typename Graph>
void test_directed_algorithms(const Graph& g)
{
}
template <typename Graph>
void test_undirected_algorithms(const Graph& g)
{
typedef typename boost::graph::parallel::process_group_type<Graph>::type
process_group_type;
process_group_type pg = process_group(g);
typename process_group_type::process_id_type id = process_id(pg);
typename process_group_type::process_size_type p = num_processes(pg);
// Connected Components
std::vector<unsigned int> local_components_vec(num_vertices(g));
typedef iterator_property_map<
std::vector<unsigned int>::iterator,
typename property_map<Graph, vertex_index_t>::type>
ComponentMap;
ComponentMap component(local_components_vec.begin(), get(vertex_index, g));
int num_components;
time_type start = get_time();
num_components = connected_components(g, component);
time_type end = get_time();
if (id == 0)
std::cerr << " Connected Components time = " << print_time(end - start)
<< " seconds.\n"
<< " " << num_components << " components identified\n";
start = get_time();
num_components = boost::graph::distributed::connected_components_ps(g, component);
end = get_time();
if (id == 0)
std::cerr << " Connected Components (parallel search) time = "
<< print_time(end - start) << " seconds.\n"
<< " " << num_components << " components identified\n";
}
/****************************************************************************
* Graph Type Tests *
****************************************************************************/
// TODO: Re-seed PRNG before sequential tests to get the same graph as the
// distributed case?
//
// Compressed Sparse Row
//
// R-MAT
template <typename ProcessGroup, typename RandomGenerator, typename Distribution>
void test_csr(const ProcessGroup& pg, RandomGenerator& gen, Distribution& distrib,
bool sequential_tests, size_t N, size_t M, size_t C,
double a, double b, double c, double d, size_t num_sources,
rmat_edge_distribution_tag)
{
if (process_id(pg) == 0)
std::cerr << " R-MAT\n";
typedef compressed_sparse_row_graph<directedS, no_property, WeightedEdge, no_property,
distributedS<mpi_process_group> > Graph;
Graph g(sorted_rmat_iterator<RandomGenerator, Graph>(gen, N, M, a, b, c, d),
sorted_rmat_iterator<RandomGenerator, Graph>(),
make_generator_iterator(gen, uniform_int<int>(1, C)),
N, pg, distrib);
test_directed_algorithms(g);
test_directed_csr_only_algorithms(g, get(&WeightedEdge::weight, g), num_sources, C);
if (sequential_tests && process_id(pg) == 0) {
typedef compressed_sparse_row_graph<directedS, no_property, WeightedEdge>
seqGraph;
seqGraph sg(edges_are_sorted,
sorted_rmat_iterator<RandomGenerator, seqGraph>(gen, N, M, a, b, c, d),
sorted_rmat_iterator<RandomGenerator, seqGraph>(),
make_generator_iterator(gen, uniform_int<int>(1, C)),
N);
test_directed_sequential_algorithms(sg);
}
}
// R-MAT with unique edges
template <typename ProcessGroup, typename RandomGenerator, typename Distribution>
void test_csr(const ProcessGroup& pg, RandomGenerator& gen, Distribution& distrib,
bool sequential_tests, size_t N, size_t M, size_t C,
double a, double b, double c, double d, size_t num_sources,
rmat_unique_edge_distribution_tag)
{
if (process_id(pg) == 0)
std::cerr << " R-MAT - unique\n";
typedef compressed_sparse_row_graph<directedS, no_property, WeightedEdge, no_property,
distributedS<mpi_process_group> > Graph;
// Last boolean parameter makes R-MAT bidirectional
Graph g(sorted_unique_rmat_iterator<RandomGenerator, Graph>(gen, N, M, a, b, c, d),
sorted_unique_rmat_iterator<RandomGenerator, Graph>(),
make_generator_iterator(gen, uniform_int<int>(1, C)),
N, pg, distrib);
test_directed_algorithms(g);
test_directed_csr_only_algorithms(g, get(&WeightedEdge::weight, g), num_sources, C);
if (sequential_tests && process_id(pg) == 0) {
typedef compressed_sparse_row_graph<directedS, no_property, WeightedEdge>
seqGraph;
seqGraph sg(edges_are_sorted,
sorted_unique_rmat_iterator<RandomGenerator, seqGraph>(gen, N, M, a, b, c, d),
sorted_unique_rmat_iterator<RandomGenerator, seqGraph>(),
make_generator_iterator(gen, uniform_int<int>(1, C)),
N);
test_directed_sequential_algorithms(sg);
}
}
// Erdos-Renyi
template <typename ProcessGroup, typename RandomGenerator, typename Distribution>
void test_csr(const ProcessGroup& pg, RandomGenerator& gen, Distribution& distrib,
bool sequential_tests, size_t N, size_t M, size_t C, size_t num_sources)
{
if (process_id(pg) == 0)
std::cerr << " Erdos-Renyi\n";
double _p = static_cast<double>(M) / (N*N);
typedef compressed_sparse_row_graph<directedS, no_property, WeightedEdge, no_property,
distributedS<mpi_process_group> > Graph;
Graph g(sorted_erdos_renyi_iterator<RandomGenerator, Graph>(gen, N, _p/2),
sorted_erdos_renyi_iterator<RandomGenerator, Graph>(),
make_generator_iterator(gen, uniform_int<int>(1, C)),
N, pg, distrib);
test_directed_algorithms(g);
test_directed_csr_only_algorithms(g, get(&WeightedEdge::weight, g), num_sources, C);
if (sequential_tests && process_id(pg) == 0) {
typedef compressed_sparse_row_graph<directedS, no_property, WeightedEdge>
seqGraph;
seqGraph sg(edges_are_sorted,
sorted_erdos_renyi_iterator<RandomGenerator, seqGraph>(gen, N, _p/2),
sorted_erdos_renyi_iterator<RandomGenerator, seqGraph>(),
make_generator_iterator(gen, uniform_int<int>(1, C)),
N);
test_directed_sequential_algorithms(sg);
}
}
// Small World
template <typename ProcessGroup, typename RandomGenerator, typename Distribution>
void test_csr(const ProcessGroup& pg, RandomGenerator& gen, Distribution& distrib,
bool sequential_tests, size_t N, size_t M, size_t C, double p,
size_t num_sources)
{
if (process_id(pg) == 0)
std::cerr << " Small-World\n";
int k = M / N;
typedef compressed_sparse_row_graph<directedS, no_property, WeightedEdge, no_property,
distributedS<mpi_process_group> > Graph;
Graph g(small_world_iterator<RandomGenerator, Graph>(gen, N, k, p),
small_world_iterator<RandomGenerator, Graph>(),
make_generator_iterator(gen, uniform_int<int>(1, C)),
N, pg, distrib);
test_directed_algorithms(g);
test_directed_csr_only_algorithms(g, get(&WeightedEdge::weight, g), num_sources, C);
if (sequential_tests && process_id(pg) == 0) {
typedef compressed_sparse_row_graph<directedS, no_property, WeightedEdge>
seqGraph;
seqGraph sg(edges_are_sorted,
small_world_iterator<RandomGenerator, seqGraph>(gen, N, k, p),
small_world_iterator<RandomGenerator, seqGraph>(),
make_generator_iterator(gen, uniform_int<int>(1, C)),
N);
test_directed_sequential_algorithms(sg);
}
}
//
// Adjacency List
//
// R-MAT
template <typename ProcessGroup, typename RandomGenerator, typename Distribution>
void test_adjacency_list(const ProcessGroup& pg, RandomGenerator& gen, Distribution& distrib,
bool sequential_tests, size_t N, size_t M, size_t C,
double a, double b, double c, double d,
rmat_edge_distribution_tag)
{
if (process_id(pg) == 0)
std::cerr << "R-MAT\n";
{
typedef adjacency_list<vecS, distributedS<mpi_process_group, vecS>,
directedS, no_property, WeightedEdge> Graph;
Graph g(rmat_iterator<RandomGenerator, Graph>(gen, N, M, a, b, c, d),
rmat_iterator<RandomGenerator, Graph>(),
make_generator_iterator(gen, uniform_int<int>(1, C)),
N, pg, distrib);
test_directed_algorithms(g);
}
{
typedef adjacency_list<vecS, distributedS<mpi_process_group, vecS>,
undirectedS, no_property, WeightedEdge> Graph;
Graph g(rmat_iterator<RandomGenerator, Graph>(gen, N, M, a, b, c, d),
rmat_iterator<RandomGenerator, Graph>(),
make_generator_iterator(gen, uniform_int<int>(1, C)),
N, pg, distrib);
test_undirected_algorithms(g);
}
if (sequential_tests && process_id(pg) == 0) {
{
typedef adjacency_list<vecS, vecS, directedS, no_property, property<edge_weight_t, int> >
seqGraph;
seqGraph sg(rmat_iterator<RandomGenerator, seqGraph>(gen, N, M, a, b, c, d),
rmat_iterator<RandomGenerator, seqGraph>(),
make_generator_iterator(gen, uniform_int<int>(1, C)),
N);
test_directed_sequential_algorithms(sg);
}
{
typedef adjacency_list<vecS, vecS, undirectedS, no_property, property<edge_weight_t, int> >
seqGraph;
seqGraph sg(rmat_iterator<RandomGenerator, seqGraph>(gen, N, M, a, b, c, d),
rmat_iterator<RandomGenerator, seqGraph>(),
make_generator_iterator(gen, uniform_int<int>(1, C)),
N);
test_undirected_sequential_algorithms(sg);
}
}
}
// R-MAT with unique edges
template <typename ProcessGroup, typename RandomGenerator, typename Distribution>
void test_adjacency_list(const ProcessGroup& pg, RandomGenerator& gen, Distribution& distrib,
bool sequential_tests, size_t N, size_t M, size_t C,
double a, double b, double c, double d,
rmat_unique_edge_distribution_tag)
{
if (process_id(pg) == 0)
std::cerr << " R-MAT - unique\n";
{
typedef adjacency_list<vecS, distributedS<mpi_process_group, vecS>,
directedS, no_property, WeightedEdge> Graph;
Graph g(sorted_unique_rmat_iterator<RandomGenerator, Graph>(gen, N, M, a, b, c, d),
sorted_unique_rmat_iterator<RandomGenerator, Graph>(),
make_generator_iterator(gen, uniform_int<int>(1, C)),
N, pg, distrib);
test_directed_algorithms(g);
}
{
typedef adjacency_list<vecS, distributedS<mpi_process_group, vecS>,
undirectedS, no_property, WeightedEdge> Graph;
Graph g(sorted_unique_rmat_iterator<RandomGenerator, Graph>(gen, N, M, a, b, c, d),
sorted_unique_rmat_iterator<RandomGenerator, Graph>(),
make_generator_iterator(gen, uniform_int<int>(1, C)),
N, pg, distrib);
test_undirected_algorithms(g);
}
if (sequential_tests && process_id(pg) == 0) {
{
typedef adjacency_list<vecS, vecS, directedS, no_property, property<edge_weight_t, int> >
seqGraph;
seqGraph sg(sorted_unique_rmat_iterator<RandomGenerator, seqGraph>(gen, N, M, a, b, c, d),
sorted_unique_rmat_iterator<RandomGenerator, seqGraph>(),
make_generator_iterator(gen, uniform_int<int>(1, C)),
N);
test_directed_sequential_algorithms(sg);
}
{
typedef adjacency_list<vecS, vecS, undirectedS, no_property, property<edge_weight_t, int> >
seqGraph;
seqGraph sg(sorted_unique_rmat_iterator<RandomGenerator, seqGraph>(gen, N, M, a, b, c, d),
sorted_unique_rmat_iterator<RandomGenerator, seqGraph>(),
make_generator_iterator(gen, uniform_int<int>(1, C)),
N);
test_undirected_sequential_algorithms(sg);
}
}
}
// Erdos-Renyi
template <typename ProcessGroup, typename RandomGenerator, typename Distribution>
void test_adjacency_list(const ProcessGroup& pg, RandomGenerator& gen, Distribution& distrib,
bool sequential_tests, size_t N, size_t M, size_t C)
{
if (process_id(pg) == 0)
std::cerr << " Erdos-Renyi\n";
double _p = static_cast<double>(M) / N*N;
{
typedef adjacency_list<vecS, distributedS<mpi_process_group, vecS>,
directedS, no_property, WeightedEdge> Graph;
Graph g(erdos_renyi_iterator<RandomGenerator, Graph>(gen, N, _p/2),
erdos_renyi_iterator<RandomGenerator, Graph>(),
make_generator_iterator(gen, uniform_int<int>(1, C)),
N, pg, distrib);
test_directed_algorithms(g);
}
{
typedef adjacency_list<vecS, distributedS<mpi_process_group, vecS>,
undirectedS, no_property, WeightedEdge> Graph;
Graph g(erdos_renyi_iterator<RandomGenerator, Graph>(gen, N, _p/2),
erdos_renyi_iterator<RandomGenerator, Graph>(),
make_generator_iterator(gen, uniform_int<int>(1, C)),
N, pg, distrib);
test_undirected_algorithms(g);
}
if (sequential_tests && process_id(pg) == 0) {
{
typedef adjacency_list<vecS, vecS, directedS, no_property, property<edge_weight_t, int> >
seqGraph;
seqGraph sg(erdos_renyi_iterator<RandomGenerator, seqGraph>(gen, N, _p/2),
erdos_renyi_iterator<RandomGenerator, seqGraph>(),
make_generator_iterator(gen, uniform_int<int>(1, C)),
N);
test_directed_sequential_algorithms(sg);
}
{
typedef adjacency_list<vecS, vecS, undirectedS, no_property, property<edge_weight_t, int> >
seqGraph;
seqGraph sg(erdos_renyi_iterator<RandomGenerator, seqGraph>(gen, N, _p/2),
erdos_renyi_iterator<RandomGenerator, seqGraph>(),
make_generator_iterator(gen, uniform_int<int>(1, C)),
N);
test_undirected_sequential_algorithms(sg);
}
}
}
// Small World
template <typename ProcessGroup, typename RandomGenerator, typename Distribution>
void test_adjacency_list(const ProcessGroup& pg, RandomGenerator& gen, Distribution& distrib,
bool sequential_tests, size_t N, size_t M, size_t C, double p)
{
if (process_id(pg) == 0)
std::cerr << " Small-World\n";
int k = M / N;
{
typedef adjacency_list<vecS, distributedS<mpi_process_group, vecS>,
directedS, no_property, WeightedEdge> Graph;
Graph g(small_world_iterator<RandomGenerator, Graph>(gen, N, k, p),
small_world_iterator<RandomGenerator, Graph>(),
make_generator_iterator(gen, uniform_int<int>(1, C)),
N, pg, distrib);
test_directed_algorithms(g);
}
{
typedef adjacency_list<vecS, distributedS<mpi_process_group, vecS>,
undirectedS, no_property, WeightedEdge> Graph;
Graph g(small_world_iterator<RandomGenerator, Graph>(gen, N, k, p),
small_world_iterator<RandomGenerator, Graph>(),
make_generator_iterator(gen, uniform_int<int>(1, C)),
N, pg, distrib);
test_undirected_algorithms(g);
}
if (sequential_tests && process_id(pg) == 0) {
{
typedef adjacency_list<vecS, vecS, directedS, no_property, property<edge_weight_t, int> >
seqGraph;
seqGraph sg(small_world_iterator<RandomGenerator, seqGraph>(gen, N, k, p),
small_world_iterator<RandomGenerator, seqGraph>(),
make_generator_iterator(gen, uniform_int<int>(1, C)),
N);
test_directed_sequential_algorithms(sg);
}
{
typedef adjacency_list<vecS, vecS, undirectedS, no_property, property<edge_weight_t, int> >
seqGraph;
seqGraph sg(small_world_iterator<RandomGenerator, seqGraph>(gen, N, k, p),
small_world_iterator<RandomGenerator, seqGraph>(),
make_generator_iterator(gen, uniform_int<int>(1, C)),
N);
test_undirected_sequential_algorithms(sg);
}
}
}
void usage()
{
std::cerr << "Algorithm Performance Test\n"
<< "Usage : algorithm_performance [options]\n\n"
<< "Options are:\n"
<< "\t--vertices v\t\t\tNumber of vertices in the graph\n"
<< "\t--edges v\t\t\tNumber of edges in the graph\n"
<< "\t--seed s\t\t\tSeed for synchronized random number generator\n"
<< "\t--max-weight miw\t\tMaximum integer edge weight\n"
<< "\t--rewire-probability\t\tRewire-probabitility (p) for small-world graphs\n"
<< "\t--dot\t\t\t\tEmit a dot file containing the graph\n"
<< "\t--verify\t\t\tVerify result\n"
<< "\t--degree-dist\t\t\tOutput degree distribution of graph\n"
<< "\t--sequential-graph\t\tRun sequential graph tests\n"
<< "\t--erdos-renyi\t\t\tRun tests on Erdos-Renyi graphs\n"
<< "\t--small-world\t\t\tRun tests on Small World graphs\n"
<< "\t--rmat\t\t\t\tRun tests on R-MAT graphs\n"
<< "\t--rmat-unique\t\t\tRun tests on R-MAT graphs with no duplicate edges\n"
<< "\t--csr <bool>\t\t\tRun tests using CSR graphs\n"
<< "\t--adjacency-list <bool>\t\tRun tests using Adjacency List graphs\n";
}
int test_main(int argc, char* argv[])
{
mpi::environment env(argc, argv);
rand48 gen;
// Default args
size_t n = 100,
m = 8*n,
c = 100,
num_sources = 32,
num_headers = 16 * 1024,
batch_buffer_size = 1024 * 1024;
uint64_t seed = 1;
bool emit_dot_file = false,
verify = false,
sequential_graph = false,
show_degree_dist = false,
erdos_renyi = false,
small_world = false,
rmat = false,
rmat_unique = false,
csr = false,
adj_list = false;
double p = 0.1,
rmat_a = 0.5,
rmat_b = 0.25,
rmat_c = 0.1,
rmat_d = 0.15;
// Parse args
for (int i = 1; i < argc; ++i) {
std::string arg = argv[i];
if (arg == "--vertices")
n = boost::lexical_cast<size_t>( argv[i+1] );
if (arg == "--seed")
seed = boost::lexical_cast<uint64_t>( argv[i+1] );
if (arg == "--edges")
m = boost::lexical_cast<size_t>( argv[i+1] );
if (arg == "--max-weight")
c = boost::lexical_cast<int>( argv[i+1] );
if (arg == "--batch-buffer-size") {
batch_buffer_size = boost::lexical_cast<size_t>( argv[i+1] );
num_headers = batch_buffer_size / 16;
num_headers = num_headers > 0 ? num_headers : 1;
}
if (arg == "--rewire-probability")
p = boost::lexical_cast<double>( argv[i+1] );
if (arg == "--num-sources")
num_sources = boost::lexical_cast<size_t>( argv[i + 1] );
if (arg == "--erdos-renyi")
erdos_renyi = true;
if (arg == "--small-world")
small_world = true;
if (arg == "--rmat")
rmat = true;
if (arg == "--rmat-unique")
rmat_unique = true;
if (arg == "--dot")
emit_dot_file = true;
if (arg == "--verify")
verify = true;
if (arg == "--degree-dist")
show_degree_dist = true;
if (arg == "--sequential-graph")
sequential_graph = true;
if (arg == "--csr")
csr = std::string(argv[i+1]) == "true";
if (arg == "--adjacency-list")
adj_list = std::string(argv[i+1]) == "true";
}
mpi_process_group pg(num_headers, batch_buffer_size);
if (argc == 1) {
if (process_id(pg) == 0)
usage();
exit(-1);
}
gen.seed(seed);
parallel::variant_distribution<mpi_process_group> distrib
= parallel::block(pg, n);
if (csr) {
if (process_id(pg) == 0)
std::cerr << "CSR Graph Tests\n";
if (erdos_renyi)
test_csr(pg, gen, distrib, sequential_graph, n, m, c, num_sources);
if (small_world)
test_csr(pg, gen, distrib, sequential_graph, n, m, c, p, num_sources);
if (rmat)
test_csr(pg, gen, distrib, sequential_graph, n, m, c,
rmat_a, rmat_b, rmat_c, rmat_d, num_sources, rmat_edge_distribution_tag());
if (rmat_unique)
test_csr(pg, gen, distrib, sequential_graph, n, m, c,
rmat_a, rmat_b, rmat_c, rmat_d, num_sources, rmat_unique_edge_distribution_tag());
}
gen.seed(seed); // DEBUG
if (adj_list) {
if (process_id(pg) == 0)
std::cerr << "Adjacency List Graph Tests\n";
if (erdos_renyi)
test_adjacency_list(pg, gen, distrib, sequential_graph, n, m, c);
if (small_world)
test_adjacency_list(pg, gen, distrib, sequential_graph, n, m, c, p);
if (rmat)
test_adjacency_list(pg, gen, distrib, sequential_graph, n, m, c,
rmat_a, rmat_b, rmat_c, rmat_d, rmat_edge_distribution_tag());
if (rmat_unique)
test_adjacency_list(pg, gen, distrib, sequential_graph, n, m, c,
rmat_a, rmat_b, rmat_c, rmat_d, rmat_unique_edge_distribution_tag());
}
return 0;
}