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