Back to index

unity  6.0.0
makebootchart.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 #
00003 # Copyright (C) 2009 Canonical Ltd
00004 #
00005 # This program is free software: you can redistribute it and/or modify
00006 # it under the terms of the GNU General Public License version 3 as
00007 # published by the Free Software Foundation.
00008 #
00009 # This program is distributed in the hope that it will be useful,
00010 # but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 # GNU General Public License for more details.
00013 #
00014 # You should have received a copy of the GNU General Public License
00015 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
00016 #
00017 # Authored by Gordon Allott <gord.allott@canonical.com>
00018 #
00019 #
00020 import os, sys
00021 import getopt
00022 import cairo
00023 import csv
00024 import math
00025 import random
00026 from string import Template
00027 from socket import gethostname
00028 from datetime import datetime
00029 import re
00030 import subprocess
00031 
00032 header = Template("""Unity bootchart for $hostname ($date)
00033 uname: $uname
00034 CPU: $cpu
00035 GPU: $gpu
00036 time: $total_time""")
00037 
00038 def sort_by_domain (x, y):
00039   if x["start"] - y["start"] < 0:
00040     return -1
00041   else:
00042     return +1
00043 
00044 def gatherinfo (filename):
00045   date =  datetime.fromtimestamp(os.path.getmtime(filename))
00046 
00047   cpufile = open ("/proc/cpuinfo")
00048   cpuinfo = cpufile.read (10024)
00049   cpure = re.search (r"^model name\s*: (.*$)", cpuinfo, re.MULTILINE)
00050   cpu = cpure.group(1)
00051 
00052   gpu_prog = subprocess.Popen("glxinfo", stdout=subprocess.PIPE)
00053   gpu_prog.wait ()
00054   gpuinfo = gpu_prog.stdout.read (10024)
00055   gpure = re.search (r"^OpenGL renderer string: (.*$)", gpuinfo, re.MULTILINE)
00056   gpu = gpure.group (1)
00057 
00058   return {"hostname":gethostname(),
00059           "date": date.strftime("%A, %d. %B %Y %I:%M%p"),
00060           "uname": " ".join (os.uname ()),
00061           "cpu": cpu,
00062           "gpu": gpu,
00063           "total_time": "undefined"
00064           }
00065 
00066 width_multiplier = 1000
00067 bar_height = 16
00068 
00069 def draw_bg_graph (ctx, seconds, height):
00070 
00071   total_width = seconds * width_multiplier
00072   ctx.set_source_rgba (0.0, 0.0, 0.0, 0.25)
00073 
00074   ctx.move_to (0, 0)
00075   ctx.line_to (total_width, 0)
00076   ctx.stroke ()
00077 
00078   per_ten = 0
00079   for pos in xrange (0, int(total_width), int (0.01 * width_multiplier)):
00080     ctx.set_line_width (1)
00081     ctx.set_source_rgba (0.0, 0.0, 0.0, 0.10)
00082 
00083     if (not per_ten):
00084       ctx.set_line_width (2)
00085       ctx.set_source_rgba (0.0, 0.0, 0.0, 0.25)
00086       ctx.move_to (pos-6, -2)
00087       ctx.show_text (str (pos / float(width_multiplier)))
00088       ctx.stroke ()
00089 
00090     ctx.move_to (pos, 0)
00091     ctx.line_to (pos, height)
00092     ctx.stroke ()
00093 
00094     per_ten += 1
00095     per_ten %= 10
00096 
00097 def build_graph (data, filename, info):
00098 
00099   padding_left = 6
00100   padding_right = 100
00101   padding_top = 6
00102   padding_bottom = 6
00103 
00104   total_size = 0.0
00105   for item in data:
00106     if item['end'] > total_size:
00107       total_size = item['end']
00108 
00109   width = total_size * width_multiplier + padding_left + padding_right
00110   height = (len(data) * (bar_height)) + 80 + padding_bottom + padding_top
00111   surface = cairo.SVGSurface(filename, max (width, 800), max (height, 600))
00112 
00113   ctx = cairo.Context (surface)
00114 
00115   #fill background
00116   ctx.set_source_rgb (1, 1, 1)
00117   ctx.rectangle (0, 0,  max (width, 800), max (height, 600))
00118   ctx.fill ()
00119 
00120   #print header
00121   info['total_time'] = "%s secs" % total_size
00122   sheader = header.substitute(info)
00123 
00124   ctx.translate (padding_left, padding_top)
00125   ctx.set_source_rgb (0, 0, 0)
00126   for line in sheader.split("\n"):
00127     ctx.translate (0, 12)
00128     ctx.show_text (line)
00129     ctx.fill ()
00130 
00131   ctx.translate (6, 12)
00132 
00133   draw_bg_graph (ctx, total_size + 0.5, max (len (data) * bar_height + 64, 500))
00134 
00135   ctx.set_line_width (1)
00136   for item in data:
00137     x = item['start'] * width_multiplier
00138     x1 = (item['end'] - item['start']) * width_multiplier
00139     ctx.translate (x, 0)
00140 
00141     ctx.set_source_rgba (0.35, 0.65, 0.8, 0.5)
00142     ctx.rectangle (0, 0, x1, 16)
00143     ctx.fill ()
00144 
00145     ctx.set_source_rgba (0.35, 0.65, 0.8, 1.0)
00146     ctx.rectangle (0, 0, x1, 16)
00147     ctx.stroke ()
00148 
00149     ctx.translate (8, 10)
00150     ctx.set_source_rgb (0.0, 0.0, 0.0)
00151     ctx.show_text ("%s %.4f seconds" % (item['name'], item["end"] - item["start"]))
00152     ctx.fill()
00153 
00154     ctx.translate (-x-8, 6)
00155 
00156 def build_data_structure (input):
00157   reader = csv.reader(open(input))
00158   structure = []
00159   print "reading", input
00160   for row in reader:
00161     name = row[0]
00162     start = float(row[1])
00163     end = float(row[2])
00164     structure.append ({"name": name, "start": start, "end": end})
00165 
00166   structure.sort (sort_by_domain)
00167   return structure
00168 
00169 
00170 def usage():
00171   print "use --input=filename.log and --output=filename.svg :)"
00172 
00173 def main():
00174 
00175   try:
00176       opts, args = getopt.getopt(sys.argv[1:], "h", ["help", "output=", "input="])
00177   except getopt.GetoptError, err:
00178     # print help information and exit:
00179     print str(err) # will print something like "option -a not recognized"
00180     usage()
00181     sys.exit(2)
00182 
00183   output = None
00184   input = None
00185   for o, a in opts:
00186     if o in ("-h", "--help"):
00187       usage()
00188       sys.exit()
00189     elif o in ("--output"):
00190       output = a
00191     elif o in ("--input"):
00192       input = a
00193     else:
00194       assert False, "unhandled option"
00195 
00196   if (not output or not input):
00197     usage()
00198     sys.exit()
00199 
00200   data = build_data_structure (input)
00201   info = gatherinfo (input)
00202   build_graph (data, output, info)
00203 
00204 
00205   return 0
00206 
00207 if __name__ == '__main__': main()