104
114
"""Output profiling data in calltree format (for KCacheGrind)."""
105
115
_CallTreeFilter(self.data).output(file)
117
def save(self, filename, format=None):
118
"""Save profiling data to a file.
120
:param filename: the name of the output file
121
:param format: 'txt' for a text representation;
122
'callgrind' for calltree format;
123
otherwise a pickled Python object. A format of None indicates
124
that the format to use is to be found from the filename. If
125
the name starts with callgrind.out, callgrind format is used
126
otherwise the format is given by the filename extension.
129
basename = os.path.basename(filename)
130
if basename.startswith('callgrind.out'):
133
ext = os.path.splitext(filename)[1]
136
outfile = open(filename, 'wb')
138
if format == "callgrind":
139
self.calltree(outfile)
140
elif format == "txt":
141
self.pprint(file=outfile)
144
cPickle.dump(self, outfile, 2)
108
149
class _CallTreeFilter(object):
150
"""Converter of a Stats object to input suitable for KCacheGrind.
152
This code is taken from http://ddaa.net/blog/python/lsprof-calltree
153
with the changes made by J.P. Calderone and Itamar applied. Note that
154
isinstance(code, str) needs to be used at times to determine if the code
155
object is actually an external code object (with a filename, etc.) or
110
159
def __init__(self, data):
112
161
self.out_file = None
114
163
def output(self, out_file):
115
self.out_file = out_file
116
print >> out_file, 'events: Ticks'
164
self.out_file = out_file
165
out_file.write('events: Ticks\n')
117
166
self._print_summary()
118
167
for entry in self.data:
119
168
self._entry(entry)
123
172
for entry in self.data:
124
173
totaltime = int(entry.totaltime * 1000)
125
174
max_cost = max(max_cost, totaltime)
126
print >> self.out_file, 'summary: %d' % (max_cost,)
175
self.out_file.write('summary: %d\n' % (max_cost,))
128
177
def _entry(self, entry):
129
178
out_file = self.out_file
130
179
code = entry.code
131
180
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)
181
#out_file.write('ob=%s\n' % (code.co_filename,))
182
if isinstance(code, str):
183
out_file.write('fi=~\n')
185
out_file.write('fi=%s\n' % (code.co_filename,))
186
out_file.write('fn=%s\n' % (label(code, True),))
187
if isinstance(code, str):
188
out_file.write('0 %s\n' % (inlinetime,))
190
out_file.write('%d %d\n' % (code.co_firstlineno, inlinetime))
136
191
# recursive calls are counted in entry.calls
138
193
calls = entry.calls
196
if isinstance(code, str):
199
lineno = code.co_firstlineno
141
200
for subentry in calls:
142
self._subentry(code.co_firstlineno, subentry)
201
self._subentry(lineno, subentry)
145
204
def _subentry(self, lineno, subentry):
146
205
out_file = self.out_file
147
206
code = subentry.code
148
207
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)
208
#out_file.write('cob=%s\n' % (code.co_filename,))
209
out_file.write('cfn=%s\n' % (label(code, True),))
210
if isinstance(code, str):
211
out_file.write('cfi=~\n')
212
out_file.write('calls=%d 0\n' % (subentry.callcount,))
214
out_file.write('cfi=%s\n' % (code.co_filename,))
215
out_file.write('calls=%d %d\n' % (
216
subentry.callcount, code.co_firstlineno))
217
out_file.write('%d %d\n' % (lineno, totaltime))