| 1 | #!/usr/bin/env python |
|---|
| 2 | |
|---|
| 3 | import profile, pstats, fpformat |
|---|
| 4 | |
|---|
| 5 | import pygtk |
|---|
| 6 | pygtk.require('2.0') |
|---|
| 7 | import gtk |
|---|
| 8 | |
|---|
| 9 | class 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 | |
|---|
| 109 | def 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 | |
|---|
| 120 | def run_file(file): |
|---|
| 121 | return run('execfile("' + file + '")') |
|---|
| 122 | |
|---|
| 123 | |
|---|
| 124 | if __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) |
|---|