main.cpp 6.6 KB

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