~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/lsprof.py

 * The internal storage of history, and logical branch identity have now
   been split into Branch, and Repository. The common locking and file 
   management routines are now in bzrlib.lockablefiles. 
   (Aaron Bentley, Robert Collins, Martin Pool)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# this is copied from the lsprof distro because somehow
 
2
# it is not installed by distutils
 
3
# I made one modification to profile so that it returns a pair
 
4
# instead of just the Stats object
 
5
 
 
6
import sys
 
7
from _lsprof import Profiler, profiler_entry, profiler_subentry
 
8
 
 
9
__all__ = ['profile', 'Stats']
 
10
 
 
11
def profile(f, *args, **kwds):
 
12
    """XXX docstring"""
 
13
    p = Profiler()
 
14
    p.enable(subcalls=True)
 
15
    try:
 
16
        ret = f(*args, **kwds)
 
17
    finally:
 
18
        p.disable()
 
19
    return ret,Stats(p.getstats())
 
20
 
 
21
 
 
22
class Stats(object):
 
23
    """XXX docstring"""
 
24
 
 
25
    def __init__(self, data):
 
26
        self.data = data
 
27
 
 
28
    def sort(self, crit="inlinetime"):
 
29
        """XXX docstring"""
 
30
        if crit not in profiler_entry.__dict__:
 
31
            raise ValueError, "Can't sort by %s" % crit
 
32
        self.data.sort(lambda b, a: cmp(getattr(a, crit),
 
33
                                        getattr(b, crit)))
 
34
        for e in self.data:
 
35
            if e.calls:
 
36
                e.calls.sort(lambda b, a: cmp(getattr(a, crit),
 
37
                                              getattr(b, crit)))
 
38
 
 
39
    def pprint(self, top=None, file=None):
 
40
        """XXX docstring"""
 
41
        if file is None:
 
42
            file = sys.stdout
 
43
        d = self.data
 
44
        if top is not None:
 
45
            d = d[:top]
 
46
        cols = "% 12s %12s %11.4f %11.4f   %s\n"
 
47
        hcols = "% 12s %12s %12s %12s %s\n"
 
48
        cols2 = "+%12s %12s %11.4f %11.4f +  %s\n"
 
49
        file.write(hcols % ("CallCount", "Recursive", "Total(ms)",
 
50
                            "Inline(ms)", "module:lineno(function)"))
 
51
        for e in d:
 
52
            file.write(cols % (e.callcount, e.reccallcount, e.totaltime,
 
53
                               e.inlinetime, label(e.code)))
 
54
            if e.calls:
 
55
                for se in e.calls:
 
56
                    file.write(cols % ("+%s" % se.callcount, se.reccallcount,
 
57
                                       se.totaltime, se.inlinetime,
 
58
                                       "+%s" % label(se.code)))
 
59
 
 
60
    def freeze(self):
 
61
        """Replace all references to code objects with string
 
62
        descriptions; this makes it possible to pickle the instance."""
 
63
 
 
64
        # this code is probably rather ickier than it needs to be!
 
65
        for i in range(len(self.data)):
 
66
            e = self.data[i]
 
67
            if not isinstance(e.code, str):
 
68
                self.data[i] = type(e)((label(e.code),) + e[1:])
 
69
                if e.calls:
 
70
                    for j in range(len(e.calls)):
 
71
                        se = e.calls[j]
 
72
                        if not isinstance(se.code, str):
 
73
                            e.calls[j] = type(se)((label(se.code),) + se[1:])
 
74
 
 
75
_fn2mod = {}
 
76
 
 
77
def label(code):
 
78
    if isinstance(code, str):
 
79
        return code
 
80
    try:
 
81
        mname = _fn2mod[code.co_filename]
 
82
    except KeyError:
 
83
        for k, v in sys.modules.iteritems():
 
84
            if v is None:
 
85
                continue
 
86
            if not hasattr(v, '__file__'):
 
87
                continue
 
88
            if not isinstance(v.__file__, str):
 
89
                continue
 
90
            if v.__file__.startswith(code.co_filename):
 
91
                mname = _fn2mod[code.co_filename] = k
 
92
                break
 
93
        else:
 
94
            mname = _fn2mod[code.co_filename] = '<%s>'%code.co_filename
 
95
    
 
96
    return '%s:%d(%s)' % (mname, code.co_firstlineno, code.co_name)
 
97
 
 
98
 
 
99
if __name__ == '__main__':
 
100
    import os
 
101
    sys.argv = sys.argv[1:]
 
102
    if not sys.argv:
 
103
        print >> sys.stderr, "usage: lsprof.py <script> <arguments...>"
 
104
        sys.exit(2)
 
105
    sys.path.insert(0, os.path.abspath(os.path.dirname(sys.argv[0])))
 
106
    stats = profile(execfile, sys.argv[0], globals(), locals())
 
107
    stats.sort()
 
108
    stats.pprint()