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  | 
||
| 
2493.2.3
by Ian Clatworthy
 changes requested in jameinel's review incorporated  | 
6  | 
import cPickle  | 
7  | 
import os  | 
|
| 
1185.33.86
by Martin Pool
 Add additional module for lsprof.  | 
8  | 
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  | 
9  | 
import thread  | 
10  | 
import threading  | 
|
| 
1773.4.1
by Martin Pool
 Add pyflakes makefile target; fix many warnings  | 
11  | 
from _lsprof import Profiler, profiler_entry  | 
| 
1185.33.86
by Martin Pool
 Add additional module for lsprof.  | 
12  | 
|
| 
2805.7.4
by Ian Clatworthy
 incorporate feedback from lifeless  | 
13  | 
|
| 
1185.33.86
by Martin Pool
 Add additional module for lsprof.  | 
14  | 
__all__ = ['profile', 'Stats']  | 
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  | 
_g_threadmap = {}  | 
17  | 
||
| 
1553.7.3
by Robey Pointer
 patch from ddaa to add kcachegrind output-format support to lsprof  | 
18  | 
|
| 
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  | 
19  | 
def _thread_profile(f, *args, **kwds):  | 
20  | 
    # we lose the first profile point for a new thread in order to trampoline
 | 
|
21  | 
    # a new Profile object into place
 | 
|
22  | 
global _g_threadmap  | 
|
23  | 
thr = thread.get_ident()  | 
|
24  | 
_g_threadmap[thr] = p = Profiler()  | 
|
25  | 
    # this overrides our sys.setprofile hook:
 | 
|
| 
1706.2.7
by Robey Pointer
 pull over some changes from the original lsprof  | 
26  | 
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  | 
27  | 
|
28  | 
||
| 
1185.33.86
by Martin Pool
 Add additional module for lsprof.  | 
29  | 
def profile(f, *args, **kwds):  | 
| 
3696.3.5
by Robert Collins
 Streamline _walkdirs_utf8 for utf8 file systems, reducing time to traverse a mozilla tree from 1s to .6 seconds. (Robert Collins)  | 
30  | 
"""Run a function profile.  | 
31  | 
    
 | 
|
32  | 
    :return: The functions return value and a stats object.
 | 
|
33  | 
    """
 | 
|
| 
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  | 
34  | 
global _g_threadmap  | 
| 
1185.33.86
by Martin Pool
 Add additional module for lsprof.  | 
35  | 
p = Profiler()  | 
36  | 
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  | 
37  | 
threading.setprofile(_thread_profile)  | 
| 
2805.7.1
by Ian Clatworthy
 Dump profiling data even when exceptions are encountered  | 
38  | 
    # Note: The except clause is needed below so that profiling data still
 | 
39  | 
    # gets dumped even when exceptions are encountered. The except clause code
 | 
|
40  | 
    # is taken straight from run_bzr_catch_errrors() in commands.py and ought
 | 
|
41  | 
    # to be kept in sync with it.
 | 
|
| 
1185.33.86
by Martin Pool
 Add additional module for lsprof.  | 
42  | 
try:  | 
| 
2805.7.4
by Ian Clatworthy
 incorporate feedback from lifeless  | 
43  | 
try:  | 
44  | 
ret = f(*args, **kwds)  | 
|
| 
2805.7.6
by Ian Clatworthy
 put back KeyboardInterrupt trapping as needed for Python 2.5  | 
45  | 
except (KeyboardInterrupt, Exception), e:  | 
| 
2805.7.4
by Ian Clatworthy
 incorporate feedback from lifeless  | 
46  | 
import bzrlib.trace  | 
47  | 
bzrlib.trace.report_exception(sys.exc_info(), sys.stderr)  | 
|
48  | 
ret = 3  | 
|
| 
1185.33.86
by Martin Pool
 Add additional module for lsprof.  | 
49  | 
finally:  | 
50  | 
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  | 
51  | 
for pp in _g_threadmap.values():  | 
52  | 
pp.disable()  | 
|
53  | 
threading.setprofile(None)  | 
|
54  | 
||
55  | 
threads = {}  | 
|
56  | 
for tid, pp in _g_threadmap.items():  | 
|
57  | 
threads[tid] = Stats(pp.getstats(), {})  | 
|
58  | 
_g_threadmap = {}  | 
|
59  | 
return ret, Stats(p.getstats(), threads)  | 
|
| 
1185.33.86
by Martin Pool
 Add additional module for lsprof.  | 
60  | 
|
61  | 
||
62  | 
class Stats(object):  | 
|
63  | 
"""XXX docstring"""  | 
|
64  | 
||
| 
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  | 
65  | 
def __init__(self, data, threads):  | 
| 
1185.33.86
by Martin Pool
 Add additional module for lsprof.  | 
66  | 
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  | 
67  | 
self.threads = threads  | 
| 
1185.33.86
by Martin Pool
 Add additional module for lsprof.  | 
68  | 
|
69  | 
def sort(self, crit="inlinetime"):  | 
|
70  | 
"""XXX docstring"""  | 
|
71  | 
if crit not in profiler_entry.__dict__:  | 
|
72  | 
raise ValueError, "Can't sort by %s" % crit  | 
|
73  | 
self.data.sort(lambda b, a: cmp(getattr(a, crit),  | 
|
74  | 
getattr(b, crit)))  | 
|
75  | 
for e in self.data:  | 
|
76  | 
if e.calls:  | 
|
77  | 
e.calls.sort(lambda b, a: cmp(getattr(a, crit),  | 
|
78  | 
getattr(b, crit)))  | 
|
79  | 
||
80  | 
def pprint(self, top=None, file=None):  | 
|
81  | 
"""XXX docstring"""  | 
|
82  | 
if file is None:  | 
|
83  | 
file = sys.stdout  | 
|
84  | 
d = self.data  | 
|
85  | 
if top is not None:  | 
|
86  | 
d = d[:top]  | 
|
87  | 
cols = "% 12s %12s %11.4f %11.4f %s\n"  | 
|
88  | 
hcols = "% 12s %12s %12s %12s %s\n"  | 
|
89  | 
cols2 = "+%12s %12s %11.4f %11.4f + %s\n"  | 
|
90  | 
file.write(hcols % ("CallCount", "Recursive", "Total(ms)",  | 
|
91  | 
"Inline(ms)", "module:lineno(function)"))  | 
|
92  | 
for e in d:  | 
|
93  | 
file.write(cols % (e.callcount, e.reccallcount, e.totaltime,  | 
|
94  | 
e.inlinetime, label(e.code)))  | 
|
95  | 
if e.calls:  | 
|
96  | 
for se in e.calls:  | 
|
97  | 
file.write(cols % ("+%s" % se.callcount, se.reccallcount,  | 
|
98  | 
se.totaltime, se.inlinetime,  | 
|
99  | 
"+%s" % label(se.code)))  | 
|
100  | 
||
101  | 
def freeze(self):  | 
|
102  | 
"""Replace all references to code objects with string  | 
|
103  | 
        descriptions; this makes it possible to pickle the instance."""
 | 
|
104  | 
||
105  | 
        # this code is probably rather ickier than it needs to be!
 | 
|
106  | 
for i in range(len(self.data)):  | 
|
107  | 
e = self.data[i]  | 
|
108  | 
if not isinstance(e.code, str):  | 
|
109  | 
self.data[i] = type(e)((label(e.code),) + e[1:])  | 
|
| 
1706.2.7
by Robey Pointer
 pull over some changes from the original lsprof  | 
110  | 
if e.calls:  | 
111  | 
for j in range(len(e.calls)):  | 
|
112  | 
se = e.calls[j]  | 
|
113  | 
if not isinstance(se.code, str):  | 
|
114  | 
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  | 
115  | 
for s in self.threads.values():  | 
116  | 
s.freeze()  | 
|
117  | 
||
| 
1553.7.3
by Robey Pointer
 patch from ddaa to add kcachegrind output-format support to lsprof  | 
118  | 
def calltree(self, file):  | 
119  | 
"""Output profiling data in calltree format (for KCacheGrind)."""  | 
|
120  | 
_CallTreeFilter(self.data).output(file)  | 
|
121  | 
||
| 
2493.2.3
by Ian Clatworthy
 changes requested in jameinel's review incorporated  | 
122  | 
def save(self, filename, format=None):  | 
123  | 
"""Save profiling data to a file.  | 
|
124  | 
||
125  | 
        :param filename: the name of the output file
 | 
|
126  | 
        :param format: 'txt' for a text representation;
 | 
|
127  | 
            'callgrind' for calltree format;
 | 
|
128  | 
            otherwise a pickled Python object. A format of None indicates
 | 
|
| 
2654.2.2
by Ian Clatworthy
 Put all format detection stuff in one spot as requested by John Arbash Meinel  | 
129  | 
            that the format to use is to be found from the filename. If
 | 
130  | 
            the name starts with callgrind.out, callgrind format is used
 | 
|
131  | 
            otherwise the format is given by the filename extension.
 | 
|
| 
2493.2.3
by Ian Clatworthy
 changes requested in jameinel's review incorporated  | 
132  | 
        """
 | 
133  | 
if format is None:  | 
|
| 
3535.5.1
by John Arbash Meinel
 cleanup a few imports to be lazily loaded.  | 
134  | 
basename = os.path.basename(filename)  | 
| 
2805.7.2
by Ian Clatworthy
 use basename, not full path, when checking for callgrind.out file prefix  | 
135  | 
if basename.startswith('callgrind.out'):  | 
| 
2654.2.2
by Ian Clatworthy
 Put all format detection stuff in one spot as requested by John Arbash Meinel  | 
136  | 
format = "callgrind"  | 
137  | 
else:  | 
|
| 
3535.5.1
by John Arbash Meinel
 cleanup a few imports to be lazily loaded.  | 
138  | 
ext = os.path.splitext(filename)[1]  | 
| 
2654.2.2
by Ian Clatworthy
 Put all format detection stuff in one spot as requested by John Arbash Meinel  | 
139  | 
if len(ext) > 1:  | 
140  | 
format = ext[1:]  | 
|
| 
2493.2.3
by Ian Clatworthy
 changes requested in jameinel's review incorporated  | 
141  | 
outfile = open(filename, 'wb')  | 
142  | 
try:  | 
|
143  | 
if format == "callgrind":  | 
|
144  | 
self.calltree(outfile)  | 
|
145  | 
elif format == "txt":  | 
|
146  | 
self.pprint(file=outfile)  | 
|
147  | 
else:  | 
|
148  | 
self.freeze()  | 
|
149  | 
cPickle.dump(self, outfile, 2)  | 
|
150  | 
finally:  | 
|
151  | 
outfile.close()  | 
|
152  | 
||
| 
1553.7.3
by Robey Pointer
 patch from ddaa to add kcachegrind output-format support to lsprof  | 
153  | 
|
154  | 
class _CallTreeFilter(object):  | 
|
| 
2493.2.2
by Ian Clatworthy
 Incorporate feedback from Robert Collins  | 
155  | 
"""Converter of a Stats object to input suitable for KCacheGrind.  | 
156  | 
||
157  | 
    This code is taken from http://ddaa.net/blog/python/lsprof-calltree
 | 
|
158  | 
    with the changes made by J.P. Calderone and Itamar applied. Note that
 | 
|
159  | 
    isinstance(code, str) needs to be used at times to determine if the code 
 | 
|
160  | 
    object is actually an external code object (with a filename, etc.) or
 | 
|
161  | 
    a Python built-in.
 | 
|
162  | 
    """
 | 
|
| 
1553.7.3
by Robey Pointer
 patch from ddaa to add kcachegrind output-format support to lsprof  | 
163  | 
|
164  | 
def __init__(self, data):  | 
|
165  | 
self.data = data  | 
|
166  | 
self.out_file = None  | 
|
167  | 
||
168  | 
def output(self, out_file):  | 
|
169  | 
self.out_file = out_file  | 
|
| 
2911.6.1
by Blake Winton
 Change 'print >> f,'s to 'f.write('s.  | 
170  | 
out_file.write('events: Ticks\n')  | 
| 
1553.7.3
by Robey Pointer
 patch from ddaa to add kcachegrind output-format support to lsprof  | 
171  | 
self._print_summary()  | 
172  | 
for entry in self.data:  | 
|
173  | 
self._entry(entry)  | 
|
174  | 
||
175  | 
def _print_summary(self):  | 
|
176  | 
max_cost = 0  | 
|
177  | 
for entry in self.data:  | 
|
178  | 
totaltime = int(entry.totaltime * 1000)  | 
|
179  | 
max_cost = max(max_cost, totaltime)  | 
|
| 
2911.6.1
by Blake Winton
 Change 'print >> f,'s to 'f.write('s.  | 
180  | 
self.out_file.write('summary: %d\n' % (max_cost,))  | 
| 
1553.7.3
by Robey Pointer
 patch from ddaa to add kcachegrind output-format support to lsprof  | 
181  | 
|
182  | 
def _entry(self, entry):  | 
|
183  | 
out_file = self.out_file  | 
|
184  | 
code = entry.code  | 
|
185  | 
inlinetime = int(entry.inlinetime * 1000)  | 
|
| 
2911.6.1
by Blake Winton
 Change 'print >> f,'s to 'f.write('s.  | 
186  | 
        #out_file.write('ob=%s\n' % (code.co_filename,))
 | 
187  | 
if isinstance(code, str):  | 
|
188  | 
out_file.write('fi=~\n')  | 
|
189  | 
else:  | 
|
190  | 
out_file.write('fi=%s\n' % (code.co_filename,))  | 
|
191  | 
out_file.write('fn=%s\n' % (label(code, True),))  | 
|
192  | 
if isinstance(code, str):  | 
|
| 
2911.6.4
by Blake Winton
 Fix test failures  | 
193  | 
out_file.write('0 %s\n' % (inlinetime,))  | 
| 
2911.6.1
by Blake Winton
 Change 'print >> f,'s to 'f.write('s.  | 
194  | 
else:  | 
195  | 
out_file.write('%d %d\n' % (code.co_firstlineno, inlinetime))  | 
|
| 
1553.7.3
by Robey Pointer
 patch from ddaa to add kcachegrind output-format support to lsprof  | 
196  | 
        # recursive calls are counted in entry.calls
 | 
197  | 
if entry.calls:  | 
|
198  | 
calls = entry.calls  | 
|
199  | 
else:  | 
|
200  | 
calls = []  | 
|
| 
2493.2.1
by Ian Clatworthy
 make profiling information easier to view and better documented  | 
201  | 
if isinstance(code, str):  | 
202  | 
lineno = 0  | 
|
203  | 
else:  | 
|
204  | 
lineno = code.co_firstlineno  | 
|
| 
1553.7.3
by Robey Pointer
 patch from ddaa to add kcachegrind output-format support to lsprof  | 
205  | 
for subentry in calls:  | 
| 
2493.2.1
by Ian Clatworthy
 make profiling information easier to view and better documented  | 
206  | 
self._subentry(lineno, subentry)  | 
| 
2911.6.1
by Blake Winton
 Change 'print >> f,'s to 'f.write('s.  | 
207  | 
out_file.write('\n')  | 
| 
1553.7.3
by Robey Pointer
 patch from ddaa to add kcachegrind output-format support to lsprof  | 
208  | 
|
209  | 
def _subentry(self, lineno, subentry):  | 
|
210  | 
out_file = self.out_file  | 
|
211  | 
code = subentry.code  | 
|
212  | 
totaltime = int(subentry.totaltime * 1000)  | 
|
| 
2911.6.1
by Blake Winton
 Change 'print >> f,'s to 'f.write('s.  | 
213  | 
        #out_file.write('cob=%s\n' % (code.co_filename,))
 | 
214  | 
out_file.write('cfn=%s\n' % (label(code, True),))  | 
|
| 
2493.2.1
by Ian Clatworthy
 make profiling information easier to view and better documented  | 
215  | 
if isinstance(code, str):  | 
| 
2911.6.1
by Blake Winton
 Change 'print >> f,'s to 'f.write('s.  | 
216  | 
out_file.write('cfi=~\n')  | 
217  | 
out_file.write('calls=%d 0\n' % (subentry.callcount,))  | 
|
| 
2493.2.1
by Ian Clatworthy
 make profiling information easier to view and better documented  | 
218  | 
else:  | 
| 
2911.6.1
by Blake Winton
 Change 'print >> f,'s to 'f.write('s.  | 
219  | 
out_file.write('cfi=%s\n' % (code.co_filename,))  | 
220  | 
out_file.write('calls=%d %d\n' % (  | 
|
221  | 
subentry.callcount, code.co_firstlineno))  | 
|
222  | 
out_file.write('%d %d\n' % (lineno, totaltime))  | 
|
| 
1553.7.3
by Robey Pointer
 patch from ddaa to add kcachegrind output-format support to lsprof  | 
223  | 
|
| 
1185.33.86
by Martin Pool
 Add additional module for lsprof.  | 
224  | 
_fn2mod = {}  | 
225  | 
||
| 
1553.7.3
by Robey Pointer
 patch from ddaa to add kcachegrind output-format support to lsprof  | 
226  | 
def label(code, calltree=False):  | 
| 
1185.33.86
by Martin Pool
 Add additional module for lsprof.  | 
227  | 
if isinstance(code, str):  | 
228  | 
return code  | 
|
229  | 
try:  | 
|
230  | 
mname = _fn2mod[code.co_filename]  | 
|
231  | 
except KeyError:  | 
|
| 
1711.2.124
by John Arbash Meinel
 Use sys.modules.items() to prevent running into site.py problems  | 
232  | 
for k, v in sys.modules.items():  | 
| 
1185.33.86
by Martin Pool
 Add additional module for lsprof.  | 
233  | 
if v is None:  | 
234  | 
                continue
 | 
|
| 
1963.2.6
by Robey Pointer
 pychecker is on crack; go back to using 'is None'.  | 
235  | 
if getattr(v, '__file__', None) is None:  | 
| 
1185.33.86
by Martin Pool
 Add additional module for lsprof.  | 
236  | 
                continue
 | 
237  | 
if not isinstance(v.__file__, str):  | 
|
238  | 
                continue
 | 
|
239  | 
if v.__file__.startswith(code.co_filename):  | 
|
240  | 
mname = _fn2mod[code.co_filename] = k  | 
|
241  | 
                break
 | 
|
242  | 
else:  | 
|
243  | 
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  | 
244  | 
if calltree:  | 
245  | 
return '%s %s:%d' % (code.co_name, mname, code.co_firstlineno)  | 
|
246  | 
else:  | 
|
247  | 
return '%s:%d(%s)' % (mname, code.co_firstlineno, code.co_name)  | 
|
| 
1185.33.86
by Martin Pool
 Add additional module for lsprof.  | 
248  | 
|
249  | 
||
250  | 
if __name__ == '__main__':  | 
|
251  | 
import os  | 
|
252  | 
sys.argv = sys.argv[1:]  | 
|
253  | 
if not sys.argv:  | 
|
| 
2911.6.1
by Blake Winton
 Change 'print >> f,'s to 'f.write('s.  | 
254  | 
sys.stderr.write("usage: lsprof.py <script> <arguments...>\n")  | 
| 
1185.33.86
by Martin Pool
 Add additional module for lsprof.  | 
255  | 
sys.exit(2)  | 
256  | 
sys.path.insert(0, os.path.abspath(os.path.dirname(sys.argv[0])))  | 
|
257  | 
stats = profile(execfile, sys.argv[0], globals(), locals())  | 
|
258  | 
stats.sort()  | 
|
259  | 
stats.pprint()  |