simu.cpp 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. #include <vector>
  2. #include <pthread.h>
  3. #include <errno.h>
  4. #include <cstdio>
  5. #include <cstdlib>
  6. #include <iostream>
  7. #include <queue>
  8. #include "simu.h"
  9. #include "basetask.h"
  10. #include "basesched.h"
  11. using namespace std;
  12. //#define DBG_THREAD
  13. #ifdef DBG_THREAD
  14. #define _D(X) X
  15. #else
  16. #define _D(X)
  17. #endif
  18. #define forn(i,n) for(int i = 0; i < (int)(n); ++i)
  19. #define DBG(X) _D(cerr << #X << " = " << X << endl;)
  20. typedef struct cpu_ctx {
  21. int pid;
  22. int remaining;
  23. } cpu_ctx_t;
  24. /* "Globales" */
  25. // static int cur_pid;
  26. //Habria que modificar el nombre de cur_pid
  27. //lo mantuve para que sea mas facil modificar
  28. //codigo y mirar que hacia antes
  29. static vector<cpu_ctx_t> contexts;
  30. static unsigned int cur_time;
  31. static pthread_mutex_t m_sched;
  32. enum status_t {ST_EXIT, ST_IO, ST_CPU};
  33. struct task_data {
  34. pthread_t tid;
  35. int pid, running;
  36. status_t blk;
  37. int blkms;
  38. TaskBase* tsk;
  39. vector<int>* prms;
  40. pthread_mutex_t mutex;
  41. int lastcpu;
  42. };
  43. static task_data* tsks;
  44. void* task_thread(task_data* tsk) {
  45. pthread_mutex_lock(&tsk->mutex);
  46. //fprintf(stderr, "Thread %d\n", tsk->pid);
  47. _D(cerr << "tsk->tsk( " << tsk->pid << ", *tsk->prms)" << endl;)
  48. tsk->tsk(tsk->pid, *tsk->prms); // Run!
  49. //
  50. tsk->blk = ST_EXIT;
  51. _D(cerr << "TSK unlock(sched) exit" << endl;) pthread_mutex_unlock(&m_sched);
  52. return NULL;
  53. }
  54. /* Funciones llamadas por el scheduler */
  55. int current_pid(int cpu) { return contexts[cpu].pid; }
  56. int current_remaining(int cpu) { return contexts[cpu].remaining; }
  57. unsigned int current_time(void) { return cur_time; }
  58. /* Funciones llamadas por las tareas */
  59. static void uso_X(task_data* tsk, enum status_t tp, unsigned int ms) {
  60. if (ms == 0) return;
  61. tsk->blk = tp;
  62. tsk->blkms = ms;
  63. _D(cerr << "TSK unlock(sched)" << endl;) pthread_mutex_unlock(&m_sched);
  64. pthread_mutex_lock(&tsk->mutex); _D(cerr << "TSK lock(mutex["<<tsk-tsks<<"])" << endl;)
  65. }
  66. //Se agrega pid para poder ver obtener
  67. //los datos en tsks
  68. void uso_CPU(int pid, unsigned int ms) {
  69. uso_X(&(tsks[pid]), ST_CPU, ms);
  70. }
  71. void uso_IO(int pid, unsigned int ms) {
  72. uso_X(&(tsks[pid]), ST_IO, ms);
  73. }
  74. void simulate(SchedBase& sch, std::vector<ptsk>& lote, const Settings& settings) {
  75. int n = lote.size();
  76. cout.flush();
  77. if (settings.output_log != "-") {
  78. /* Oh yeah! */
  79. freopen(settings.output_log.c_str(), "wt", stdout);
  80. }
  81. tsks = (task_data*)malloc(sizeof(task_data)*n);
  82. if (!tsks) { perror("malloc(task_data)"); return; }
  83. forn(i, n) {
  84. tsks[i].pid = i;
  85. pthread_mutex_init(&(tsks[i].mutex), NULL);
  86. pthread_mutex_lock(&(tsks[i].mutex));
  87. tsks[i].tsk = lote[i].tsk;
  88. tsks[i].prms = &(lote[i].prms);
  89. tsks[i].running = 0;
  90. tsks[i].blk = ST_CPU;
  91. tsks[i].blkms = 0;
  92. tsks[i].lastcpu = -1;
  93. if (pthread_create(&(tsks[i].tid), NULL, (void*(*)(void*))task_thread, (void*)(&(tsks[i]))) < 0) {
  94. perror("Lanzando la tarea (no use muchas tareas, < 500)"); return;
  95. }
  96. }
  97. pthread_mutex_init(&m_sched, NULL);
  98. pthread_mutex_lock(&m_sched);
  99. int finished = 0;
  100. //Inicializa los cpus
  101. contexts = vector<cpu_ctx_t>(settings.num_cores);
  102. for (int i = 0; i <settings.num_cores; i++) {
  103. contexts[i].pid = IDLE_TASK;
  104. contexts[i].remaining = 0;
  105. }
  106. cur_time = 0;
  107. priority_queue<pair<int, int> > load;
  108. forn(i, n) load.push(make_pair(-lote[i].start, -i));
  109. vector<pair<unsigned int, int> > dlote(0);
  110. forn(i, n){
  111. if(lote[i].end > 0)
  112. dlote.push_back(make_pair(lote[i].end, i));
  113. }
  114. priority_queue<pair<int, int> > unblock;
  115. int context_remain = 0; /* Remaining context_switch ticks */
  116. while (finished < n || context_remain) {
  117. if (settings.verbose) {
  118. //cerr << "--- sched, tm=" << cur_time << " pid=" << cur_pid;
  119. cerr << "--- sched, tm=" << cur_time << endl;
  120. for(int i = 0; i < settings.num_cores; i++) {
  121. int pid=contexts[i].pid;
  122. cerr << "cpu " << i << " pid = " << pid << " rem " << contexts[i].remaining;
  123. if (pid != IDLE_TASK) { cerr << " [" << pid << " ST:"<< tsks[pid].blk << " ms:" << tsks[pid].blkms << "]"; }
  124. cerr << endl;
  125. }
  126. cerr << "--------------" << cur_time << endl;
  127. }
  128. // Load de las tareas
  129. while (!load.empty() && load.top().first >= -(int)cur_time) {
  130. int pid = -load.top().second;
  131. int deadline = lote[-load.top().second].end;
  132. load.pop();
  133. tsks[pid].running = 1;
  134. sch.load(pid,deadline);
  135. cout << "LOAD " << cur_time << " " << pid << endl;
  136. }
  137. vector<int> to_unblock;
  138. while (!unblock.empty() && unblock.top().first >= -(int)cur_time) {
  139. int pid = -unblock.top().second; unblock.pop();
  140. _D(cerr << "SCH unblock(" << pid << ")" << endl;)
  141. sch.unblock(pid); // pid
  142. to_unblock.push_back(pid);
  143. int unblocked = 0;
  144. for(int i = 0; i < settings.num_cores && !unblocked; i++) {
  145. int it = contexts[i].pid;
  146. if (it == pid) {
  147. tsks[pid].blkms = -2;
  148. unblocked = true;
  149. }
  150. }
  151. if (!unblocked) {
  152. tsks[pid].blk = ST_CPU;
  153. tsks[pid].blkms = 0;
  154. }
  155. }
  156. //Itera por cada cpu
  157. for(int cpu= 0; cpu < settings.num_cores; cpu++){
  158. int cpu_pid= contexts[cpu].pid;
  159. int cpu_context_remain = contexts[cpu].remaining;
  160. if (!cpu_context_remain) {
  161. int npid;
  162. if (cpu_pid == IDLE_TASK) {
  163. npid = sch.tick(cpu, TICK);
  164. _D(cerr << "SCH tick( " << cpu << " ,TICK) -> " << npid << endl;)
  165. } else {
  166. if (tsks[cpu_pid].blk == ST_CPU && !tsks[cpu_pid].blkms){
  167. _D(cerr << "SCH unlock(" << cpu_pid << ") tick" << endl;) pthread_mutex_unlock(&(tsks[cpu_pid].mutex));
  168. pthread_mutex_lock(&m_sched); _D(cerr << "SCH lock(sched)" << endl;)
  169. }
  170. switch (tsks[cpu_pid].blk) {
  171. case ST_EXIT:
  172. finished++;
  173. npid = sch.tick(cpu, EXIT);
  174. cout << "EXIT " << cur_time << " " << cpu_pid << " " << cpu << endl;
  175. _D(cerr << "SCH tick( " << cpu << " ,EXIT) -> " << npid << endl;)
  176. tsks[cpu_pid].running = 0;
  177. break;
  178. case ST_IO:
  179. if (tsks[cpu_pid].blkms >= 0) {
  180. unblock.push(make_pair(-(cur_time+tsks[cpu_pid].blkms), -cpu_pid));
  181. tsks[cpu_pid].blkms = -1;
  182. }
  183. if (tsks[cpu_pid].blkms == -2) {
  184. tsks[cpu_pid].blk = ST_CPU;
  185. tsks[cpu_pid].blkms = 0;
  186. }
  187. cout << "BLOCK " << cur_time << " " << cpu_pid << endl;
  188. npid = sch.tick(cpu, BLOCK);
  189. _D(cerr << "SCH tick( " << cpu << " ,BLOCK) -> " << npid << endl;)
  190. break;
  191. case ST_CPU:
  192. if (tsks[cpu_pid].blkms) {
  193. tsks[cpu_pid].blkms--;
  194. } else {
  195. cerr << "FATAL ERROR, this should not happend" << endl;
  196. }
  197. npid = sch.tick(cpu, TICK);
  198. _D(cerr << "SCH tick( " << cpu << " ,TICK) -> " << npid << endl;)
  199. break;
  200. }
  201. }
  202. if (npid == IDLE_TASK) {
  203. // cerr << "SCH unlock(sched)" << endl;pthread_mutex_unlock(&m_sched);
  204. } else {
  205. if (npid < 0 || npid >= n) { cerr << "Error!, scheduler sent an invalid pid="<<npid<< endl; return; }
  206. if (!tsks[npid].running) { cerr << "Error!, scheduler sent pid="<<npid << " but that process has exited." << endl; return; }
  207. if (!tsks[npid].blk == ST_IO) { cerr << "Error!, scheduler sent pid="<<npid << " but that process is still blocked." << endl; return; }
  208. }
  209. if (cpu_pid != npid){
  210. if (npid != IDLE_TASK) {
  211. if (settings.switch_cost > 0) {
  212. contexts[cpu].remaining += settings.switch_cost;
  213. }
  214. if (cpu != tsks[npid].lastcpu && tsks[npid].lastcpu != -1) {
  215. contexts[cpu].remaining += settings.migrate_cost;
  216. }
  217. tsks[npid].lastcpu = cpu;
  218. }
  219. }
  220. cpu_pid = npid;
  221. } else {
  222. contexts[cpu].remaining--;
  223. }
  224. contexts[cpu].pid = cpu_pid;
  225. }
  226. //Hasta aca el codigo para cada CPU
  227. /* Unblock tasks at the end of the tick */
  228. for(int j=0; j<(int)to_unblock.size(); j++) cout << "UNBLOCK " << cur_time << " " << to_unblock[j] << endl;
  229. context_remain= 0;
  230. //Muestra que esta realizando cada cpu
  231. //y calcula si hay contexto total restante (ver while)
  232. for(int i= 0; i < contexts.size(); i++){
  233. context_remain += contexts[i].remaining;
  234. if (contexts[i].remaining /*context_remain*/) {
  235. cout << "# CONTEXT CPU " << i << " " << cur_time << endl;
  236. } else{
  237. cout << "CPU "<< cur_time << " " << contexts[i].pid << " " << i <<endl;
  238. }
  239. }
  240. //Muestra si se cumple el deadline de alguna tarea en este tick
  241. forn(i, dlote.size()){
  242. if(dlote[i].first == cur_time)
  243. cout << "DEADLINE "<< cur_time << " " << dlote[i].second << endl;
  244. }
  245. cur_time++;
  246. }
  247. forn(i, n) {
  248. pthread_join( tsks[i].tid, NULL);
  249. }
  250. free(tsks);
  251. }