event_parser.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. #!/usr/bin/env python
  2. # coding: utf-8
  3. import sys, os
  4. import matplotlib
  5. matplotlib.use('Agg')
  6. from pylab import *
  7. from matplotlib.transforms import TransformedBbox
  8. class EventFactory(object):
  9. #CPU time pid cpu (si pid == -1 -> idle)
  10. cpu_event= lambda x: Event(x[0],EventFactory.Events.keys().index(x[0]),int(x[1]),int(x[2]),int(x[3]))
  11. #EVENT time pid
  12. other_event= lambda x: Event(x[0],EventFactory.Events.keys().index(x[0]),int(x[1]),int(x[2]),-1)
  13. #CONTEXT CPU cpu time (se pone pid == -2)
  14. context_switch_event= lambda x: Event(x[0] ,EventFactory.Events.keys().index(x[0]),int(x[3]),-2,int(x[2]))
  15. Events = {'LOAD': other_event,
  16. 'CPU':cpu_event,
  17. 'BLOCK': other_event,
  18. 'UNBLOCK': other_event,
  19. 'EXIT': other_event,
  20. 'CONTEXT':context_switch_event,
  21. 'WAITING':None,
  22. 'NOT_LOAD': None,
  23. 'CPU_BLOCK': None}
  24. @classmethod
  25. def get_event(cls, event_line):
  26. splited_event_line= event_line.split()
  27. if splited_event_line[0] in EventFactory.Events.keys():
  28. print splited_event_line
  29. return EventFactory.Events[splited_event_line[0]](splited_event_line)
  30. else:
  31. return None
  32. class Event(object):
  33. def __init__(self, event_type, event_code, time, pid, core):
  34. self.event_type= event_type
  35. self.event_code= event_code
  36. self.time= time
  37. self.pid= pid
  38. self.core= core
  39. def __str__(self):
  40. return 'Type: ' + self.event_type + ', Code: ' + str(self.event_code) + ', Time: ' + str(self.time) + ', Pid: ' + str(self.pid) + ', Core: ' + str(self.core)
  41. def parseInput(fin):
  42. ln = 0
  43. result = []
  44. cores = 0
  45. pids= 0
  46. settings = None
  47. cpus_timeline= dict()
  48. print fin
  49. for line in fin:
  50. ln += 1
  51. vls = line.split()
  52. if line and line[0] == '#':
  53. if line.startswith('# SETTINGS '):
  54. settings = line[11:].strip()
  55. continue
  56. else:
  57. line= line[2:].strip() # Queda --> 'CONTEXT CPU[cpu] time
  58. event= EventFactory.get_event(line)
  59. result.append(event)
  60. if event.event_type == 'CPU':
  61. if (cores <=event.core):
  62. cores = event.core+1
  63. if event.event_type == 'LOAD':
  64. if(pids <= event.pid):
  65. pids = event.pid +1
  66. return settings, result, cores, pids
  67. def dataGathering(data, cores, pids):
  68. core_resume= dict() # core: {processing_time: #, switching_time: #, idle_time: #}
  69. core_timeline= dict() # core: list(pids) NOTA: se supone que en cada tick hay un pid
  70. pid_resume= dict() # pid: {load_time: #, running_time: #, blocked: #, end_time: #}
  71. pids_timeline= dict() # pid: list((event_code, core))
  72. block_lapse= dict()
  73. for event in data:
  74. #core_time
  75. if event.core != -1:
  76. if event.core not in core_timeline: core_timeline[event.core]= []
  77. core_timeline[event.core].append(event.pid)
  78. #core_time
  79. if event.core != -1:
  80. if event.core not in core_resume: core_resume[event.core]= {'processing_time': 0, 'switching_time': 0, 'idle_time': 0}
  81. if event.event_type == 'CPU':
  82. if event.pid != -1: core_resume[event.core]['processing_time'] = core_resume[event.core]['processing_time'] + 1
  83. else: core_resume[event.core]['idle_time'] = core_resume[event.core]['idle_time'] + 1
  84. elif event.event_type == 'CONTEXT': core_resume[event.core]['switching_time'] = core_resume[event.core]['switching_time'] + 1
  85. if event.pid != -2 and event.pid != -1:
  86. #task_resume
  87. if event.pid not in pid_resume: pid_resume[event.pid]= {'running_time': 0, 'blocked': 0}
  88. if event.event_type == 'LOAD': pid_resume[event.pid]['load_time']= event.time
  89. if event.event_type == 'CPU': pid_resume[event.pid]['running_time']= pid_resume[event.pid]['running_time'] + 1
  90. if event.event_type == 'BLOCK':
  91. if event.pid not in block_lapse: block_lapse[event.pid]= -1
  92. if block_lapse[event.pid] == -1:
  93. block_lapse[event.pid]= event.time
  94. if event.event_type == 'UNBLOCK':
  95. pid_resume[event.pid]['blocked']= pid_resume[event.pid]['blocked'] + event.time - block_lapse[event.pid] + 1
  96. block_lapse[event.pid]= -1
  97. if event.event_type == 'EXIT': pid_resume[event.pid]['end_time']= event.time
  98. #task_timeline no hay interes en mostrar los context switchs
  99. if event.pid not in pids_timeline: pids_timeline[event.pid]= []
  100. if event.event_type == 'LOAD':
  101. #NOT LOADED
  102. for i in range(0, event.time):
  103. pids_timeline[event.pid].append((EventFactory.Events.keys().index('NOT_LOAD'),-1))
  104. elif event.event_type == 'CPU':
  105. prev_event_code, prev_event_core= pids_timeline[event.pid][-1]
  106. #POSIBLE BLOCK ANTES QUE CPU
  107. if len(pids_timeline[event.pid]) == event.time:
  108. prev_event_code, prev_event_core= pids_timeline[event.pid][-1]
  109. if (EventFactory.Events.keys().index('BLOCK') == prev_event_code or
  110. EventFactory.Events.keys().index('CPU_BLOCK') == prev_event_code):
  111. pid_resume[event.pid]['running_time']= pid_resume[event.pid]['running_time'] - 1
  112. pids_timeline[event.pid][-1]= (EventFactory.Events.keys().index('CPU_BLOCK'),event.core)
  113. continue
  114. #WAITING EVENT
  115. for i in range(len(pids_timeline[event.pid])+1, event.time):
  116. pids_timeline[event.pid].append((EventFactory.Events.keys().index('LOAD'),-1))
  117. elif event.event_type == 'BLOCK':
  118. #ESTA BLOQUEADO Y EJECUTANDO
  119. if len(pids_timeline[event.pid]) == event.time:
  120. prev_event_code, prev_event_core= pids_timeline[event.pid][-1]
  121. if (EventFactory.Events.keys().index('CPU') == prev_event_code or
  122. EventFactory.Events.keys().index('CPU_BLOCK') == prev_event_code):
  123. pids_timeline[event.pid][-1]= (EventFactory.Events.keys().index('CPU_BLOCK'),prev_event_core)
  124. continue
  125. elif event.event_type == 'UNBLOCK':
  126. #Agrego el gap que queda de todo el tiempo bloqueado
  127. block_code, block_dummy_core= pids_timeline[event.pid][-1]
  128. if block_code != EventFactory.Events.keys().index('CPU_BLOCK'):
  129. for i in range(len(pids_timeline[event.pid])+1, event.time+1):
  130. pids_timeline[event.pid].append((block_code,block_dummy_core))
  131. if event.event_type != 'UNBLOCK' and event.event_type != 'EXIT':
  132. pids_timeline[event.pid].append((event.event_code,event.core))
  133. return core_resume, core_timeline, pid_resume, pids_timeline
  134. def draw_cores_resume_bars(cores_resume, filename):
  135. ''' pre: cores_resume = { core: {processing_time: #, switching_time: #, idle_time: #}}'''
  136. ''' post: horizonal bar diagram in filenaname.png '''
  137. colors={'processing_time': 'green', 'switching_time': 'yellow', 'idle_time': 'red'}
  138. labels={'processing_time': 'Procesando', 'switching_time': 'Cambiando contexto', 'idle_time': 'Sin uso'}
  139. fig= figure(figsize=(11.8,8.3))
  140. bars_lenghts= []
  141. for core in cores_resume:
  142. bars_lenghts.append(sum(cores_resume[core].values()))
  143. values= sorted(zip(cores_resume[core].values(), cores_resume[core].keys()), reverse= True)
  144. base= 0
  145. for value in values:
  146. broken_barh([(base,value[0])], (core-0.4,0.8), color=colors[value[1]], edgecolor='black')
  147. base= base+value[0]
  148. title('Tiempo total por tipo de tarea por core')
  149. yticks(cores_resume.keys())
  150. xlabel('Tiempo total')
  151. ylabel('Core')
  152. xlim((0,max(bars_lenghts)+1))
  153. ylim((-1,len(cores_resume.keys())+1))
  154. tight_layout()
  155. legend()
  156. savefig(filename+'.png', dpi=300, format='png')
  157. return None
  158. def draw_cores_timeline_gannt(cores_timeline, filename):
  159. ''' pre: cores_timeline = {core: list(pid) } '''
  160. # Necesitaria tener la info algo asi como
  161. # core: {pid: ini_1,fin_1,ini_2,fin_2} (es decir por intervalos)
  162. # broken_barh necesita (inicio, longitud)
  163. colors={'pid':'#c0ffc0','switch':'#b7b7f7', 'idle':'#d0d0d0'}
  164. fig= figure(figsize=(11.8,8.3))
  165. ax = fig.add_subplot(111)
  166. title('Tareas en Core por tiempo')
  167. yticks(cores_timeline.keys())
  168. # ax.xaxis.set_major_locator(
  169. ax.xaxis.set_major_locator( IndexLocator(2,1) )
  170. #xticks(range(len(cores_timeline[0])),range(0,len(cores_timeline[0]),5))
  171. xlabel('Tiempo')
  172. ylabel('Core')
  173. ylim((-1,len(cores_timeline.keys())))
  174. ax.grid(True)
  175. for core in cores_timeline:
  176. pids_by_time= cores_timeline[core]
  177. intervals= dict()
  178. last_pid= -1
  179. for time in range(len(pids_by_time)):
  180. if last_pid != pids_by_time[time]:
  181. last_pid = pids_by_time[time]
  182. if last_pid not in intervals: intervals[last_pid]= []
  183. intervals[last_pid].append((time, 1))
  184. #intervals.push((last_pid,time,1))
  185. else:
  186. #pid, time, interval_size= intervals.pop()
  187. #intervals.push((pid, time, interval_size+1))
  188. time, interval_size= intervals[last_pid].pop()
  189. intervals[last_pid].append((time, interval_size+1))
  190. for pid in intervals:
  191. if pid >= 0:
  192. rect= ax.broken_barh(intervals[pid], (core-0.25, 0.5), facecolor=colors['pid'])
  193. for init, size in intervals[pid]:
  194. ax.text(init+(size/2.0),core, str(pid), ha="center", va="center", size=9, weight='bold')
  195. elif pid == -1:
  196. rect= ax.broken_barh(intervals[pid], (core-0.25, 0.5), facecolor=colors['idle'])
  197. elif pid == -2:
  198. rect= ax.broken_barh(intervals[pid], (core-0.25, 0.5), facecolor=colors['switch'])
  199. else:
  200. print 'ERROR!'
  201. tarea_dummy = Rectangle((0, 0), 1, 1, fc=colors['pid'])
  202. switch_dummy = Rectangle((0, 0), 1, 1, fc=colors['switch'])
  203. idle_dummy = Rectangle((0, 0), 1, 1, fc=colors['idle'])
  204. legend([tarea_dummy, switch_dummy, idle_dummy], ['Tarea','Cambio de contexto','Inactivo'])
  205. tight_layout()
  206. fig.autofmt_xdate()
  207. ax.legend()
  208. savefig(filename+'.png', dpi=300, format='png')
  209. def draw_tasks_resume_bars(pids_resume, filename):
  210. ''' pre: pid: {load_time: #, running_time: #, blocked: #, end_time: #}'''
  211. ''' post: horizonal bar diagram in filenaname.png '''
  212. colors={'running_time': '#c0ffc0', 'blocked': '#b7b7f7', 'waiting_time': '#d0d0d0'}
  213. labels={'running_time': 'En ejecucion', 'blocked': 'Bloqueado', 'waiting_time': 'Esperando'}
  214. fig= figure(figsize=(11.8,8.3))
  215. pids_resume.pop(-1,None)
  216. max_time= 0
  217. for pid in pids_resume:
  218. load_time= pids_resume[pid].pop('load_time',-1)
  219. end_time= pids_resume[pid].pop('end_time',-1)
  220. max_time= max([end_time-load_time,max_time])
  221. pids_resume[pid]['waiting_time']= end_time - load_time - pids_resume[pid]['running_time'] - pids_resume[pid]['blocked']
  222. values= sorted(zip(pids_resume[pid].values(), pids_resume[pid].keys()), reverse= True)
  223. base= 0
  224. for value in values:
  225. broken_barh([(base,value[0])], (pid-0.25, 0.5), facecolor=colors[value[1]])
  226. #if pid != 0:
  227. # barh(pid, base + value[0], align='center', color=colors[value[1]], edgecolor='black')
  228. #else:
  229. # barh(pid, base + value[0], align='center', color=colors[value[1]], edgecolor='black', label=labels[value[1]])
  230. base= base + value[0]
  231. running_dummy = Rectangle((0, 0), 1, 1, fc=colors['running_time'])
  232. blocked_dummy = Rectangle((0, 0), 1, 1, fc=colors['blocked'])
  233. waiting_dummy = Rectangle((0, 0), 1, 1, fc=colors['waiting_time'])
  234. legend([running_dummy, blocked_dummy, waiting_dummy],[labels['running_time'],labels['blocked'], labels['waiting_time']],loc='best', ncol=3)
  235. title('Tiempo total de la tarea divido en estados')
  236. yticks(pids_resume.keys())
  237. xlabel('Tiempo total')
  238. ylabel('Tarea')
  239. ylim((-1,len(pids_resume.keys())+1))
  240. xlim((0,max_time+2))
  241. tight_layout()
  242. #show()
  243. savefig(filename+'.png', dpi=300, format='png')
  244. return None
  245. def draw_pids_timeline_gannt(pids_timeline, filename):
  246. ''' pre: pids_timeline = { pid: list((event_code, core))}'''
  247. ''' post: horizonal bar diagram in filenaname.png '''
  248. # Necesitaria tener la info algo asi como
  249. # core: {pid: ini_1,fin_1,ini_2,fin_2} (es decir por intervalos)
  250. # broken_barh necesita (inicio, longitud)
  251. colors={'CPU':'#f7b7b7','BLOCK':'#b7b7f7', 'WAITING':'#e7ffe7', 'LOAD':'#e7ffe7', 'NOT_LOAD':'#d0d0d0', 'CPU_BLOCK':'#b7b7f7'}
  252. fig= figure(figsize=(11.8,8.3))
  253. ax = fig.add_subplot(111)
  254. title('Estado de las tareas por tiempo')
  255. yticks(pids_timeline.keys(), sorted(pids_timeline.keys(),reverse=True))
  256. # ax.xaxis.set_major_locator(
  257. ax.xaxis.set_major_locator( IndexLocator(5,1) )
  258. #xticks(range(len(cores_timeline[0])),range(0,len(cores_timeline[0]),5))
  259. xlabel('Tiempo')
  260. ylabel('Tarea')
  261. ax.grid(True)
  262. for pid in pids_timeline:
  263. pid_state_by_time= pids_timeline[pid]
  264. intervals= dict()
  265. last_state= (None,None)
  266. for time in range(len(pid_state_by_time)):
  267. if last_state != pid_state_by_time[time]:
  268. last_state = pid_state_by_time[time]
  269. if last_state not in intervals: intervals[last_state]= []
  270. intervals[last_state].append((time, 1))
  271. #intervals.push((last_pid,time,1))
  272. else:
  273. #pid, time, interval_size= intervals.pop()
  274. #intervals.push((pid, time, interval_size+1))
  275. time, interval_size= intervals[last_state].pop()
  276. intervals[last_state].append((time, interval_size+1))
  277. for event_code, core in intervals.keys():
  278. event_name= EventFactory.Events.keys()[event_code]
  279. rect= ax.broken_barh(intervals[(event_code, core)], ((len(pids_timeline)-pid-1)-0.25, 0.5), facecolor=colors[event_name])
  280. if core >= 0:
  281. for init, size in intervals[(event_code, core)]:
  282. ax.text(init+(size/2.0),(len(pids_timeline)-pid-1), str(core), ha="center", va="center", size=9, weight='bold')
  283. #else:
  284. #if event_code == -1:
  285. #elif event_code == -2:
  286. #rect= ax.broken_barh(intervals[(event_code, core)], (pid-0.25, 0.5), facecolor=colors['not_loaded'])
  287. #elif event_name == 'LOAD':
  288. #rect= ax.broken_barh(intervals[(event_code, core)], (pid-0.25, 0.5), facecolor=colors['load'])
  289. #elif event_name == 'BLOCK':
  290. #rect= ax.broken_barh(intervals[(event_code, core)], (pid-0.25, 0.5), facecolor=colors['blocked'])
  291. #else:
  292. # print 'ERROR!', event_code, core
  293. running_dummy = Rectangle((0, 0), 1, 1, fc=colors['CPU'])
  294. waiting_dummy = Rectangle((0, 0), 1, 1, fc=colors['WAITING'])
  295. not_loaded_dummy = Rectangle((0, 0), 1, 1, fc=colors['NOT_LOAD'])
  296. #load_dummy = Rectangle((0, 0), 1, 1, fc=colors['LOAD'])
  297. blocked_dummy = Rectangle((0, 0), 1, 1, fc=colors['BLOCK'])
  298. legend([not_loaded_dummy,running_dummy, waiting_dummy, blocked_dummy], ['No cargada','En ejecucion','Lista','Bloqueada'],loc='best', ncol=4)
  299. ylim((-1,len(pids_timeline.keys())+1))
  300. xlim((0,max([len(x) for x in pids_timeline.values()])+1))
  301. tight_layout()
  302. fig.autofmt_xdate()
  303. ax.legend()
  304. #show()
  305. savefig(filename+'.png', dpi=300, format='png')
  306. return None
  307. def main(argv):
  308. if '-c' in argv or '--caption' in argv:
  309. hit = '-c' if '-c' in argv else '--caption'
  310. pos = argv.index(hit)
  311. argv.pop(pos)
  312. caption = argv.pop(pos)
  313. else:
  314. caption = None
  315. if len(argv) <= 1:
  316. fin = sys.stdin
  317. fout_cores_resume= 'out_cores_resume'
  318. fout_cores_timeline= 'out_cores_timeline'
  319. fout_pids_resume= 'out_pids_resume'
  320. fout_pids_timeline= 'out_pids_timeline'
  321. else:
  322. fin = open(argv[1], 'r')
  323. preffix= argv[1]
  324. fout_cores_resume= preffix + '_cores_resume'
  325. fout_cores_timeline= preffix + '_cores_timeline'
  326. fout_pids_resume= preffix + '_pids_resume'
  327. fout_pids_timeline= preffix + '_pids_timeline'
  328. print 'parsing input'
  329. settings, data, cores, pids = parseInput(fin)
  330. print 'data gathering'
  331. cores_resume, cores_timeline, pids_resume, pids_timeline= dataGathering(data, cores, pids)
  332. #todo dump de los datos
  333. print 'drawing cores resumen'
  334. draw_cores_resume_bars(cores_resume, fout_cores_resume)
  335. print 'drawing cores timeline'
  336. draw_cores_timeline_gannt(cores_timeline, fout_cores_timeline)
  337. print 'drawing cores timeline'
  338. draw_tasks_resume_bars(pids_resume, fout_pids_resume)
  339. print 'drawing pids timeline'
  340. draw_pids_timeline_gannt(pids_timeline, fout_pids_timeline)
  341. if __name__ == "__main__":
  342. main(sys.argv)