lsprof.py
127 lines
| 4.1 KiB
| text/x-python
|
PythonLexer
/ mercurial / lsprof.py
Gregory Szorc
|
r27617 | from __future__ import absolute_import, print_function | ||
Gregory Szorc
|
r27061 | |||
import _lsprof | ||||
Vadim Gelfer
|
r2422 | import sys | ||
Gregory Szorc
|
r27061 | |||
Profiler = _lsprof.Profiler | ||||
# PyPy doesn't expose profiler_entry from the module. | ||||
profiler_entry = getattr(_lsprof, 'profiler_entry', None) | ||||
Vadim Gelfer
|
r2422 | |||
__all__ = ['profile', 'Stats'] | ||||
def profile(f, *args, **kwds): | ||||
"""XXX docstring""" | ||||
p = Profiler() | ||||
Dirkjan Ochtman
|
r5992 | p.enable(subcalls=True, builtins=True) | ||
Vadim Gelfer
|
r2422 | try: | ||
Dirkjan Ochtman
|
r5992 | f(*args, **kwds) | ||
Vadim Gelfer
|
r2422 | finally: | ||
p.disable() | ||||
Dirkjan Ochtman
|
r5992 | return Stats(p.getstats()) | ||
Vadim Gelfer
|
r2422 | |||
class Stats(object): | ||||
"""XXX docstring""" | ||||
def __init__(self, data): | ||||
self.data = data | ||||
Augie Fackler
|
r35854 | def sort(self, crit=r"inlinetime"): | ||
Vadim Gelfer
|
r2422 | """XXX docstring""" | ||
Gregory Szorc
|
r27061 | # profiler_entries isn't defined when running under PyPy. | ||
if profiler_entry: | ||||
if crit not in profiler_entry.__dict__: | ||||
raise ValueError("Can't sort by %s" % crit) | ||||
elif self.data and not getattr(self.data[0], crit, None): | ||||
Peter Ruibal
|
r7008 | raise ValueError("Can't sort by %s" % crit) | ||
Gregory Szorc
|
r27061 | |||
Alejandro Santos
|
r9032 | self.data.sort(key=lambda x: getattr(x, crit), reverse=True) | ||
Vadim Gelfer
|
r2422 | for e in self.data: | ||
if e.calls: | ||||
Alejandro Santos
|
r9032 | e.calls.sort(key=lambda x: getattr(x, crit), reverse=True) | ||
Vadim Gelfer
|
r2422 | |||
def pprint(self, top=None, file=None, limit=None, climit=None): | ||||
"""XXX docstring""" | ||||
if file is None: | ||||
file = sys.stdout | ||||
d = self.data | ||||
if top is not None: | ||||
d = d[:top] | ||||
Gregory Szorc
|
r40229 | cols = "% 12d %12d %11.4f %11.4f %s\n" | ||
Dirkjan Ochtman
|
r5992 | hcols = "% 12s %12s %12s %12s %s\n" | ||
Bryan O'Sullivan
|
r16804 | file.write(hcols % ("CallCount", "Recursive", "Total(s)", | ||
"Inline(s)", "module:lineno(function)")) | ||||
Vadim Gelfer
|
r2422 | count = 0 | ||
for e in d: | ||||
Dirkjan Ochtman
|
r5992 | file.write(cols % (e.callcount, e.reccallcount, e.totaltime, | ||
Vadim Gelfer
|
r2422 | e.inlinetime, label(e.code))) | ||
count += 1 | ||||
if limit is not None and count == limit: | ||||
return | ||||
ccount = 0 | ||||
Matt Mackall
|
r16263 | if climit and e.calls: | ||
Vadim Gelfer
|
r2422 | for se in e.calls: | ||
Mads Kiilerich
|
r18642 | file.write(cols % (se.callcount, se.reccallcount, | ||
Vadim Gelfer
|
r2422 | se.totaltime, se.inlinetime, | ||
Mads Kiilerich
|
r18642 | " %s" % label(se.code))) | ||
Vadim Gelfer
|
r2422 | count += 1 | ||
ccount += 1 | ||||
if limit is not None and count == limit: | ||||
return | ||||
if climit is not None and ccount == climit: | ||||
break | ||||
def freeze(self): | ||||
"""Replace all references to code objects with string | ||||
descriptions; this makes it possible to pickle the instance.""" | ||||
# this code is probably rather ickier than it needs to be! | ||||
for i in range(len(self.data)): | ||||
e = self.data[i] | ||||
if not isinstance(e.code, str): | ||||
self.data[i] = type(e)((label(e.code),) + e[1:]) | ||||
Dirkjan Ochtman
|
r5992 | if e.calls: | ||
for j in range(len(e.calls)): | ||||
se = e.calls[j] | ||||
if not isinstance(se.code, str): | ||||
e.calls[j] = type(se)((label(se.code),) + se[1:]) | ||||
Vadim Gelfer
|
r2422 | |||
_fn2mod = {} | ||||
def label(code): | ||||
if isinstance(code, str): | ||||
Gregory Szorc
|
r40238 | if sys.version_info.major >= 3: | ||
code = code.encode('latin-1') | ||||
Vadim Gelfer
|
r2422 | return code | ||
try: | ||||
mname = _fn2mod[code.co_filename] | ||||
except KeyError: | ||||
Dirkjan Ochtman
|
r9314 | for k, v in list(sys.modules.iteritems()): | ||
Vadim Gelfer
|
r2422 | if v is None: | ||
continue | ||||
Augie Fackler
|
r14959 | if not isinstance(getattr(v, '__file__', None), str): | ||
Vadim Gelfer
|
r2422 | continue | ||
if v.__file__.startswith(code.co_filename): | ||||
mname = _fn2mod[code.co_filename] = k | ||||
break | ||||
else: | ||||
Gregory Szorc
|
r40238 | mname = _fn2mod[code.co_filename] = r'<%s>' % code.co_filename | ||
res = r'%s:%d(%s)' % (mname, code.co_firstlineno, code.co_name) | ||||
Vadim Gelfer
|
r2422 | |||
Gregory Szorc
|
r40238 | if sys.version_info.major >= 3: | ||
res = res.encode('latin-1') | ||||
Vadim Gelfer
|
r2422 | |||
Gregory Szorc
|
r40238 | return res | ||
Vadim Gelfer
|
r2422 | |||
if __name__ == '__main__': | ||||
import os | ||||
sys.argv = sys.argv[1:] | ||||
if not sys.argv: | ||||
Gregory Szorc
|
r27617 | print("usage: lsprof.py <script> <arguments...>", file=sys.stderr) | ||
Vadim Gelfer
|
r2422 | sys.exit(2) | ||
sys.path.insert(0, os.path.abspath(os.path.dirname(sys.argv[0]))) | ||||
stats = profile(execfile, sys.argv[0], globals(), locals()) | ||||
stats.sort() | ||||
stats.pprint() | ||||