114
104
"""Output profiling data in calltree format (for KCacheGrind)."""
115
105
_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)
149
108
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
159
110
def __init__(self, data):
161
112
self.out_file = None
163
114
def output(self, out_file):
164
self.out_file = out_file
165
out_file.write('events: Ticks\n')
115
self.out_file = out_file
116
print >> out_file, 'events: Ticks'
166
117
self._print_summary()
167
118
for entry in self.data:
168
119
self._entry(entry)
172
123
for entry in self.data:
173
124
totaltime = int(entry.totaltime * 1000)
174
125
max_cost = max(max_cost, totaltime)
175
self.out_file.write('summary: %d\n' % (max_cost,))
126
print >> self.out_file, 'summary: %d' % (max_cost,)
177
128
def _entry(self, entry):
178
129
out_file = self.out_file
179
130
code = entry.code
180
131
inlinetime = int(entry.inlinetime * 1000)
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))
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)
191
136
# recursive calls are counted in entry.calls
193
138
calls = entry.calls
196
if isinstance(code, str):
199
lineno = code.co_firstlineno
200
141
for subentry in calls:
201
self._subentry(lineno, subentry)
142
self._subentry(code.co_firstlineno, subentry)
204
145
def _subentry(self, lineno, subentry):
205
146
out_file = self.out_file
206
147
code = subentry.code
207
148
totaltime = int(subentry.totaltime * 1000)
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))
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)