A 2nd implementation conforming to vector creation [need optimization]
This commit is contained in:
+86
-36
@@ -16,6 +16,7 @@
|
||||
|
||||
// Global session data
|
||||
session_t session;
|
||||
Log logger;
|
||||
|
||||
/*!
|
||||
* A small command line argument parser
|
||||
@@ -35,74 +36,123 @@ bool get_options(int argc, char* argv[]){
|
||||
else
|
||||
status = false;
|
||||
}
|
||||
else if (arg == "-g" || arg == "--generate")
|
||||
else if (arg == "-o" || arg == "--output") {
|
||||
session.outputMode = OutputMode::FILE;
|
||||
if (i+1 < argc)
|
||||
session.outFile = std::ofstream(argv[++i]);
|
||||
else
|
||||
status = false;
|
||||
}
|
||||
else if (arg == "-g" || arg == "--generate") {
|
||||
session.inputMatrix = InputMatrix::GENERATE;
|
||||
else if (arg == "-s" || arg == "--size")
|
||||
session.size = (i+1 < argc) ? std::atoi(argv[++i]) : session.size;
|
||||
else if (arg == "-p" || arg == "--probability")
|
||||
session.probability = (i+1 < argc) ? std::atof(argv[++i]) : session.probability;
|
||||
else if (arg == "--print") {
|
||||
session.print = true;
|
||||
session.print_size = (i+1 < argc) ? std::atoi(argv[++i]) : session.print_size;
|
||||
if (i+2 < argc) {
|
||||
session.gen_size = std::atoi(argv[++i]);
|
||||
session.gen_prob = std::atof(argv[++i]);
|
||||
}
|
||||
else
|
||||
status = false;
|
||||
}
|
||||
else if (arg == "-n" || arg == "--max_trheads") {
|
||||
session.max_threads = (i+1 < argc) ? std::atoi(argv[++i]) : session.max_threads;
|
||||
}
|
||||
else if (arg == "--make_symmetric")
|
||||
session.makeSymmetric = true;
|
||||
else if (arg == "-t" || arg == "--timing")
|
||||
session.timing = true;
|
||||
else if (arg == "-v" || arg == "--verbose")
|
||||
session.verbose = true;
|
||||
else if (arg == "--triangular_only")
|
||||
session.makeSymmetric = false;
|
||||
else if (arg == "--validate_mtx")
|
||||
session.validate_mtx = true;
|
||||
else if (arg == "--print_count")
|
||||
session.print_count = true;
|
||||
else if (arg == "--print_graph") {
|
||||
session.mtx_print = true;
|
||||
session.mtx_print_size = (i+1 < argc) ? std::atoi(argv[++i]) : session.mtx_print_size;
|
||||
}
|
||||
else if (arg == "-h" || arg == "--help") {
|
||||
std::cout << "Help message\n";
|
||||
exit(0);
|
||||
}
|
||||
else {
|
||||
else { // parse error
|
||||
std::cout << "Error message\n";
|
||||
status = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Input checkers
|
||||
if (session.inputMatrix == InputMatrix::UNSPECIFIED) {
|
||||
std::cout << "Error message\n";
|
||||
status = false;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char* argv[]) try {
|
||||
Timing timer;
|
||||
matrix A;
|
||||
|
||||
// try to read command line
|
||||
if (!get_options(argc, argv))
|
||||
exit(1);
|
||||
|
||||
// get or generate matrix
|
||||
/*!
|
||||
* get or generate matrix
|
||||
* \param A Reference to matrix for output (move using RVO)
|
||||
* \param timer Reference to timer utility to access time printing functionality
|
||||
*/
|
||||
void prepare_matrix (matrix& A, Timing& timer) {
|
||||
if (session.inputMatrix == InputMatrix::GENERATE) {
|
||||
std::cout << "Initialize matrix with size: " << session.size << " and probability: " << session.probability << '\n';
|
||||
logger << "Initialize matrix with size: " << session.gen_size << " and probability: " << session.gen_prob << logger.endl;
|
||||
timer.start();
|
||||
A.size(session.size);
|
||||
init_ER_graph(A, session.probability);
|
||||
A.size(session.gen_size);
|
||||
init_ER_graph(A, session.gen_prob);
|
||||
timer.stop();
|
||||
if (session.timing) timer.print_dt();
|
||||
timer.print_dt("generate matrix");
|
||||
}
|
||||
else {
|
||||
std::cout << "Read matrix from file\n";
|
||||
logger << "Read matrix from file" << logger.endl;
|
||||
timer.start();
|
||||
if (session.makeSymmetric && !Mtx::is_triangular<matrix::indexType> (session.mtxFile))
|
||||
if (session.validate_mtx && !Mtx::is_triangular<matrix::indexType> (session.mtxFile))
|
||||
throw std::runtime_error("Error: Matrix is not strictly upper or lower");
|
||||
if (!Mtx::load (A, session.mtxFile)) {
|
||||
throw std::runtime_error("Error: fail to load matrix");
|
||||
}
|
||||
timer.stop();
|
||||
std::cout << "Matrix size: " << A.size() << " and capacity: " << A.capacity() <<'\n';
|
||||
if (session.timing) timer.print_dt();
|
||||
logger << "Matrix size: " << A.size() << " and capacity: " << A.capacity() << logger.endl;
|
||||
timer.print_dt("load matrix");
|
||||
}
|
||||
|
||||
if (session.print) {
|
||||
std::cout << "Array A:\n";
|
||||
print_ER_graph (A);
|
||||
if (session.verbose && session.mtx_print) {
|
||||
logger << "\nMatrix:" << logger.endl;
|
||||
print_graph (A);
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "count triangles\n";
|
||||
/*
|
||||
* main program
|
||||
*/
|
||||
int main(int argc, char* argv[]) try {
|
||||
Timing timer;
|
||||
matrix A;
|
||||
std::vector<value_t> c;
|
||||
index_t s;
|
||||
|
||||
// try to read command line
|
||||
if (!get_options(argc, argv))
|
||||
exit(1);
|
||||
|
||||
prepare_matrix(A, timer);
|
||||
threads_info();
|
||||
logger << "Create count vector" << logger.endl;
|
||||
timer.start();
|
||||
std::cout << "There are " << triang_count(A) << " triangles\n";
|
||||
c = triang_v (A);
|
||||
timer.stop();
|
||||
if (session.timing) timer.print_dt();
|
||||
|
||||
timer.print_dt("create count vector");
|
||||
if (session.print_count) {
|
||||
logger << "Calculate total triangles" << logger.endl;
|
||||
timer.start();
|
||||
s = triang_count(c);
|
||||
timer.stop();
|
||||
logger << "There are " << s << " triangles" << logger.endl;
|
||||
timer.print_dt("calculate sum");
|
||||
}
|
||||
// output results
|
||||
if (session.print_count)
|
||||
triangle_out (s, (session.outputMode == OutputMode::FILE) ? session.outFile : std::cout);
|
||||
else
|
||||
vector_out (c, (session.outputMode == OutputMode::FILE) ? session.outFile : std::cout);
|
||||
return 0;
|
||||
}
|
||||
catch (std::exception& e) {
|
||||
|
||||
+19
-2
@@ -40,8 +40,8 @@ void init_ER_graph (matrix& A, double p) {
|
||||
/*!
|
||||
* Utility to print the graph to sdtout
|
||||
*/
|
||||
void print_ER_graph (matrix& A) {
|
||||
matrix::indexType N = (A.size() < (matrix::indexType)session.print_size) ? A.size() : session.print_size;
|
||||
void print_graph (matrix& A) {
|
||||
matrix::indexType N = (A.size() < (matrix::indexType)session.mtx_print_size) ? A.size() : session.mtx_print_size;
|
||||
|
||||
A.for_each_in(0, N, [&](auto i){
|
||||
A.for_each_in(0, N, [&](auto j) {
|
||||
@@ -51,3 +51,20 @@ void print_ER_graph (matrix& A) {
|
||||
});
|
||||
}
|
||||
|
||||
/*!
|
||||
* Utility to print to logger thread information
|
||||
*/
|
||||
void threads_info () {
|
||||
#if defined CILK
|
||||
logger << "Running with max threads: " << __cilkrts_get_nworkers() << logger.endl;
|
||||
logger << "Utilizing " << __cilkrts_get_nworkers() << " threads for calculating vector." << logger.endl;
|
||||
logger << "Utilizing " << nworkers() << " threads for calculating sum." << logger.endl;
|
||||
#elif defined OMP
|
||||
logger << "Running with max threads: " << nworkers() << logger.endl;
|
||||
#elif defined THREADS
|
||||
logger << "Running with max threads: " << nworkers() << logger.endl;
|
||||
#else
|
||||
logger << "Running the serial version of the algorithm." << logger.endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
+114
-14
@@ -6,30 +6,128 @@
|
||||
* Christos Choutouridis AEM:8997
|
||||
* <cchoutou@ece.auth.gr>
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
#include <v3.h>
|
||||
|
||||
// for (int i=0 ; i<A.size() ; ++i) {
|
||||
// for (int j = A.col_ptr[i]; j<A.col_ptr[i+1] ; ++j) {
|
||||
// int j_idx = A.rows[j];
|
||||
// for (int k = A.col_ptr[j_idx] ; k<A.col_ptr[j_idx+1] ; ++k) {
|
||||
// int k_idx = A.rows[k];
|
||||
// if (A.get(k_idx, i)) {
|
||||
// ++c[i];
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
namespace v3 {
|
||||
|
||||
using index_t = typename matrix::indexType;
|
||||
using value_t = typename matrix::dataType;
|
||||
#if defined CILK
|
||||
|
||||
/*!
|
||||
* A naive triangle counting algorithm
|
||||
* \param A The adjacency matrix
|
||||
* \return The number of triangles
|
||||
// export CILK_NWORKERS=<num>
|
||||
int nworkers() {
|
||||
if (session.max_threads)
|
||||
return (session.max_threads < __cilkrts_get_nworkers()) ?
|
||||
session.max_threads : __cilkrts_get_nworkers();
|
||||
else
|
||||
return __cilkrts_get_nworkers();
|
||||
}
|
||||
|
||||
std::vector<value_t> triang_v(matrix& A) {
|
||||
std::vector<value_t> c(A.size());
|
||||
|
||||
cilk_for (int i=0 ; i<A.size() ; ++i) {
|
||||
for (auto j = A.getCol(i); j.index() != j.end() ; ++j) // j list all the edges with i
|
||||
for (auto k = A.getCol(j.index()); k.index() != k.end() ; ++k) // k list all the edges with j
|
||||
if (A.get(k.index(), i)) // search for i-k edge
|
||||
++c[i];
|
||||
}
|
||||
if (session.makeSymmetric)
|
||||
std::transform (c.begin(), c.end(), c.begin(), [] (value_t& x) {
|
||||
return x/2;
|
||||
});
|
||||
return c;
|
||||
}
|
||||
|
||||
void do_sum (value_t& out_sum, std::vector<value_t>& v, index_t begin, index_t end) {
|
||||
for (auto i =begin ; i != end ; ++i)
|
||||
out_sum += v[i];
|
||||
}
|
||||
|
||||
value_t sum (std::vector<value_t>& v) {
|
||||
int n = nworkers();
|
||||
std::vector<value_t> sum_v(n, 0);
|
||||
|
||||
for (index_t i =0 ; i < n ; ++i) {
|
||||
cilk_spawn do_sum(sum_v[i], v, i*v.size()/n, (i+1)*v.size()/n);
|
||||
}
|
||||
cilk_sync;
|
||||
|
||||
value_t s =0;
|
||||
for (auto& it : sum_v) s += it;
|
||||
return s;
|
||||
}
|
||||
|
||||
#elif defined OMP
|
||||
|
||||
/*
|
||||
// export OMP_NUM_THREADS=<num>
|
||||
*/
|
||||
int nworkers() {
|
||||
if (session.max_threads && session.max_threads < (size_t)omp_get_max_threads()) {
|
||||
omp_set_dynamic(0);
|
||||
omp_set_num_threads(session.max_threads);
|
||||
return session.max_threads;
|
||||
}
|
||||
else {
|
||||
omp_set_dynamic(1);
|
||||
return omp_get_max_threads();
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<value_t> triang_v(matrix& A) {
|
||||
std::vector<value_t> c(A.size());
|
||||
|
||||
#pragma omp parallel for shared(c)
|
||||
for (int i=0 ; i<A.size() ; ++i) {
|
||||
for (auto j = A.getCol(i); j.index() != j.end() ; ++j) // j list all the edges with i
|
||||
for (auto k = A.getCol(j.index()); k.index() != k.end() ; ++k) // k list all the edges with j
|
||||
if (A.get(k.index(), i)) // search for i-k edge
|
||||
++c[i];
|
||||
}
|
||||
if (session.makeSymmetric)
|
||||
std::transform (c.begin(), c.end(), c.begin(), [] (value_t& x) {
|
||||
return x/2;
|
||||
});
|
||||
return c;
|
||||
}
|
||||
|
||||
value_t sum (std::vector<value_t>& v) {
|
||||
value_t s =0;
|
||||
|
||||
#pragma omp parallel for reduction(+:s)
|
||||
for (auto i =0u ; i<v.size() ; ++i)
|
||||
s += v[i];
|
||||
return s;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int nworkers() { return 1; }
|
||||
|
||||
std::vector<value_t> triang_v(matrix& A) {
|
||||
std::vector<value_t> c(A.size());
|
||||
|
||||
for (int i=0 ; i<A.size() ; ++i) {
|
||||
for (auto j = A.getCol(i); j.index() != j.end() ; ++j) // j list all the edges with i
|
||||
for (auto k = A.getCol(j.index()); k.index() != k.end() ; ++k) // k list all the edges with j
|
||||
for (auto ii = A.getCol(i) ; ii.index() <= k.index() ; ++ii) // search for i-k edge (this could be binary search)
|
||||
if (ii.index() == k.index()) ++c[i];
|
||||
if (A.get(k.index(), i)) // search for i-k edge
|
||||
++c[i];
|
||||
}
|
||||
if (session.makeSymmetric)
|
||||
std::transform (c.begin(), c.end(), c.begin(), [] (value_t& x) {
|
||||
return x/2;
|
||||
});
|
||||
return c;
|
||||
}
|
||||
|
||||
@@ -40,9 +138,11 @@ value_t sum (std::vector<value_t>& v) {
|
||||
return s;
|
||||
}
|
||||
|
||||
value_t triang_count (matrix& A) {
|
||||
auto v = triang_v(A);
|
||||
return sum(v);
|
||||
#endif
|
||||
|
||||
|
||||
value_t triang_count (std::vector<value_t>& c) {
|
||||
return (session.makeSymmetric) ? sum(c)/3 : sum(c);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+163
-9
@@ -6,16 +6,162 @@
|
||||
* Christos Choutouridis AEM:8997
|
||||
* <cchoutou@ece.auth.gr>
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
#include <v4.h>
|
||||
|
||||
namespace v4 {
|
||||
|
||||
using index_t = typename matrix::indexType;
|
||||
using value_t = typename matrix::dataType;
|
||||
#if defined CILK
|
||||
|
||||
// export CILK_NWORKERS=<num>
|
||||
int nworkers() {
|
||||
if (session.max_threads)
|
||||
return (session.max_threads < __cilkrts_get_nworkers()) ?
|
||||
session.max_threads : __cilkrts_get_nworkers();
|
||||
else
|
||||
return __cilkrts_get_nworkers();
|
||||
}
|
||||
|
||||
std::vector<value_t> mmacc_v(matrix& A, matrix& B) {
|
||||
std::vector<value_t> c(A.size());
|
||||
|
||||
cilk_for (int i=0 ; i<A.size() ; ++i) {
|
||||
for (auto j = A.getRow(i); j.index() != j.end() ; ++j){
|
||||
c[i] += A.getRow(i)*B.getCol(j.index());
|
||||
}
|
||||
}
|
||||
if (session.makeSymmetric)
|
||||
std::transform (c.begin(), c.end(), c.begin(), [] (value_t& x) {
|
||||
return x/2;
|
||||
});
|
||||
return c;
|
||||
}
|
||||
|
||||
void do_sum (value_t& out_sum, std::vector<value_t>& v, index_t begin, index_t end) {
|
||||
for (auto i =begin ; i != end ; ++i)
|
||||
out_sum += v[i];
|
||||
}
|
||||
|
||||
value_t sum (std::vector<value_t>& v) {
|
||||
int n = nworkers();
|
||||
std::vector<value_t> sum_v(n, 0);
|
||||
|
||||
for (index_t i =0 ; i < n ; ++i) {
|
||||
cilk_spawn do_sum(sum_v[i], v, i*v.size()/n, (i+1)*v.size()/n);
|
||||
}
|
||||
cilk_sync;
|
||||
|
||||
value_t s =0;
|
||||
for (auto& it : sum_v) s += it;
|
||||
return s;
|
||||
}
|
||||
|
||||
#elif defined OMP
|
||||
|
||||
/*
|
||||
// export OMP_NUM_THREADS=<num>
|
||||
*/
|
||||
int nworkers() {
|
||||
if (session.max_threads && session.max_threads < (size_t)omp_get_max_threads()) {
|
||||
omp_set_dynamic(0);
|
||||
omp_set_num_threads(session.max_threads);
|
||||
return session.max_threads;
|
||||
}
|
||||
else {
|
||||
omp_set_dynamic(1);
|
||||
return omp_get_max_threads();
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<value_t> mmacc_v(matrix& A, matrix& B) {
|
||||
std::vector<value_t> c(A.size());
|
||||
|
||||
#pragma omp parallel for shared(c)
|
||||
for (int i=0 ; i<A.size() ; ++i) {
|
||||
for (auto j = A.getRow(i); j.index() != j.end() ; ++j) {
|
||||
c[i] += A.getRow(i)*B.getCol(j.index());
|
||||
}
|
||||
}
|
||||
if (session.makeSymmetric)
|
||||
std::transform (c.begin(), c.end(), c.begin(), [] (value_t& x) {
|
||||
return x/2;
|
||||
});
|
||||
return c;
|
||||
}
|
||||
|
||||
value_t sum (std::vector<value_t>& v) {
|
||||
value_t s =0;
|
||||
|
||||
#pragma omp parallel for reduction(+:s)
|
||||
for (auto i =0u ; i<v.size() ; ++i)
|
||||
s += v[i];
|
||||
return s;
|
||||
}
|
||||
|
||||
#elif defined THREADS
|
||||
|
||||
/*
|
||||
* std::thread::hardware_concurrency()
|
||||
*/
|
||||
int nworkers() {
|
||||
if (session.max_threads)
|
||||
return (session.max_threads < std::thread::hardware_concurrency()) ?
|
||||
session.max_threads : std::thread::hardware_concurrency();
|
||||
else
|
||||
return std::thread::hardware_concurrency();
|
||||
}
|
||||
|
||||
std::vector<value_t> mmacc_v_rng(std::vector<value_t>& out, matrix& A, matrix& B, index_t begin, index_t end) {
|
||||
for (index_t i=begin ; i<end ; ++i) {
|
||||
for (auto j = A.getRow(i); j.index() != j.end() ; ++j){
|
||||
out[i] += A.getRow(i)*B.getCol(j.index());
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
std::vector<value_t> mmacc_v(matrix& A, matrix& B) {
|
||||
std::vector<std::thread> workers;
|
||||
std::vector<value_t> c(A.size());
|
||||
int n = nworkers();
|
||||
|
||||
for (index_t i=0 ; i<n ; ++i)
|
||||
workers.push_back (std::thread (mmacc_v_rng, std::ref(c), std::ref(A), std::ref(B), i*c.size()/n, (i+1)*c.size()/n));
|
||||
|
||||
std::for_each(workers.begin(), workers.end(), [](std::thread& t){
|
||||
t.join();
|
||||
});
|
||||
if (session.makeSymmetric)
|
||||
std::transform (c.begin(), c.end(), c.begin(), [] (value_t& x) {
|
||||
return x/2;
|
||||
});
|
||||
return c;
|
||||
}
|
||||
|
||||
void do_sum (value_t& out_sum, std::vector<value_t>& v, index_t begin, index_t end) {
|
||||
for (auto i =begin ; i != end ; ++i)
|
||||
out_sum += v[i];
|
||||
}
|
||||
|
||||
value_t sum (std::vector<value_t>& v) {
|
||||
int n = nworkers();
|
||||
std::vector<value_t> sum_v(n, 0);
|
||||
std::vector<std::thread> workers;
|
||||
|
||||
for (index_t i =0 ; i < n ; ++i)
|
||||
workers.push_back (std::thread (do_sum, std::ref(sum_v[i]), std::ref(v), i*v.size()/n, (i+1)*v.size()/n));
|
||||
|
||||
std::for_each(workers.begin(), workers.end(), [](std::thread& t){
|
||||
t.join();
|
||||
});
|
||||
|
||||
value_t s =0;
|
||||
for (auto& it : sum_v) s += it;
|
||||
return s;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int nworkers() { return 1; }
|
||||
|
||||
std::vector<value_t> mmacc_v(matrix& A, matrix& B) {
|
||||
std::vector<value_t> c(A.size());
|
||||
@@ -24,10 +170,13 @@ std::vector<value_t> mmacc_v(matrix& A, matrix& B) {
|
||||
c[i] += A.getRow(i)*B.getCol(j.index());
|
||||
}
|
||||
}
|
||||
if (session.makeSymmetric)
|
||||
std::transform (c.begin(), c.end(), c.begin(), [] (value_t& x) {
|
||||
return x/2;
|
||||
});
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
value_t sum (std::vector<value_t>& v) {
|
||||
value_t s =0;
|
||||
for (auto& it : v)
|
||||
@@ -35,9 +184,14 @@ value_t sum (std::vector<value_t>& v) {
|
||||
return s;
|
||||
}
|
||||
|
||||
value_t triang_count (matrix& A) {
|
||||
auto v = mmacc_v(A, A);
|
||||
return (session.makeSymmetric) ? sum(v)/6 : sum(v);
|
||||
#endif
|
||||
|
||||
std::vector<value_t> triang_v(matrix& A) {
|
||||
return mmacc_v(A, A);
|
||||
}
|
||||
|
||||
value_t triang_count (std::vector<value_t>& c) {
|
||||
return (session.makeSymmetric) ? sum(c)/3 : sum(c);
|
||||
}
|
||||
|
||||
} // namespace v4
|
||||
|
||||
Reference in New Issue
Block a user