main.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. #include <vector>
  2. #include <queue>
  3. #include <cstdlib>
  4. #include <cstring>
  5. #include <iostream>
  6. #include <fstream>
  7. #include <sstream>
  8. #include "simu.h"
  9. #include "basetask.h"
  10. #include "basesched.h"
  11. #include "tasks.h"
  12. #include "sched_fcfs.h"
  13. #include "sched_rr.h"
  14. #include "sched_sjf.h"
  15. #include "sched_rsjf.h"
  16. #include "sched_mfq.h"
  17. using namespace std;
  18. ostream& operator<<(ostream &os, const Settings &s)
  19. {
  20. os << "tasks_file: " << s.tasks_file << endl
  21. << "num_cores: " << s.num_cores << endl
  22. << "switch_cost: " << s.switch_cost << endl
  23. << "migrate_cost: " << s.migrate_cost << endl
  24. << "sched_class: " << s.sched_class << endl
  25. << "sched_args: ";
  26. for(vector<int>::const_iterator it = s.sched_args.begin();
  27. it != s.sched_args.end(); ++it) os << *it << " ";
  28. os << "(" << s.sched_args.size() << " ints)" << endl;
  29. os << "verbose: " << (s.verbose? "yes" : "no") << endl
  30. << "output_log: " << s.output_log << endl;
  31. return os;
  32. }
  33. string one_line_summary(const Settings &s)
  34. {
  35. ostringstream os;
  36. os << s.tasks_file << " " << s.num_cores << " " << s.switch_cost << " " << s.migrate_cost << " " << s.sched_class;
  37. vector<int>::const_iterator it = s.sched_args.begin();
  38. ++it; //Saco el primer parametro que es un agregado para que muestre los cores.
  39. while(it != s.sched_args.end()) os << " " << *it++;
  40. return os.str();
  41. }
  42. const char *USAGE =
  43. " [-h] [-v] [-o output] tasks_file num_cores switch_cost migrate_cost sched_class args\n"
  44. "\n"
  45. " tasks_file define el lote de tareas\n"
  46. " num_cores define la cantidad de cores\n"
  47. " switch_cost en ticks completos por c/cambio de contexto\n"
  48. " migrate_cost en ticks completos por c/cambio de cpu\n"
  49. " sched_class nombre de la subclase de SchedBase deseada\n"
  50. " args argumentos enteros para pasarle al scheduler\n"
  51. " (ver detalles en constructor de sched_class)\n"
  52. "\n"
  53. " -v mayor nivel de verborragia\n"
  54. " -o nombre base para archivos generados\n"
  55. " -h mostrar este texto de ayuda y salir\n"
  56. "\n"
  57. "ejs: simusched lote.tsk 1 10 2 SchedFCFS\n"
  58. " donde 1 es la cantidad de núcleos\n"
  59. " donde 10 es el costo de cambio de contexto\n"
  60. " donde 2 es el costo de cambio de cpu\n"
  61. " (el algoritmo FCFS no recibe argumentos)\n"
  62. "\n"
  63. " simusched -v -o probando lote15.tsk 1 2 3 SchedRR 8\n"
  64. " donde 1 es la cantidad de núcleos\n"
  65. " donde 2 es el costo de cambio de contexto\n"
  66. " donde 3 es el costo de cambio de cpu\n"
  67. " y 8 es el quantum para el algoritmo RR\n"
  68. "\n"
  69. " simusched foo.tsk 1 1 2 SchedFCFS | python graphsched.py | png_viewer\n"
  70. " simusched foo.tsk 2 1 2 SchedFCFS | python graphsched.py > foo.png\n"
  71. " para graficar (ver script .py para más detalles)\n"
  72. ;
  73. bool file_readable(const string pathname)
  74. {
  75. // Feucho pero bien portable:
  76. ifstream tf(pathname.c_str());
  77. if(!tf) return false;
  78. tf.close();
  79. return true;
  80. }
  81. int cmdline_parse(int argc, char* argv[], Settings &s)
  82. {
  83. string prog_name(argv[0]);
  84. int i = 1; // #args seen
  85. /* Opciones y flags */
  86. s.verbose = false;
  87. s.output_log = "-";
  88. while(i < argc && argv[i][0] == '-') {
  89. string optn(argv[i] + 1);
  90. if(optn == "h") {
  91. cerr << "uso: " << prog_name << USAGE << endl;
  92. return 1;
  93. } else if(optn == "v") {
  94. s.verbose = true;
  95. } else if(optn == "o") {
  96. if(++i < argc && argv[i][0] != '-') {
  97. s.output_log = argv[i];
  98. } else {
  99. cerr << "error: uso ilegal de -o" << endl;
  100. cerr << "uso: " << prog_name << USAGE << endl;
  101. return 2;
  102. }
  103. }
  104. ++i;
  105. }
  106. /* Argumentos posicionales */
  107. if(argc - i < 3) {
  108. cerr << "error: argumentos insuficientes" << endl;
  109. cerr << "uso: " << prog_name << USAGE << endl;
  110. return 3;
  111. }
  112. s.tasks_file = argv[i++];
  113. if(!file_readable(s.tasks_file)) {
  114. cerr << "error: no se pudo leer: " << s.tasks_file << endl;
  115. return 4;
  116. }
  117. char *cptr;
  118. s.num_cores = static_cast<unsigned int>(strtol(argv[i++], &cptr, 10));
  119. if(*cptr != '\0') {
  120. cerr << "error: no es un natural: " << argv[i-1] << endl;
  121. return 5;
  122. }
  123. char *eptr;
  124. s.switch_cost = static_cast<unsigned int>(strtol(argv[i++], &eptr, 10));
  125. if(*eptr != '\0') {
  126. cerr << "error: no es un natural: " << argv[i-1] << endl;
  127. return 6;
  128. }
  129. s.migrate_cost = static_cast<unsigned int>(strtol(argv[i++], &eptr, 10));
  130. if(*eptr != '\0') {
  131. cerr << "error: no es un natural: " << argv[i-1] << endl;
  132. return 7;
  133. }
  134. s.sched_class = argv[i++];
  135. if(s.sched_class[0] != 'S') { // TODO: mejor error checking
  136. cerr << "error: scheduler desconocido: " << s.sched_class << endl;
  137. return 8;
  138. }
  139. s.sched_args.clear();
  140. //Agrego la cantidad de cores como primer parametros de los argumentos.
  141. s.sched_args.push_back(s.num_cores);
  142. while(i < argc) {
  143. int argint = static_cast<int>(strtol(argv[i++], &eptr, 10));
  144. if(*eptr != '\0') {
  145. cerr << "error: no es un entero: " << argv[i-1] << endl;
  146. return 9;
  147. } else s.sched_args.push_back(argint);
  148. }
  149. return 0;
  150. }
  151. SchedBase* sched_create(const char* sched, vector<int> argn) {
  152. #define _sched_create(tipo, prms) if (!strcmp(#tipo, sched)) { if (!(prms == -1 || (int)(argn.size()) == prms)) { cerr << "error: "#tipo" recibe " << prms << " parámetro(s)." << endl; return NULL; } return new tipo(argn); }
  153. /* Agregue aquí los schedulers nuevos que cree agregando una línea con:
  154. * _sched_create(SchedX, n)
  155. * donde "SchedX" es la nueva clase implementada y n es la cantidad de
  156. * parámetros que recibe su scheduler como un vector de enteros (vector<int>)
  157. o ponga -1 para una cantidad de parámetros arbitraria. */
  158. _sched_create(SchedFCFS, -1)
  159. _sched_create(SchedRR, -1)
  160. _sched_create(SchedSJF, -1)
  161. _sched_create(SchedRSJF, -1)
  162. _sched_create(SchedMFQ, -1)
  163. return NULL;
  164. }
  165. int main(int argc, char* argv[]) {
  166. Settings settings;
  167. int rc = cmdline_parse(argc, argv, settings);
  168. if(rc != 0) return rc;
  169. //Obtengo el scheduler a usar.
  170. SchedBase *scheduler = sched_create(settings.sched_class.c_str(), settings.sched_args);
  171. if(!scheduler) {
  172. cerr << "error: scheduler desconocido: " << settings.sched_class;
  173. for(int j=0; j<(int)settings.sched_args.size(); j++) cerr << (j?',':'(') << settings.sched_args[j];
  174. if (!settings.sched_args.size()) cerr << "(";
  175. cerr << ")" << endl;
  176. return 3;
  177. }
  178. if (settings.verbose) {
  179. cerr << endl << settings;
  180. }
  181. cout << "# SETTINGS " << argv[0] << " " << one_line_summary(settings) << endl;
  182. //Registro los tipos de tareas.
  183. tasks_init();
  184. //Cargo las tareas definidas por el usuario.
  185. vector<ptsk> tasks = tasks_load(settings.tasks_file.c_str());
  186. simulate(*scheduler, tasks, settings);
  187. delete scheduler;
  188. return rc;
  189. }