bzr branch
http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
| 
1185.33.86
by Martin Pool
 Add additional module for lsprof.  | 
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  | 
|
| 
1553.7.2
by Robey Pointer
 add threading support -- each thread created during an lsprof session gets its own profile object, and the Stats objects are attached to a 'threads' member of the final Stats object  | 
7  | 
import thread  | 
8  | 
import threading  | 
|
| 
1773.4.1
by Martin Pool
 Add pyflakes makefile target; fix many warnings  | 
9  | 
from _lsprof import Profiler, profiler_entry  | 
| 
1185.33.86
by Martin Pool
 Add additional module for lsprof.  | 
10  | 
|
11  | 
__all__ = ['profile', 'Stats']  | 
|
12  | 
||
| 
1553.7.2
by Robey Pointer
 add threading support -- each thread created during an lsprof session gets its own profile object, and the Stats objects are attached to a 'threads' member of the final Stats object  | 
13  | 
_g_threadmap = {}  | 
14  | 
||
| 
1553.7.3
by Robey Pointer
 patch from ddaa to add kcachegrind output-format support to lsprof  | 
15  | 
|
| 
1553.7.2
by Robey Pointer
 add threading support -- each thread created during an lsprof session gets its own profile object, and the Stats objects are attached to a 'threads' member of the final Stats object  | 
16  | 
def _thread_profile(f, *args, **kwds):  | 
17  | 
    # we lose the first profile point for a new thread in order to trampoline
 | 
|
18  | 
    # a new Profile object into place
 | 
|
19  | 
global _g_threadmap  | 
|
20  | 
thr = thread.get_ident()  | 
|
21  | 
_g_threadmap[thr] = p = Profiler()  | 
|
22  | 
    # this overrides our sys.setprofile hook:
 | 
|
| 
1706.2.7
by Robey Pointer
 pull over some changes from the original lsprof  | 
23  | 
p.enable(subcalls=True, builtins=True)  | 
| 
1553.7.2
by Robey Pointer
 add threading support -- each thread created during an lsprof session gets its own profile object, and the Stats objects are attached to a 'threads' member of the final Stats object  | 
24  | 
|
25  | 
||
| 
1185.33.86
by Martin Pool
 Add additional module for lsprof.  | 
26  | 
def profile(f, *args, **kwds):  | 
27  | 
"""XXX docstring"""  | 
|
| 
1553.7.2
by Robey Pointer
 add threading support -- each thread created during an lsprof session gets its own profile object, and the Stats objects are attached to a 'threads' member of the final Stats object  | 
28  | 
global _g_threadmap  | 
| 
1185.33.86
by Martin Pool
 Add additional module for lsprof.  | 
29  | 
p = Profiler()  | 
30  | 
p.enable(subcalls=True)  | 
|
| 
1553.7.2
by Robey Pointer
 add threading support -- each thread created during an lsprof session gets its own profile object, and the Stats objects are attached to a 'threads' member of the final Stats object  | 
31  | 
threading.setprofile(_thread_profile)  | 
| 
1185.33.86
by Martin Pool
 Add additional module for lsprof.  | 
32  | 
try:  | 
33  | 
ret = f(*args, **kwds)  | 
|
34  | 
finally:  | 
|
35  | 
p.disable()  | 
|
| 
1553.7.2
by Robey Pointer
 add threading support -- each thread created during an lsprof session gets its own profile object, and the Stats objects are attached to a 'threads' member of the final Stats object  | 
36  | 
for pp in _g_threadmap.values():  | 
37  | 
pp.disable()  | 
|
38  | 
threading.setprofile(None)  | 
|
39  | 
||
40  | 
threads = {}  | 
|
41  | 
for tid, pp in _g_threadmap.items():  | 
|
42  | 
threads[tid] = Stats(pp.getstats(), {})  | 
|
43  | 
_g_threadmap = {}  | 
|
44  | 
return ret, Stats(p.getstats(), threads)  | 
|
| 
1185.33.86
by Martin Pool
 Add additional module for lsprof.  | 
45  | 
|
46  | 
||
47  | 
class Stats(object):  | 
|
48  | 
"""XXX docstring"""  | 
|
49  | 
||
| 
1553.7.2
by Robey Pointer
 add threading support -- each thread created during an lsprof session gets its own profile object, and the Stats objects are attached to a 'threads' member of the final Stats object  | 
50  | 
def __init__(self, data, threads):  | 
| 
1185.33.86
by Martin Pool
 Add additional module for lsprof.  | 
51  | 
self.data = data  | 
| 
1553.7.2
by Robey Pointer
 add threading support -- each thread created during an lsprof session gets its own profile object, and the Stats objects are attached to a 'threads' member of the final Stats object  | 
52  | 
self.threads = threads  | 
| 
1185.33.86
by Martin Pool
 Add additional module for lsprof.  | 
53  | 
|
54  | 
def sort(self, crit="inlinetime"):  | 
|
55  | 
"""XXX docstring"""  | 
|
56  | 
if crit not in profiler_entry.__dict__:  | 
|
57  | 
raise ValueError, "Can't sort by %s" % crit  | 
|
58  | 
self.data.sort(lambda b, a: cmp(getattr(a, crit),  | 
|
59  | 
getattr(b, crit)))  | 
|
60  | 
for e in self.data:  | 
|
61  | 
if e.calls:  | 
|
62  | 
e.calls.sort(lambda b, a: cmp(getattr(a, crit),  | 
|
63  | 
getattr(b, crit)))  | 
|
64  | 
||
65  | 
def pprint(self, top=None, file=None):  | 
|
66  | 
"""XXX docstring"""  | 
|
67  | 
if file is None:  | 
|
68  | 
file = sys.stdout  | 
|
69  | 
d = self.data  | 
|
70  | 
if top is not None:  | 
|
71  | 
d = d[:top]  | 
|
72  | 
cols = "% 12s %12s %11.4f %11.4f %s\n"  | 
|
73  | 
hcols = "% 12s %12s %12s %12s %s\n"  | 
|
74  | 
cols2 = "+%12s %12s %11.4f %11.4f + %s\n"  | 
|
75  | 
file.write(hcols % ("CallCount", "Recursive", "Total(ms)",  | 
|
76  | 
"Inline(ms)", "module:lineno(function)"))  | 
|
77  | 
for e in d:  | 
|
78  | 
file.write(cols % (e.callcount, e.reccallcount, e.totaltime,  | 
|
79  | 
e.inlinetime, label(e.code)))  | 
|
80  | 
if e.calls:  | 
|
81  | 
for se in e.calls:  | 
|
82  | 
file.write(cols % ("+%s" % se.callcount, se.reccallcount,  | 
|
83  | 
se.totaltime, se.inlinetime,  | 
|
84  | 
"+%s" % label(se.code)))  | 
|
85  | 
||
86  | 
def freeze(self):  | 
|
87  | 
"""Replace all references to code objects with string  | 
|
88  | 
        descriptions; this makes it possible to pickle the instance."""
 | 
|
89  | 
||
90  | 
        # this code is probably rather ickier than it needs to be!
 | 
|
91  | 
for i in range(len(self.data)):  | 
|
92  | 
e = self.data[i]  | 
|
93  | 
if not isinstance(e.code, str):  | 
|
94  | 
self.data[i] = type(e)((label(e.code),) + e[1:])  | 
|
| 
1706.2.7
by Robey Pointer
 pull over some changes from the original lsprof  | 
95  | 
if e.calls:  | 
96  | 
for j in range(len(e.calls)):  | 
|
97  | 
se = e.calls[j]  | 
|
98  | 
if not isinstance(se.code, str):  | 
|
99  | 
e.calls[j] = type(se)((label(se.code),) + se[1:])  | 
|
| 
1553.7.2
by Robey Pointer
 add threading support -- each thread created during an lsprof session gets its own profile object, and the Stats objects are attached to a 'threads' member of the final Stats object  | 
100  | 
for s in self.threads.values():  | 
101  | 
s.freeze()  | 
|
102  | 
||
| 
1553.7.3
by Robey Pointer
 patch from ddaa to add kcachegrind output-format support to lsprof  | 
103  | 
def calltree(self, file):  | 
104  | 
"""Output profiling data in calltree format (for KCacheGrind)."""  | 
|
105  | 
_CallTreeFilter(self.data).output(file)  | 
|
106  | 
||
107  | 
||
108  | 
class _CallTreeFilter(object):  | 
|
109  | 
||
110  | 
def __init__(self, data):  | 
|
111  | 
self.data = data  | 
|
112  | 
self.out_file = None  | 
|
113  | 
||
114  | 
def output(self, out_file):  | 
|
115  | 
self.out_file = out_file  | 
|
116  | 
print >> out_file, 'events: Ticks'  | 
|
117  | 
self._print_summary()  | 
|
118  | 
for entry in self.data:  | 
|
119  | 
self._entry(entry)  | 
|
120  | 
||
121  | 
def _print_summary(self):  | 
|
122  | 
max_cost = 0  | 
|
123  | 
for entry in self.data:  | 
|
124  | 
totaltime = int(entry.totaltime * 1000)  | 
|
125  | 
max_cost = max(max_cost, totaltime)  | 
|
126  | 
print >> self.out_file, 'summary: %d' % (max_cost,)  | 
|
127  | 
||
128  | 
def _entry(self, entry):  | 
|
129  | 
out_file = self.out_file  | 
|
130  | 
code = entry.code  | 
|
131  | 
inlinetime = int(entry.inlinetime * 1000)  | 
|
132  | 
        #print >> out_file, 'ob=%s' % (code.co_filename,)
 | 
|
133  | 
print >> out_file, 'fi=%s' % (code.co_filename,)  | 
|
134  | 
print >> out_file, 'fn=%s' % (label(code, True),)  | 
|
135  | 
print >> out_file, '%d %d' % (code.co_firstlineno, inlinetime)  | 
|
136  | 
        # recursive calls are counted in entry.calls
 | 
|
137  | 
if entry.calls:  | 
|
138  | 
calls = entry.calls  | 
|
139  | 
else:  | 
|
140  | 
calls = []  | 
|
141  | 
for subentry in calls:  | 
|
142  | 
self._subentry(code.co_firstlineno, subentry)  | 
|
143  | 
print >> out_file  | 
|
144  | 
||
145  | 
def _subentry(self, lineno, subentry):  | 
|
146  | 
out_file = self.out_file  | 
|
147  | 
code = subentry.code  | 
|
148  | 
totaltime = int(subentry.totaltime * 1000)  | 
|
149  | 
        #print >> out_file, 'cob=%s' % (code.co_filename,)
 | 
|
150  | 
print >> out_file, 'cfn=%s' % (label(code, True),)  | 
|
151  | 
print >> out_file, 'cfi=%s' % (code.co_filename,)  | 
|
152  | 
print >> out_file, 'calls=%d %d' % (  | 
|
153  | 
subentry.callcount, code.co_firstlineno)  | 
|
154  | 
print >> out_file, '%d %d' % (lineno, totaltime)  | 
|
155  | 
||
| 
1185.33.86
by Martin Pool
 Add additional module for lsprof.  | 
156  | 
|
157  | 
_fn2mod = {}  | 
|
158  | 
||
| 
1553.7.3
by Robey Pointer
 patch from ddaa to add kcachegrind output-format support to lsprof  | 
159  | 
def label(code, calltree=False):  | 
| 
1185.33.86
by Martin Pool
 Add additional module for lsprof.  | 
160  | 
if isinstance(code, str):  | 
161  | 
return code  | 
|
162  | 
try:  | 
|
163  | 
mname = _fn2mod[code.co_filename]  | 
|
164  | 
except KeyError:  | 
|
| 
1711.2.124
by John Arbash Meinel
 Use sys.modules.items() to prevent running into site.py problems  | 
165  | 
for k, v in sys.modules.items():  | 
| 
1185.33.86
by Martin Pool
 Add additional module for lsprof.  | 
166  | 
if v is None:  | 
167  | 
                continue
 | 
|
168  | 
if not hasattr(v, '__file__'):  | 
|
169  | 
                continue
 | 
|
170  | 
if not isinstance(v.__file__, str):  | 
|
171  | 
                continue
 | 
|
172  | 
if v.__file__.startswith(code.co_filename):  | 
|
173  | 
mname = _fn2mod[code.co_filename] = k  | 
|
174  | 
                break
 | 
|
175  | 
else:  | 
|
176  | 
mname = _fn2mod[code.co_filename] = '<%s>'%code.co_filename  | 
|
| 
1553.7.3
by Robey Pointer
 patch from ddaa to add kcachegrind output-format support to lsprof  | 
177  | 
if calltree:  | 
178  | 
return '%s %s:%d' % (code.co_name, mname, code.co_firstlineno)  | 
|
179  | 
else:  | 
|
180  | 
return '%s:%d(%s)' % (mname, code.co_firstlineno, code.co_name)  | 
|
| 
1185.33.86
by Martin Pool
 Add additional module for lsprof.  | 
181  | 
|
182  | 
||
183  | 
if __name__ == '__main__':  | 
|
184  | 
import os  | 
|
185  | 
sys.argv = sys.argv[1:]  | 
|
186  | 
if not sys.argv:  | 
|
187  | 
print >> sys.stderr, "usage: lsprof.py <script> <arguments...>"  | 
|
188  | 
sys.exit(2)  | 
|
189  | 
sys.path.insert(0, os.path.abspath(os.path.dirname(sys.argv[0])))  | 
|
190  | 
stats = profile(execfile, sys.argv[0], globals(), locals())  | 
|
191  | 
stats.sort()  | 
|
192  | 
stats.pprint()  |