|
- /*!
- * \file main.cpp
- * \brief Main application file
- *
- * \author
- * Christos Choutouridis AEM:8997
- * <cchoutou@ece.auth.gr>
- */
-
- #include <iostream>
- #include <string>
- #include <exception>
-
- #include <utils.h>
- #include <config.h>
-
- // Global session data
- session_t session;
- Log logger;
-
- /*!
- * A small command line argument parser
- * \return The status of the operation
- */
- bool get_options(int argc, char* argv[]){
- bool status =true;
-
- // iterate over the passed arguments
- for (int i=1 ; i<argc ; ++i) {
- std::string arg(argv[i]); // get current argument
-
- if (arg == "-i" || arg == "--input") {
- session.inputMatrix = InputMatrix::MTX;
- if (i+1 < argc)
- session.mtxFile = std::ifstream(argv[++i]);
- else
- status = false;
- }
- 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;
- 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 == "-r" || arg == "--repeat") {
- session.repeat = (i+1 < argc) ? std::atoi(argv[++i]) : session.repeat;
- }
- else if (arg == "-t" || arg == "--timing")
- session.timing = true;
- else if (arg == "-v" || arg == "--verbose")
- session.verbose = true;
- else if (arg == "--make_symmetric")
- session.makeSymmetric = true;
- else if (arg == "--triangular_only")
- session.makeSymmetric = false;
- else if (arg == "--validate_mtx")
- session.validate_mtx = true;
- else if (arg == "--dynamic")
- session.dynamic = true;
- else if (arg == "--print_count") {
- session.print_count = true;
- session.makeSymmetric = false;
- }
- 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 << "vertex-wise triangular count utility.\n\n";
- std::cout << "tcount -i <file> | -g <size> <probability> [-o <file>] [-n <threads>] [--dynamic] [-r <times>] [-t] [-v]\n";
- std::cout << " [--make_symmetric] [--triangular_only] [--print_count] [--validate_mtx] [--print_graph <size>]\n";
- std::cout << '\n';
- std::cout << "Options:\n\n";
- std::cout << " -i | --input <file>\n";
- std::cout << " Path to mtx file to load.\n\n";
- std::cout << " -g | --generate <size> <probability>\n";
- std::cout << " Request a random generated graph with size <size> and probability <probability>.\n";
- std::cout << " This is very slow, use it with care.\n\n";
- std::cout << " -o | --output <file>\n";
- std::cout << " Select <file> as output file. Default is stdout.\n\n";
- std::cout << " -n | --max_trheads <threads>\n";
- std::cout << " Reduce the thread number for the execution to <threads>. <threads> must be less or equal to available CPUs.\n\n";
- std::cout << " --dynamic\n";
- std::cout << " Request of dynamic scheduling for OpenMP and pthreads. Does not affect cilk versions.\n\n";
- std::cout << " -r | --repeat <times>\n";
- std::cout << " Repeat the vector calculation <times> times.\n\n";
- std::cout << " -t | --timing\n";
- std::cout << " Request timing measurements output to stdout.\n\n";
- std::cout << " -v | --verbose\n";
- std::cout << " Request a more verbose output to stdout.\n\n";
- std::cout << " --make_symmetric\n";
- std::cout << " Explicitly request a symmetric graph generation. This affects only V3 versions where by default a lower\n";
- std::cout << " triangular matrix is used.\n\n";
- std::cout << " --triangular_only\n";
- std::cout << " NOTE: Requires also \"--print_count\".\n";
- std::cout << " Explicitly request to use a lower triangular matrix. This affects only V4 versions where a symmetric\n";
- std::cout << " matrix is used by default and produce correct answer ONLY for total triangle counting (--print_count).\n\n";
- std::cout << " --print_count\n";
- std::cout << " NOTE: When used, also implies \"---triangular_only\" for all versions.\n";
- std::cout << " Request a total triangle counting output.\n\n";
- std::cout << " --validate_mtx\n";
- std::cout << " Request an input matrix validation before execution.\n\n";
- std::cout << " --print_graph <size>\n";
- std::cout << " Prints the first <size> x <size> part of the matrix to stdout.\n\n";
- std::cout << " -h | --help <size>\n";
- std::cout << " Prints this and exit.\n";
- exit(0);
- }
- else { // parse error
- std::cout << "Invokation error. Try -h for details.\n";
- status = false;
- }
- }
-
- // Input checkers
- if (session.inputMatrix == InputMatrix::UNSPECIFIED) {
- std::cout << "Invokation error. Try -h for details.\n";
- status = false;
- }
- #if CODE_VERSION == V4
- else if (!session.makeSymmetric && !session.print_count) {
- std::cout << "\"--triangular_only\" requires \"--print_count\"\n";
- status = false;
- }
- #endif
- return status;
- }
-
- /*!
- * 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) {
- logger << "Initialize matrix with size: " << session.gen_size << " and probability: " << session.gen_prob << logger.endl;
- timer.start();
- A.size(session.gen_size);
- init_ER_graph(A, session.gen_prob);
- timer.stop();
- timer.print_dt("generate matrix");
- }
- else {
- logger << "Read matrix from file" << logger.endl;
- timer.start();
- 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();
- logger << "Matrix size: " << A.size() << " and capacity: " << A.capacity() << logger.endl;
- timer.print_dt("load matrix");
- }
-
- if (session.verbose && session.mtx_print) {
- logger << "\nMatrix:" << logger.endl;
- print_graph (A);
- }
- }
-
- /*
- * main program
- */
- int main(int argc, char* argv[]) try {
- Timing timer;
- matrix A;
- std::vector<value_t> c;
- index_t s;
-
- #if defined ELEARNING
- if (!elearn_test()) std::cout << "E-learning test: FAIL\n";
- else std::cout << "E-learning test: PASS\n";
- exit(0);
- #endif
-
- // try to read command line
- if (!get_options(argc, argv))
- exit(1);
-
- prepare_matrix(A, timer);
- threads_info();
- for (size_t i =0 ; i<session.repeat ; ++i) {
- // repeat calculations as requested by user
- logger << "Create vector" << logger.endl;
- timer.start();
- c = triang_v (A);
- timer.stop();
- timer.print_dt("create 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) {
- //we probably pollute the user's screen. Comment `cerr << ...` if you don't like it.
- std::cerr << e.what() << '\n';
- exit(1);
- }
|