3
3
# I made one modification to profile so that it returns a pair
4
4
# instead of just the Stats object
11
from _lsprof import Profiler, profiler_entry
7
from _lsprof import Profiler, profiler_entry, profiler_subentry
13
9
__all__ = ['profile', 'Stats']
18
def _thread_profile(f, *args, **kwds):
19
# we lose the first profile point for a new thread in order to trampoline
20
# a new Profile object into place
22
thr = thread.get_ident()
23
_g_threadmap[thr] = p = Profiler()
24
# this overrides our sys.setprofile hook:
25
p.enable(subcalls=True, builtins=True)
28
11
def profile(f, *args, **kwds):
29
12
"""XXX docstring"""
32
14
p.enable(subcalls=True)
33
threading.setprofile(_thread_profile)
35
16
ret = f(*args, **kwds)
38
for pp in _g_threadmap.values():
40
threading.setprofile(None)
43
for tid, pp in _g_threadmap.items():
44
threads[tid] = Stats(pp.getstats(), {})
46
return ret, Stats(p.getstats(), threads)
19
return ret,Stats(p.getstats())
49
22
class Stats(object):
50
23
"""XXX docstring"""
52
def __init__(self, data, threads):
25
def __init__(self, data):
54
self.threads = threads
56
28
def sort(self, crit="inlinetime"):
57
29
"""XXX docstring"""
95
67
if not isinstance(e.code, str):
96
68
self.data[i] = type(e)((label(e.code),) + e[1:])
98
for j in range(len(e.calls)):
100
if not isinstance(se.code, str):
101
e.calls[j] = type(se)((label(se.code),) + se[1:])
102
for s in self.threads.values():
105
def calltree(self, file):
106
"""Output profiling data in calltree format (for KCacheGrind)."""
107
_CallTreeFilter(self.data).output(file)
109
def save(self, filename, format=None):
110
"""Save profiling data to a file.
112
:param filename: the name of the output file
113
:param format: 'txt' for a text representation;
114
'callgrind' for calltree format;
115
otherwise a pickled Python object. A format of None indicates
116
that the format to use is to be found from the extension of
120
ext = os.path.splitext(filename)[1]
123
outfile = open(filename, 'wb')
125
if format == "callgrind":
126
self.calltree(outfile)
127
elif format == "txt":
128
self.pprint(file=outfile)
131
cPickle.dump(self, outfile, 2)
136
class _CallTreeFilter(object):
137
"""Converter of a Stats object to input suitable for KCacheGrind.
139
This code is taken from http://ddaa.net/blog/python/lsprof-calltree
140
with the changes made by J.P. Calderone and Itamar applied. Note that
141
isinstance(code, str) needs to be used at times to determine if the code
142
object is actually an external code object (with a filename, etc.) or
146
def __init__(self, data):
150
def output(self, out_file):
151
self.out_file = out_file
152
print >> out_file, 'events: Ticks'
153
self._print_summary()
154
for entry in self.data:
157
def _print_summary(self):
159
for entry in self.data:
160
totaltime = int(entry.totaltime * 1000)
161
max_cost = max(max_cost, totaltime)
162
print >> self.out_file, 'summary: %d' % (max_cost,)
164
def _entry(self, entry):
165
out_file = self.out_file
167
inlinetime = int(entry.inlinetime * 1000)
168
#print >> out_file, 'ob=%s' % (code.co_filename,)
169
if isinstance(code, str):
170
print >> out_file, 'fi=~'
172
print >> out_file, 'fi=%s' % (code.co_filename,)
173
print >> out_file, 'fn=%s' % (label(code, True),)
174
if isinstance(code, str):
175
print >> out_file, '0 ', inlinetime
177
print >> out_file, '%d %d' % (code.co_firstlineno, inlinetime)
178
# recursive calls are counted in entry.calls
183
if isinstance(code, str):
186
lineno = code.co_firstlineno
187
for subentry in calls:
188
self._subentry(lineno, subentry)
191
def _subentry(self, lineno, subentry):
192
out_file = self.out_file
194
totaltime = int(subentry.totaltime * 1000)
195
#print >> out_file, 'cob=%s' % (code.co_filename,)
196
print >> out_file, 'cfn=%s' % (label(code, True),)
197
if isinstance(code, str):
198
print >> out_file, 'cfi=~'
199
print >> out_file, 'calls=%d 0' % (subentry.callcount,)
201
print >> out_file, 'cfi=%s' % (code.co_filename,)
202
print >> out_file, 'calls=%d %d' % (
203
subentry.callcount, code.co_firstlineno)
204
print >> out_file, '%d %d' % (lineno, totaltime)
70
for j in range(len(e.calls)):
72
if not isinstance(se.code, str):
73
e.calls[j] = type(se)((label(se.code),) + se[1:])
208
def label(code, calltree=False):
209
78
if isinstance(code, str):
212
81
mname = _fn2mod[code.co_filename]
214
for k, v in sys.modules.items():
83
for k, v in sys.modules.iteritems():
217
if getattr(v, '__file__', None) is None:
86
if not hasattr(v, '__file__'):
219
88
if not isinstance(v.__file__, str):