comparison mercurial/profiling.py @ 43076:2372284d9457

formatting: blacken the codebase This is using my patch to black (https://github.com/psf/black/pull/826) so we don't un-wrap collection literals. Done with: hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**"' | xargs black -S # skip-blame mass-reformatting only # no-check-commit reformats foo_bar functions Differential Revision: https://phab.mercurial-scm.org/D6971
author Augie Fackler <augie@google.com>
date Sun, 06 Oct 2019 09:45:02 -0400
parents 0ae593e791fb
children 687b865b95ad
comparison
equal deleted inserted replaced
43075:57875cf423c9 43076:2372284d9457
16 extensions, 16 extensions,
17 pycompat, 17 pycompat,
18 util, 18 util,
19 ) 19 )
20 20
21
21 def _loadprofiler(ui, profiler): 22 def _loadprofiler(ui, profiler):
22 """load profiler extension. return profile method, or None on failure""" 23 """load profiler extension. return profile method, or None on failure"""
23 extname = profiler 24 extname = profiler
24 extensions.loadall(ui, whitelist=[extname]) 25 extensions.loadall(ui, whitelist=[extname])
25 try: 26 try:
26 mod = extensions.find(extname) 27 mod = extensions.find(extname)
27 except KeyError: 28 except KeyError:
28 return None 29 return None
29 else: 30 else:
30 return getattr(mod, 'profile', None) 31 return getattr(mod, 'profile', None)
32
31 33
32 @contextlib.contextmanager 34 @contextlib.contextmanager
33 def lsprofile(ui, fp): 35 def lsprofile(ui, fp):
34 format = ui.config('profiling', 'format') 36 format = ui.config('profiling', 'format')
35 field = ui.config('profiling', 'sort') 37 field = ui.config('profiling', 'sort')
36 limit = ui.configint('profiling', 'limit') 38 limit = ui.configint('profiling', 'limit')
37 climit = ui.configint('profiling', 'nested') 39 climit = ui.configint('profiling', 'nested')
38 40
39 if format not in ['text', 'kcachegrind']: 41 if format not in ['text', 'kcachegrind']:
40 ui.warn(_("unrecognized profiling format '%s'" 42 ui.warn(_("unrecognized profiling format '%s'" " - Ignored\n") % format)
41 " - Ignored\n") % format)
42 format = 'text' 43 format = 'text'
43 44
44 try: 45 try:
45 from . import lsprof 46 from . import lsprof
46 except ImportError: 47 except ImportError:
47 raise error.Abort(_( 48 raise error.Abort(
48 'lsprof not available - install from ' 49 _(
49 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/')) 50 'lsprof not available - install from '
51 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'
52 )
53 )
50 p = lsprof.Profiler() 54 p = lsprof.Profiler()
51 p.enable(subcalls=True) 55 p.enable(subcalls=True)
52 try: 56 try:
53 yield 57 yield
54 finally: 58 finally:
55 p.disable() 59 p.disable()
56 60
57 if format == 'kcachegrind': 61 if format == 'kcachegrind':
58 from . import lsprofcalltree 62 from . import lsprofcalltree
63
59 calltree = lsprofcalltree.KCacheGrind(p) 64 calltree = lsprofcalltree.KCacheGrind(p)
60 calltree.output(fp) 65 calltree.output(fp)
61 else: 66 else:
62 # format == 'text' 67 # format == 'text'
63 stats = lsprof.Stats(p.getstats()) 68 stats = lsprof.Stats(p.getstats())
64 stats.sort(pycompat.sysstr(field)) 69 stats.sort(pycompat.sysstr(field))
65 stats.pprint(limit=limit, file=fp, climit=climit) 70 stats.pprint(limit=limit, file=fp, climit=climit)
66 71
72
67 @contextlib.contextmanager 73 @contextlib.contextmanager
68 def flameprofile(ui, fp): 74 def flameprofile(ui, fp):
69 try: 75 try:
70 from flamegraph import flamegraph 76 from flamegraph import flamegraph
71 except ImportError: 77 except ImportError:
72 raise error.Abort(_( 78 raise error.Abort(
73 'flamegraph not available - install from ' 79 _(
74 'https://github.com/evanhempel/python-flamegraph')) 80 'flamegraph not available - install from '
81 'https://github.com/evanhempel/python-flamegraph'
82 )
83 )
75 # developer config: profiling.freq 84 # developer config: profiling.freq
76 freq = ui.configint('profiling', 'freq') 85 freq = ui.configint('profiling', 'freq')
77 filter_ = None 86 filter_ = None
78 collapse_recursion = True 87 collapse_recursion = True
79 thread = flamegraph.ProfileThread(fp, 1.0 / freq, 88 thread = flamegraph.ProfileThread(
80 filter_, collapse_recursion) 89 fp, 1.0 / freq, filter_, collapse_recursion
90 )
81 start_time = util.timer() 91 start_time = util.timer()
82 try: 92 try:
83 thread.start() 93 thread.start()
84 yield 94 yield
85 finally: 95 finally:
86 thread.stop() 96 thread.stop()
87 thread.join() 97 thread.join()
88 print('Collected %d stack frames (%d unique) in %2.2f seconds.' % ( 98 print(
89 util.timer() - start_time, thread.num_frames(), 99 'Collected %d stack frames (%d unique) in %2.2f seconds.'
90 thread.num_frames(unique=True))) 100 % (
101 util.timer() - start_time,
102 thread.num_frames(),
103 thread.num_frames(unique=True),
104 )
105 )
106
91 107
92 @contextlib.contextmanager 108 @contextlib.contextmanager
93 def statprofile(ui, fp): 109 def statprofile(ui, fp):
94 from . import statprof 110 from . import statprof
95 111
99 if statprof.state.profile_level == 0: 115 if statprof.state.profile_level == 0:
100 statprof.reset(freq) 116 statprof.reset(freq)
101 else: 117 else:
102 ui.warn(_("invalid sampling frequency '%s' - ignoring\n") % freq) 118 ui.warn(_("invalid sampling frequency '%s' - ignoring\n") % freq)
103 119
104 track = ui.config('profiling', 'time-track', 120 track = ui.config(
105 pycompat.iswindows and 'cpu' or 'real') 121 'profiling', 'time-track', pycompat.iswindows and 'cpu' or 'real'
122 )
106 statprof.start(mechanism='thread', track=track) 123 statprof.start(mechanism='thread', track=track)
107 124
108 try: 125 try:
109 yield 126 yield
110 finally: 127 finally:
150 showtime = ui.configbool('profiling', 'showtime') 167 showtime = ui.configbool('profiling', 'showtime')
151 kwargs[r'showtime'] = showtime 168 kwargs[r'showtime'] = showtime
152 169
153 statprof.display(fp, data=data, format=displayformat, **kwargs) 170 statprof.display(fp, data=data, format=displayformat, **kwargs)
154 171
172
155 class profile(object): 173 class profile(object):
156 """Start profiling. 174 """Start profiling.
157 175
158 Profiling is active when the context manager is active. When the context 176 Profiling is active when the context manager is active. When the context
159 manager exits, profiling results will be written to the configured output. 177 manager exits, profiling results will be written to the configured output.
160 """ 178 """
179
161 def __init__(self, ui, enabled=True): 180 def __init__(self, ui, enabled=True):
162 self._ui = ui 181 self._ui = ui
163 self._output = None 182 self._output = None
164 self._fp = None 183 self._fp = None
165 self._fpdoclose = True 184 self._fpdoclose = True
191 profiler = self._ui.config('profiling', 'type') 210 profiler = self._ui.config('profiling', 'type')
192 if profiler not in ('ls', 'stat', 'flame'): 211 if profiler not in ('ls', 'stat', 'flame'):
193 # try load profiler from extension with the same name 212 # try load profiler from extension with the same name
194 proffn = _loadprofiler(self._ui, profiler) 213 proffn = _loadprofiler(self._ui, profiler)
195 if proffn is None: 214 if proffn is None:
196 self._ui.warn(_("unrecognized profiler '%s' - ignored\n") 215 self._ui.warn(
197 % profiler) 216 _("unrecognized profiler '%s' - ignored\n") % profiler
217 )
198 profiler = 'stat' 218 profiler = 'stat'
199 219
200 self._output = self._ui.config('profiling', 'output') 220 self._output = self._ui.config('profiling', 'output')
201 221
202 try: 222 try:
208 elif pycompat.iswindows: 228 elif pycompat.iswindows:
209 # parse escape sequence by win32print() 229 # parse escape sequence by win32print()
210 class uifp(object): 230 class uifp(object):
211 def __init__(self, ui): 231 def __init__(self, ui):
212 self._ui = ui 232 self._ui = ui
233
213 def write(self, data): 234 def write(self, data):
214 self._ui.write_err(data) 235 self._ui.write_err(data)
236
215 def flush(self): 237 def flush(self):
216 self._ui.flush() 238 self._ui.flush()
239
217 self._fpdoclose = False 240 self._fpdoclose = False
218 self._fp = uifp(self._ui) 241 self._fp = uifp(self._ui)
219 else: 242 else:
220 self._fpdoclose = False 243 self._fpdoclose = False
221 self._fp = self._ui.ferr 244 self._fp = self._ui.ferr
229 else: 252 else:
230 proffn = statprofile 253 proffn = statprofile
231 254
232 self._profiler = proffn(self._ui, self._fp) 255 self._profiler = proffn(self._ui, self._fp)
233 self._profiler.__enter__() 256 self._profiler.__enter__()
234 except: # re-raises 257 except: # re-raises
235 self._closefp() 258 self._closefp()
236 raise 259 raise
237 260
238 def __exit__(self, exception_type, exception_value, traceback): 261 def __exit__(self, exception_type, exception_value, traceback):
239 propagate = None 262 propagate = None
240 if self._profiler is not None: 263 if self._profiler is not None:
241 propagate = self._profiler.__exit__(exception_type, exception_value, 264 propagate = self._profiler.__exit__(
242 traceback) 265 exception_type, exception_value, traceback
266 )
243 if self._output == 'blackbox': 267 if self._output == 'blackbox':
244 val = 'Profile:\n%s' % self._fp.getvalue() 268 val = 'Profile:\n%s' % self._fp.getvalue()
245 # ui.log treats the input as a format string, 269 # ui.log treats the input as a format string,
246 # so we need to escape any % signs. 270 # so we need to escape any % signs.
247 val = val.replace('%', '%%') 271 val = val.replace('%', '%%')