36
30
p.enable(subcalls=True)
37
31
threading.setprofile(_thread_profile)
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.
44
ret = f(*args, **kwds)
45
except (KeyboardInterrupt, Exception), e:
47
bzrlib.trace.report_exception(sys.exc_info(), sys.stderr)
33
ret = f(*args, **kwds)
51
36
for pp in _g_threadmap.values():
119
104
"""Output profiling data in calltree format (for KCacheGrind)."""
120
105
_CallTreeFilter(self.data).output(file)
122
def save(self, filename, format=None):
123
"""Save profiling data to a file.
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
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.
134
basename = bzrlib.osutils.basename(filename)
135
if basename.startswith('callgrind.out'):
138
ext = bzrlib.osutils.splitext(filename)[1]
141
outfile = open(filename, 'wb')
143
if format == "callgrind":
144
self.calltree(outfile)
145
elif format == "txt":
146
self.pprint(file=outfile)
149
cPickle.dump(self, outfile, 2)
154
108
class _CallTreeFilter(object):
155
"""Converter of a Stats object to input suitable for KCacheGrind.
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
164
110
def __init__(self, data):
177
123
for entry in self.data:
178
124
totaltime = int(entry.totaltime * 1000)
179
125
max_cost = max(max_cost, totaltime)
180
self.out_file.write('summary: %d\n' % (max_cost,))
126
print >> self.out_file, 'summary: %d' % (max_cost,)
182
128
def _entry(self, entry):
183
129
out_file = self.out_file
184
130
code = entry.code
185
131
inlinetime = int(entry.inlinetime * 1000)
186
#out_file.write('ob=%s\n' % (code.co_filename,))
187
if isinstance(code, str):
188
out_file.write('fi=~\n')
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):
193
out_file.write('0 %s\n' % (inlinetime,))
195
out_file.write('%d %d\n' % (code.co_firstlineno, inlinetime))
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)
196
136
# recursive calls are counted in entry.calls
198
138
calls = entry.calls
201
if isinstance(code, str):
204
lineno = code.co_firstlineno
205
141
for subentry in calls:
206
self._subentry(lineno, subentry)
142
self._subentry(code.co_firstlineno, subentry)
209
145
def _subentry(self, lineno, subentry):
210
146
out_file = self.out_file
211
147
code = subentry.code
212
148
totaltime = int(subentry.totaltime * 1000)
213
#out_file.write('cob=%s\n' % (code.co_filename,))
214
out_file.write('cfn=%s\n' % (label(code, True),))
215
if isinstance(code, str):
216
out_file.write('cfi=~\n')
217
out_file.write('calls=%d 0\n' % (subentry.callcount,))
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))
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)