lsprof.py
145 lines
| 4.2 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 | |||
Gregory Szorc
|
r43359 | from .pycompat import getattr | ||
Gregory Szorc
|
r43376 | from . import pycompat | ||
Gregory Szorc
|
r43359 | |||
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 | |||
Augie Fackler
|
r43347 | __all__ = [b'profile', b'Stats'] | ||
Vadim Gelfer
|
r2422 | |||
Augie Fackler
|
r43346 | |||
Vadim Gelfer
|
r2422 | 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
|
r43809 | def sort(self, crit="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__: | ||||
Augie Fackler
|
r43347 | raise ValueError(b"Can't sort by %s" % crit) | ||
Gregory Szorc
|
r27061 | elif self.data and not getattr(self.data[0], crit, None): | ||
Augie Fackler
|
r43347 | raise ValueError(b"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] | ||||
Augie Fackler
|
r43347 | cols = b"% 12d %12d %11.4f %11.4f %s\n" | ||
hcols = b"% 12s %12s %12s %12s %s\n" | ||||
Augie Fackler
|
r43346 | file.write( | ||
hcols | ||||
% ( | ||||
Augie Fackler
|
r43347 | b"CallCount", | ||
b"Recursive", | ||||
b"Total(s)", | ||||
b"Inline(s)", | ||||
b"module:lineno(function)", | ||||
Augie Fackler
|
r43346 | ) | ||
) | ||||
Vadim Gelfer
|
r2422 | count = 0 | ||
for e in d: | ||||
Augie Fackler
|
r43346 | file.write( | ||
cols | ||||
% ( | ||||
e.callcount, | ||||
e.reccallcount, | ||||
e.totaltime, | ||||
e.inlinetime, | ||||
label(e.code), | ||||
) | ||||
) | ||||
Vadim Gelfer
|
r2422 | 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: | ||
Augie Fackler
|
r43346 | file.write( | ||
cols | ||||
% ( | ||||
se.callcount, | ||||
se.reccallcount, | ||||
se.totaltime, | ||||
se.inlinetime, | ||||
Augie Fackler
|
r43347 | b" %s" % label(se.code), | ||
Augie Fackler
|
r43346 | ) | ||
) | ||||
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 | |||
Augie Fackler
|
r43346 | |||
Vadim Gelfer
|
r2422 | _fn2mod = {} | ||
Augie Fackler
|
r43346 | |||
Vadim Gelfer
|
r2422 | 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: | ||||
Gregory Szorc
|
r43376 | for k, v in list(pycompat.iteritems(sys.modules)): | ||
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: | ||||
Augie Fackler
|
r43906 | mname = _fn2mod[code.co_filename] = '<%s>' % code.co_filename | ||
Gregory Szorc
|
r40238 | |||
Augie Fackler
|
r43906 | res = '%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 | ||