timelines.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. #
  2. # Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
  3. # All rights reserved.
  4. # This component and the accompanying materials are made available
  5. # under the terms of the License "Eclipse Public License v1.0"
  6. # which accompanies this distribution, and is available
  7. # at the URL "http://www.eclipse.org/legal/epl-v10.html".
  8. #
  9. # Initial Contributors:
  10. # Nokia Corporation - initial contribution.
  11. #
  12. # Contributors:
  13. #
  14. # Description:
  15. #
  16. # Raptor log visualisation program. Takes a raptor log as standard input
  17. # and displays timelines that represent build progress and
  18. # how much actual parallelism there is in the build.
  19. # This program requires the pygame and PyOpenGL modules.
  20. from OpenGL.GL import *
  21. from OpenGL.GLU import *
  22. import pygame
  23. from pygame.locals import *
  24. import time
  25. class Timeline(object):
  26. """A bar representing a number of recipes which were executed in
  27. time sequence. There is no guarantee about what host but in
  28. theory they could have been executed on the same host."""
  29. globalmax = 2.0
  30. def __init__(self,ylevel):
  31. self.maxtime = 0.0
  32. self.recipes = []
  33. self.ylevel = ylevel
  34. def append(self, recipe):
  35. "" add this recipe to this timeline if it happens after the latest recipe already in the timeline ""
  36. if recipe.starttime + recipe.duration > self.maxtime:
  37. self.maxtime = recipe.starttime + recipe.duration
  38. if self.maxtime > Timeline.globalmax:
  39. Timeline.globalmax = self.maxtime
  40. else:
  41. pass
  42. self.recipes.append(recipe)
  43. def draw(self):
  44. glLoadIdentity()
  45. self.xscale = 4.0 / Timeline.globalmax
  46. glTranslatef(-2.0, -1.5, -6.0)
  47. count = 0
  48. for r in self.recipes:
  49. if count % 2 == 0:
  50. coloff=0.8
  51. else:
  52. coloff = 1.0
  53. count += 1
  54. r.draw(self.xscale, self.ylevel, coloff)
  55. class Recipe(object):
  56. """Represents a task completed in a raptor build.
  57. Drawn as a colour-coded bar with different
  58. colours for the various recipe types."""
  59. STAT_OK = 0
  60. colours = {
  61. 'compile': (0.5,0.5,1.0),
  62. 'compile2object': (0.5,0.5,1.0),
  63. 'win32compile2object': (0.5,0.5,1.0),
  64. 'tools2linkexe': (0.5,1.0,0.5),
  65. 'link': (0.5,1.0,0.5),
  66. 'linkandpostlink': (0.5,1.0,0.5),
  67. 'win32stageonelink': (0.5,1.0,0.5),
  68. 'tools2lib': (0.5,1.0,1.0),
  69. 'win32stagetwolink': (1.0,0.1,1.0),
  70. 'postlink': (1.0,0.5,1.0)
  71. }
  72. def __init__(self, starttime, duration, name, status):
  73. self.starttime = starttime
  74. self.duration = duration
  75. self.status = status
  76. self.colour = (1.0, 1.0, 1.0)
  77. if name in Recipe.colours:
  78. self.colour = Recipe.colours[name]
  79. else:
  80. self.colour = (1.0,1.0,1.0)
  81. self.name = name
  82. def draw(self, scale, ylevel, coloff):
  83. if self.status == Recipe.STAT_OK:
  84. glColor4f(self.colour[0]*coloff, self.colour[1]*coloff, self.colour[2]*coloff,0.2)
  85. else:
  86. glColor4f(1.0*coloff, 0.6*coloff, 0.6*coloff,0.2)
  87. x = self.starttime * scale
  88. y = ylevel
  89. x2 = x + self.duration * scale
  90. y2 = ylevel + 0.2
  91. glBegin(GL_QUADS)
  92. glVertex3f(x, y, 0)
  93. glVertex3f(x, y2, 0)
  94. glVertex3f(x2, y2, 0)
  95. glVertex3f(x2, y, 0)
  96. glEnd()
  97. def resize((width, height)):
  98. if height==0:
  99. height=1
  100. glViewport(0, 0, width, height)
  101. glMatrixMode(GL_PROJECTION)
  102. glLoadIdentity()
  103. gluPerspective(45, 1.0*width/height, 0.1, 100.0)
  104. glMatrixMode(GL_MODELVIEW)
  105. glLoadIdentity()
  106. def init():
  107. glShadeModel(GL_SMOOTH)
  108. glClearColor(0.0, 0.0, 0.0, 0.0)
  109. glClearDepth(1.0)
  110. glEnable(GL_DEPTH_TEST)
  111. glDepthFunc(GL_LEQUAL)
  112. glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)
  113. import sys
  114. import re
  115. def main():
  116. video_flags = OPENGL|DOUBLEBUF
  117. pygame.init()
  118. pygame.display.set_mode((800,600), video_flags)
  119. resize((800,600))
  120. init()
  121. frames = 0
  122. ticks = pygame.time.get_ticks()
  123. lines = 4
  124. timelines = []
  125. ylevel = 0.0
  126. for i in xrange(0,4):
  127. ylevel += 0.6
  128. timelines.append(Timeline(ylevel))
  129. f = sys.stdin
  130. recipe_re = re.compile(".*<recipe name='([^']+)'.*")
  131. time_re = re.compile(".*<time start='([0-9]+\.[0-9]+)' *elapsed='([0-9]+\.[0-9]+)'.*")
  132. status_re = re.compile(".*<status exit='([^']*)'.*")
  133. alternating = 0
  134. start_time = 0.0
  135. for l in f.xreadlines():
  136. l2 = l.rstrip("\n")
  137. rm = recipe_re.match(l2)
  138. if rm is not None:
  139. rname = rm.groups()[0]
  140. continue
  141. tm = time_re.match(l2)
  142. if tm is not None:
  143. s = float(tm.groups()[0])
  144. elapsed = float(tm.groups()[1])
  145. if start_time == 0.0:
  146. start_time = s
  147. s -= start_time
  148. continue
  149. sm = status_re.match(l2)
  150. if sm is None:
  151. continue
  152. if sm.groups()[0] == 'ok':
  153. status = 0
  154. else:
  155. status = int(sm.groups()[0])
  156. olddiff = 999999999.0
  157. tnum = 0
  158. for t in timelines:
  159. newdiff = s - t.maxtime
  160. if newdiff < 0.0:
  161. continue
  162. if olddiff > newdiff:
  163. dest_timeline = t
  164. olddiff = newdiff
  165. tnum += 1
  166. dest_timeline.append(Recipe(s, elapsed, rname, status))
  167. event = pygame.event.poll()
  168. if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
  169. break
  170. glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
  171. for t in timelines:
  172. t.draw()
  173. pygame.display.flip()
  174. frames = frames+1
  175. print "fps: %de" % ((frames*1000)/(pygame.time.get_ticks()-ticks))
  176. event = pygame.event.wait()
  177. if __name__ == '__main__': main()