| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392 |
- #!/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)
|