~azzar1/unity/lp-1165097

« back to all changes in this revision

Viewing changes to tools/makebootchart.py

  • Committer: Gordon Allott
  • Date: 2009-12-16 13:25:32 UTC
  • mto: This revision was merged to the branch mainline in revision 45.
  • Revision ID: mail@gordallott.com-20091216132532-3zp0dlxqkqjnsmwf
performance logger support and boot chart generation script

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python
 
2
#
 
3
# Copyright (C) 2009 Canonical Ltd
 
4
#
 
5
# This program is free software: you can redistribute it and/or modify
 
6
# it under the terms of the GNU General Public License version 3 as
 
7
# published by the Free Software Foundation.
 
8
#
 
9
# This program is distributed in the hope that it will be useful,
 
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
# GNU General Public License for more details.
 
13
#
 
14
# You should have received a copy of the GNU General Public License
 
15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
16
#
 
17
# Authored by Gordon Allott <gord.allott@canonical.com>
 
18
#
 
19
#
 
20
import os, sys
 
21
import getopt
 
22
import cairo
 
23
import csv
 
24
import math
 
25
import random
 
26
from string import Template
 
27
from socket import gethostname 
 
28
from datetime import datetime 
 
29
import re
 
30
import subprocess
 
31
 
 
32
header = Template("""Unity bootchart for $hostname ($date)
 
33
uname: $uname
 
34
CPU: $cpu
 
35
GPU: $gpu
 
36
time: $total_time""")
 
37
 
 
38
def sort_by_domain (x, y):
 
39
  domain_x = x["name"].split("/")
 
40
  domain_y = y["name"].split("/")
 
41
  
 
42
  def recurse_domain (a, b, pos, xstart, ystart):
 
43
    
 
44
    if len(a) > len(b):
 
45
      #check to see if the last item of the shortest is the same
 
46
      if a[len(b)-1] == b[-1]:
 
47
        return -1
 
48
      
 
49
      #not in the same tree, 
 
50
      return int(ystart - xstart)
 
51
      
 
52
    if len(b) > len(a):
 
53
      if b[len(a)-1] == a[-1]:
 
54
        return -1
 
55
      
 
56
      return int(ystart - xstart)
 
57
    
 
58
    if pos + 1 > len(a):
 
59
      return -1
 
60
    if pos + 1 > len(b):
 
61
      return +1
 
62
    
 
63
    if (pos+2 > len(a) and pos+2 > len(b)):
 
64
      return int(ystart - xstart)
 
65
    
 
66
    if a[pos] == b[pos]:
 
67
      return recurse_domain(a, b, pos+1, xstart, ystart)
 
68
      
 
69
    if a[pos] < b[pos]:
 
70
      return -1
 
71
    
 
72
    if a[pos] > b[pos]:
 
73
      return +1
 
74
  
 
75
  return recurse_domain (domain_x, domain_y, 0, x['start'], y['start'])
 
76
    
 
77
    
 
78
def gatherinfo (filename):
 
79
  date =  datetime.fromtimestamp(os.path.getmtime(filename))
 
80
  
 
81
  cpufile = open ("/proc/cpuinfo")
 
82
  cpuinfo = cpufile.read (10024)
 
83
  cpure = re.search (r"^model name\s*: (.*$)", cpuinfo, re.MULTILINE)
 
84
  cpu = cpure.group(1)
 
85
  
 
86
  gpu_prog = subprocess.Popen("glxinfo", stdout=subprocess.PIPE)
 
87
  gpu_prog.wait () 
 
88
  gpuinfo = gpu_prog.stdout.read (10024)
 
89
  gpure = re.search (r"^OpenGL renderer string: (.*$)", gpuinfo, re.MULTILINE)
 
90
  gpu = gpure.group (1)
 
91
  
 
92
  return {"hostname":gethostname(),
 
93
          "date": date.strftime("%A, %d. %B %Y %I:%M%p"),
 
94
          "uname": " ".join (os.uname ()),
 
95
          "cpu": cpu,
 
96
          "gpu": gpu,
 
97
          "total_time": "undefined"
 
98
          }
 
99
 
 
100
width_multiplier = 1000
 
101
bar_height = 16
 
102
 
 
103
def draw_bg_graph (ctx, seconds, height):
 
104
  
 
105
  total_width = seconds * width_multiplier
 
106
  ctx.set_source_rgba (0.0, 0.0, 0.0, 0.25)
 
107
  
 
108
  ctx.move_to (0, 0)
 
109
  ctx.line_to (total_width, 0)
 
110
  ctx.stroke ()
 
111
  
 
112
  per_ten = 0
 
113
  for pos in xrange (0, int(total_width), int (0.01 * width_multiplier)):
 
114
    ctx.set_line_width (1)
 
115
    ctx.set_source_rgba (0.0, 0.0, 0.0, 0.10)
 
116
 
 
117
    if (not per_ten):
 
118
      ctx.set_line_width (2)
 
119
      ctx.set_source_rgba (0.0, 0.0, 0.0, 0.25)
 
120
      ctx.move_to (pos-6, -2)
 
121
      ctx.show_text (str (pos / float(width_multiplier)))
 
122
      ctx.stroke ()
 
123
 
 
124
    ctx.move_to (pos, 0)
 
125
    ctx.line_to (pos, height)
 
126
    ctx.stroke ()
 
127
    
 
128
    per_ten += 1
 
129
    per_ten %= 10
 
130
 
 
131
    
 
132
 
 
133
    
 
134
 
 
135
def build_graph (data, filename, info):
 
136
  
 
137
  padding_left = 6
 
138
  padding_right = 6
 
139
  padding_top = 6
 
140
  padding_bottom = 6
 
141
  
 
142
  total_size = 0.0
 
143
  for item in data:
 
144
    if item['end'] > total_size:
 
145
      total_size = item['end']
 
146
      
 
147
  width = total_size * width_multiplier + padding_left + padding_right
 
148
  height = len(data) * (bar_height+6) + 60 + padding_left + padding_right
 
149
  surface = cairo.SVGSurface(filename, width, height)
 
150
  
 
151
  ctx = cairo.Context (surface)
 
152
 
 
153
  #fill background
 
154
  ctx.set_source_rgb (1, 1, 1)
 
155
  ctx.rectangle (0, 0, width, height)
 
156
  ctx.fill ()
 
157
  
 
158
  #print header
 
159
  info['total_time'] = "%s secs" % total_size
 
160
  sheader = header.substitute(info)
 
161
  
 
162
  ctx.translate (padding_left, padding_right)
 
163
  ctx.set_source_rgb (0, 0, 0)
 
164
  for line in sheader.split("\n"):
 
165
    ctx.translate (0, 12)
 
166
    ctx.show_text (line)
 
167
    ctx.fill ()
 
168
  
 
169
  ctx.translate (0, 12)
 
170
  
 
171
  draw_bg_graph (ctx, total_size, len (data) * bar_height + 16)
 
172
  
 
173
  ctx.set_line_width (1)
 
174
  for item in data:
 
175
    x = item['start'] * width_multiplier
 
176
    x1 = (item['end'] - item['start']) * width_multiplier
 
177
    ctx.translate (x, 0)
 
178
    
 
179
    ctx.set_source_rgba (0.35, 0.65, 0.8, 0.5)
 
180
    ctx.rectangle (0, 0, x1, 16)
 
181
    ctx.fill ()
 
182
    
 
183
    ctx.set_source_rgba (0.35, 0.65, 0.8, 1.0)
 
184
    ctx.rectangle (0, 0, x1, 16)
 
185
    ctx.stroke ()
 
186
    
 
187
    ctx.translate (8, 10)
 
188
    ctx.set_source_rgb (0.0, 0.0, 0.0)
 
189
    ctx.show_text (item['name'])
 
190
    ctx.fill()
 
191
    
 
192
    ctx.translate (-x-8, 6)
 
193
    
 
194
 
 
195
  
 
196
  
 
197
def build_data_structure (input):
 
198
  reader = csv.reader(open(input))
 
199
  structure = []
 
200
  print "reading", input
 
201
  for row in reader:
 
202
    name = row[0]
 
203
    start = float(row[1])
 
204
    end = float(row[2])
 
205
    structure.append ({"name": name, "start": start, "end": end})
 
206
    
 
207
  return structure
 
208
    
 
209
 
 
210
def usage():
 
211
  print "use --input=filename.log and --output=filename.svg :)" 
 
212
 
 
213
def main():
 
214
 
 
215
  try:
 
216
      opts, args = getopt.getopt(sys.argv[1:], "h", ["help", "output=", "input="])
 
217
  except getopt.GetoptError, err:
 
218
    # print help information and exit:
 
219
    print str(err) # will print something like "option -a not recognized"
 
220
    usage()
 
221
    sys.exit(2)
 
222
    
 
223
  output = None
 
224
  input = None
 
225
  for o, a in opts:
 
226
    if o in ("-h", "--help"):
 
227
      usage()
 
228
      sys.exit()
 
229
    elif o in ("--output"):
 
230
      output = a
 
231
    elif o in ("--input"):
 
232
      input = a
 
233
    else:
 
234
      assert False, "unhandled option"
 
235
 
 
236
  if (not output or not input):
 
237
    usage()
 
238
    sys.exit()
 
239
    
 
240
  data = build_data_structure (input)
 
241
  info = gatherinfo (input)
 
242
  build_graph (data, output, info)
 
243
 
 
244
 
 
245
  return 0
 
246
 
 
247
if __name__ == '__main__': main()