Fabian пре 10 година
комит
888a25f68b
28 измењених фајлова са 19375 додато и 0 уклоњено
  1. 2 0
      .gitignore
  2. 26 0
      Makefile
  3. 7 0
      basesched.cpp
  4. 43 0
      basesched.h
  5. 64 0
      basetask.cpp
  6. 27 0
      basetask.h
  7. 7 0
      consola.tsk
  8. 392 0
      event_parser.py
  9. 17474 0
      get-pip.py
  10. 168 0
      graph_cores.py
  11. 306 0
      graphsched.py
  12. 2 0
      lote.tsk
  13. 224 0
      main.cpp
  14. 37 0
      sched_fcfs.cpp
  15. 20 0
      sched_fcfs.h
  16. 28 0
      sched_mfq.cpp
  17. 22 0
      sched_mfq.h
  18. 29 0
      sched_rr.cpp
  19. 23 0
      sched_rr.h
  20. 25 0
      sched_rsjf.cpp
  21. 24 0
      sched_rsjf.h
  22. 28 0
      sched_sjf.cpp
  23. 23 0
      sched_sjf.h
  24. 288 0
      simu.cpp
  25. 23 0
      simu.h
  26. 15 0
      simusched.cpp
  27. 41 0
      tasks.cpp
  28. 7 0
      tasks.h

+ 2 - 0
.gitignore

@@ -0,0 +1,2 @@
+*png
+*.o

+ 26 - 0
Makefile

@@ -0,0 +1,26 @@
+export LC_ALL=C
+CXXFLAGS= -Wall -pedantic -g -ggdb
+LDFLAGS= -lpthread
+
+OBJS=main.o simu.o basesched.o basetask.o tasks.o sched_rr.o sched_fcfs.o sched_sjf.o sched_rsjf.o sched_mfq.o
+MAIN=simusched
+
+.PHONY: all clean new
+all: $(MAIN)
+
+$(MAIN): $(OBJS)
+	$(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS)
+
+%.o: %.cpp %.h basesched.h
+basesched.o: basesched.cpp basesched.h
+basetask.o: basetask.cpp basetask.h
+main.o: main.cpp simu.h basetask.h basesched.h tasks.h sched_fcfs.h \
+	sched_mfq.h sched_rr.h sched_rsjf.h sched_sjf.h
+simu.o: simu.cpp simu.h basetask.h basesched.h
+simusched.o: simusched.cpp basetask.h basesched.h tasks.h
+tasks.o: tasks.cpp tasks.h basetask.h
+
+clean:
+	rm -f $(OBJS) $(MAIN)
+
+new: clean all

+ 7 - 0
basesched.cpp

@@ -0,0 +1,7 @@
+#include "basesched.h"
+
+using namespace std;
+
+void SchedBase::load(int pid,int deadline) {
+  load(pid);
+}

+ 43 - 0
basesched.h

@@ -0,0 +1,43 @@
+#ifndef __BASESCHED_H__
+#define __BASESCHED_H__
+
+#define IDLE_TASK -1
+#include <vector>
+
+enum Motivo { TICK, BLOCK, EXIT };
+
+class SchedBase {
+	public:
+
+	virtual ~SchedBase() {};
+	/* Constructor, recibe los parámetros pasados al scheduler como una lista de enteros. */
+
+	/* load(pid) será llamada cuando una tarea nueva (pid) es creada.
+		si deadline > 0, significa que la tarea debe terminarse antes de deadline
+	*/
+	virtual void load(int pid, int deadline);
+	virtual void load(int pid) = 0;
+
+	/* unblock(pid) será llamada cuando OTRA tarea (pid), previamente bloqueda,
+	 * haya terminado la operación de I/O (pasa de BLOCKED a READY). */
+	virtual void unblock(int pid) = 0;
+
+	/* tick() será llamada con cada "tick" del reloj de la máquina (1 ms).
+	 * El parámetro m indica si en la ejecución del último ms, la tarea:
+	 *  - BLOCK: Ejecutó una syscall bloqueante
+	 *  - EXIT: Terminó (return)
+	 *  - TICL: Consumió el CPU todo el milisegundo.
+	 * Esta función devuelve qué pid utilizará el CPU ahora, o IDLE_TASK. */
+	virtual int tick(int cpu, const enum Motivo m) = 0;
+};
+
+/* Getters */
+//int current_pid();
+int current_pid(int cpu);
+unsigned int current_time();
+
+/* Factory (ignorar) */
+template<typename T>
+SchedBase& create_sched(const std::vector<int>& argn) { return ( new T(argn) ); }
+
+#endif

+ 64 - 0
basetask.cpp

@@ -0,0 +1,64 @@
+#include "basetask.h"
+#include <fstream>
+#include <iostream>
+#include <sstream>
+#include <cstdlib>
+
+using namespace std;
+
+#define esta(e, X) ((X).find(e) != (X).end())
+map<string, ptski> task_defs;
+vector<TaskBase*> tasks;
+
+vector<ptsk> tasks_load(const char* filename) {
+	vector<ptsk> ts(0);
+	ifstream f(filename);
+	string s; int l = 0;
+	unsigned int starttm = 0;
+	unsigned int deadline = 0;
+	while(getline(f, s)) { l++;
+
+		//Salteo comentarios o líneas en blanco
+		if (s == "" || s[0] == '#') continue;
+
+		istringstream iss(s);
+
+		//Ready time
+		if (s[0] == '@') {
+			char c; iss >> c;
+			iss >> starttm;
+			continue;
+		}
+
+		//Deadline time
+		if (s[0] == '$') {
+			char c; iss >> c;
+			iss >> deadline;
+			continue;
+		}
+
+		int times = 1;
+		if (s[0] == '*') {
+			char c; iss >> c;
+			iss >> times;
+			if (times<=0) { cerr << "WARNING: '*n' should have a positive number n." << endl; times = 1; }
+		}
+		string nom = "";
+		vector<int> params; int x;
+		if (!(iss >> nom) || !esta(nom, task_defs)) {
+			cerr << filename << ":" << l << ": ERROR: Unknow task type (" << nom << "): " << s << endl;
+			exit(1);
+		}
+		while (iss >> x) params.push_back(x);
+		ptski ti = task_defs[nom];
+		if (ti.second != -1 && ti.second != (int)params.size()) {
+			cerr << filename << ":" << l << ": ERROR: expected " << ti.second << " parameters but " << params.size() << " found: " << s << endl;
+			exit(1);
+		}
+		for(int j=0; j<times; j++) ts.push_back(ptsk(ti.first, params, starttm,deadline));
+	}
+	return ts;
+}
+
+ptsk::ptsk(TaskBase* vtsk, const std::vector<int>& vprms, unsigned int vstart, unsigned int vend) : tsk(vtsk), prms(vprms), start(vstart), end(vend) {}
+ptsk::ptsk(void) {}

+ 27 - 0
basetask.h

@@ -0,0 +1,27 @@
+#ifndef __BASETASK_H__
+#define __BASETASK_H__
+
+#include <vector>
+#include <map>
+#include <utility>
+#include <string>
+
+typedef void (TaskBase)(int, std::vector<int> params);
+
+/* Funciones que llaman las tareas para simular uso */
+
+void uso_CPU(int pid, unsigned int ms);
+void uso_IO(int pid, unsigned int ms);
+
+/* Factory (ignorar) */
+#define register_task(tipo, nprms) { task_defs[#tipo] = ptski(tipo, nprms); }
+typedef std::pair<TaskBase*, int> ptski;
+extern std::map<std::string, ptski> task_defs;
+
+struct ptsk {
+	TaskBase* tsk; std::vector<int> prms; unsigned int start; unsigned int end;
+	ptsk(TaskBase* vtsk, const std::vector<int>& vprms, unsigned int vstart, unsigned int vend);
+	ptsk(void);
+};
+std::vector<ptsk> tasks_load(const char* filename);
+#endif

+ 7 - 0
consola.tsk

@@ -0,0 +1,7 @@
+#comentario
+#@t donde t es release time de la proxima task
+@3:
+TaskConsola 5 1 3
+@5:
+*2 TaskConsola 2 4 8
+#Lanzo 1 taskCpu

+ 392 - 0
event_parser.py

@@ -0,0 +1,392 @@
+#!/usr/bin/env python
+# coding: utf-8
+
+import sys, os
+import matplotlib
+matplotlib.use('Agg')
+from pylab import *
+from matplotlib.transforms import TransformedBbox 
+
+class EventFactory(object):
+    #CPU time pid cpu (si pid == -1 -> idle)
+    cpu_event= lambda x: Event(x[0],EventFactory.Events.keys().index(x[0]),int(x[1]),int(x[2]),int(x[3]))
+    #EVENT time pid  
+    other_event= lambda x: Event(x[0],EventFactory.Events.keys().index(x[0]),int(x[1]),int(x[2]),-1)
+    #CONTEXT CPU cpu time (se pone pid == -2) 
+    context_switch_event= lambda x: Event(x[0] ,EventFactory.Events.keys().index(x[0]),int(x[3]),-2,int(x[2]))
+    Events = {'LOAD': other_event,
+              'CPU':cpu_event, 
+              'BLOCK': other_event, 
+              'UNBLOCK': other_event, 
+              'EXIT': other_event,
+              'CONTEXT':context_switch_event,
+              'WAITING':None,
+              'NOT_LOAD': None,
+              'CPU_BLOCK': None}
+    
+    @classmethod
+    def get_event(cls, event_line):
+        splited_event_line= event_line.split()
+        if splited_event_line[0] in EventFactory.Events.keys():
+            print splited_event_line
+            return EventFactory.Events[splited_event_line[0]](splited_event_line)
+        else:
+            return None
+        
+
+class Event(object):
+    def __init__(self, event_type, event_code, time, pid, core):
+        self.event_type= event_type
+        self.event_code= event_code
+        self.time= time
+        self.pid= pid
+        self.core= core
+    def __str__(self):
+        return 'Type: ' + self.event_type + ', Code: ' + str(self.event_code) + ', Time: ' + str(self.time) + ', Pid: ' + str(self.pid) + ', Core: ' + str(self.core)
+
+def parseInput(fin):
+    ln = 0
+    result = []
+    cores = 0
+    pids= 0
+    settings = None
+    cpus_timeline= dict()
+    print fin
+    for line in fin:
+        ln += 1
+        vls = line.split()
+        if line and line[0] == '#':
+            if line.startswith('# SETTINGS '):
+                settings = line[11:].strip()
+                continue
+            else:
+                line= line[2:].strip() # Queda --> 'CONTEXT CPU[cpu] time
+
+        event= EventFactory.get_event(line)
+        result.append(event)
+        
+        if event.event_type == 'CPU':
+            if (cores <=event.core):
+                cores = event.core+1
+
+        if event.event_type == 'LOAD':
+            if(pids <= event.pid):
+                pids = event.pid +1
+            
+    return settings, result, cores, pids
+
+def dataGathering(data, cores, pids):
+    core_resume= dict() # core: {processing_time: #, switching_time: #, idle_time: #}
+    core_timeline= dict() # core: list(pids) NOTA: se supone que en cada tick hay un pid
+    pid_resume= dict() # pid: {load_time: #, running_time: #, blocked: #, end_time: #}
+    pids_timeline= dict() # pid: list((event_code, core))
+    
+    block_lapse= dict()
+
+    for event in data:
+        #core_time
+        if event.core != -1:
+             if event.core not in core_timeline: core_timeline[event.core]= []
+             core_timeline[event.core].append(event.pid)
+        
+        #core_time
+        if event.core != -1:
+            if event.core not in core_resume: core_resume[event.core]= {'processing_time': 0, 'switching_time': 0, 'idle_time': 0}
+            if event.event_type == 'CPU':
+                if event.pid != -1: core_resume[event.core]['processing_time'] = core_resume[event.core]['processing_time'] + 1
+                else: core_resume[event.core]['idle_time'] = core_resume[event.core]['idle_time'] + 1
+            elif event.event_type == 'CONTEXT': core_resume[event.core]['switching_time'] = core_resume[event.core]['switching_time'] + 1
+        
+        if event.pid != -2 and event.pid != -1:
+            #task_resume
+            if event.pid not in pid_resume: pid_resume[event.pid]= {'running_time': 0, 'blocked': 0}
+            if event.event_type == 'LOAD': pid_resume[event.pid]['load_time']= event.time
+            if event.event_type == 'CPU': pid_resume[event.pid]['running_time']= pid_resume[event.pid]['running_time'] + 1
+            if event.event_type == 'BLOCK': 
+                if event.pid not in block_lapse: block_lapse[event.pid]= -1
+                if block_lapse[event.pid] == -1:
+                    block_lapse[event.pid]= event.time
+            if event.event_type == 'UNBLOCK':
+                pid_resume[event.pid]['blocked']= pid_resume[event.pid]['blocked'] + event.time - block_lapse[event.pid] + 1
+                block_lapse[event.pid]= -1
+            if event.event_type == 'EXIT': pid_resume[event.pid]['end_time']= event.time
+        
+            #task_timeline no hay interes en mostrar los context switchs
+            
+            if event.pid not in pids_timeline: pids_timeline[event.pid]= []
+            if event.event_type == 'LOAD':
+                #NOT LOADED
+                for i in range(0, event.time):
+                    pids_timeline[event.pid].append((EventFactory.Events.keys().index('NOT_LOAD'),-1))
+            elif event.event_type == 'CPU':
+                prev_event_code, prev_event_core= pids_timeline[event.pid][-1]
+                #POSIBLE BLOCK ANTES QUE CPU
+                if len(pids_timeline[event.pid]) == event.time:
+                    prev_event_code, prev_event_core= pids_timeline[event.pid][-1]
+                    if (EventFactory.Events.keys().index('BLOCK') == prev_event_code or
+                        EventFactory.Events.keys().index('CPU_BLOCK') == prev_event_code):
+                        pid_resume[event.pid]['running_time']= pid_resume[event.pid]['running_time'] - 1    
+                        pids_timeline[event.pid][-1]= (EventFactory.Events.keys().index('CPU_BLOCK'),event.core)
+                        continue
+                #WAITING EVENT
+                for i in range(len(pids_timeline[event.pid])+1, event.time):
+                    pids_timeline[event.pid].append((EventFactory.Events.keys().index('LOAD'),-1))
+            elif event.event_type == 'BLOCK':
+                #ESTA BLOQUEADO Y EJECUTANDO
+                if len(pids_timeline[event.pid]) == event.time:
+                    prev_event_code, prev_event_core= pids_timeline[event.pid][-1]
+                    if (EventFactory.Events.keys().index('CPU') == prev_event_code or
+                        EventFactory.Events.keys().index('CPU_BLOCK') == prev_event_code):
+                        pids_timeline[event.pid][-1]= (EventFactory.Events.keys().index('CPU_BLOCK'),prev_event_core)
+                        continue
+            elif event.event_type == 'UNBLOCK':
+                #Agrego el gap que queda de todo el tiempo bloqueado
+                block_code, block_dummy_core= pids_timeline[event.pid][-1]
+                if block_code != EventFactory.Events.keys().index('CPU_BLOCK'): 
+                    for i in range(len(pids_timeline[event.pid])+1, event.time+1):
+                        pids_timeline[event.pid].append((block_code,block_dummy_core))
+
+            if event.event_type != 'UNBLOCK' and event.event_type != 'EXIT':
+                pids_timeline[event.pid].append((event.event_code,event.core))
+    
+    return core_resume, core_timeline, pid_resume, pids_timeline
+
+def draw_cores_resume_bars(cores_resume, filename):
+    ''' pre: cores_resume = { core: {processing_time: #, switching_time: #, idle_time: #}}'''
+    ''' post: horizonal bar diagram in filenaname.png '''
+    
+    colors={'processing_time': 'green', 'switching_time': 'yellow', 'idle_time': 'red'}
+    labels={'processing_time': 'Procesando', 'switching_time': 'Cambiando contexto', 'idle_time': 'Sin uso'}
+    
+    fig= figure(figsize=(11.8,8.3))
+    
+    
+    bars_lenghts= []
+    for core in cores_resume:
+        bars_lenghts.append(sum(cores_resume[core].values()))
+        values= sorted(zip(cores_resume[core].values(), cores_resume[core].keys()), reverse= True)
+        base= 0
+        for value in values:
+            broken_barh([(base,value[0])], (core-0.4,0.8), color=colors[value[1]], edgecolor='black')
+            base= base+value[0]
+    
+    title('Tiempo total por tipo de tarea por core')
+    yticks(cores_resume.keys())
+    xlabel('Tiempo total')
+    ylabel('Core')
+    xlim((0,max(bars_lenghts)+1))
+    ylim((-1,len(cores_resume.keys())+1))
+    tight_layout()
+    legend()
+    savefig(filename+'.png', dpi=300, format='png')
+    return None
+
+def draw_cores_timeline_gannt(cores_timeline, filename):
+    ''' pre: cores_timeline = {core: list(pid) } '''
+    
+    # Necesitaria tener la info algo asi como
+    # core: {pid: ini_1,fin_1,ini_2,fin_2} (es decir por intervalos)
+    # broken_barh necesita (inicio, longitud)
+    
+    colors={'pid':'#c0ffc0','switch':'#b7b7f7', 'idle':'#d0d0d0'}
+
+    fig= figure(figsize=(11.8,8.3))
+    ax = fig.add_subplot(111) 
+    title('Tareas en Core por tiempo')
+    yticks(cores_timeline.keys())
+#    ax.xaxis.set_major_locator( 
+    ax.xaxis.set_major_locator( IndexLocator(2,1) )
+    #xticks(range(len(cores_timeline[0])),range(0,len(cores_timeline[0]),5))
+    xlabel('Tiempo')
+    ylabel('Core')
+    ylim((-1,len(cores_timeline.keys())))
+    ax.grid(True)            
+
+    for core in cores_timeline:
+        pids_by_time= cores_timeline[core]
+        intervals= dict()
+        last_pid= -1
+        for time in range(len(pids_by_time)):
+            if last_pid != pids_by_time[time]:
+                last_pid = pids_by_time[time]
+                if last_pid not in intervals: intervals[last_pid]= []
+                intervals[last_pid].append((time, 1))
+                #intervals.push((last_pid,time,1))
+            else:
+                #pid, time, interval_size= intervals.pop()
+                #intervals.push((pid, time, interval_size+1))
+                time, interval_size= intervals[last_pid].pop()
+                intervals[last_pid].append((time, interval_size+1))
+        
+        for pid in intervals:
+            if pid >= 0:
+                rect= ax.broken_barh(intervals[pid], (core-0.25, 0.5), facecolor=colors['pid'])
+                for init, size in intervals[pid]:
+                    ax.text(init+(size/2.0),core, str(pid), ha="center", va="center", size=9, weight='bold')
+            elif pid == -1:
+                rect= ax.broken_barh(intervals[pid], (core-0.25, 0.5), facecolor=colors['idle'])
+            elif pid == -2:
+                rect= ax.broken_barh(intervals[pid], (core-0.25, 0.5), facecolor=colors['switch'])
+            else:
+                print 'ERROR!'
+    
+    tarea_dummy = Rectangle((0, 0), 1, 1, fc=colors['pid'])
+    switch_dummy = Rectangle((0, 0), 1, 1, fc=colors['switch'])
+    idle_dummy = Rectangle((0, 0), 1, 1, fc=colors['idle'])
+    legend([tarea_dummy, switch_dummy, idle_dummy], ['Tarea','Cambio de contexto','Inactivo'])
+    tight_layout()
+    fig.autofmt_xdate()
+    ax.legend()
+    savefig(filename+'.png', dpi=300, format='png')
+
+def draw_tasks_resume_bars(pids_resume, filename):
+    ''' pre: pid: {load_time: #, running_time: #, blocked: #, end_time: #}'''
+    ''' post: horizonal bar diagram in filenaname.png '''
+    
+    colors={'running_time': '#c0ffc0', 'blocked': '#b7b7f7', 'waiting_time': '#d0d0d0'}
+    labels={'running_time': 'En ejecucion', 'blocked': 'Bloqueado', 'waiting_time': 'Esperando'}
+    
+    fig= figure(figsize=(11.8,8.3))
+    pids_resume.pop(-1,None)
+
+    max_time= 0
+    for pid in pids_resume:
+        load_time= pids_resume[pid].pop('load_time',-1)
+        end_time= pids_resume[pid].pop('end_time',-1)
+        max_time= max([end_time-load_time,max_time])
+        pids_resume[pid]['waiting_time']= end_time - load_time - pids_resume[pid]['running_time'] - pids_resume[pid]['blocked']
+        values= sorted(zip(pids_resume[pid].values(), pids_resume[pid].keys()), reverse= True)
+        base= 0
+        for value in values:
+            broken_barh([(base,value[0])], (pid-0.25, 0.5), facecolor=colors[value[1]])
+            #if pid != 0:
+            #    barh(pid, base + value[0], align='center', color=colors[value[1]], edgecolor='black')
+            #else:
+            #    barh(pid, base + value[0], align='center', color=colors[value[1]], edgecolor='black', label=labels[value[1]])
+            base= base + value[0]
+
+    running_dummy = Rectangle((0, 0), 1, 1, fc=colors['running_time'])
+    blocked_dummy = Rectangle((0, 0), 1, 1, fc=colors['blocked'])
+    waiting_dummy = Rectangle((0, 0), 1, 1, fc=colors['waiting_time'])
+    legend([running_dummy, blocked_dummy, waiting_dummy],[labels['running_time'],labels['blocked'], labels['waiting_time']],loc='best', ncol=3)
+    title('Tiempo total de la tarea divido en estados')
+    yticks(pids_resume.keys())
+    xlabel('Tiempo total')
+    ylabel('Tarea')
+    ylim((-1,len(pids_resume.keys())+1))
+    xlim((0,max_time+2))
+    tight_layout()
+    #show()
+    savefig(filename+'.png', dpi=300, format='png')
+    return None
+
+def draw_pids_timeline_gannt(pids_timeline, filename):
+    ''' pre: pids_timeline = { pid: list((event_code, core))}'''
+    ''' post: horizonal bar diagram in filenaname.png '''
+    
+    # Necesitaria tener la info algo asi como
+    # core: {pid: ini_1,fin_1,ini_2,fin_2} (es decir por intervalos)
+    # broken_barh necesita (inicio, longitud)
+    
+    colors={'CPU':'#f7b7b7','BLOCK':'#b7b7f7', 'WAITING':'#e7ffe7', 'LOAD':'#e7ffe7', 'NOT_LOAD':'#d0d0d0', 'CPU_BLOCK':'#b7b7f7'}
+
+    fig= figure(figsize=(11.8,8.3))
+    ax = fig.add_subplot(111) 
+    title('Estado de las tareas por tiempo')
+    yticks(pids_timeline.keys(), sorted(pids_timeline.keys(),reverse=True))
+#    ax.xaxis.set_major_locator( 
+    ax.xaxis.set_major_locator( IndexLocator(5,1) )
+    #xticks(range(len(cores_timeline[0])),range(0,len(cores_timeline[0]),5))
+    xlabel('Tiempo')
+    ylabel('Tarea')
+    ax.grid(True)            
+
+    for pid in pids_timeline:
+        pid_state_by_time= pids_timeline[pid]
+        intervals= dict()
+        last_state= (None,None)
+        for time in range(len(pid_state_by_time)):
+            if last_state != pid_state_by_time[time]:
+                last_state = pid_state_by_time[time]
+                if last_state not in intervals: intervals[last_state]= []
+                intervals[last_state].append((time, 1))
+                #intervals.push((last_pid,time,1))
+            else:
+                #pid, time, interval_size= intervals.pop()
+                #intervals.push((pid, time, interval_size+1))
+                time, interval_size= intervals[last_state].pop()
+                intervals[last_state].append((time, interval_size+1))
+
+        for event_code, core in intervals.keys():
+            event_name= EventFactory.Events.keys()[event_code]
+            rect= ax.broken_barh(intervals[(event_code, core)], ((len(pids_timeline)-pid-1)-0.25, 0.5), facecolor=colors[event_name])
+            if core >= 0:
+                for init, size in intervals[(event_code, core)]:
+                    ax.text(init+(size/2.0),(len(pids_timeline)-pid-1), str(core), ha="center", va="center", size=9, weight='bold')
+            #else:
+                #if event_code == -1:
+                #elif event_code == -2:
+                    #rect= ax.broken_barh(intervals[(event_code, core)], (pid-0.25, 0.5), facecolor=colors['not_loaded'])
+                #elif event_name == 'LOAD':
+                    #rect= ax.broken_barh(intervals[(event_code, core)], (pid-0.25, 0.5), facecolor=colors['load'])
+                #elif event_name == 'BLOCK':
+                    #rect= ax.broken_barh(intervals[(event_code, core)], (pid-0.25, 0.5), facecolor=colors['blocked'])
+                #else:
+                #    print 'ERROR!', event_code, core
+    
+    running_dummy = Rectangle((0, 0), 1, 1, fc=colors['CPU'])
+    waiting_dummy = Rectangle((0, 0), 1, 1, fc=colors['WAITING'])
+    not_loaded_dummy = Rectangle((0, 0), 1, 1, fc=colors['NOT_LOAD'])
+    #load_dummy = Rectangle((0, 0), 1, 1, fc=colors['LOAD'])
+    blocked_dummy = Rectangle((0, 0), 1, 1, fc=colors['BLOCK'])
+    legend([not_loaded_dummy,running_dummy, waiting_dummy, blocked_dummy], ['No cargada','En ejecucion','Lista','Bloqueada'],loc='best', ncol=4)
+    ylim((-1,len(pids_timeline.keys())+1))
+    xlim((0,max([len(x) for x in pids_timeline.values()])+1))
+    tight_layout()
+    fig.autofmt_xdate()
+    ax.legend()
+    #show()
+    savefig(filename+'.png', dpi=300, format='png')
+    return None
+
+
+def main(argv):
+    if '-c' in argv or '--caption' in argv:
+        hit = '-c' if '-c' in argv else '--caption'
+        pos = argv.index(hit)
+        argv.pop(pos)
+        caption = argv.pop(pos)
+    else:
+        caption = None
+
+    if len(argv) <= 1:
+        fin = sys.stdin
+        fout_cores_resume= 'out_cores_resume'
+        fout_cores_timeline= 'out_cores_timeline'
+        fout_pids_resume= 'out_pids_resume'
+        fout_pids_timeline= 'out_pids_timeline'
+    else:
+        fin = open(argv[1], 'r')
+        preffix= argv[1]
+        fout_cores_resume= preffix + '_cores_resume' 
+        fout_cores_timeline= preffix + '_cores_timeline' 
+        fout_pids_resume= preffix + '_pids_resume' 
+        fout_pids_timeline= preffix + '_pids_timeline' 
+    
+    print 'parsing input'
+    settings, data, cores, pids = parseInput(fin)
+    
+    print 'data gathering'
+    cores_resume, cores_timeline, pids_resume, pids_timeline= dataGathering(data, cores, pids)
+    #todo dump de los datos
+    print 'drawing cores resumen'
+    draw_cores_resume_bars(cores_resume, fout_cores_resume)
+    print 'drawing cores timeline'
+    draw_cores_timeline_gannt(cores_timeline, fout_cores_timeline)
+    print 'drawing cores timeline'
+    draw_tasks_resume_bars(pids_resume, fout_pids_resume)
+    print 'drawing pids timeline'
+    draw_pids_timeline_gannt(pids_timeline, fout_pids_timeline)
+
+if __name__ == "__main__":
+    main(sys.argv)

Разлика између датотеке није приказан због своје велике величине
+ 17474 - 0
get-pip.py


+ 168 - 0
graph_cores.py

@@ -0,0 +1,168 @@
+#!/usr/bin/env python
+# coding: utf-8
+
+import sys, os
+import matplotlib
+matplotlib.use('Agg')
+from pylab import *
+from matplotlib.transforms import TransformedBbox
+
+class EventFactory(object):
+    #CPU time pid cpu (si pid == -1 -> idle)
+    cpu_event= lambda x: Event(x[0],EventFactory.Events.keys().index(x[0]),int(x[1]),int(x[2]),int(x[3]))
+    #EVENT time pid
+    other_event= lambda x: Event(x[0],EventFactory.Events.keys().index(x[0]),int(x[1]),int(x[2]),-1)
+    #CONTEXT CPU cpu time (se pone pid == -2)
+    context_switch_event= lambda x: Event(x[0] ,EventFactory.Events.keys().index(x[0]),int(x[3]),-2,int(x[2]))
+    Events = {'LOAD': other_event,
+              'CPU':cpu_event,
+              'BLOCK': other_event,
+              'UNBLOCK': other_event,
+              'DEADLINE': other_event,
+              'EXIT': other_event,
+              'CONTEXT':context_switch_event,
+              'WAITING':None,
+              'NOT_LOAD': None,
+              'CPU_BLOCK': None}
+
+    @classmethod
+    def get_event(cls, event_line):
+        splited_event_line= event_line.split()
+        if splited_event_line[0] in EventFactory.Events.keys():
+            return EventFactory.Events[splited_event_line[0]](splited_event_line)
+        else:
+            return None
+
+
+class Event(object):
+    def __init__(self, event_type, event_code, time, pid, core):
+        self.event_type= event_type
+        self.event_code= event_code
+        self.time= time
+        self.pid= pid
+        self.core= core
+    def __str__(self):
+        return 'Type: ' + self.event_type + ', Code: ' + str(self.event_code) + ', Time: ' + str(self.time) + ', Pid: ' + str(self.pid) + ', Core: ' + str(self.core)
+
+def parseInput(fin):
+    ln = 0
+    result = []
+    cores = 0
+    pids= 0
+    settings = None
+    cpus_timeline= dict()
+    for line in fin:
+        ln += 1
+        vls = line.split()
+        if line and line[0] == '#':
+            if line.startswith('# SETTINGS '):
+                settings = line[11:].strip()
+                continue
+            else:
+                line= line[2:].strip() # Queda --> 'CONTEXT CPU cpu  time
+
+        event= EventFactory.get_event(line)
+        result.append(event)
+
+        if event.event_type == 'CPU':
+            if (cores <=event.core):
+                cores = event.core+1
+
+        if event.event_type == 'LOAD':
+            if(pids <= event.pid):
+                pids = event.pid +1
+
+    return settings, result, cores, pids
+
+def dataGathering(data, cores, pids):
+    core_timeline= dict() # core: list(pids) NOTA: se supone que en cada tick hay un pid
+
+    block_lapse= dict()
+
+    for event in data:
+        #core_time
+        if event.core != -1:
+             if event.core not in core_timeline: core_timeline[event.core]= []
+             core_timeline[event.core].append(event.pid)
+
+    return core_timeline
+
+def draw_cores_timeline_gannt(cores_timeline, filename):
+    ''' pre: cores_timeline = {core: list(pid) } '''
+
+    # Necesitaria tener la info algo asi como
+    # core: {pid: ini_1,fin_1,ini_2,fin_2} (es decir por intervalos)
+    # broken_barh necesita (inicio, longitud)
+
+    colors={'pid':'#c0ffc0','switch':'#b7b7f7', 'idle':'#d0d0d0'}
+
+    fig= figure(figsize=(11.8,8.3))
+    ax = fig.add_subplot(111)
+    title('Tareas en Core por tiempo')
+    yticks(cores_timeline.keys())
+#    ax.xaxis.set_major_locator(
+    ax.xaxis.set_major_locator( IndexLocator(2,1) )
+    #xticks(range(len(cores_timeline[0])),range(0,len(cores_timeline[0]),5))
+    xlabel('Tiempo')
+    ylabel('Core')
+    ylim((-1,len(cores_timeline.keys())))
+    ax.grid(True)
+
+    for core in cores_timeline:
+        pids_by_time= cores_timeline[core]
+        intervals= dict()
+        last_pid= None
+        for time in range(len(pids_by_time)):
+            if last_pid != pids_by_time[time]:
+                last_pid = pids_by_time[time]
+                if last_pid not in intervals: intervals[last_pid]= []
+                intervals[last_pid].append((time, 1))
+                #intervals.push((last_pid,time,1))
+            else:
+                #pid, time, interval_size= intervals.pop()
+                #intervals.push((pid, time, interval_size+1))
+                time, interval_size= intervals[last_pid].pop()
+                intervals[last_pid].append((time, interval_size+1))
+
+        for pid in intervals:
+            if pid >= 0:
+                rect= ax.broken_barh(intervals[pid], (core-0.25, 0.5), facecolor=colors['pid'])
+                for init, size in intervals[pid]:
+                    ax.text(init+(size/2.0),core, str(pid), ha="center", va="center", size=9, weight='bold')
+            elif pid == -1:
+                rect= ax.broken_barh(intervals[pid], (core-0.25, 0.5), facecolor=colors['idle'])
+            elif pid == -2:
+                rect= ax.broken_barh(intervals[pid], (core-0.25, 0.5), facecolor=colors['switch'])
+            else:
+                print 'ERROR!'
+
+    tarea_dummy = Rectangle((0, 0), 1, 1, fc=colors['pid'])
+    switch_dummy = Rectangle((0, 0), 1, 1, fc=colors['switch'])
+    idle_dummy = Rectangle((0, 0), 1, 1, fc=colors['idle'])
+    legend([tarea_dummy, switch_dummy, idle_dummy], ['Tarea','Cambio de contexto','Inactivo'])
+    tight_layout()
+    fig.autofmt_xdate()
+    ax.legend()
+    savefig(filename+'.png', dpi=300, format='png')
+
+def main(argv):
+    if len(argv) <= 1:
+        fin = sys.stdin
+        fout_cores_timeline= 'out_cores_timeline'
+    else:
+        fin = open(argv[1], 'r')
+        preffix= argv[1]
+        fout_cores_timeline= preffix + '_cores_timeline'
+
+    print 'parsing input'
+    settings, data, cores, pids = parseInput(fin)
+
+    print 'data gathering'
+    cores_timeline= dataGathering(data, cores, pids)
+    print cores_timeline
+    #todo dump de los datos
+    print 'drawing cores timeline'
+    draw_cores_timeline_gannt(cores_timeline, fout_cores_timeline)
+
+if __name__ == "__main__":
+    main(sys.argv)

+ 306 - 0
graphsched.py

@@ -0,0 +1,306 @@
+#!/usr/bin/env python
+# coding: utf-8
+
+import re, sys, os
+
+from PIL import Image, ImageDraw, ImageFont
+
+# Font search paths and acceptable names. Order matters.
+FONT_DIRS = "/usr/share/fonts/truetype/freefont", "/usr/lib/fonts/", "/Library/Fonts"
+FONT_NAMES = "FreeMono.ttf", "Andale Mono.ttf", "Arial Black.ttf", "Hei.ttf.ttf", "Courier New.ttf"
+
+def findfont(names=FONT_NAMES, dirs=FONT_DIRS):
+	"""Return first existing path or None."""
+	for d in dirs:
+		if os.path.isdir(d):
+			for f in names:
+				f = os.path.join(d, f)
+				if os.path.isfile(f):
+					return f
+	assert False, 'Error: check FONT_NAMES / FONT_DIRS.'
+
+CMDS = ['LOAD', 'CPU', 'BLOCK', 'UNBLOCK', 'EXIT', 'DEADLINE']
+LOAD, CPU, BLOCK, UNBLOCK, EXIT, DEADLINE = range(6)
+
+COLOR_GRAY = ('#a0a0a0', '#d0d0d0')
+COLOR_BLACK = '#000000'
+COLORS = [
+	('#c0ffc0', '#e7ffe7'), # Verde claro
+	('#0000ff', '#b7b7f7'), # Azul
+	('#ff0000', '#f7b7b7'), # Rojo
+	('#d0d0d0', '#f4f4f4'), # Gris
+	('#00e000', '#b7efb7'), # Verde
+	('#ffff00', '#f7f7b7'), # Amarillo
+	('#c0c0ff', '#e7e7ff'), # Azul claro
+]
+
+STATES = ['READY', 'BLOCKED', 'RUNNING', 'UNLOADED']
+READY, BLOCKED, RUNNING, UNLOAD, RUNNINGBLOCKED = range(5)
+
+
+
+
+def iround(m):
+	"""Rounds the number to the nearest number with only one significative digit."""
+	n = 1
+	while (m + n/2) / n >= 10:
+		n*= 10
+	while (m + n/2) / n >= 5:
+		n*= 5
+	rm = m - (m/n)*n
+	return ((m+rm)/n)*n
+
+def parseData(fin):
+	ln = 0
+	result = []
+	cores = 0
+	settings = None
+	idleCore = -1
+	lastTick = -1
+	for l in fin:
+		ln += 1
+		vls = l.split()
+		if l and l[0] == '#':
+			if l[:11] == '# SETTINGS ':
+				settings = l[11:].strip()
+			continue
+		if (vls[0] not in CMDS):
+			sys.stderr.write('Warning: Ignoring line %d: %s' % (ln, l))
+			continue
+		if len(vls) == 4 and vls[0] == 'CPU':
+			if vls[1] != lastTick:
+				idleCore = -1
+				lastTick = vls[1]
+			#Muestro solo el primer core en llegar a idle
+			if vls[2] == "-1" and idleCore == -1:
+				idleCore = int(vls[3])
+				lastTick = vls[1]
+			if vls[2] != "-1" or int(vls[3]) == idleCore:
+				result.append((CMDS.index(vls[0]), int(vls[1]), int(vls[2]), int(vls[3])))
+			core = int(vls[3])
+			if (cores <=core):
+				cores = core+1
+		else:
+			result.append((CMDS.index(vls[0]), int(vls[1]), int(vls[2]), -1))
+
+	#Sobra una ronda de cores idles
+	result.pop()
+	return settings, result, cores
+
+def dataGantt(data, cores):
+	g = dict()
+	for cmd, tm, pid, core in data:
+		if pid not in g: g[pid] = []
+		g[pid].append((tm,cmd,core))
+	return g
+
+def drawGantt(data, fout, rg=3, width=1024, height=600, fontpath=None, settings=None, caption=None):
+
+	if fontpath is None:
+		fontpath = findfont()
+
+	xmarks = 10
+	subxmarks = 5
+
+	n = len(data)
+	xmin = min(min(tm for tm,_,_ in data[pid]) for pid in data)
+	xmax = max(max(tm for tm,_,_ in data[pid]) for pid in data)+1
+
+	# Inicializa Grafico
+	xstp = iround((xmax+xmarks-1)/xmarks)
+	xgap = xstp*xmarks
+	ystp = 30
+	if ystp*n > height: ystp = height/n
+
+	gw,gh = width-60,n*ystp
+	gx,gy = 5+20+ 30 , 5 + 30 + 5 + gh
+	iw,ih = gx+gw+8, gy+5+17+5
+	if caption: ih += 24
+
+	# Nueva IMG
+	img = Image.new("RGB", (iw,ih), (255,255,255))
+	draw = ImageDraw.Draw(img)
+	font = ImageFont.truetype(fontpath, 12)
+
+	# Marcas en Y:
+	pids = sorted(pid for pid in data if pid >= 0)
+	if -1 in data: pids.append(-1)
+	pids.reverse()
+	for i in xrange(len(pids)):
+		ly = gy - i*ystp - ystp/2
+		draw.line((gx-2,ly,gx-4,ly), fill=COLOR_BLACK)
+		txt = str(pids[i] if pids[i] >= 0 else 'IDLE')
+		tw,th = draw.textsize(txt, font=font)
+		draw.text((gx-2 -5 -tw, ly - th/2), txt, font=font, fill=COLOR_BLACK)
+
+	# Marcas en X:
+	for i in xrange(2*subxmarks*xmarks):
+		x = xmin - xmin%xstp + xstp * i / subxmarks
+		if x < xmin: continue
+		if x > xmax: break
+		lx = gx + x*gw / xmax
+		draw.line((lx,gy+1,lx,gy+3), fill=COLOR_BLACK if i%subxmarks==0 else COLOR_GRAY[0])
+		if x > xmin: draw.line((lx,gy-1,lx,gy-gh), fill=COLOR_BLACK if i%subxmarks==0 else COLOR_GRAY[0])
+		if i%subxmarks==0:
+			txt = str(x)
+			tw,th = draw.textsize(txt, font=font)
+			draw.text((lx-tw/2, gy+3), txt, font=font, fill=COLOR_BLACK)
+
+	# Ejes
+	draw.line((gx,gy,gx+gw,gy), fill=COLOR_BLACK)
+	draw.line((gx-1,gy,gx-1,gy-gh), fill=COLOR_BLACK)
+
+	# Leyenda
+	lx,ly = gx,gy-gh-25
+	bzs = 15
+	for i in xrange(len(STATES)):
+		draw.rectangle((lx,ly,lx+bzs,ly+bzs), fill=COLORS[i][0])
+		draw.rectangle((lx+1,ly+1,lx+bzs-1,ly+bzs-1), fill=COLORS[i][1])
+		lx += bzs + 3
+		vl = STATES[i]
+		tw,th = draw.textsize(vl, font=font)
+		draw.text((lx, ly+(bzs-th)/2), vl, font=font, fill=COLOR_BLACK)
+		lx += tw + 10
+
+	if settings:
+		draw.text((lx + 20, ly+(bzs-th)/2), str(settings), font=font, fill=COLOR_BLACK)
+
+	if caption:
+		draw.text((50, ih - 24), str(caption), font=font, fill=COLOR_BLACK)
+
+	# Grafico
+	for i in xrange(len(pids)):
+		sts = [UNLOAD for j in xrange(xmax+2)]
+		cores = [0 for j in xrange(xmax+2)]
+		p = 0
+		l = data[pids[i]]
+		blk = False
+		ldd = False
+		deadline = 0
+
+		for j in xrange(xmax+1):
+
+			cpu = False
+			core = -1
+			while p < len(l) and l[p][0] <= j:
+				ev = l[p][1]
+				if ev == BLOCK: blk = True
+				elif ev == DEADLINE: deadline = j
+				elif ev == UNBLOCK: blk = False
+				elif ev == LOAD: ldd = True
+				elif ev == EXIT: ldd = False
+				elif ev == CPU:
+					cpu = True
+					core = l[p][2]
+				p += 1
+			if not ldd and pids[i] != -1: st = UNLOAD
+			elif cpu and blk: st = RUNNINGBLOCKED
+			elif cpu and not blk: st = RUNNING
+			elif not cpu and blk: st = BLOCKED
+			else: st = READY
+			sts[j] = st
+			cores[j] = core
+
+		ly = gy - i*ystp - ystp/2
+		uy = ly-ystp/3
+		by = ly+ystp/3
+		loadedj = -1;
+		unloadedx = -1
+		for j in xrange(xmax):
+			x = gx + j*gw / xmax
+			nx = gx + (j+1)*gw / xmax
+			st = sts[j]
+			extend = (j>0) and (sts[j-1] == sts[j])
+			if st != UNLOAD or True:
+
+				if st == RUNNINGBLOCKED:
+					extend = (j>0) and (sts[j-1] == BLOCKED or sts[j-1] == sts[j])
+					draw.rectangle((x,uy-1,nx-1,ly), fill=COLORS[BLOCKED][0])
+					draw.rectangle((x+1-(2 if extend else 0),uy,nx-2,ly-1), fill=COLORS[BLOCKED][1])
+					extend = (j>0) and (sts[j-1] == RUNNING or sts[j-1] == sts[j])
+					draw.rectangle((x,ly+1,nx-1,by+1), fill=COLORS[RUNNING][0])
+					draw.rectangle((x+1-(2 if extend else 0),ly+2,nx-2,by), fill=COLORS[RUNNING][1])
+
+					#l TIENE LA TUPLA (CICLO, , CORE)
+					#ACA HAY QUE CHEQUEAR SI ESTA TUPLA ES LA PRIMERA CON CICLO C Y EL CICLO (C-1) NO ESTA EN LA LISTA
+					#if pids[i] >= 0:
+					#	draw.text((x+1, by+1), str(cores[j]), font=font, fill=COLOR_BLACK)
+					if unloadedx == -1:
+						unloadedx = x
+						loadedj = cores[j];
+					elif loadedj != cores[j]:
+						dist = (x-unloadedx)/2
+						draw.text((unloadedx + dist -2, by-16), str(loadedj), font=font, fill=COLOR_BLACK)
+						unloadedx = x
+						loadedj = cores[j];
+				elif st == RUNNING:
+					draw.rectangle((x,uy-1,nx,by+1), fill=COLORS[st][0])
+					draw.rectangle((x+1-(2 if extend else 0),uy,nx-2,by), fill=COLORS[st][1])
+					if unloadedx == -1:
+						unloadedx = x
+						loadedj = cores[j];
+					elif loadedj != cores[j]:
+						if pids[i] >= 0:
+							dist = (x-unloadedx)/2
+							draw.text((unloadedx + dist -2, by-16), str(loadedj), font=font, fill=COLOR_BLACK)
+							unloadedx = x
+							loadedj = cores[j];
+
+					#l TIENE LA TUPLA (CICLO, , CORE)
+						#ACA HAY QUE CHEQUEAR SI ESTA TUPLA ES LA PRIMERA CON CICLO C Y EL CICLO (C-1) NO ESTA EN LA LISTA
+						#if pids[i] >= 0:
+						#	draw.text((x+5, by-16), str(cores[j]), font=font, fill=COLOR_BLACK)
+				else:
+					draw.rectangle((x,uy-1,nx,by+1), fill=COLORS[st][0])
+					draw.rectangle((x+1-(2 if extend else 0),uy,nx-2,by), fill=COLORS[st][1])
+					if unloadedx <> -1:
+						if pids[i] >= 0:
+							dist = (x-unloadedx)/2
+							draw.text((unloadedx + dist -2, by-16), str(loadedj), font=font, fill=COLOR_BLACK)
+							unloadedx = -1
+
+				if st == RUNNING and j>0 and sts[j-1] == RUNNINGBLOCKED:
+					draw.rectangle((x+1-2,ly+2,nx-2,by), fill=COLORS[st][1])
+				if st == BLOCKED and j>0 and sts[j-1] == RUNNINGBLOCKED:
+					draw.rectangle((x+1-2,uy,nx-2,ly-1), fill=COLORS[st][1])
+
+				if deadline > 0 and j == deadline:
+					#Linea de DEADLINE
+					draw.line((nx-1,uy-1,nx-1,by+1), fill='#790000',width=6)
+
+
+
+
+	if isinstance(fout, str):
+		dr = os.path.dirname(fout)
+		if dr != "" and not os.path.isdir(dr):
+			os.makedirs(dr, 0755)
+
+	img.save(fout, "PNG")
+	#img.resize(((png_box+1)*n-1, png_box), Image.ANTIALIAS).save(pngfn, "PNG")
+
+
+def main(argv):
+	if '-c' in argv or '--caption' in argv:
+		hit = '-c' if '-c' in argv else '--caption'
+		pos = argv.index(hit)
+		argv.pop(pos)
+		caption = argv.pop(pos)
+	else:
+		caption = None
+
+	if len(argv) <= 1:
+		fin = sys.stdin
+		fout = sys.stdout
+	else:
+		fin = open(argv[1], 'r')
+		fout = argv[1]+'.png'
+
+	settings, data, cores = parseData(fin)
+	#print data
+	gantt = dataGantt(data, cores)
+	#for x in gantt: print gantt[x]
+	drawGantt(gantt, fout, settings=settings, caption=caption)
+
+if __name__ == "__main__":
+	main(sys.argv)

+ 2 - 0
lote.tsk

@@ -0,0 +1,2 @@
+TaskCPU 8
+TaskAlterno 2 5 6 

+ 224 - 0
main.cpp

@@ -0,0 +1,224 @@
+#include <vector>
+#include <queue>
+#include <cstdlib>
+#include <cstring>
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include "simu.h"
+#include "basetask.h"
+#include "basesched.h"
+#include "tasks.h"
+
+#include "sched_fcfs.h"
+#include "sched_rr.h"
+#include "sched_sjf.h"
+#include "sched_rsjf.h"
+#include "sched_mfq.h"
+
+using namespace std;
+
+ostream& operator<<(ostream &os, const Settings &s)
+{
+	os << "tasks_file:     " << s.tasks_file << endl
+	   << "num_cores:      " << s.num_cores << endl
+	   << "switch_cost:    " << s.switch_cost << endl
+       << "migrate_cost:   " << s.migrate_cost << endl
+	   << "sched_class:    " << s.sched_class << endl
+	   << "sched_args:     ";
+
+	for(vector<int>::const_iterator it = s.sched_args.begin();
+	    it != s.sched_args.end(); ++it)  os << *it << " ";
+	os << "(" << s.sched_args.size() << " ints)" << endl;
+
+	os << "verbose:        " << (s.verbose? "yes" : "no") << endl
+	   << "output_log:     " << s.output_log << endl;
+
+	return os;
+}
+
+string one_line_summary(const Settings &s)
+{
+	ostringstream os;
+	os << s.tasks_file << " " << s.num_cores << " " << s.switch_cost << " " << s.migrate_cost << " " << s.sched_class;
+	vector<int>::const_iterator it = s.sched_args.begin();
+	++it; //Saco el primer parametro que es un agregado para que muestre los cores.
+	while(it != s.sched_args.end()) os << " " << *it++;
+	return os.str();
+}
+
+
+const char *USAGE =
+" [-h] [-v] [-o output] tasks_file num_cores switch_cost migrate_cost sched_class args\n"
+"\n"
+"         tasks_file    define el lote de tareas\n"
+"         num_cores     define la cantidad de cores\n"
+"         switch_cost   en ticks completos por c/cambio de contexto\n"
+"         migrate_cost  en ticks completos por c/cambio de cpu\n"
+"         sched_class   nombre de la subclase de SchedBase deseada\n"
+"         args          argumentos enteros para pasarle al scheduler\n"
+"                       (ver detalles en constructor de sched_class)\n"
+"\n"
+"         -v    mayor nivel de verborragia\n"
+"         -o    nombre base para archivos generados\n"
+"         -h    mostrar este texto de ayuda y salir\n"
+"\n"
+"ejs:  simusched lote.tsk 1 10 2 SchedFCFS\n"
+"         donde 1 es la cantidad de núcleos\n"
+"         donde 10 es el costo de cambio de contexto\n"
+"         donde 2 es el costo de cambio de cpu\n"
+"         (el algoritmo FCFS no recibe argumentos)\n"
+"\n"
+"      simusched -v -o probando lote15.tsk 1 2 3 SchedRR 8\n"
+"         donde 1 es la cantidad de núcleos\n"
+"         donde 2 es el costo de cambio de contexto\n"
+"         donde 3 es el costo de cambio de cpu\n"
+"         y 8 es el quantum para el algoritmo RR\n"
+"\n"
+"      simusched foo.tsk 1 1 2 SchedFCFS | python graphsched.py | png_viewer\n"
+"      simusched foo.tsk 2 1 2 SchedFCFS | python graphsched.py > foo.png\n"
+"         para graficar (ver script .py para más detalles)\n"
+;
+
+
+bool file_readable(const string pathname)
+{
+	// Feucho pero bien portable:
+	ifstream tf(pathname.c_str());
+	if(!tf) return false;
+	tf.close();
+	return true;
+}
+
+
+int cmdline_parse(int argc, char* argv[], Settings &s)
+{
+	string prog_name(argv[0]);
+	int i = 1;  // #args seen
+
+	/* Opciones y flags */
+
+	s.verbose = false;
+	s.output_log = "-";
+
+	while(i < argc && argv[i][0] == '-') {
+		string optn(argv[i] + 1);
+		if(optn == "h") {
+			cerr << "uso: " << prog_name << USAGE << endl;
+			return 1;
+		} else if(optn == "v") {
+			s.verbose = true;
+		} else if(optn == "o") {
+			if(++i < argc && argv[i][0] != '-') {
+				s.output_log = argv[i];
+			} else {
+				cerr << "error: uso ilegal de -o" << endl;
+				cerr << "uso: " << prog_name << USAGE << endl;
+				return 2;
+			}
+		}
+		++i;
+	}
+
+	/* Argumentos posicionales */
+
+	if(argc - i < 3) {
+		cerr << "error: argumentos insuficientes" << endl;
+		cerr << "uso: " << prog_name << USAGE << endl;
+		return 3;
+	}
+
+	s.tasks_file = argv[i++];
+	if(!file_readable(s.tasks_file)) {
+		cerr << "error: no se pudo leer: " << s.tasks_file << endl;
+		return 4;
+	}
+
+	char *cptr;
+	s.num_cores = static_cast<unsigned int>(strtol(argv[i++], &cptr, 10));
+	if(*cptr != '\0') {
+		cerr << "error: no es un natural: " << argv[i-1] << endl;
+		return 5;
+	}
+
+	char *eptr;
+	s.switch_cost = static_cast<unsigned int>(strtol(argv[i++], &eptr, 10));
+	if(*eptr != '\0') {
+		cerr << "error: no es un natural: " << argv[i-1] << endl;
+		return 6;
+	}
+
+	s.migrate_cost = static_cast<unsigned int>(strtol(argv[i++], &eptr, 10));
+	if(*eptr != '\0') {
+		cerr << "error: no es un natural: " << argv[i-1] << endl;
+		return 7;
+	}
+
+	s.sched_class = argv[i++];
+	if(s.sched_class[0] != 'S') { // TODO: mejor error checking
+		cerr << "error: scheduler desconocido: " << s.sched_class << endl;
+		return 8;
+	}
+
+	s.sched_args.clear();
+	//Agrego la cantidad de cores como primer parametros de los argumentos.
+	s.sched_args.push_back(s.num_cores);
+	while(i < argc) {
+		int argint = static_cast<int>(strtol(argv[i++], &eptr, 10));
+		if(*eptr != '\0') {
+			cerr << "error: no es un entero: " << argv[i-1] << endl;
+			return 9;
+		} else s.sched_args.push_back(argint);
+	}
+
+	return 0;
+}
+
+SchedBase* sched_create(const char* sched, vector<int> argn) {
+	#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); }
+	/* Agregue aquí los schedulers nuevos que cree agregando una línea con:
+	 *   _sched_create(SchedX, n)
+	 * donde "SchedX" es la nueva clase implementada y n es la cantidad de
+	 * parámetros que recibe su scheduler como un vector de enteros (vector<int>)
+	  o ponga -1 para una cantidad de parámetros arbitraria. */
+	_sched_create(SchedFCFS, -1)
+	_sched_create(SchedRR, -1)
+	_sched_create(SchedSJF, -1)
+	_sched_create(SchedRSJF, -1)
+	_sched_create(SchedMFQ, -1)
+	return NULL;
+}
+
+int main(int argc, char* argv[]) {
+
+	Settings settings;
+	int rc = cmdline_parse(argc, argv, settings);
+	if(rc != 0) return rc;
+
+	//Obtengo el scheduler a usar.
+	SchedBase *scheduler = sched_create(settings.sched_class.c_str(), settings.sched_args);
+	if(!scheduler) {
+		cerr << "error: scheduler desconocido: " << settings.sched_class;
+		for(int j=0; j<(int)settings.sched_args.size(); j++) cerr << (j?',':'(') << settings.sched_args[j];
+		if (!settings.sched_args.size()) cerr << "(";
+		cerr << ")" << endl;
+		return 3;
+	}
+
+	if (settings.verbose) {
+		cerr << endl << settings;
+	}
+	cout << "# SETTINGS " << argv[0] << " " << one_line_summary(settings) << endl;
+
+	//Registro los tipos de tareas.
+	tasks_init();
+	//Cargo las tareas definidas por el usuario.
+	vector<ptsk> tasks = tasks_load(settings.tasks_file.c_str());
+
+	simulate(*scheduler, tasks, settings);
+
+	delete scheduler;
+
+	return rc;
+
+}

+ 37 - 0
sched_fcfs.cpp

@@ -0,0 +1,37 @@
+#include "sched_fcfs.h"
+
+using namespace std;
+
+SchedFCFS::SchedFCFS(vector<int> argn) {
+	// FCFS recibe la cantidad de cores.
+}
+
+SchedFCFS::~SchedFCFS() {
+}
+
+void SchedFCFS::load(int pid) {
+	q.push(pid); // llegó una tarea nueva
+}
+
+void SchedFCFS::unblock(int pid) {
+	// Uy! unblock!... bueno, ya seguir'a en el próximo tick
+}
+
+int SchedFCFS::tick(int cpu, const enum Motivo m) {
+	if (m == EXIT) {
+		// Si el pid actual terminó, sigue el próximo.
+		if (q.empty()) return IDLE_TASK;
+		else {
+			int sig = q.front(); q.pop();
+			return sig;
+		}
+	} else {
+		// Siempre sigue el pid actual mientras no termine.
+		if (current_pid(cpu) == IDLE_TASK && !q.empty()) {
+			int sig = q.front(); q.pop();
+			return sig;
+		} else {
+			return current_pid(cpu);
+		}
+	}
+}

+ 20 - 0
sched_fcfs.h

@@ -0,0 +1,20 @@
+#ifndef __SCHED_FCFS__
+#define __SCHED_FCFS__
+
+#include <vector>
+#include <queue>
+#include "basesched.h"
+
+class SchedFCFS : public SchedBase {
+	public:
+		SchedFCFS(std::vector<int> argn);
+        ~SchedFCFS();
+		virtual void load(int pid);
+		virtual void unblock(int pid);
+		virtual int tick(int cpu, const enum Motivo m);
+
+	private:
+		std::queue<int> q;
+};
+
+#endif

+ 28 - 0
sched_mfq.cpp

@@ -0,0 +1,28 @@
+#include <vector>
+#include <queue>
+#include "sched_mfq.h"
+#include "basesched.h"
+
+using namespace std;
+
+SchedMFQ::SchedMFQ(vector<int> argn) {
+	// MFQ recibe los quantums por parámetro
+/* llenar */
+}
+
+SchedMFQ::~SchedMFQ() {
+/* llenar */
+}
+
+void SchedMFQ::load(int pid) {
+/* llenar */
+}
+
+void SchedMFQ::unblock(int pid) {
+/* llenar */
+}
+
+int SchedMFQ::tick(int core, const enum Motivo m) {
+/* llenar */
+	return 0;
+}

+ 22 - 0
sched_mfq.h

@@ -0,0 +1,22 @@
+#ifndef __SCHED_MFQ__
+#define __SCHED_MFQ__
+
+#include <vector>
+#include <queue>
+#include "basesched.h"
+
+using namespace std;
+class SchedMFQ : public SchedBase {
+	public:
+		SchedMFQ(std::vector<int> argn);
+        ~SchedMFQ();
+		virtual void initialize() {};
+		virtual void load(int pid);
+		virtual void unblock(int pid);
+		virtual int tick(int n, const enum Motivo m);
+	
+	private:
+/* llenar */
+};
+
+#endif

+ 29 - 0
sched_rr.cpp

@@ -0,0 +1,29 @@
+#include <vector>
+#include <queue>
+#include "sched_rr.h"
+#include "basesched.h"
+#include <iostream>
+
+using namespace std;
+
+SchedRR::SchedRR(vector<int> argn) {
+	// Round robin recibe la cantidad de cores y sus cpu_quantum por parámetro
+}
+
+SchedRR::~SchedRR() {
+/* completar */
+}
+
+
+void SchedRR::load(int pid) {
+/* completar */
+}
+
+void SchedRR::unblock(int pid) {
+/* completar */
+}
+
+int SchedRR::tick(int cpu, const enum Motivo m) {
+/* completar */
+	return 0;
+}

+ 23 - 0
sched_rr.h

@@ -0,0 +1,23 @@
+#ifndef __SCHED_RR__
+#define __SCHED_RR__
+
+#include <vector>
+#include <queue>
+#include <algorithm>
+#include "basesched.h"
+
+using namespace std;
+
+class SchedRR : public SchedBase {
+	public:
+		SchedRR(std::vector<int> argn);
+        ~SchedRR();
+		virtual void initialize() {};
+		virtual void load(int pid);
+		virtual void unblock(int pid);
+		virtual int tick(int cpu, const enum Motivo m);	
+	private:
+/* llenar */
+};
+
+#endif

+ 25 - 0
sched_rsjf.cpp

@@ -0,0 +1,25 @@
+#include "sched_rsjf.h"
+
+using namespace std;
+
+SchedRSJF::SchedRSJF(vector<int> argn) {
+        // Recibe la cantidad de cores y sus cpu_quantum por parámetro
+/* llenar */
+}
+
+SchedRSJF::~SchedRSJF() {
+/* llenar */
+}
+
+void SchedRSJF::load(int pid) {
+/* llenar */
+}
+
+void SchedRSJF::unblock(int pid) {
+/* llenar */
+}
+
+int SchedRSJF::tick(int core, const enum Motivo m) {
+/* llenar */
+	return 0;
+}

+ 24 - 0
sched_rsjf.h

@@ -0,0 +1,24 @@
+#ifndef __SCHED_RSJF__
+#define __SCHED_RSJF__
+
+#include <vector>
+#include <queue>
+#include <algorithm>
+#include "basesched.h"
+
+using namespace std;
+
+class SchedRSJF : public SchedBase {
+	public:
+		SchedRSJF(std::vector<int> argn);
+        ~SchedRSJF();
+		virtual void initialize() {};
+		virtual void load(int pid);
+		virtual void unblock(int pid);
+		virtual int tick(int cpu, const enum Motivo m);	
+	private:
+/* llenar */
+	
+};
+
+#endif

+ 28 - 0
sched_sjf.cpp

@@ -0,0 +1,28 @@
+#include <vector>
+#include <queue>
+#include <iostream>
+#include "sched_sjf.h"
+
+using namespace std;
+
+SchedSJF::SchedSJF(vector<int> argn) {
+        // Recibe la cantidad de cores 
+/* llenar */
+}
+
+SchedSJF::~SchedSJF() {
+/* llenar */
+}
+
+void SchedSJF::load(int pid) {
+/* llenar */
+}
+
+void SchedSJF::unblock(int pid) {
+/* llenar */
+}
+
+int SchedSJF::tick(int cpu, const enum Motivo m) {
+/* llenar */
+	return 0;
+}

+ 23 - 0
sched_sjf.h

@@ -0,0 +1,23 @@
+#ifndef __SCHED_SJF__
+#define __SCHED_SJF__
+
+#include <vector>
+#include <queue>
+#include <algorithm>
+#include "basesched.h"
+
+using namespace std;
+
+class SchedSJF : public SchedBase {
+	public:
+		SchedSJF(std::vector<int> argn);
+        ~SchedSJF();
+		virtual void initialize() {};
+		virtual void load(int pid);
+		virtual void unblock(int pid);
+		virtual int tick(int cpu, const enum Motivo m);	
+	private:
+/* llenar */
+};
+
+#endif

+ 288 - 0
simu.cpp

@@ -0,0 +1,288 @@
+#include <vector>
+#include <pthread.h>
+#include <errno.h>
+#include <cstdio>
+#include <cstdlib>
+#include <iostream>
+#include <queue>
+#include "simu.h"
+
+#include "basetask.h"
+#include "basesched.h"
+
+using namespace std;
+
+//#define DBG_THREAD
+
+#ifdef DBG_THREAD
+#define _D(X) X
+#else
+#define _D(X)
+#endif
+
+#define forn(i,n) for(int i = 0; i < (int)(n); ++i)
+#define DBG(X) _D(cerr << #X << " = " << X << endl;)
+
+typedef struct cpu_ctx {
+    int pid;
+    int remaining;
+} cpu_ctx_t;
+
+/* "Globales" */
+// static int cur_pid;
+//Habria que modificar el nombre de cur_pid
+//lo mantuve para que sea mas facil modificar
+//codigo y mirar que hacia antes
+static vector<cpu_ctx_t> contexts;
+static unsigned int cur_time;
+static pthread_mutex_t m_sched;
+
+enum status_t {ST_EXIT, ST_IO, ST_CPU};
+
+struct task_data {
+	pthread_t tid;
+	int pid, running;
+	status_t blk;
+	int blkms;
+	TaskBase* tsk;
+	vector<int>* prms;
+	pthread_mutex_t mutex;
+    int lastcpu;
+};
+static task_data* tsks;
+
+void* task_thread(task_data* tsk) {
+	pthread_mutex_lock(&tsk->mutex);
+	//fprintf(stderr, "Thread %d\n", tsk->pid);
+	_D(cerr << "tsk->tsk( " << tsk->pid << ", *tsk->prms)" << endl;)
+	tsk->tsk(tsk->pid, *tsk->prms); // Run!
+	//
+	tsk->blk = ST_EXIT;
+	_D(cerr << "TSK unlock(sched) exit" << endl;) pthread_mutex_unlock(&m_sched);
+	return NULL;
+}
+
+
+/* Funciones llamadas por el scheduler */
+int current_pid(int cpu) { return contexts[cpu].pid; }
+int current_remaining(int cpu) { return contexts[cpu].remaining; }
+unsigned int current_time(void) { return cur_time; }
+
+/* Funciones llamadas por las tareas */
+static void uso_X(task_data* tsk, enum status_t tp, unsigned int ms) {
+	if (ms == 0) return;
+	tsk->blk = tp;
+	tsk->blkms = ms;
+	_D(cerr << "TSK unlock(sched)" << endl;) pthread_mutex_unlock(&m_sched);
+	pthread_mutex_lock(&tsk->mutex); _D(cerr << "TSK lock(mutex["<<tsk-tsks<<"])" << endl;)
+}
+
+//Se agrega pid para poder ver obtener
+//los datos en tsks
+void uso_CPU(int pid, unsigned int ms) {
+	uso_X(&(tsks[pid]), ST_CPU, ms);
+}
+
+void uso_IO(int pid, unsigned int ms) {
+	uso_X(&(tsks[pid]), ST_IO, ms);
+}
+
+
+void simulate(SchedBase& sch, std::vector<ptsk>& lote, const Settings& settings) {
+	int n = lote.size();
+
+	cout.flush();
+	if (settings.output_log != "-") {
+		/* Oh yeah! */
+		freopen(settings.output_log.c_str(), "wt", stdout);
+	}
+
+	tsks = (task_data*)malloc(sizeof(task_data)*n);
+
+	if (!tsks) { perror("malloc(task_data)"); return; }
+	forn(i, n) {
+		tsks[i].pid = i;
+		pthread_mutex_init(&(tsks[i].mutex), NULL);
+		pthread_mutex_lock(&(tsks[i].mutex));
+		tsks[i].tsk = lote[i].tsk;
+		tsks[i].prms = &(lote[i].prms);
+		tsks[i].running = 0;
+		tsks[i].blk = ST_CPU;
+		tsks[i].blkms = 0;
+        tsks[i].lastcpu = -1;
+		if (pthread_create(&(tsks[i].tid), NULL, (void*(*)(void*))task_thread, (void*)(&(tsks[i]))) < 0) {
+			perror("Lanzando la tarea (no use muchas tareas, < 500)"); return;
+		}
+	}
+	pthread_mutex_init(&m_sched, NULL);
+	pthread_mutex_lock(&m_sched);
+	int finished = 0;
+
+	//Inicializa los cpus
+    contexts = vector<cpu_ctx_t>(settings.num_cores);
+    for (int i = 0; i <settings.num_cores; i++)	{
+        contexts[i].pid = IDLE_TASK;
+        contexts[i].remaining = 0;
+    }
+	cur_time = 0;
+
+	priority_queue<pair<int, int> > load;
+	forn(i, n) load.push(make_pair(-lote[i].start, -i));
+
+  vector<pair<unsigned int, int> > dlote(0);
+  forn(i, n){
+    if(lote[i].end > 0)
+      dlote.push_back(make_pair(lote[i].end, i));
+  }
+
+	priority_queue<pair<int, int> > unblock;
+
+	int context_remain = 0; /* Remaining context_switch ticks */
+
+
+	while (finished < n || context_remain) {
+		if (settings.verbose) {
+			//cerr << "--- sched, tm=" << cur_time << " pid=" << cur_pid;
+			cerr << "--- sched, tm=" << cur_time << endl;
+			for(int i = 0; i < settings.num_cores; i++) {
+				int pid=contexts[i].pid;
+				cerr << "cpu " << i << " pid = " << pid << " rem " << contexts[i].remaining;
+				if (pid != IDLE_TASK) { cerr << " [" << pid << " ST:"<< tsks[pid].blk << " ms:" << tsks[pid].blkms << "]"; }
+				cerr << endl;
+			}
+            cerr << "--------------" << cur_time << endl;
+		}
+
+		// Load de las tareas
+		while (!load.empty() && load.top().first >= -(int)cur_time) {
+			int pid = -load.top().second;
+      int deadline = lote[-load.top().second].end;
+      load.pop();
+			tsks[pid].running = 1;
+			sch.load(pid,deadline);
+			cout << "LOAD " << cur_time << " " << pid << endl;
+		}
+
+		vector<int> to_unblock;
+		while (!unblock.empty() && unblock.top().first >= -(int)cur_time) {
+			int pid = -unblock.top().second; unblock.pop();
+			_D(cerr << "SCH unblock(" << pid << ")" << endl;)
+			sch.unblock(pid); // pid
+			to_unblock.push_back(pid);
+            int unblocked = 0;
+			for(int i = 0; i < settings.num_cores && !unblocked; i++) {
+                int it = contexts[i].pid;
+				if (it == pid) {
+					tsks[pid].blkms = -2;
+                    unblocked = true;
+				}
+            }
+            if (!unblocked) {
+				tsks[pid].blk = ST_CPU;
+				tsks[pid].blkms = 0;
+			}
+		}
+		//Itera por cada cpu
+		for(int cpu= 0; cpu < settings.num_cores; cpu++){
+			int cpu_pid= contexts[cpu].pid;
+			int cpu_context_remain = contexts[cpu].remaining;
+			if (!cpu_context_remain) {
+				int npid;
+				if (cpu_pid == IDLE_TASK) {
+					npid = sch.tick(cpu, TICK);
+					_D(cerr << "SCH tick( " << cpu << " ,TICK) -> " << npid << endl;)
+				} else {
+                    if (tsks[cpu_pid].blk == ST_CPU && !tsks[cpu_pid].blkms){
+                        _D(cerr << "SCH unlock(" << cpu_pid << ") tick" << endl;) pthread_mutex_unlock(&(tsks[cpu_pid].mutex));
+                        pthread_mutex_lock(&m_sched); _D(cerr << "SCH lock(sched)" << endl;)
+                    }
+                    switch (tsks[cpu_pid].blk) {
+                        case ST_EXIT:
+                            finished++;
+                            npid = sch.tick(cpu, EXIT);
+                            cout << "EXIT " << cur_time << " " << cpu_pid << " " << cpu << endl;
+                            _D(cerr << "SCH tick( " << cpu << " ,EXIT) -> " << npid << endl;)
+                            tsks[cpu_pid].running = 0;
+                            break;
+                        case ST_IO:
+                            if (tsks[cpu_pid].blkms >= 0) {
+                                unblock.push(make_pair(-(cur_time+tsks[cpu_pid].blkms), -cpu_pid));
+                                tsks[cpu_pid].blkms = -1;
+                            }
+                            if (tsks[cpu_pid].blkms == -2) {
+                                tsks[cpu_pid].blk = ST_CPU;
+                                tsks[cpu_pid].blkms = 0;
+                            }
+                            cout << "BLOCK " << cur_time << " " << cpu_pid << endl;
+                            npid = sch.tick(cpu, BLOCK);
+                            _D(cerr << "SCH tick( " << cpu << " ,BLOCK) -> " << npid << endl;)
+                            break;
+                        case ST_CPU:
+                            if (tsks[cpu_pid].blkms) {
+                                tsks[cpu_pid].blkms--;
+                            } else {
+                                cerr << "FATAL ERROR, this should not happend" << endl;
+                            }
+                            npid = sch.tick(cpu, TICK);
+                            _D(cerr << "SCH tick( " << cpu << " ,TICK) -> " << npid << endl;)
+                            break;
+                    }
+				}
+				if (npid == IDLE_TASK) {
+					// cerr << "SCH unlock(sched)" << endl;pthread_mutex_unlock(&m_sched);
+				} else {
+					if (npid < 0 || npid >= n) { cerr << "Error!, scheduler sent an invalid pid="<<npid<< endl; return; }
+					if (!tsks[npid].running) { cerr << "Error!, scheduler sent pid="<<npid << " but that process has exited." << endl; return; }
+					if (!tsks[npid].blk == ST_IO) { cerr << "Error!, scheduler sent pid="<<npid << " but that process is still blocked." << endl; return; }
+				}
+                if (cpu_pid != npid){
+                    if (npid != IDLE_TASK) {
+                        if (settings.switch_cost > 0) {
+                            contexts[cpu].remaining += settings.switch_cost;
+                        }
+                        if (cpu != tsks[npid].lastcpu && tsks[npid].lastcpu != -1) {
+                            contexts[cpu].remaining += settings.migrate_cost;
+                        }
+                        tsks[npid].lastcpu = cpu;
+                    }
+                }
+                cpu_pid = npid;
+
+			} else {
+                contexts[cpu].remaining--;
+			}
+
+            contexts[cpu].pid = cpu_pid;
+		}
+		//Hasta aca el codigo para cada CPU
+
+
+		/* Unblock tasks at the end of the tick */
+		for(int j=0; j<(int)to_unblock.size(); j++) cout << "UNBLOCK " << cur_time << " " << to_unblock[j] << endl;
+		context_remain= 0;
+
+		//Muestra que esta realizando cada cpu
+		//y calcula si hay contexto total restante (ver while)
+		for(int i= 0; i < contexts.size(); i++){
+			context_remain += contexts[i].remaining;
+			if (contexts[i].remaining /*context_remain*/) {
+				cout << "# CONTEXT CPU " << i << " " << cur_time << endl;
+			} else{
+				cout << "CPU "<< cur_time << " " << contexts[i].pid << " " << i <<endl;
+			}
+		}
+
+    //Muestra si se cumple el deadline de alguna tarea en este tick
+    forn(i, dlote.size()){
+      if(dlote[i].first == cur_time)
+        cout << "DEADLINE "<< cur_time << " " << dlote[i].second << endl;
+    }
+
+
+		cur_time++;
+	}
+	forn(i, n) {
+		pthread_join( tsks[i].tid, NULL);
+	}
+	free(tsks);
+}

+ 23 - 0
simu.h

@@ -0,0 +1,23 @@
+#ifndef __SIMU_H__
+#define __SIMU_H__
+
+#include "basetask.h"
+#include "basesched.h"
+#include <vector>
+#include <string>
+
+class Settings {
+	public:
+		std::string tasks_file;
+		unsigned int switch_cost;
+        unsigned int migrate_cost;
+		std::string sched_class;
+		std::vector<int> sched_args;
+		bool verbose;
+		std::string output_log;
+		unsigned int num_cores;
+};
+
+void simulate(SchedBase& sch, std::vector<ptsk>& lote, const Settings& settings);
+
+#endif

+ 15 - 0
simusched.cpp

@@ -0,0 +1,15 @@
+#include <vector>
+#include "basetask.h"
+#include "basesched.h"
+#include "tasks.h"
+
+using namespace std;
+
+
+int main(int argc, char* argv[]) {
+	tasks_init();
+	
+	vector<ptskvi> ts = tasks_load("lote.tsk");
+	
+	return 0;
+}

+ 41 - 0
tasks.cpp

@@ -0,0 +1,41 @@
+#include "tasks.h"
+#include "stdlib.h"
+
+using namespace std;
+
+void TaskCPU(int pid, vector<int> params) { // params: n
+	uso_CPU(pid, params[0] - 1); // Uso el CPU n milisegundos.
+}
+
+void TaskIO(int pid, vector<int> params) { // params: ms_pid, ms_io,
+	uso_CPU(pid, params[0]); // Uso el CPU ms_pid milisegundos.
+	uso_IO(pid, params[1]); // Uso IO ms_io milisegundos.
+}
+
+void TaskAlterno(int pid, vector<int> params) { // params: ms_pid, ms_io, ms_pid, ...
+	for(int i = 0; i < (int)params.size(); i++) {
+		if (i % 2 == 0) uso_CPU(pid, params[i] - 1);
+		else uso_IO(pid, params[i]);
+	}
+}
+
+void TaskConsola(int pid, vector<int> params) {
+	int calls = params[0];
+	int bmin = params[1];
+	int bmax = params[2];
+
+	for (int i = 0; i < calls; i++) {
+		uso_IO(pid, rand() %(bmax-bmin) + bmin);
+	}
+}
+
+
+void tasks_init(void) {
+	/* Todos los tipos de tareas se deben registrar acá para poder ser usadas.
+	 * El segundo parámetro indica la cantidad de parámetros que recibe la tarea
+	 * como un vector de enteros, o -1 para una cantidad de parámetros variable. */
+	register_task(TaskCPU, 1);
+	register_task(TaskIO, 2);
+	register_task(TaskConsola, 3);
+	register_task(TaskAlterno, -1);
+}

+ 7 - 0
tasks.h

@@ -0,0 +1,7 @@
+#ifndef __TASKS_H__
+#define __TASKS_H__
+
+#include "basetask.h"
+void tasks_init(void);
+
+#endif