A 2nd implementation conforming to vector creation [need optimization]

This commit is contained in:
2020-11-30 18:42:09 +02:00
parent 2398be8e50
commit e3b96138c8
11 changed files with 863 additions and 161 deletions
+86 -36
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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