A triangle counting assignment for A.U.TH Parallel and distributed systems class.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

231 lines
8.9 KiB

  1. /*!
  2. * \file main.cpp
  3. * \brief Main application file
  4. *
  5. * \author
  6. * Christos Choutouridis AEM:8997
  7. * <cchoutou@ece.auth.gr>
  8. */
  9. #include <iostream>
  10. #include <string>
  11. #include <exception>
  12. #include <utils.h>
  13. #include <config.h>
  14. // Global session data
  15. session_t session;
  16. Log logger;
  17. /*!
  18. * A small command line argument parser
  19. * \return The status of the operation
  20. */
  21. bool get_options(int argc, char* argv[]){
  22. bool status =true;
  23. // iterate over the passed arguments
  24. for (int i=1 ; i<argc ; ++i) {
  25. std::string arg(argv[i]); // get current argument
  26. if (arg == "-i" || arg == "--input") {
  27. session.inputMatrix = InputMatrix::MTX;
  28. if (i+1 < argc)
  29. session.mtxFile = std::ifstream(argv[++i]);
  30. else
  31. status = false;
  32. }
  33. else if (arg == "-o" || arg == "--output") {
  34. session.outputMode = OutputMode::FILE;
  35. if (i+1 < argc)
  36. session.outFile = std::ofstream(argv[++i]);
  37. else
  38. status = false;
  39. }
  40. else if (arg == "-g" || arg == "--generate") {
  41. session.inputMatrix = InputMatrix::GENERATE;
  42. if (i+2 < argc) {
  43. session.gen_size = std::atoi(argv[++i]);
  44. session.gen_prob = std::atof(argv[++i]);
  45. }
  46. else
  47. status = false;
  48. }
  49. else if (arg == "-n" || arg == "--max_trheads") {
  50. session.max_threads = (i+1 < argc) ? std::atoi(argv[++i]) : session.max_threads;
  51. }
  52. else if (arg == "-r" || arg == "--repeat") {
  53. session.repeat = (i+1 < argc) ? std::atoi(argv[++i]) : session.repeat;
  54. }
  55. else if (arg == "-t" || arg == "--timing")
  56. session.timing = true;
  57. else if (arg == "-v" || arg == "--verbose")
  58. session.verbose = true;
  59. else if (arg == "--make_symmetric")
  60. session.makeSymmetric = true;
  61. else if (arg == "--triangular_only")
  62. session.makeSymmetric = false;
  63. else if (arg == "--validate_mtx")
  64. session.validate_mtx = true;
  65. else if (arg == "--dynamic")
  66. session.dynamic = true;
  67. else if (arg == "--print_count") {
  68. session.print_count = true;
  69. session.makeSymmetric = false;
  70. }
  71. else if (arg == "--print_graph") {
  72. session.mtx_print = true;
  73. session.mtx_print_size = (i+1 < argc) ? std::atoi(argv[++i]) : session.mtx_print_size;
  74. }
  75. else if (arg == "-h" || arg == "--help") {
  76. std::cout << "vertex-wise triangular count utility.\n\n";
  77. std::cout << "tcount -i <file> | -g <size> <probability> [-o <file>] [-n <threads>] [--dynamic] [-r <times>] [-t] [-v]\n";
  78. std::cout << " [--make_symmetric] [--triangular_only] [--print_count] [--validate_mtx] [--print_graph <size>]\n";
  79. std::cout << '\n';
  80. std::cout << "Options:\n\n";
  81. std::cout << " -i | --input <file>\n";
  82. std::cout << " Path to mtx file to load.\n\n";
  83. std::cout << " -g | --generate <size> <probability>\n";
  84. std::cout << " Request a random generated graph with size <size> and probability <probability>.\n";
  85. std::cout << " This is very slow, use it with care.\n\n";
  86. std::cout << " -o | --output <file>\n";
  87. std::cout << " Select <file> as output file. Default is stdout.\n\n";
  88. std::cout << " -n | --max_trheads <threads>\n";
  89. std::cout << " Reduce the thread number for the execution to <threads>. <threads> must be less or equal to available CPUs.\n\n";
  90. std::cout << " --dynamic\n";
  91. std::cout << " Request of dynamic scheduling for OpenMP and pthreads. Does not affect cilk versions.\n\n";
  92. std::cout << " -r | --repeat <times>\n";
  93. std::cout << " Repeat the vector calculation <times> times.\n\n";
  94. std::cout << " -t | --timing\n";
  95. std::cout << " Request timing measurements output to stdout.\n\n";
  96. std::cout << " -v | --verbose\n";
  97. std::cout << " Request a more verbose output to stdout.\n\n";
  98. std::cout << " --make_symmetric\n";
  99. std::cout << " Explicitly request a symmetric graph generation. This affects only V3 versions where by default a lower\n";
  100. std::cout << " triangular matrix is used.\n\n";
  101. std::cout << " --triangular_only\n";
  102. std::cout << " NOTE: Requires also \"--print_count\".\n";
  103. std::cout << " Explicitly request to use a lower triangular matrix. This affects only V4 versions where a symmetric\n";
  104. std::cout << " matrix is used by default and produce correct answer ONLY for total triangle counting (--print_count).\n\n";
  105. std::cout << " --print_count\n";
  106. std::cout << " NOTE: When used, also implies \"---triangular_only\" for all versions.\n";
  107. std::cout << " Request a total triangle counting output.\n\n";
  108. std::cout << " --validate_mtx\n";
  109. std::cout << " Request an input matrix validation before execution.\n\n";
  110. std::cout << " --print_graph <size>\n";
  111. std::cout << " Prints the first <size> x <size> part of the matrix to stdout.\n\n";
  112. std::cout << " -h | --help <size>\n";
  113. std::cout << " Prints this and exit.\n\n";
  114. std::cout << "Examples:\n\n";
  115. std::cout << " Get the total count of matrix in <MFILE> and calculate the time for vector creation 5 times:\n";
  116. std::cout << " > ./tcount -i <MFILE> --timing --print_count -r 5\n\n";
  117. std::cout << " Get the vector to <OUTFILE> of matrix in <MFILE> and print the time to stdout using dynamic scheduling\n";
  118. std::cout << " > ./tcount -i <MFILE> -o <OUTFILE> --timing --dynamic\n\n";
  119. std::cout << " Get the total count of matrix in <MFILE> using <N> workers only\n";
  120. std::cout << " > ./tcount -i <MFILE> -n <N> --print_count\n";
  121. exit(0);
  122. }
  123. else { // parse error
  124. std::cout << "Invocation error. Try -h for details.\n";
  125. status = false;
  126. }
  127. }
  128. // Input checkers
  129. if (session.inputMatrix == InputMatrix::UNSPECIFIED) {
  130. std::cout << "Invocation error. Try -h for details.\n";
  131. status = false;
  132. }
  133. #if CODE_VERSION == V4
  134. else if (!session.makeSymmetric && !session.print_count) {
  135. std::cout << "\"--triangular_only\" requires \"--print_count\"\n";
  136. status = false;
  137. }
  138. #endif
  139. return status;
  140. }
  141. /*!
  142. * get or generate matrix
  143. * \param A Reference to matrix for output (move using RVO)
  144. * \param timer Reference to timer utility to access time printing functionality
  145. */
  146. void prepare_matrix (matrix& A, Timing& timer) {
  147. if (session.inputMatrix == InputMatrix::GENERATE) {
  148. logger << "Initialize matrix with size: " << session.gen_size << " and probability: " << session.gen_prob << logger.endl;
  149. timer.start();
  150. A.size(session.gen_size);
  151. init_ER_graph(A, session.gen_prob);
  152. timer.stop();
  153. timer.print_dt("generate matrix");
  154. }
  155. else {
  156. logger << "Read matrix from file" << logger.endl;
  157. timer.start();
  158. if (session.validate_mtx && !Mtx::is_triangular<matrix::indexType> (session.mtxFile))
  159. throw std::runtime_error("Error: Matrix is not strictly upper or lower");
  160. if (!Mtx::load (A, session.mtxFile)) {
  161. throw std::runtime_error("Error: fail to load matrix");
  162. }
  163. timer.stop();
  164. logger << "Matrix size: " << A.size() << " and capacity: " << A.capacity() << logger.endl;
  165. timer.print_dt("load matrix");
  166. }
  167. if (session.mtx_print) {
  168. logger << "\nMatrix:" << logger.endl;
  169. print_graph (A);
  170. }
  171. }
  172. /*
  173. * main program
  174. */
  175. int main(int argc, char* argv[]) try {
  176. Timing timer;
  177. matrix A;
  178. std::vector<value_t> c;
  179. index_t s;
  180. #if defined ELEARNING
  181. if (!elearn_test()) std::cout << "E-learning test: FAIL\n";
  182. else std::cout << "E-learning test: PASS\n";
  183. exit(0);
  184. #endif
  185. // try to read command line
  186. if (!get_options(argc, argv))
  187. exit(1);
  188. prepare_matrix(A, timer);
  189. threads_info();
  190. for (size_t i =0 ; i<session.repeat ; ++i) {
  191. // repeat calculations as requested by user
  192. logger << "Create vector" << logger.endl;
  193. timer.start();
  194. c = triang_v (A);
  195. timer.stop();
  196. timer.print_dt("create vector");
  197. }
  198. if (session.print_count) {
  199. logger << "Calculate total triangles" << logger.endl;
  200. timer.start();
  201. s = triang_count(c);
  202. timer.stop();
  203. logger << "There are " << s << " triangles" << logger.endl;
  204. timer.print_dt("calculate sum");
  205. }
  206. // output results
  207. if (session.print_count)
  208. triangle_out (s, (session.outputMode == OutputMode::FILE) ? session.outFile : std::cout);
  209. else
  210. vector_out (c, (session.outputMode == OutputMode::FILE) ? session.outFile : std::cout);
  211. return 0;
  212. }
  213. catch (std::exception& e) {
  214. //we probably pollute the user's screen. Comment `cerr << ...` if you don't like it.
  215. std::cerr << e.what() << '\n';
  216. exit(1);
  217. }