annotate mercurial/profiling.py @ 37557:734515aca84d

wireproto: define and implement HTTP handshake to upgrade protocol When clients connect to repositories over HTTP, they issue a request to the well-known URL "?cmd=capabilities" to fetch the repository capabilities. This is the handshake portion of the HTTP protocol. This commit defines a mechanism to use that HTTP request to return information about modern server features. If a client sends an X-HgUpgrade-* header containing a list of client-supported API names, the server responds with a response containing information about available services. This includes the normal capabilities string. So if the server doesn't support any newer services, the client can easily fall back. By advertising supported services from clients, server operators can see and log what client support exists in the wild. This will also help with debugging. The response contains the base path to API services. We know there are potential issues with the <repo>/api/ URL space conflicting with hgwebdir and subrepos. By making the API URL dynamic from the perspective of the client, the URL for APIs is not subject to backwards compatibility concerns - at least as long as a ?cmd=capabilities request is made. We've also defined the ``cbor`` client capability for the X-HgProto-* header. This MUST be sent in order to get the modern response from "?cmd=capabilities". During implementation, I initially always sent an application/mercurial-cbor response. However, the handshake mechanism will be more future compatible if the client is in charge of which formats to request. We already perform content negotiation from X-HgProto-*, so keying off this for the capabilities response feels appropriate. In addition, I initially used application/cbor. However, it is conceivable that a non-Mercurial server could serve application/cbor. To rule out this possibility, I've invented a new media type that is Mercurial specific and can't be confused for generic CBOR. Differential Revision: https://phab.mercurial-scm.org/D3242
author Gregory Szorc <gregory.szorc@gmail.com>
date Tue, 10 Apr 2018 14:29:15 -0700
parents e39953fdd924
children 15a1e37f80bd
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
29781
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
1 # profiling.py - profiling functions
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
2 #
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
3 # Copyright 2016 Gregory Szorc <gregory.szorc@gmail.com>
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
4 #
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
5 # This software may be used and distributed according to the terms of the
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
6 # GNU General Public License version 2 or any later version.
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
7
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
8 from __future__ import absolute_import, print_function
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
9
29783
5d44197c208b profiling: make profiling functions context managers (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29781
diff changeset
10 import contextlib
29781
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
11
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
12 from .i18n import _
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
13 from . import (
30820
6a70cf94d1b5 py3: replace pycompat.getenv with encoding.environ.get
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30664
diff changeset
14 encoding,
29781
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
15 error,
32417
f40dc6f7c12f profiling: allow loading profiling extension before everything else
Jun Wu <quark@fb.com>
parents: 30975
diff changeset
16 extensions,
36683
e39953fdd924 profile: colorize output on Windows
Matt Harbison <matt_harbison@yahoo.com>
parents: 36400
diff changeset
17 pycompat,
29781
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
18 util,
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
19 )
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
20
32417
f40dc6f7c12f profiling: allow loading profiling extension before everything else
Jun Wu <quark@fb.com>
parents: 30975
diff changeset
21 def _loadprofiler(ui, profiler):
f40dc6f7c12f profiling: allow loading profiling extension before everything else
Jun Wu <quark@fb.com>
parents: 30975
diff changeset
22 """load profiler extension. return profile method, or None on failure"""
f40dc6f7c12f profiling: allow loading profiling extension before everything else
Jun Wu <quark@fb.com>
parents: 30975
diff changeset
23 extname = profiler
f40dc6f7c12f profiling: allow loading profiling extension before everything else
Jun Wu <quark@fb.com>
parents: 30975
diff changeset
24 extensions.loadall(ui, whitelist=[extname])
f40dc6f7c12f profiling: allow loading profiling extension before everything else
Jun Wu <quark@fb.com>
parents: 30975
diff changeset
25 try:
f40dc6f7c12f profiling: allow loading profiling extension before everything else
Jun Wu <quark@fb.com>
parents: 30975
diff changeset
26 mod = extensions.find(extname)
f40dc6f7c12f profiling: allow loading profiling extension before everything else
Jun Wu <quark@fb.com>
parents: 30975
diff changeset
27 except KeyError:
f40dc6f7c12f profiling: allow loading profiling extension before everything else
Jun Wu <quark@fb.com>
parents: 30975
diff changeset
28 return None
f40dc6f7c12f profiling: allow loading profiling extension before everything else
Jun Wu <quark@fb.com>
parents: 30975
diff changeset
29 else:
f40dc6f7c12f profiling: allow loading profiling extension before everything else
Jun Wu <quark@fb.com>
parents: 30975
diff changeset
30 return getattr(mod, 'profile', None)
f40dc6f7c12f profiling: allow loading profiling extension before everything else
Jun Wu <quark@fb.com>
parents: 30975
diff changeset
31
29783
5d44197c208b profiling: make profiling functions context managers (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29781
diff changeset
32 @contextlib.contextmanager
5d44197c208b profiling: make profiling functions context managers (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29781
diff changeset
33 def lsprofile(ui, fp):
33499
0407a51b9d8c codemod: register core configitems using a script
Jun Wu <quark@fb.com>
parents: 33195
diff changeset
34 format = ui.config('profiling', 'format')
0407a51b9d8c codemod: register core configitems using a script
Jun Wu <quark@fb.com>
parents: 33195
diff changeset
35 field = ui.config('profiling', 'sort')
0407a51b9d8c codemod: register core configitems using a script
Jun Wu <quark@fb.com>
parents: 33195
diff changeset
36 limit = ui.configint('profiling', 'limit')
0407a51b9d8c codemod: register core configitems using a script
Jun Wu <quark@fb.com>
parents: 33195
diff changeset
37 climit = ui.configint('profiling', 'nested')
29781
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
38
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
39 if format not in ['text', 'kcachegrind']:
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
40 ui.warn(_("unrecognized profiling format '%s'"
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
41 " - Ignored\n") % format)
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
42 format = 'text'
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
43
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
44 try:
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
45 from . import lsprof
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
46 except ImportError:
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
47 raise error.Abort(_(
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
48 'lsprof not available - install from '
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
49 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
50 p = lsprof.Profiler()
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
51 p.enable(subcalls=True)
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
52 try:
29783
5d44197c208b profiling: make profiling functions context managers (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29781
diff changeset
53 yield
29781
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
54 finally:
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
55 p.disable()
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
56
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
57 if format == 'kcachegrind':
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
58 from . import lsprofcalltree
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
59 calltree = lsprofcalltree.KCacheGrind(p)
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
60 calltree.output(fp)
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
61 else:
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
62 # format == 'text'
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
63 stats = lsprof.Stats(p.getstats())
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
64 stats.sort(field)
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
65 stats.pprint(limit=limit, file=fp, climit=climit)
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
66
29783
5d44197c208b profiling: make profiling functions context managers (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29781
diff changeset
67 @contextlib.contextmanager
5d44197c208b profiling: make profiling functions context managers (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29781
diff changeset
68 def flameprofile(ui, fp):
29781
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
69 try:
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
70 from flamegraph import flamegraph
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
71 except ImportError:
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
72 raise error.Abort(_(
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
73 'flamegraph not available - install from '
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
74 'https://github.com/evanhempel/python-flamegraph'))
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
75 # developer config: profiling.freq
33499
0407a51b9d8c codemod: register core configitems using a script
Jun Wu <quark@fb.com>
parents: 33195
diff changeset
76 freq = ui.configint('profiling', 'freq')
29781
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
77 filter_ = None
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
78 collapse_recursion = True
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
79 thread = flamegraph.ProfileThread(fp, 1.0 / freq,
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
80 filter_, collapse_recursion)
30975
22fbca1d11ed mercurial: switch to util.timer for all interval timings
Simon Farnsworth <simonfar@fb.com>
parents: 30930
diff changeset
81 start_time = util.timer()
29781
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
82 try:
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
83 thread.start()
29783
5d44197c208b profiling: make profiling functions context managers (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29781
diff changeset
84 yield
29781
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
85 finally:
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
86 thread.stop()
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
87 thread.join()
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
88 print('Collected %d stack frames (%d unique) in %2.2f seconds.' % (
30975
22fbca1d11ed mercurial: switch to util.timer for all interval timings
Simon Farnsworth <simonfar@fb.com>
parents: 30930
diff changeset
89 util.timer() - start_time, thread.num_frames(),
29781
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
90 thread.num_frames(unique=True)))
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
91
29783
5d44197c208b profiling: make profiling functions context managers (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29781
diff changeset
92 @contextlib.contextmanager
5d44197c208b profiling: make profiling functions context managers (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29781
diff changeset
93 def statprofile(ui, fp):
30316
faf1b8923da2 profiling: use vendored statprof and upstream enhancements (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29785
diff changeset
94 from . import statprof
29781
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
95
33499
0407a51b9d8c codemod: register core configitems using a script
Jun Wu <quark@fb.com>
parents: 33195
diff changeset
96 freq = ui.configint('profiling', 'freq')
29781
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
97 if freq > 0:
29785
88d3c1ab03a7 profiling: don't error with statprof when profiling has already started
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29784
diff changeset
98 # Cannot reset when profiler is already active. So silently no-op.
88d3c1ab03a7 profiling: don't error with statprof when profiling has already started
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29784
diff changeset
99 if statprof.state.profile_level == 0:
88d3c1ab03a7 profiling: don't error with statprof when profiling has already started
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29784
diff changeset
100 statprof.reset(freq)
29781
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
101 else:
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
102 ui.warn(_("invalid sampling frequency '%s' - ignoring\n") % freq)
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
103
30316
faf1b8923da2 profiling: use vendored statprof and upstream enhancements (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29785
diff changeset
104 statprof.start(mechanism='thread')
faf1b8923da2 profiling: use vendored statprof and upstream enhancements (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29785
diff changeset
105
29781
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
106 try:
29783
5d44197c208b profiling: make profiling functions context managers (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29781
diff changeset
107 yield
29781
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
108 finally:
30316
faf1b8923da2 profiling: use vendored statprof and upstream enhancements (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29785
diff changeset
109 data = statprof.stop()
faf1b8923da2 profiling: use vendored statprof and upstream enhancements (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29785
diff changeset
110
33499
0407a51b9d8c codemod: register core configitems using a script
Jun Wu <quark@fb.com>
parents: 33195
diff changeset
111 profformat = ui.config('profiling', 'statformat')
30316
faf1b8923da2 profiling: use vendored statprof and upstream enhancements (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29785
diff changeset
112
faf1b8923da2 profiling: use vendored statprof and upstream enhancements (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29785
diff changeset
113 formats = {
faf1b8923da2 profiling: use vendored statprof and upstream enhancements (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29785
diff changeset
114 'byline': statprof.DisplayFormats.ByLine,
faf1b8923da2 profiling: use vendored statprof and upstream enhancements (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29785
diff changeset
115 'bymethod': statprof.DisplayFormats.ByMethod,
faf1b8923da2 profiling: use vendored statprof and upstream enhancements (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29785
diff changeset
116 'hotpath': statprof.DisplayFormats.Hotpath,
faf1b8923da2 profiling: use vendored statprof and upstream enhancements (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29785
diff changeset
117 'json': statprof.DisplayFormats.Json,
30930
517bc1cd7033 profiling: add statprof support for Chrome trace viewer rendering
Bryan O'Sullivan <bryano@fb.com>
parents: 30820
diff changeset
118 'chrome': statprof.DisplayFormats.Chrome,
30316
faf1b8923da2 profiling: use vendored statprof and upstream enhancements (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29785
diff changeset
119 }
faf1b8923da2 profiling: use vendored statprof and upstream enhancements (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29785
diff changeset
120
faf1b8923da2 profiling: use vendored statprof and upstream enhancements (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29785
diff changeset
121 if profformat in formats:
faf1b8923da2 profiling: use vendored statprof and upstream enhancements (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29785
diff changeset
122 displayformat = formats[profformat]
faf1b8923da2 profiling: use vendored statprof and upstream enhancements (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29785
diff changeset
123 else:
faf1b8923da2 profiling: use vendored statprof and upstream enhancements (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29785
diff changeset
124 ui.warn(_('unknown profiler output format: %s\n') % profformat)
faf1b8923da2 profiling: use vendored statprof and upstream enhancements (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29785
diff changeset
125 displayformat = statprof.DisplayFormats.Hotpath
faf1b8923da2 profiling: use vendored statprof and upstream enhancements (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29785
diff changeset
126
30930
517bc1cd7033 profiling: add statprof support for Chrome trace viewer rendering
Bryan O'Sullivan <bryano@fb.com>
parents: 30820
diff changeset
127 kwargs = {}
517bc1cd7033 profiling: add statprof support for Chrome trace viewer rendering
Bryan O'Sullivan <bryano@fb.com>
parents: 30820
diff changeset
128
517bc1cd7033 profiling: add statprof support for Chrome trace viewer rendering
Bryan O'Sullivan <bryano@fb.com>
parents: 30820
diff changeset
129 def fraction(s):
32978
41b081ac2145 profiling: cope with configwith default value handling changes
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32851
diff changeset
130 if isinstance(s, (float, int)):
41b081ac2145 profiling: cope with configwith default value handling changes
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32851
diff changeset
131 return float(s)
30930
517bc1cd7033 profiling: add statprof support for Chrome trace viewer rendering
Bryan O'Sullivan <bryano@fb.com>
parents: 30820
diff changeset
132 if s.endswith('%'):
517bc1cd7033 profiling: add statprof support for Chrome trace viewer rendering
Bryan O'Sullivan <bryano@fb.com>
parents: 30820
diff changeset
133 v = float(s[:-1]) / 100
517bc1cd7033 profiling: add statprof support for Chrome trace viewer rendering
Bryan O'Sullivan <bryano@fb.com>
parents: 30820
diff changeset
134 else:
517bc1cd7033 profiling: add statprof support for Chrome trace viewer rendering
Bryan O'Sullivan <bryano@fb.com>
parents: 30820
diff changeset
135 v = float(s)
517bc1cd7033 profiling: add statprof support for Chrome trace viewer rendering
Bryan O'Sullivan <bryano@fb.com>
parents: 30820
diff changeset
136 if 0 <= v <= 1:
517bc1cd7033 profiling: add statprof support for Chrome trace viewer rendering
Bryan O'Sullivan <bryano@fb.com>
parents: 30820
diff changeset
137 return v
517bc1cd7033 profiling: add statprof support for Chrome trace viewer rendering
Bryan O'Sullivan <bryano@fb.com>
parents: 30820
diff changeset
138 raise ValueError(s)
517bc1cd7033 profiling: add statprof support for Chrome trace viewer rendering
Bryan O'Sullivan <bryano@fb.com>
parents: 30820
diff changeset
139
517bc1cd7033 profiling: add statprof support for Chrome trace viewer rendering
Bryan O'Sullivan <bryano@fb.com>
parents: 30820
diff changeset
140 if profformat == 'chrome':
517bc1cd7033 profiling: add statprof support for Chrome trace viewer rendering
Bryan O'Sullivan <bryano@fb.com>
parents: 30820
diff changeset
141 showmin = ui.configwith(fraction, 'profiling', 'showmin', 0.005)
34410
fecea78ff2af configitems: register the 'profiling.showmax' config
Boris Feld <boris.feld@octobus.net>
parents: 33499
diff changeset
142 showmax = ui.configwith(fraction, 'profiling', 'showmax')
30930
517bc1cd7033 profiling: add statprof support for Chrome trace viewer rendering
Bryan O'Sullivan <bryano@fb.com>
parents: 30820
diff changeset
143 kwargs.update(minthreshold=showmin, maxthreshold=showmax)
32851
cb6436e051ca profiling: allow configuring minimum display threshold for hotpath
Gregory Szorc <gregory.szorc@gmail.com>
parents: 32810
diff changeset
144 elif profformat == 'hotpath':
33195
5d8942dbe49e check-config: syntax to allow inconsistent config values
Gregory Szorc <gregory.szorc@gmail.com>
parents: 32978
diff changeset
145 # inconsistent config: profiling.showmin
32851
cb6436e051ca profiling: allow configuring minimum display threshold for hotpath
Gregory Szorc <gregory.szorc@gmail.com>
parents: 32810
diff changeset
146 limit = ui.configwith(fraction, 'profiling', 'showmin', 0.05)
36400
7b86aa31b004 py3: fix handling of keyword arguments at more places
Pulkit Goyal <7895pulkit@gmail.com>
parents: 34412
diff changeset
147 kwargs[r'limit'] = limit
30930
517bc1cd7033 profiling: add statprof support for Chrome trace viewer rendering
Bryan O'Sullivan <bryano@fb.com>
parents: 30820
diff changeset
148
517bc1cd7033 profiling: add statprof support for Chrome trace viewer rendering
Bryan O'Sullivan <bryano@fb.com>
parents: 30820
diff changeset
149 statprof.display(fp, data=data, format=displayformat, **kwargs)
29781
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
150
32783
4483696dacee profile: upgrade the "profile" context manager to a full class
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32417
diff changeset
151 class profile(object):
29783
5d44197c208b profiling: make profiling functions context managers (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29781
diff changeset
152 """Start profiling.
5d44197c208b profiling: make profiling functions context managers (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29781
diff changeset
153
5d44197c208b profiling: make profiling functions context managers (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29781
diff changeset
154 Profiling is active when the context manager is active. When the context
5d44197c208b profiling: make profiling functions context managers (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29781
diff changeset
155 manager exits, profiling results will be written to the configured output.
5d44197c208b profiling: make profiling functions context managers (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29781
diff changeset
156 """
32785
37ec8f24d912 profile: introduce a knob to control if the context is actually profiling
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32784
diff changeset
157 def __init__(self, ui, enabled=True):
32783
4483696dacee profile: upgrade the "profile" context manager to a full class
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32417
diff changeset
158 self._ui = ui
4483696dacee profile: upgrade the "profile" context manager to a full class
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32417
diff changeset
159 self._output = None
4483696dacee profile: upgrade the "profile" context manager to a full class
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32417
diff changeset
160 self._fp = None
32805
2b0fc56840d0 profile: use explicit logic to control file closing
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32804
diff changeset
161 self._fpdoclose = True
32783
4483696dacee profile: upgrade the "profile" context manager to a full class
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32417
diff changeset
162 self._profiler = None
32785
37ec8f24d912 profile: introduce a knob to control if the context is actually profiling
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32784
diff changeset
163 self._enabled = enabled
32784
086c1ef0f666 profile: introduce a "start" method to the profile context
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32783
diff changeset
164 self._entered = False
086c1ef0f666 profile: introduce a "start" method to the profile context
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32783
diff changeset
165 self._started = False
29781
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
166
32783
4483696dacee profile: upgrade the "profile" context manager to a full class
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32417
diff changeset
167 def __enter__(self):
32784
086c1ef0f666 profile: introduce a "start" method to the profile context
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32783
diff changeset
168 self._entered = True
32785
37ec8f24d912 profile: introduce a knob to control if the context is actually profiling
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32784
diff changeset
169 if self._enabled:
37ec8f24d912 profile: introduce a knob to control if the context is actually profiling
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32784
diff changeset
170 self.start()
32786
0ead06d54ffe profile: make the contextmanager object available to the callers
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32785
diff changeset
171 return self
32784
086c1ef0f666 profile: introduce a "start" method to the profile context
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32783
diff changeset
172
086c1ef0f666 profile: introduce a "start" method to the profile context
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32783
diff changeset
173 def start(self):
086c1ef0f666 profile: introduce a "start" method to the profile context
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32783
diff changeset
174 """Start profiling.
086c1ef0f666 profile: introduce a "start" method to the profile context
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32783
diff changeset
175
086c1ef0f666 profile: introduce a "start" method to the profile context
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32783
diff changeset
176 The profiling will stop at the context exit.
086c1ef0f666 profile: introduce a "start" method to the profile context
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32783
diff changeset
177
086c1ef0f666 profile: introduce a "start" method to the profile context
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32783
diff changeset
178 If the profiler was already started, this has no effect."""
086c1ef0f666 profile: introduce a "start" method to the profile context
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32783
diff changeset
179 if not self._entered:
086c1ef0f666 profile: introduce a "start" method to the profile context
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32783
diff changeset
180 raise error.ProgrammingError()
086c1ef0f666 profile: introduce a "start" method to the profile context
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32783
diff changeset
181 if self._started:
086c1ef0f666 profile: introduce a "start" method to the profile context
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32783
diff changeset
182 return
086c1ef0f666 profile: introduce a "start" method to the profile context
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32783
diff changeset
183 self._started = True
32783
4483696dacee profile: upgrade the "profile" context manager to a full class
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32417
diff changeset
184 profiler = encoding.environ.get('HGPROF')
4483696dacee profile: upgrade the "profile" context manager to a full class
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32417
diff changeset
185 proffn = None
4483696dacee profile: upgrade the "profile" context manager to a full class
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32417
diff changeset
186 if profiler is None:
34412
83dfbda40e67 configitems: register the 'profiling.type' config
Boris Feld <boris.feld@octobus.net>
parents: 34410
diff changeset
187 profiler = self._ui.config('profiling', 'type')
32783
4483696dacee profile: upgrade the "profile" context manager to a full class
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32417
diff changeset
188 if profiler not in ('ls', 'stat', 'flame'):
4483696dacee profile: upgrade the "profile" context manager to a full class
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32417
diff changeset
189 # try load profiler from extension with the same name
4483696dacee profile: upgrade the "profile" context manager to a full class
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32417
diff changeset
190 proffn = _loadprofiler(self._ui, profiler)
4483696dacee profile: upgrade the "profile" context manager to a full class
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32417
diff changeset
191 if proffn is None:
4483696dacee profile: upgrade the "profile" context manager to a full class
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32417
diff changeset
192 self._ui.warn(_("unrecognized profiler '%s' - ignored\n")
4483696dacee profile: upgrade the "profile" context manager to a full class
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32417
diff changeset
193 % profiler)
4483696dacee profile: upgrade the "profile" context manager to a full class
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32417
diff changeset
194 profiler = 'stat'
29781
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
195
32783
4483696dacee profile: upgrade the "profile" context manager to a full class
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32417
diff changeset
196 self._output = self._ui.config('profiling', 'output')
29781
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
197
32808
336700745a5c profile: close 'fp' on error within '__enter__'
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32807
diff changeset
198 try:
32807
54b356d65079 profile: indent part of '__enter__'
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32806
diff changeset
199 if self._output == 'blackbox':
54b356d65079 profile: indent part of '__enter__'
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32806
diff changeset
200 self._fp = util.stringio()
54b356d65079 profile: indent part of '__enter__'
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32806
diff changeset
201 elif self._output:
54b356d65079 profile: indent part of '__enter__'
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32806
diff changeset
202 path = self._ui.expandpath(self._output)
54b356d65079 profile: indent part of '__enter__'
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32806
diff changeset
203 self._fp = open(path, 'wb')
36683
e39953fdd924 profile: colorize output on Windows
Matt Harbison <matt_harbison@yahoo.com>
parents: 36400
diff changeset
204 elif pycompat.iswindows:
e39953fdd924 profile: colorize output on Windows
Matt Harbison <matt_harbison@yahoo.com>
parents: 36400
diff changeset
205 # parse escape sequence by win32print()
e39953fdd924 profile: colorize output on Windows
Matt Harbison <matt_harbison@yahoo.com>
parents: 36400
diff changeset
206 class uifp(object):
e39953fdd924 profile: colorize output on Windows
Matt Harbison <matt_harbison@yahoo.com>
parents: 36400
diff changeset
207 def __init__(self, ui):
e39953fdd924 profile: colorize output on Windows
Matt Harbison <matt_harbison@yahoo.com>
parents: 36400
diff changeset
208 self._ui = ui
e39953fdd924 profile: colorize output on Windows
Matt Harbison <matt_harbison@yahoo.com>
parents: 36400
diff changeset
209 def write(self, data):
e39953fdd924 profile: colorize output on Windows
Matt Harbison <matt_harbison@yahoo.com>
parents: 36400
diff changeset
210 self._ui.write_err(data)
e39953fdd924 profile: colorize output on Windows
Matt Harbison <matt_harbison@yahoo.com>
parents: 36400
diff changeset
211 def flush(self):
e39953fdd924 profile: colorize output on Windows
Matt Harbison <matt_harbison@yahoo.com>
parents: 36400
diff changeset
212 self._ui.flush()
e39953fdd924 profile: colorize output on Windows
Matt Harbison <matt_harbison@yahoo.com>
parents: 36400
diff changeset
213 self._fpdoclose = False
e39953fdd924 profile: colorize output on Windows
Matt Harbison <matt_harbison@yahoo.com>
parents: 36400
diff changeset
214 self._fp = uifp(self._ui)
32807
54b356d65079 profile: indent part of '__enter__'
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32806
diff changeset
215 else:
54b356d65079 profile: indent part of '__enter__'
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32806
diff changeset
216 self._fpdoclose = False
54b356d65079 profile: indent part of '__enter__'
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32806
diff changeset
217 self._fp = self._ui.ferr
32783
4483696dacee profile: upgrade the "profile" context manager to a full class
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32417
diff changeset
218
32807
54b356d65079 profile: indent part of '__enter__'
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32806
diff changeset
219 if proffn is not None:
54b356d65079 profile: indent part of '__enter__'
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32806
diff changeset
220 pass
54b356d65079 profile: indent part of '__enter__'
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32806
diff changeset
221 elif profiler == 'ls':
54b356d65079 profile: indent part of '__enter__'
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32806
diff changeset
222 proffn = lsprofile
54b356d65079 profile: indent part of '__enter__'
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32806
diff changeset
223 elif profiler == 'flame':
54b356d65079 profile: indent part of '__enter__'
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32806
diff changeset
224 proffn = flameprofile
54b356d65079 profile: indent part of '__enter__'
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32806
diff changeset
225 else:
54b356d65079 profile: indent part of '__enter__'
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32806
diff changeset
226 proffn = statprofile
29783
5d44197c208b profiling: make profiling functions context managers (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29781
diff changeset
227
32807
54b356d65079 profile: indent part of '__enter__'
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32806
diff changeset
228 self._profiler = proffn(self._ui, self._fp)
54b356d65079 profile: indent part of '__enter__'
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32806
diff changeset
229 self._profiler.__enter__()
32808
336700745a5c profile: close 'fp' on error within '__enter__'
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32807
diff changeset
230 except: # re-raises
336700745a5c profile: close 'fp' on error within '__enter__'
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32807
diff changeset
231 self._closefp()
336700745a5c profile: close 'fp' on error within '__enter__'
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32807
diff changeset
232 raise
29783
5d44197c208b profiling: make profiling functions context managers (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29781
diff changeset
233
32783
4483696dacee profile: upgrade the "profile" context manager to a full class
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32417
diff changeset
234 def __exit__(self, exception_type, exception_value, traceback):
32810
6675d23da748 profile: properly propagate exception from the sub-context manager
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32809
diff changeset
235 propagate = None
32809
062eb859d3ee profile: close 'fp' in all cases
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32808
diff changeset
236 if self._profiler is not None:
32810
6675d23da748 profile: properly propagate exception from the sub-context manager
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32809
diff changeset
237 propagate = self._profiler.__exit__(exception_type, exception_value,
6675d23da748 profile: properly propagate exception from the sub-context manager
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32809
diff changeset
238 traceback)
32809
062eb859d3ee profile: close 'fp' in all cases
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32808
diff changeset
239 if self._output == 'blackbox':
062eb859d3ee profile: close 'fp' in all cases
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32808
diff changeset
240 val = 'Profile:\n%s' % self._fp.getvalue()
062eb859d3ee profile: close 'fp' in all cases
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32808
diff changeset
241 # ui.log treats the input as a format string,
062eb859d3ee profile: close 'fp' in all cases
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32808
diff changeset
242 # so we need to escape any % signs.
062eb859d3ee profile: close 'fp' in all cases
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32808
diff changeset
243 val = val.replace('%', '%%')
062eb859d3ee profile: close 'fp' in all cases
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32808
diff changeset
244 self._ui.log('profile', val)
32806
3a4c677cbd6e profile: remove now useless indent
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32805
diff changeset
245 self._closefp()
32810
6675d23da748 profile: properly propagate exception from the sub-context manager
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32809
diff changeset
246 return propagate
32804
c0b2c8f25ad9 profiling: move 'fp' closing logic into its own function
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32788
diff changeset
247
c0b2c8f25ad9 profiling: move 'fp' closing logic into its own function
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32788
diff changeset
248 def _closefp(self):
32805
2b0fc56840d0 profile: use explicit logic to control file closing
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32804
diff changeset
249 if self._fpdoclose and self._fp is not None:
2b0fc56840d0 profile: use explicit logic to control file closing
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32804
diff changeset
250 self._fp.close()