1#!/usr/bin/env python 2 3import profile, pstats, fpformat 4 5import pygtk 6pygtk.require('2.0') 7import gtk 8 9class PStatWindow(gtk.Window): 10 def __init__(self, stats): 11 gtk.Window.__init__(self) 12 self.connect("destroy", self.quit) 13 self.connect("delete_event", self.quit) 14 self.set_title("Profile Statistics") 15 16 self.stats = stats 17 18 box1 = gtk.VBox() 19 self.add(box1) 20 box1.show() 21 22 text = `stats.total_calls` + " function calls " 23 if stats.total_calls != stats.prim_calls: 24 text = text + "( " + `stats.prim_calls` + " primitive calls) " 25 text = text + "in " + fpformat.fix(stats.total_tt, 3) + " CPU seconds" 26 label = gtk.Label(text) 27 label.set_padding(2, 2) 28 box1.pack_start(label, expand=False) 29 label.show() 30 31 swin = gtk.ScrolledWindow() 32 swin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) 33 box1.pack_start(swin) 34 swin.show() 35 36 titles = [('ncalls', 40), ('tottime', 50), ('percall', 50), 37 ('cumtime', 50), ('percall', 50), 38 ('filename:lineno(function)', 10)] 39 ls = gtk.ListStore(*((str,)*len(titles))) 40 list = gtk.TreeView(ls) 41 for n in range(len(titles)): 42 cell = gtk.CellRendererText() 43 cell.set_property('xalign', 1.0) 44 tvc = gtk.TreeViewColumn(titles[n][0], cell, text=n) 45 tvc.set_min_width(titles[n][1]) 46 list.append_column(tvc) 47 list.set_size_request(500, 200) 48 self.list = list 49 list.set_border_width(10) 50 swin.add(list) 51 list.show() 52 53 self.insert_stats() 54 55 separator = gtk.HSeparator() 56 box1.pack_start(separator, expand=False) 57 separator.show() 58 59 box2 = gtk.VBox(spacing=10) 60 box2.set_border_width(10) 61 box1.pack_start(box2, expand=False) 62 box2.show() 63 64 button = gtk.Button("close") 65 button.connect("clicked", self.quit) 66 self.close_button = button 67 box2.pack_start(button) 68 button.set_flags(gtk.CAN_DEFAULT) 69 button.grab_default() 70 button.show() 71 72 def quit(self, *args): 73 self.hide() 74 self.destroy() 75 gtk.main_quit() 76 77 def get_stats_list(self): 78 if self.stats.fcn_list: 79 return self.stats.fcn_list[:] 80 else: 81 return self.stats.stats.keys() 82 83 def insert_stats(self): 84 list = self.get_stats_list() 85 if list: 86 row = [None] * 6 87 model = self.list.get_model() 88 for func in list: 89 cc,nc,tt,ct,callers = self.stats.stats[func] 90 row[0] = `nc` 91 if nc != cc: 92 row[0] = row[0] + '/' + `cc` 93 row[1] = fpformat.fix(tt, 3) 94 if nc == 0: 95 row[2] = '' 96 else: 97 row[2] = fpformat.fix(tt/nc, 3) 98 row[3] = fpformat.fix(ct, 3) 99 if cc == 0: 100 row[4] = '' 101 else: 102 row[4] = fpformat.fix(ct/cc, 3) 103 file,line,name = func 104 row[5] = file + ":" + `line` + "(" + name + \ 105 ")" 106 self.list.get_model().append(row) 107 return 108 109def run(cmd): 110 prof = profile.Profile() 111 try: 112 stats = pstats.Stats(prof.run(cmd)) 113 except SystemExit: 114 pass 115 stats.strip_dirs().sort_stats("time", "module", "name") 116 win = PStatWindow(stats) 117 win.show() 118 gtk.main() 119 120def run_file(file): 121 return run('execfile("' + file + '")') 122 123 124if __name__ == '__main__': 125 import sys, os 126 if not sys.argv[1:]: 127 print "usage: gtkprof.py scriptfile [args ...]" 128 sys.exit(2) 129 filename = sys.argv[1] 130 del sys.argv[0] 131 sys.path.insert(0, os.path.dirname(filename)) 132 133 run_file(filename) 134