annotate mercurial/lsprof.py @ 29765:19578bb84731

extensions: add unwrapfunction to undo wrapfunction Before this patch, we don't have a safe way to undo a wrapfunction because other extensions may wrap the same function and calling setattr will undo them accidentally. This patch adds an "unwrapfunction" to address the issue. It removes the wrapper from the wrapper chain, and re-wraps everything, which is not the most efficient but short and easy to understand. We can revisit the code if we have perf issues with long chains. The "undo" feature is useful in cases like wrapping a function just in a scope. Like, having a "select" command to interactively (using arrow keys) select content from some output (ex. smartlog). It could wrap "ui.label" to extract interesting texts just in the "select" command.
author Jun Wu <quark@fb.com>
date Wed, 10 Aug 2016 16:27:33 +0100
parents b1a59b80e1a3
children d4e5b2653693
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
27617
b1a59b80e1a3 lsprof: use print function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27061
diff changeset
1 from __future__ import absolute_import, print_function
27061
9c75daf89450 lsprof: support PyPy (issue4573)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 18642
diff changeset
2
9c75daf89450 lsprof: support PyPy (issue4573)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 18642
diff changeset
3 import _lsprof
2422
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
4 import sys
27061
9c75daf89450 lsprof: support PyPy (issue4573)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 18642
diff changeset
5
9c75daf89450 lsprof: support PyPy (issue4573)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 18642
diff changeset
6 Profiler = _lsprof.Profiler
9c75daf89450 lsprof: support PyPy (issue4573)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 18642
diff changeset
7
9c75daf89450 lsprof: support PyPy (issue4573)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 18642
diff changeset
8 # PyPy doesn't expose profiler_entry from the module.
9c75daf89450 lsprof: support PyPy (issue4573)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 18642
diff changeset
9 profiler_entry = getattr(_lsprof, 'profiler_entry', None)
2422
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
10
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
11 __all__ = ['profile', 'Stats']
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
12
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
13 def profile(f, *args, **kwds):
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
14 """XXX docstring"""
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
15 p = Profiler()
5992
30c40ba10963 updating lsprof.py from remote repository
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 2497
diff changeset
16 p.enable(subcalls=True, builtins=True)
2422
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
17 try:
5992
30c40ba10963 updating lsprof.py from remote repository
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 2497
diff changeset
18 f(*args, **kwds)
2422
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
19 finally:
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
20 p.disable()
5992
30c40ba10963 updating lsprof.py from remote repository
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 2497
diff changeset
21 return Stats(p.getstats())
2422
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
22
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
23
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
24 class Stats(object):
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
25 """XXX docstring"""
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
26
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
27 def __init__(self, data):
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
28 self.data = data
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
29
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
30 def sort(self, crit="inlinetime"):
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
31 """XXX docstring"""
27061
9c75daf89450 lsprof: support PyPy (issue4573)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 18642
diff changeset
32 # profiler_entries isn't defined when running under PyPy.
9c75daf89450 lsprof: support PyPy (issue4573)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 18642
diff changeset
33 if profiler_entry:
9c75daf89450 lsprof: support PyPy (issue4573)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 18642
diff changeset
34 if crit not in profiler_entry.__dict__:
9c75daf89450 lsprof: support PyPy (issue4573)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 18642
diff changeset
35 raise ValueError("Can't sort by %s" % crit)
9c75daf89450 lsprof: support PyPy (issue4573)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 18642
diff changeset
36 elif self.data and not getattr(self.data[0], crit, None):
7008
8fee8ff13d37 use Exception(args)-style raising consistently (py3k compatibility)
Peter Ruibal <peter.ruibal@intel.com>
parents: 6212
diff changeset
37 raise ValueError("Can't sort by %s" % crit)
27061
9c75daf89450 lsprof: support PyPy (issue4573)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 18642
diff changeset
38
9032
1fa80c5428b8 compat: use 'key' argument instead of 'cmp' when sorting a list
Alejandro Santos <alejolp@alejolp.com>
parents: 7875
diff changeset
39 self.data.sort(key=lambda x: getattr(x, crit), reverse=True)
2422
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
40 for e in self.data:
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
41 if e.calls:
9032
1fa80c5428b8 compat: use 'key' argument instead of 'cmp' when sorting a list
Alejandro Santos <alejolp@alejolp.com>
parents: 7875
diff changeset
42 e.calls.sort(key=lambda x: getattr(x, crit), reverse=True)
2422
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
43
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
44 def pprint(self, top=None, file=None, limit=None, climit=None):
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
45 """XXX docstring"""
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
46 if file is None:
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
47 file = sys.stdout
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
48 d = self.data
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
49 if top is not None:
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
50 d = d[:top]
5992
30c40ba10963 updating lsprof.py from remote repository
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 2497
diff changeset
51 cols = "% 12s %12s %11.4f %11.4f %s\n"
30c40ba10963 updating lsprof.py from remote repository
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 2497
diff changeset
52 hcols = "% 12s %12s %12s %12s %s\n"
16804
a455a18bfdac lsprof: report units correctly
Bryan O'Sullivan <bryano@fb.com>
parents: 16263
diff changeset
53 file.write(hcols % ("CallCount", "Recursive", "Total(s)",
a455a18bfdac lsprof: report units correctly
Bryan O'Sullivan <bryano@fb.com>
parents: 16263
diff changeset
54 "Inline(s)", "module:lineno(function)"))
2422
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
55 count = 0
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
56 for e in d:
5992
30c40ba10963 updating lsprof.py from remote repository
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 2497
diff changeset
57 file.write(cols % (e.callcount, e.reccallcount, e.totaltime,
2422
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
58 e.inlinetime, label(e.code)))
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
59 count += 1
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
60 if limit is not None and count == limit:
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
61 return
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
62 ccount = 0
16263
be92ddc636e3 profile: add undocumented config options for profiler output
Matt Mackall <mpm@selenic.com>
parents: 14959
diff changeset
63 if climit and e.calls:
2422
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
64 for se in e.calls:
18642
a40d608e2a7b profiling: replace '+' markup of nested lines with indentation
Mads Kiilerich <mads@kiilerich.com>
parents: 16804
diff changeset
65 file.write(cols % (se.callcount, se.reccallcount,
2422
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
66 se.totaltime, se.inlinetime,
18642
a40d608e2a7b profiling: replace '+' markup of nested lines with indentation
Mads Kiilerich <mads@kiilerich.com>
parents: 16804
diff changeset
67 " %s" % label(se.code)))
2422
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
68 count += 1
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
69 ccount += 1
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
70 if limit is not None and count == limit:
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
71 return
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
72 if climit is not None and ccount == climit:
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
73 break
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
74
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
75 def freeze(self):
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
76 """Replace all references to code objects with string
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
77 descriptions; this makes it possible to pickle the instance."""
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
78
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
79 # this code is probably rather ickier than it needs to be!
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
80 for i in range(len(self.data)):
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
81 e = self.data[i]
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
82 if not isinstance(e.code, str):
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
83 self.data[i] = type(e)((label(e.code),) + e[1:])
5992
30c40ba10963 updating lsprof.py from remote repository
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 2497
diff changeset
84 if e.calls:
30c40ba10963 updating lsprof.py from remote repository
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 2497
diff changeset
85 for j in range(len(e.calls)):
30c40ba10963 updating lsprof.py from remote repository
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 2497
diff changeset
86 se = e.calls[j]
30c40ba10963 updating lsprof.py from remote repository
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 2497
diff changeset
87 if not isinstance(se.code, str):
30c40ba10963 updating lsprof.py from remote repository
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 2497
diff changeset
88 e.calls[j] = type(se)((label(se.code),) + se[1:])
2422
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
89
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
90 _fn2mod = {}
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
91
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
92 def label(code):
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
93 if isinstance(code, str):
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
94 return code
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
95 try:
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
96 mname = _fn2mod[code.co_filename]
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
97 except KeyError:
9314
3f93f6838639 lsprof: make profile not die when imported modules changes (issue1774)
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 7875
diff changeset
98 for k, v in list(sys.modules.iteritems()):
2422
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
99 if v is None:
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
100 continue
14959
b1dcc5ab86cd lsprof: use getattr instead of hasattr
Augie Fackler <durin42@gmail.com>
parents: 12842
diff changeset
101 if not isinstance(getattr(v, '__file__', None), str):
2422
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
102 continue
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
103 if v.__file__.startswith(code.co_filename):
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
104 mname = _fn2mod[code.co_filename] = k
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
105 break
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
106 else:
10339
23e608f42f2c fix spaces/identation issues
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 9316
diff changeset
107 mname = _fn2mod[code.co_filename] = '<%s>' % code.co_filename
2422
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
108
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
109 return '%s:%d(%s)' % (mname, code.co_firstlineno, code.co_name)
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
110
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
111
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
112 if __name__ == '__main__':
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
113 import os
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
114 sys.argv = sys.argv[1:]
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
115 if not sys.argv:
27617
b1a59b80e1a3 lsprof: use print function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27061
diff changeset
116 print("usage: lsprof.py <script> <arguments...>", file=sys.stderr)
2422
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
117 sys.exit(2)
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
118 sys.path.insert(0, os.path.abspath(os.path.dirname(sys.argv[0])))
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
119 stats = profile(execfile, sys.argv[0], globals(), locals())
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
120 stats.sort()
6aa75e77cafe add --lsprof option. 3x faster than --profile, more useful output.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
121 stats.pprint()