##// END OF EJS Templates
perfphases: add 'perfphases' command...
marmoute -
r32467:ad37c569 default
parent child Browse files
Show More
@@ -1,1345 +1,1356
1 # perf.py - performance test routines
1 # perf.py - performance test routines
2 '''helper extension to measure performance'''
2 '''helper extension to measure performance'''
3
3
4 # "historical portability" policy of perf.py:
4 # "historical portability" policy of perf.py:
5 #
5 #
6 # We have to do:
6 # We have to do:
7 # - make perf.py "loadable" with as wide Mercurial version as possible
7 # - make perf.py "loadable" with as wide Mercurial version as possible
8 # This doesn't mean that perf commands work correctly with that Mercurial.
8 # This doesn't mean that perf commands work correctly with that Mercurial.
9 # BTW, perf.py itself has been available since 1.1 (or eb240755386d).
9 # BTW, perf.py itself has been available since 1.1 (or eb240755386d).
10 # - make historical perf command work correctly with as wide Mercurial
10 # - make historical perf command work correctly with as wide Mercurial
11 # version as possible
11 # version as possible
12 #
12 #
13 # We have to do, if possible with reasonable cost:
13 # We have to do, if possible with reasonable cost:
14 # - make recent perf command for historical feature work correctly
14 # - make recent perf command for historical feature work correctly
15 # with early Mercurial
15 # with early Mercurial
16 #
16 #
17 # We don't have to do:
17 # We don't have to do:
18 # - make perf command for recent feature work correctly with early
18 # - make perf command for recent feature work correctly with early
19 # Mercurial
19 # Mercurial
20
20
21 from __future__ import absolute_import
21 from __future__ import absolute_import
22 import functools
22 import functools
23 import gc
23 import gc
24 import os
24 import os
25 import random
25 import random
26 import sys
26 import sys
27 import time
27 import time
28 from mercurial import (
28 from mercurial import (
29 changegroup,
29 changegroup,
30 cmdutil,
30 cmdutil,
31 commands,
31 commands,
32 copies,
32 copies,
33 error,
33 error,
34 extensions,
34 extensions,
35 mdiff,
35 mdiff,
36 merge,
36 merge,
37 util,
37 util,
38 )
38 )
39
39
40 # for "historical portability":
40 # for "historical portability":
41 # try to import modules separately (in dict order), and ignore
41 # try to import modules separately (in dict order), and ignore
42 # failure, because these aren't available with early Mercurial
42 # failure, because these aren't available with early Mercurial
43 try:
43 try:
44 from mercurial import branchmap # since 2.5 (or bcee63733aad)
44 from mercurial import branchmap # since 2.5 (or bcee63733aad)
45 except ImportError:
45 except ImportError:
46 pass
46 pass
47 try:
47 try:
48 from mercurial import obsolete # since 2.3 (or ad0d6c2b3279)
48 from mercurial import obsolete # since 2.3 (or ad0d6c2b3279)
49 except ImportError:
49 except ImportError:
50 pass
50 pass
51 try:
51 try:
52 from mercurial import registrar # since 3.7 (or 37d50250b696)
52 from mercurial import registrar # since 3.7 (or 37d50250b696)
53 dir(registrar) # forcibly load it
53 dir(registrar) # forcibly load it
54 except ImportError:
54 except ImportError:
55 registrar = None
55 registrar = None
56 try:
56 try:
57 from mercurial import repoview # since 2.5 (or 3a6ddacb7198)
57 from mercurial import repoview # since 2.5 (or 3a6ddacb7198)
58 except ImportError:
58 except ImportError:
59 pass
59 pass
60 try:
60 try:
61 from mercurial import scmutil # since 1.9 (or 8b252e826c68)
61 from mercurial import scmutil # since 1.9 (or 8b252e826c68)
62 except ImportError:
62 except ImportError:
63 pass
63 pass
64
64
65 # for "historical portability":
65 # for "historical portability":
66 # define util.safehasattr forcibly, because util.safehasattr has been
66 # define util.safehasattr forcibly, because util.safehasattr has been
67 # available since 1.9.3 (or 94b200a11cf7)
67 # available since 1.9.3 (or 94b200a11cf7)
68 _undefined = object()
68 _undefined = object()
69 def safehasattr(thing, attr):
69 def safehasattr(thing, attr):
70 return getattr(thing, attr, _undefined) is not _undefined
70 return getattr(thing, attr, _undefined) is not _undefined
71 setattr(util, 'safehasattr', safehasattr)
71 setattr(util, 'safehasattr', safehasattr)
72
72
73 # for "historical portability":
73 # for "historical portability":
74 # define util.timer forcibly, because util.timer has been available
74 # define util.timer forcibly, because util.timer has been available
75 # since ae5d60bb70c9
75 # since ae5d60bb70c9
76 if safehasattr(time, 'perf_counter'):
76 if safehasattr(time, 'perf_counter'):
77 util.timer = time.perf_counter
77 util.timer = time.perf_counter
78 elif os.name == 'nt':
78 elif os.name == 'nt':
79 util.timer = time.clock
79 util.timer = time.clock
80 else:
80 else:
81 util.timer = time.time
81 util.timer = time.time
82
82
83 # for "historical portability":
83 # for "historical portability":
84 # use locally defined empty option list, if formatteropts isn't
84 # use locally defined empty option list, if formatteropts isn't
85 # available, because commands.formatteropts has been available since
85 # available, because commands.formatteropts has been available since
86 # 3.2 (or 7a7eed5176a4), even though formatting itself has been
86 # 3.2 (or 7a7eed5176a4), even though formatting itself has been
87 # available since 2.2 (or ae5f92e154d3)
87 # available since 2.2 (or ae5f92e154d3)
88 formatteropts = getattr(cmdutil, "formatteropts",
88 formatteropts = getattr(cmdutil, "formatteropts",
89 getattr(commands, "formatteropts", []))
89 getattr(commands, "formatteropts", []))
90
90
91 # for "historical portability":
91 # for "historical portability":
92 # use locally defined option list, if debugrevlogopts isn't available,
92 # use locally defined option list, if debugrevlogopts isn't available,
93 # because commands.debugrevlogopts has been available since 3.7 (or
93 # because commands.debugrevlogopts has been available since 3.7 (or
94 # 5606f7d0d063), even though cmdutil.openrevlog() has been available
94 # 5606f7d0d063), even though cmdutil.openrevlog() has been available
95 # since 1.9 (or a79fea6b3e77).
95 # since 1.9 (or a79fea6b3e77).
96 revlogopts = getattr(cmdutil, "debugrevlogopts",
96 revlogopts = getattr(cmdutil, "debugrevlogopts",
97 getattr(commands, "debugrevlogopts", [
97 getattr(commands, "debugrevlogopts", [
98 ('c', 'changelog', False, ('open changelog')),
98 ('c', 'changelog', False, ('open changelog')),
99 ('m', 'manifest', False, ('open manifest')),
99 ('m', 'manifest', False, ('open manifest')),
100 ('', 'dir', False, ('open directory manifest')),
100 ('', 'dir', False, ('open directory manifest')),
101 ]))
101 ]))
102
102
103 cmdtable = {}
103 cmdtable = {}
104
104
105 # for "historical portability":
105 # for "historical portability":
106 # define parsealiases locally, because cmdutil.parsealiases has been
106 # define parsealiases locally, because cmdutil.parsealiases has been
107 # available since 1.5 (or 6252852b4332)
107 # available since 1.5 (or 6252852b4332)
108 def parsealiases(cmd):
108 def parsealiases(cmd):
109 return cmd.lstrip("^").split("|")
109 return cmd.lstrip("^").split("|")
110
110
111 if safehasattr(registrar, 'command'):
111 if safehasattr(registrar, 'command'):
112 command = registrar.command(cmdtable)
112 command = registrar.command(cmdtable)
113 elif safehasattr(cmdutil, 'command'):
113 elif safehasattr(cmdutil, 'command'):
114 import inspect
114 import inspect
115 command = cmdutil.command(cmdtable)
115 command = cmdutil.command(cmdtable)
116 if 'norepo' not in inspect.getargspec(command)[0]:
116 if 'norepo' not in inspect.getargspec(command)[0]:
117 # for "historical portability":
117 # for "historical portability":
118 # wrap original cmdutil.command, because "norepo" option has
118 # wrap original cmdutil.command, because "norepo" option has
119 # been available since 3.1 (or 75a96326cecb)
119 # been available since 3.1 (or 75a96326cecb)
120 _command = command
120 _command = command
121 def command(name, options=(), synopsis=None, norepo=False):
121 def command(name, options=(), synopsis=None, norepo=False):
122 if norepo:
122 if norepo:
123 commands.norepo += ' %s' % ' '.join(parsealiases(name))
123 commands.norepo += ' %s' % ' '.join(parsealiases(name))
124 return _command(name, list(options), synopsis)
124 return _command(name, list(options), synopsis)
125 else:
125 else:
126 # for "historical portability":
126 # for "historical portability":
127 # define "@command" annotation locally, because cmdutil.command
127 # define "@command" annotation locally, because cmdutil.command
128 # has been available since 1.9 (or 2daa5179e73f)
128 # has been available since 1.9 (or 2daa5179e73f)
129 def command(name, options=(), synopsis=None, norepo=False):
129 def command(name, options=(), synopsis=None, norepo=False):
130 def decorator(func):
130 def decorator(func):
131 if synopsis:
131 if synopsis:
132 cmdtable[name] = func, list(options), synopsis
132 cmdtable[name] = func, list(options), synopsis
133 else:
133 else:
134 cmdtable[name] = func, list(options)
134 cmdtable[name] = func, list(options)
135 if norepo:
135 if norepo:
136 commands.norepo += ' %s' % ' '.join(parsealiases(name))
136 commands.norepo += ' %s' % ' '.join(parsealiases(name))
137 return func
137 return func
138 return decorator
138 return decorator
139
139
140 def getlen(ui):
140 def getlen(ui):
141 if ui.configbool("perf", "stub"):
141 if ui.configbool("perf", "stub"):
142 return lambda x: 1
142 return lambda x: 1
143 return len
143 return len
144
144
145 def gettimer(ui, opts=None):
145 def gettimer(ui, opts=None):
146 """return a timer function and formatter: (timer, formatter)
146 """return a timer function and formatter: (timer, formatter)
147
147
148 This function exists to gather the creation of formatter in a single
148 This function exists to gather the creation of formatter in a single
149 place instead of duplicating it in all performance commands."""
149 place instead of duplicating it in all performance commands."""
150
150
151 # enforce an idle period before execution to counteract power management
151 # enforce an idle period before execution to counteract power management
152 # experimental config: perf.presleep
152 # experimental config: perf.presleep
153 time.sleep(getint(ui, "perf", "presleep", 1))
153 time.sleep(getint(ui, "perf", "presleep", 1))
154
154
155 if opts is None:
155 if opts is None:
156 opts = {}
156 opts = {}
157 # redirect all to stderr unless buffer api is in use
157 # redirect all to stderr unless buffer api is in use
158 if not ui._buffers:
158 if not ui._buffers:
159 ui = ui.copy()
159 ui = ui.copy()
160 uifout = safeattrsetter(ui, 'fout', ignoremissing=True)
160 uifout = safeattrsetter(ui, 'fout', ignoremissing=True)
161 if uifout:
161 if uifout:
162 # for "historical portability":
162 # for "historical portability":
163 # ui.fout/ferr have been available since 1.9 (or 4e1ccd4c2b6d)
163 # ui.fout/ferr have been available since 1.9 (or 4e1ccd4c2b6d)
164 uifout.set(ui.ferr)
164 uifout.set(ui.ferr)
165
165
166 # get a formatter
166 # get a formatter
167 uiformatter = getattr(ui, 'formatter', None)
167 uiformatter = getattr(ui, 'formatter', None)
168 if uiformatter:
168 if uiformatter:
169 fm = uiformatter('perf', opts)
169 fm = uiformatter('perf', opts)
170 else:
170 else:
171 # for "historical portability":
171 # for "historical portability":
172 # define formatter locally, because ui.formatter has been
172 # define formatter locally, because ui.formatter has been
173 # available since 2.2 (or ae5f92e154d3)
173 # available since 2.2 (or ae5f92e154d3)
174 from mercurial import node
174 from mercurial import node
175 class defaultformatter(object):
175 class defaultformatter(object):
176 """Minimized composition of baseformatter and plainformatter
176 """Minimized composition of baseformatter and plainformatter
177 """
177 """
178 def __init__(self, ui, topic, opts):
178 def __init__(self, ui, topic, opts):
179 self._ui = ui
179 self._ui = ui
180 if ui.debugflag:
180 if ui.debugflag:
181 self.hexfunc = node.hex
181 self.hexfunc = node.hex
182 else:
182 else:
183 self.hexfunc = node.short
183 self.hexfunc = node.short
184 def __nonzero__(self):
184 def __nonzero__(self):
185 return False
185 return False
186 __bool__ = __nonzero__
186 __bool__ = __nonzero__
187 def startitem(self):
187 def startitem(self):
188 pass
188 pass
189 def data(self, **data):
189 def data(self, **data):
190 pass
190 pass
191 def write(self, fields, deftext, *fielddata, **opts):
191 def write(self, fields, deftext, *fielddata, **opts):
192 self._ui.write(deftext % fielddata, **opts)
192 self._ui.write(deftext % fielddata, **opts)
193 def condwrite(self, cond, fields, deftext, *fielddata, **opts):
193 def condwrite(self, cond, fields, deftext, *fielddata, **opts):
194 if cond:
194 if cond:
195 self._ui.write(deftext % fielddata, **opts)
195 self._ui.write(deftext % fielddata, **opts)
196 def plain(self, text, **opts):
196 def plain(self, text, **opts):
197 self._ui.write(text, **opts)
197 self._ui.write(text, **opts)
198 def end(self):
198 def end(self):
199 pass
199 pass
200 fm = defaultformatter(ui, 'perf', opts)
200 fm = defaultformatter(ui, 'perf', opts)
201
201
202 # stub function, runs code only once instead of in a loop
202 # stub function, runs code only once instead of in a loop
203 # experimental config: perf.stub
203 # experimental config: perf.stub
204 if ui.configbool("perf", "stub"):
204 if ui.configbool("perf", "stub"):
205 return functools.partial(stub_timer, fm), fm
205 return functools.partial(stub_timer, fm), fm
206 return functools.partial(_timer, fm), fm
206 return functools.partial(_timer, fm), fm
207
207
208 def stub_timer(fm, func, title=None):
208 def stub_timer(fm, func, title=None):
209 func()
209 func()
210
210
211 def _timer(fm, func, title=None):
211 def _timer(fm, func, title=None):
212 gc.collect()
212 gc.collect()
213 results = []
213 results = []
214 begin = util.timer()
214 begin = util.timer()
215 count = 0
215 count = 0
216 while True:
216 while True:
217 ostart = os.times()
217 ostart = os.times()
218 cstart = util.timer()
218 cstart = util.timer()
219 r = func()
219 r = func()
220 cstop = util.timer()
220 cstop = util.timer()
221 ostop = os.times()
221 ostop = os.times()
222 count += 1
222 count += 1
223 a, b = ostart, ostop
223 a, b = ostart, ostop
224 results.append((cstop - cstart, b[0] - a[0], b[1]-a[1]))
224 results.append((cstop - cstart, b[0] - a[0], b[1]-a[1]))
225 if cstop - begin > 3 and count >= 100:
225 if cstop - begin > 3 and count >= 100:
226 break
226 break
227 if cstop - begin > 10 and count >= 3:
227 if cstop - begin > 10 and count >= 3:
228 break
228 break
229
229
230 fm.startitem()
230 fm.startitem()
231
231
232 if title:
232 if title:
233 fm.write('title', '! %s\n', title)
233 fm.write('title', '! %s\n', title)
234 if r:
234 if r:
235 fm.write('result', '! result: %s\n', r)
235 fm.write('result', '! result: %s\n', r)
236 m = min(results)
236 m = min(results)
237 fm.plain('!')
237 fm.plain('!')
238 fm.write('wall', ' wall %f', m[0])
238 fm.write('wall', ' wall %f', m[0])
239 fm.write('comb', ' comb %f', m[1] + m[2])
239 fm.write('comb', ' comb %f', m[1] + m[2])
240 fm.write('user', ' user %f', m[1])
240 fm.write('user', ' user %f', m[1])
241 fm.write('sys', ' sys %f', m[2])
241 fm.write('sys', ' sys %f', m[2])
242 fm.write('count', ' (best of %d)', count)
242 fm.write('count', ' (best of %d)', count)
243 fm.plain('\n')
243 fm.plain('\n')
244
244
245 # utilities for historical portability
245 # utilities for historical portability
246
246
247 def getint(ui, section, name, default):
247 def getint(ui, section, name, default):
248 # for "historical portability":
248 # for "historical portability":
249 # ui.configint has been available since 1.9 (or fa2b596db182)
249 # ui.configint has been available since 1.9 (or fa2b596db182)
250 v = ui.config(section, name, None)
250 v = ui.config(section, name, None)
251 if v is None:
251 if v is None:
252 return default
252 return default
253 try:
253 try:
254 return int(v)
254 return int(v)
255 except ValueError:
255 except ValueError:
256 raise error.ConfigError(("%s.%s is not an integer ('%s')")
256 raise error.ConfigError(("%s.%s is not an integer ('%s')")
257 % (section, name, v))
257 % (section, name, v))
258
258
259 def safeattrsetter(obj, name, ignoremissing=False):
259 def safeattrsetter(obj, name, ignoremissing=False):
260 """Ensure that 'obj' has 'name' attribute before subsequent setattr
260 """Ensure that 'obj' has 'name' attribute before subsequent setattr
261
261
262 This function is aborted, if 'obj' doesn't have 'name' attribute
262 This function is aborted, if 'obj' doesn't have 'name' attribute
263 at runtime. This avoids overlooking removal of an attribute, which
263 at runtime. This avoids overlooking removal of an attribute, which
264 breaks assumption of performance measurement, in the future.
264 breaks assumption of performance measurement, in the future.
265
265
266 This function returns the object to (1) assign a new value, and
266 This function returns the object to (1) assign a new value, and
267 (2) restore an original value to the attribute.
267 (2) restore an original value to the attribute.
268
268
269 If 'ignoremissing' is true, missing 'name' attribute doesn't cause
269 If 'ignoremissing' is true, missing 'name' attribute doesn't cause
270 abortion, and this function returns None. This is useful to
270 abortion, and this function returns None. This is useful to
271 examine an attribute, which isn't ensured in all Mercurial
271 examine an attribute, which isn't ensured in all Mercurial
272 versions.
272 versions.
273 """
273 """
274 if not util.safehasattr(obj, name):
274 if not util.safehasattr(obj, name):
275 if ignoremissing:
275 if ignoremissing:
276 return None
276 return None
277 raise error.Abort(("missing attribute %s of %s might break assumption"
277 raise error.Abort(("missing attribute %s of %s might break assumption"
278 " of performance measurement") % (name, obj))
278 " of performance measurement") % (name, obj))
279
279
280 origvalue = getattr(obj, name)
280 origvalue = getattr(obj, name)
281 class attrutil(object):
281 class attrutil(object):
282 def set(self, newvalue):
282 def set(self, newvalue):
283 setattr(obj, name, newvalue)
283 setattr(obj, name, newvalue)
284 def restore(self):
284 def restore(self):
285 setattr(obj, name, origvalue)
285 setattr(obj, name, origvalue)
286
286
287 return attrutil()
287 return attrutil()
288
288
289 # utilities to examine each internal API changes
289 # utilities to examine each internal API changes
290
290
291 def getbranchmapsubsettable():
291 def getbranchmapsubsettable():
292 # for "historical portability":
292 # for "historical portability":
293 # subsettable is defined in:
293 # subsettable is defined in:
294 # - branchmap since 2.9 (or 175c6fd8cacc)
294 # - branchmap since 2.9 (or 175c6fd8cacc)
295 # - repoview since 2.5 (or 59a9f18d4587)
295 # - repoview since 2.5 (or 59a9f18d4587)
296 for mod in (branchmap, repoview):
296 for mod in (branchmap, repoview):
297 subsettable = getattr(mod, 'subsettable', None)
297 subsettable = getattr(mod, 'subsettable', None)
298 if subsettable:
298 if subsettable:
299 return subsettable
299 return subsettable
300
300
301 # bisecting in bcee63733aad::59a9f18d4587 can reach here (both
301 # bisecting in bcee63733aad::59a9f18d4587 can reach here (both
302 # branchmap and repoview modules exist, but subsettable attribute
302 # branchmap and repoview modules exist, but subsettable attribute
303 # doesn't)
303 # doesn't)
304 raise error.Abort(("perfbranchmap not available with this Mercurial"),
304 raise error.Abort(("perfbranchmap not available with this Mercurial"),
305 hint="use 2.5 or later")
305 hint="use 2.5 or later")
306
306
307 def getsvfs(repo):
307 def getsvfs(repo):
308 """Return appropriate object to access files under .hg/store
308 """Return appropriate object to access files under .hg/store
309 """
309 """
310 # for "historical portability":
310 # for "historical portability":
311 # repo.svfs has been available since 2.3 (or 7034365089bf)
311 # repo.svfs has been available since 2.3 (or 7034365089bf)
312 svfs = getattr(repo, 'svfs', None)
312 svfs = getattr(repo, 'svfs', None)
313 if svfs:
313 if svfs:
314 return svfs
314 return svfs
315 else:
315 else:
316 return getattr(repo, 'sopener')
316 return getattr(repo, 'sopener')
317
317
318 def getvfs(repo):
318 def getvfs(repo):
319 """Return appropriate object to access files under .hg
319 """Return appropriate object to access files under .hg
320 """
320 """
321 # for "historical portability":
321 # for "historical portability":
322 # repo.vfs has been available since 2.3 (or 7034365089bf)
322 # repo.vfs has been available since 2.3 (or 7034365089bf)
323 vfs = getattr(repo, 'vfs', None)
323 vfs = getattr(repo, 'vfs', None)
324 if vfs:
324 if vfs:
325 return vfs
325 return vfs
326 else:
326 else:
327 return getattr(repo, 'opener')
327 return getattr(repo, 'opener')
328
328
329 def repocleartagscachefunc(repo):
329 def repocleartagscachefunc(repo):
330 """Return the function to clear tags cache according to repo internal API
330 """Return the function to clear tags cache according to repo internal API
331 """
331 """
332 if util.safehasattr(repo, '_tagscache'): # since 2.0 (or 9dca7653b525)
332 if util.safehasattr(repo, '_tagscache'): # since 2.0 (or 9dca7653b525)
333 # in this case, setattr(repo, '_tagscache', None) or so isn't
333 # in this case, setattr(repo, '_tagscache', None) or so isn't
334 # correct way to clear tags cache, because existing code paths
334 # correct way to clear tags cache, because existing code paths
335 # expect _tagscache to be a structured object.
335 # expect _tagscache to be a structured object.
336 def clearcache():
336 def clearcache():
337 # _tagscache has been filteredpropertycache since 2.5 (or
337 # _tagscache has been filteredpropertycache since 2.5 (or
338 # 98c867ac1330), and delattr() can't work in such case
338 # 98c867ac1330), and delattr() can't work in such case
339 if '_tagscache' in vars(repo):
339 if '_tagscache' in vars(repo):
340 del repo.__dict__['_tagscache']
340 del repo.__dict__['_tagscache']
341 return clearcache
341 return clearcache
342
342
343 repotags = safeattrsetter(repo, '_tags', ignoremissing=True)
343 repotags = safeattrsetter(repo, '_tags', ignoremissing=True)
344 if repotags: # since 1.4 (or 5614a628d173)
344 if repotags: # since 1.4 (or 5614a628d173)
345 return lambda : repotags.set(None)
345 return lambda : repotags.set(None)
346
346
347 repotagscache = safeattrsetter(repo, 'tagscache', ignoremissing=True)
347 repotagscache = safeattrsetter(repo, 'tagscache', ignoremissing=True)
348 if repotagscache: # since 0.6 (or d7df759d0e97)
348 if repotagscache: # since 0.6 (or d7df759d0e97)
349 return lambda : repotagscache.set(None)
349 return lambda : repotagscache.set(None)
350
350
351 # Mercurial earlier than 0.6 (or d7df759d0e97) logically reaches
351 # Mercurial earlier than 0.6 (or d7df759d0e97) logically reaches
352 # this point, but it isn't so problematic, because:
352 # this point, but it isn't so problematic, because:
353 # - repo.tags of such Mercurial isn't "callable", and repo.tags()
353 # - repo.tags of such Mercurial isn't "callable", and repo.tags()
354 # in perftags() causes failure soon
354 # in perftags() causes failure soon
355 # - perf.py itself has been available since 1.1 (or eb240755386d)
355 # - perf.py itself has been available since 1.1 (or eb240755386d)
356 raise error.Abort(("tags API of this hg command is unknown"))
356 raise error.Abort(("tags API of this hg command is unknown"))
357
357
358 # perf commands
358 # perf commands
359
359
360 @command('perfwalk', formatteropts)
360 @command('perfwalk', formatteropts)
361 def perfwalk(ui, repo, *pats, **opts):
361 def perfwalk(ui, repo, *pats, **opts):
362 timer, fm = gettimer(ui, opts)
362 timer, fm = gettimer(ui, opts)
363 try:
363 try:
364 m = scmutil.match(repo[None], pats, {})
364 m = scmutil.match(repo[None], pats, {})
365 timer(lambda: len(list(repo.dirstate.walk(m, [], True, False))))
365 timer(lambda: len(list(repo.dirstate.walk(m, [], True, False))))
366 except Exception:
366 except Exception:
367 try:
367 try:
368 m = scmutil.match(repo[None], pats, {})
368 m = scmutil.match(repo[None], pats, {})
369 timer(lambda: len([b for a, b, c in repo.dirstate.statwalk([], m)]))
369 timer(lambda: len([b for a, b, c in repo.dirstate.statwalk([], m)]))
370 except Exception:
370 except Exception:
371 timer(lambda: len(list(cmdutil.walk(repo, pats, {}))))
371 timer(lambda: len(list(cmdutil.walk(repo, pats, {}))))
372 fm.end()
372 fm.end()
373
373
374 @command('perfannotate', formatteropts)
374 @command('perfannotate', formatteropts)
375 def perfannotate(ui, repo, f, **opts):
375 def perfannotate(ui, repo, f, **opts):
376 timer, fm = gettimer(ui, opts)
376 timer, fm = gettimer(ui, opts)
377 fc = repo['.'][f]
377 fc = repo['.'][f]
378 timer(lambda: len(fc.annotate(True)))
378 timer(lambda: len(fc.annotate(True)))
379 fm.end()
379 fm.end()
380
380
381 @command('perfstatus',
381 @command('perfstatus',
382 [('u', 'unknown', False,
382 [('u', 'unknown', False,
383 'ask status to look for unknown files')] + formatteropts)
383 'ask status to look for unknown files')] + formatteropts)
384 def perfstatus(ui, repo, **opts):
384 def perfstatus(ui, repo, **opts):
385 #m = match.always(repo.root, repo.getcwd())
385 #m = match.always(repo.root, repo.getcwd())
386 #timer(lambda: sum(map(len, repo.dirstate.status(m, [], False, False,
386 #timer(lambda: sum(map(len, repo.dirstate.status(m, [], False, False,
387 # False))))
387 # False))))
388 timer, fm = gettimer(ui, opts)
388 timer, fm = gettimer(ui, opts)
389 timer(lambda: sum(map(len, repo.status(unknown=opts['unknown']))))
389 timer(lambda: sum(map(len, repo.status(unknown=opts['unknown']))))
390 fm.end()
390 fm.end()
391
391
392 @command('perfaddremove', formatteropts)
392 @command('perfaddremove', formatteropts)
393 def perfaddremove(ui, repo, **opts):
393 def perfaddremove(ui, repo, **opts):
394 timer, fm = gettimer(ui, opts)
394 timer, fm = gettimer(ui, opts)
395 try:
395 try:
396 oldquiet = repo.ui.quiet
396 oldquiet = repo.ui.quiet
397 repo.ui.quiet = True
397 repo.ui.quiet = True
398 matcher = scmutil.match(repo[None])
398 matcher = scmutil.match(repo[None])
399 timer(lambda: scmutil.addremove(repo, matcher, "", dry_run=True))
399 timer(lambda: scmutil.addremove(repo, matcher, "", dry_run=True))
400 finally:
400 finally:
401 repo.ui.quiet = oldquiet
401 repo.ui.quiet = oldquiet
402 fm.end()
402 fm.end()
403
403
404 def clearcaches(cl):
404 def clearcaches(cl):
405 # behave somewhat consistently across internal API changes
405 # behave somewhat consistently across internal API changes
406 if util.safehasattr(cl, 'clearcaches'):
406 if util.safehasattr(cl, 'clearcaches'):
407 cl.clearcaches()
407 cl.clearcaches()
408 elif util.safehasattr(cl, '_nodecache'):
408 elif util.safehasattr(cl, '_nodecache'):
409 from mercurial.node import nullid, nullrev
409 from mercurial.node import nullid, nullrev
410 cl._nodecache = {nullid: nullrev}
410 cl._nodecache = {nullid: nullrev}
411 cl._nodepos = None
411 cl._nodepos = None
412
412
413 @command('perfheads', formatteropts)
413 @command('perfheads', formatteropts)
414 def perfheads(ui, repo, **opts):
414 def perfheads(ui, repo, **opts):
415 timer, fm = gettimer(ui, opts)
415 timer, fm = gettimer(ui, opts)
416 cl = repo.changelog
416 cl = repo.changelog
417 def d():
417 def d():
418 len(cl.headrevs())
418 len(cl.headrevs())
419 clearcaches(cl)
419 clearcaches(cl)
420 timer(d)
420 timer(d)
421 fm.end()
421 fm.end()
422
422
423 @command('perftags', formatteropts)
423 @command('perftags', formatteropts)
424 def perftags(ui, repo, **opts):
424 def perftags(ui, repo, **opts):
425 import mercurial.changelog
425 import mercurial.changelog
426 import mercurial.manifest
426 import mercurial.manifest
427 timer, fm = gettimer(ui, opts)
427 timer, fm = gettimer(ui, opts)
428 svfs = getsvfs(repo)
428 svfs = getsvfs(repo)
429 repocleartagscache = repocleartagscachefunc(repo)
429 repocleartagscache = repocleartagscachefunc(repo)
430 def t():
430 def t():
431 repo.changelog = mercurial.changelog.changelog(svfs)
431 repo.changelog = mercurial.changelog.changelog(svfs)
432 repo.manifestlog = mercurial.manifest.manifestlog(svfs, repo)
432 repo.manifestlog = mercurial.manifest.manifestlog(svfs, repo)
433 repocleartagscache()
433 repocleartagscache()
434 return len(repo.tags())
434 return len(repo.tags())
435 timer(t)
435 timer(t)
436 fm.end()
436 fm.end()
437
437
438 @command('perfancestors', formatteropts)
438 @command('perfancestors', formatteropts)
439 def perfancestors(ui, repo, **opts):
439 def perfancestors(ui, repo, **opts):
440 timer, fm = gettimer(ui, opts)
440 timer, fm = gettimer(ui, opts)
441 heads = repo.changelog.headrevs()
441 heads = repo.changelog.headrevs()
442 def d():
442 def d():
443 for a in repo.changelog.ancestors(heads):
443 for a in repo.changelog.ancestors(heads):
444 pass
444 pass
445 timer(d)
445 timer(d)
446 fm.end()
446 fm.end()
447
447
448 @command('perfancestorset', formatteropts)
448 @command('perfancestorset', formatteropts)
449 def perfancestorset(ui, repo, revset, **opts):
449 def perfancestorset(ui, repo, revset, **opts):
450 timer, fm = gettimer(ui, opts)
450 timer, fm = gettimer(ui, opts)
451 revs = repo.revs(revset)
451 revs = repo.revs(revset)
452 heads = repo.changelog.headrevs()
452 heads = repo.changelog.headrevs()
453 def d():
453 def d():
454 s = repo.changelog.ancestors(heads)
454 s = repo.changelog.ancestors(heads)
455 for rev in revs:
455 for rev in revs:
456 rev in s
456 rev in s
457 timer(d)
457 timer(d)
458 fm.end()
458 fm.end()
459
459
460 @command('perfchangegroupchangelog', formatteropts +
460 @command('perfchangegroupchangelog', formatteropts +
461 [('', 'version', '02', 'changegroup version'),
461 [('', 'version', '02', 'changegroup version'),
462 ('r', 'rev', '', 'revisions to add to changegroup')])
462 ('r', 'rev', '', 'revisions to add to changegroup')])
463 def perfchangegroupchangelog(ui, repo, version='02', rev=None, **opts):
463 def perfchangegroupchangelog(ui, repo, version='02', rev=None, **opts):
464 """Benchmark producing a changelog group for a changegroup.
464 """Benchmark producing a changelog group for a changegroup.
465
465
466 This measures the time spent processing the changelog during a
466 This measures the time spent processing the changelog during a
467 bundle operation. This occurs during `hg bundle` and on a server
467 bundle operation. This occurs during `hg bundle` and on a server
468 processing a `getbundle` wire protocol request (handles clones
468 processing a `getbundle` wire protocol request (handles clones
469 and pull requests).
469 and pull requests).
470
470
471 By default, all revisions are added to the changegroup.
471 By default, all revisions are added to the changegroup.
472 """
472 """
473 cl = repo.changelog
473 cl = repo.changelog
474 revs = [cl.lookup(r) for r in repo.revs(rev or 'all()')]
474 revs = [cl.lookup(r) for r in repo.revs(rev or 'all()')]
475 bundler = changegroup.getbundler(version, repo)
475 bundler = changegroup.getbundler(version, repo)
476
476
477 def lookup(node):
477 def lookup(node):
478 # The real bundler reads the revision in order to access the
478 # The real bundler reads the revision in order to access the
479 # manifest node and files list. Do that here.
479 # manifest node and files list. Do that here.
480 cl.read(node)
480 cl.read(node)
481 return node
481 return node
482
482
483 def d():
483 def d():
484 for chunk in bundler.group(revs, cl, lookup):
484 for chunk in bundler.group(revs, cl, lookup):
485 pass
485 pass
486
486
487 timer, fm = gettimer(ui, opts)
487 timer, fm = gettimer(ui, opts)
488 timer(d)
488 timer(d)
489 fm.end()
489 fm.end()
490
490
491 @command('perfdirs', formatteropts)
491 @command('perfdirs', formatteropts)
492 def perfdirs(ui, repo, **opts):
492 def perfdirs(ui, repo, **opts):
493 timer, fm = gettimer(ui, opts)
493 timer, fm = gettimer(ui, opts)
494 dirstate = repo.dirstate
494 dirstate = repo.dirstate
495 'a' in dirstate
495 'a' in dirstate
496 def d():
496 def d():
497 dirstate.dirs()
497 dirstate.dirs()
498 del dirstate._dirs
498 del dirstate._dirs
499 timer(d)
499 timer(d)
500 fm.end()
500 fm.end()
501
501
502 @command('perfdirstate', formatteropts)
502 @command('perfdirstate', formatteropts)
503 def perfdirstate(ui, repo, **opts):
503 def perfdirstate(ui, repo, **opts):
504 timer, fm = gettimer(ui, opts)
504 timer, fm = gettimer(ui, opts)
505 "a" in repo.dirstate
505 "a" in repo.dirstate
506 def d():
506 def d():
507 repo.dirstate.invalidate()
507 repo.dirstate.invalidate()
508 "a" in repo.dirstate
508 "a" in repo.dirstate
509 timer(d)
509 timer(d)
510 fm.end()
510 fm.end()
511
511
512 @command('perfdirstatedirs', formatteropts)
512 @command('perfdirstatedirs', formatteropts)
513 def perfdirstatedirs(ui, repo, **opts):
513 def perfdirstatedirs(ui, repo, **opts):
514 timer, fm = gettimer(ui, opts)
514 timer, fm = gettimer(ui, opts)
515 "a" in repo.dirstate
515 "a" in repo.dirstate
516 def d():
516 def d():
517 "a" in repo.dirstate._dirs
517 "a" in repo.dirstate._dirs
518 del repo.dirstate._dirs
518 del repo.dirstate._dirs
519 timer(d)
519 timer(d)
520 fm.end()
520 fm.end()
521
521
522 @command('perfdirstatefoldmap', formatteropts)
522 @command('perfdirstatefoldmap', formatteropts)
523 def perfdirstatefoldmap(ui, repo, **opts):
523 def perfdirstatefoldmap(ui, repo, **opts):
524 timer, fm = gettimer(ui, opts)
524 timer, fm = gettimer(ui, opts)
525 dirstate = repo.dirstate
525 dirstate = repo.dirstate
526 'a' in dirstate
526 'a' in dirstate
527 def d():
527 def d():
528 dirstate._filefoldmap.get('a')
528 dirstate._filefoldmap.get('a')
529 del dirstate._filefoldmap
529 del dirstate._filefoldmap
530 timer(d)
530 timer(d)
531 fm.end()
531 fm.end()
532
532
533 @command('perfdirfoldmap', formatteropts)
533 @command('perfdirfoldmap', formatteropts)
534 def perfdirfoldmap(ui, repo, **opts):
534 def perfdirfoldmap(ui, repo, **opts):
535 timer, fm = gettimer(ui, opts)
535 timer, fm = gettimer(ui, opts)
536 dirstate = repo.dirstate
536 dirstate = repo.dirstate
537 'a' in dirstate
537 'a' in dirstate
538 def d():
538 def d():
539 dirstate._dirfoldmap.get('a')
539 dirstate._dirfoldmap.get('a')
540 del dirstate._dirfoldmap
540 del dirstate._dirfoldmap
541 del dirstate._dirs
541 del dirstate._dirs
542 timer(d)
542 timer(d)
543 fm.end()
543 fm.end()
544
544
545 @command('perfdirstatewrite', formatteropts)
545 @command('perfdirstatewrite', formatteropts)
546 def perfdirstatewrite(ui, repo, **opts):
546 def perfdirstatewrite(ui, repo, **opts):
547 timer, fm = gettimer(ui, opts)
547 timer, fm = gettimer(ui, opts)
548 ds = repo.dirstate
548 ds = repo.dirstate
549 "a" in ds
549 "a" in ds
550 def d():
550 def d():
551 ds._dirty = True
551 ds._dirty = True
552 ds.write(repo.currenttransaction())
552 ds.write(repo.currenttransaction())
553 timer(d)
553 timer(d)
554 fm.end()
554 fm.end()
555
555
556 @command('perfmergecalculate',
556 @command('perfmergecalculate',
557 [('r', 'rev', '.', 'rev to merge against')] + formatteropts)
557 [('r', 'rev', '.', 'rev to merge against')] + formatteropts)
558 def perfmergecalculate(ui, repo, rev, **opts):
558 def perfmergecalculate(ui, repo, rev, **opts):
559 timer, fm = gettimer(ui, opts)
559 timer, fm = gettimer(ui, opts)
560 wctx = repo[None]
560 wctx = repo[None]
561 rctx = scmutil.revsingle(repo, rev, rev)
561 rctx = scmutil.revsingle(repo, rev, rev)
562 ancestor = wctx.ancestor(rctx)
562 ancestor = wctx.ancestor(rctx)
563 # we don't want working dir files to be stat'd in the benchmark, so prime
563 # we don't want working dir files to be stat'd in the benchmark, so prime
564 # that cache
564 # that cache
565 wctx.dirty()
565 wctx.dirty()
566 def d():
566 def d():
567 # acceptremote is True because we don't want prompts in the middle of
567 # acceptremote is True because we don't want prompts in the middle of
568 # our benchmark
568 # our benchmark
569 merge.calculateupdates(repo, wctx, rctx, [ancestor], False, False,
569 merge.calculateupdates(repo, wctx, rctx, [ancestor], False, False,
570 acceptremote=True, followcopies=True)
570 acceptremote=True, followcopies=True)
571 timer(d)
571 timer(d)
572 fm.end()
572 fm.end()
573
573
574 @command('perfpathcopies', [], "REV REV")
574 @command('perfpathcopies', [], "REV REV")
575 def perfpathcopies(ui, repo, rev1, rev2, **opts):
575 def perfpathcopies(ui, repo, rev1, rev2, **opts):
576 timer, fm = gettimer(ui, opts)
576 timer, fm = gettimer(ui, opts)
577 ctx1 = scmutil.revsingle(repo, rev1, rev1)
577 ctx1 = scmutil.revsingle(repo, rev1, rev1)
578 ctx2 = scmutil.revsingle(repo, rev2, rev2)
578 ctx2 = scmutil.revsingle(repo, rev2, rev2)
579 def d():
579 def d():
580 copies.pathcopies(ctx1, ctx2)
580 copies.pathcopies(ctx1, ctx2)
581 timer(d)
581 timer(d)
582 fm.end()
582 fm.end()
583
583
584 @command('perfphases', [], "")
585 def perfphases(ui, repo, **opts):
586 """benchmark phasesets computation"""
587 timer, fm = gettimer(ui, opts)
588 phases = repo._phasecache
589 def d():
590 phases.invalidate()
591 phases.loadphaserevs(repo)
592 timer(d)
593 fm.end()
594
584 @command('perfmanifest', [], 'REV')
595 @command('perfmanifest', [], 'REV')
585 def perfmanifest(ui, repo, rev, **opts):
596 def perfmanifest(ui, repo, rev, **opts):
586 timer, fm = gettimer(ui, opts)
597 timer, fm = gettimer(ui, opts)
587 ctx = scmutil.revsingle(repo, rev, rev)
598 ctx = scmutil.revsingle(repo, rev, rev)
588 t = ctx.manifestnode()
599 t = ctx.manifestnode()
589 def d():
600 def d():
590 repo.manifestlog.clearcaches()
601 repo.manifestlog.clearcaches()
591 repo.manifestlog[t].read()
602 repo.manifestlog[t].read()
592 timer(d)
603 timer(d)
593 fm.end()
604 fm.end()
594
605
595 @command('perfchangeset', formatteropts)
606 @command('perfchangeset', formatteropts)
596 def perfchangeset(ui, repo, rev, **opts):
607 def perfchangeset(ui, repo, rev, **opts):
597 timer, fm = gettimer(ui, opts)
608 timer, fm = gettimer(ui, opts)
598 n = repo[rev].node()
609 n = repo[rev].node()
599 def d():
610 def d():
600 repo.changelog.read(n)
611 repo.changelog.read(n)
601 #repo.changelog._cache = None
612 #repo.changelog._cache = None
602 timer(d)
613 timer(d)
603 fm.end()
614 fm.end()
604
615
605 @command('perfindex', formatteropts)
616 @command('perfindex', formatteropts)
606 def perfindex(ui, repo, **opts):
617 def perfindex(ui, repo, **opts):
607 import mercurial.revlog
618 import mercurial.revlog
608 timer, fm = gettimer(ui, opts)
619 timer, fm = gettimer(ui, opts)
609 mercurial.revlog._prereadsize = 2**24 # disable lazy parser in old hg
620 mercurial.revlog._prereadsize = 2**24 # disable lazy parser in old hg
610 n = repo["tip"].node()
621 n = repo["tip"].node()
611 svfs = getsvfs(repo)
622 svfs = getsvfs(repo)
612 def d():
623 def d():
613 cl = mercurial.revlog.revlog(svfs, "00changelog.i")
624 cl = mercurial.revlog.revlog(svfs, "00changelog.i")
614 cl.rev(n)
625 cl.rev(n)
615 timer(d)
626 timer(d)
616 fm.end()
627 fm.end()
617
628
618 @command('perfstartup', formatteropts)
629 @command('perfstartup', formatteropts)
619 def perfstartup(ui, repo, **opts):
630 def perfstartup(ui, repo, **opts):
620 timer, fm = gettimer(ui, opts)
631 timer, fm = gettimer(ui, opts)
621 cmd = sys.argv[0]
632 cmd = sys.argv[0]
622 def d():
633 def d():
623 if os.name != 'nt':
634 if os.name != 'nt':
624 os.system("HGRCPATH= %s version -q > /dev/null" % cmd)
635 os.system("HGRCPATH= %s version -q > /dev/null" % cmd)
625 else:
636 else:
626 os.environ['HGRCPATH'] = ''
637 os.environ['HGRCPATH'] = ''
627 os.system("%s version -q > NUL" % cmd)
638 os.system("%s version -q > NUL" % cmd)
628 timer(d)
639 timer(d)
629 fm.end()
640 fm.end()
630
641
631 @command('perfparents', formatteropts)
642 @command('perfparents', formatteropts)
632 def perfparents(ui, repo, **opts):
643 def perfparents(ui, repo, **opts):
633 timer, fm = gettimer(ui, opts)
644 timer, fm = gettimer(ui, opts)
634 # control the number of commits perfparents iterates over
645 # control the number of commits perfparents iterates over
635 # experimental config: perf.parentscount
646 # experimental config: perf.parentscount
636 count = getint(ui, "perf", "parentscount", 1000)
647 count = getint(ui, "perf", "parentscount", 1000)
637 if len(repo.changelog) < count:
648 if len(repo.changelog) < count:
638 raise error.Abort("repo needs %d commits for this test" % count)
649 raise error.Abort("repo needs %d commits for this test" % count)
639 repo = repo.unfiltered()
650 repo = repo.unfiltered()
640 nl = [repo.changelog.node(i) for i in xrange(count)]
651 nl = [repo.changelog.node(i) for i in xrange(count)]
641 def d():
652 def d():
642 for n in nl:
653 for n in nl:
643 repo.changelog.parents(n)
654 repo.changelog.parents(n)
644 timer(d)
655 timer(d)
645 fm.end()
656 fm.end()
646
657
647 @command('perfctxfiles', formatteropts)
658 @command('perfctxfiles', formatteropts)
648 def perfctxfiles(ui, repo, x, **opts):
659 def perfctxfiles(ui, repo, x, **opts):
649 x = int(x)
660 x = int(x)
650 timer, fm = gettimer(ui, opts)
661 timer, fm = gettimer(ui, opts)
651 def d():
662 def d():
652 len(repo[x].files())
663 len(repo[x].files())
653 timer(d)
664 timer(d)
654 fm.end()
665 fm.end()
655
666
656 @command('perfrawfiles', formatteropts)
667 @command('perfrawfiles', formatteropts)
657 def perfrawfiles(ui, repo, x, **opts):
668 def perfrawfiles(ui, repo, x, **opts):
658 x = int(x)
669 x = int(x)
659 timer, fm = gettimer(ui, opts)
670 timer, fm = gettimer(ui, opts)
660 cl = repo.changelog
671 cl = repo.changelog
661 def d():
672 def d():
662 len(cl.read(x)[3])
673 len(cl.read(x)[3])
663 timer(d)
674 timer(d)
664 fm.end()
675 fm.end()
665
676
666 @command('perflookup', formatteropts)
677 @command('perflookup', formatteropts)
667 def perflookup(ui, repo, rev, **opts):
678 def perflookup(ui, repo, rev, **opts):
668 timer, fm = gettimer(ui, opts)
679 timer, fm = gettimer(ui, opts)
669 timer(lambda: len(repo.lookup(rev)))
680 timer(lambda: len(repo.lookup(rev)))
670 fm.end()
681 fm.end()
671
682
672 @command('perfrevrange', formatteropts)
683 @command('perfrevrange', formatteropts)
673 def perfrevrange(ui, repo, *specs, **opts):
684 def perfrevrange(ui, repo, *specs, **opts):
674 timer, fm = gettimer(ui, opts)
685 timer, fm = gettimer(ui, opts)
675 revrange = scmutil.revrange
686 revrange = scmutil.revrange
676 timer(lambda: len(revrange(repo, specs)))
687 timer(lambda: len(revrange(repo, specs)))
677 fm.end()
688 fm.end()
678
689
679 @command('perfnodelookup', formatteropts)
690 @command('perfnodelookup', formatteropts)
680 def perfnodelookup(ui, repo, rev, **opts):
691 def perfnodelookup(ui, repo, rev, **opts):
681 timer, fm = gettimer(ui, opts)
692 timer, fm = gettimer(ui, opts)
682 import mercurial.revlog
693 import mercurial.revlog
683 mercurial.revlog._prereadsize = 2**24 # disable lazy parser in old hg
694 mercurial.revlog._prereadsize = 2**24 # disable lazy parser in old hg
684 n = repo[rev].node()
695 n = repo[rev].node()
685 cl = mercurial.revlog.revlog(getsvfs(repo), "00changelog.i")
696 cl = mercurial.revlog.revlog(getsvfs(repo), "00changelog.i")
686 def d():
697 def d():
687 cl.rev(n)
698 cl.rev(n)
688 clearcaches(cl)
699 clearcaches(cl)
689 timer(d)
700 timer(d)
690 fm.end()
701 fm.end()
691
702
692 @command('perflog',
703 @command('perflog',
693 [('', 'rename', False, 'ask log to follow renames')] + formatteropts)
704 [('', 'rename', False, 'ask log to follow renames')] + formatteropts)
694 def perflog(ui, repo, rev=None, **opts):
705 def perflog(ui, repo, rev=None, **opts):
695 if rev is None:
706 if rev is None:
696 rev=[]
707 rev=[]
697 timer, fm = gettimer(ui, opts)
708 timer, fm = gettimer(ui, opts)
698 ui.pushbuffer()
709 ui.pushbuffer()
699 timer(lambda: commands.log(ui, repo, rev=rev, date='', user='',
710 timer(lambda: commands.log(ui, repo, rev=rev, date='', user='',
700 copies=opts.get('rename')))
711 copies=opts.get('rename')))
701 ui.popbuffer()
712 ui.popbuffer()
702 fm.end()
713 fm.end()
703
714
704 @command('perfmoonwalk', formatteropts)
715 @command('perfmoonwalk', formatteropts)
705 def perfmoonwalk(ui, repo, **opts):
716 def perfmoonwalk(ui, repo, **opts):
706 """benchmark walking the changelog backwards
717 """benchmark walking the changelog backwards
707
718
708 This also loads the changelog data for each revision in the changelog.
719 This also loads the changelog data for each revision in the changelog.
709 """
720 """
710 timer, fm = gettimer(ui, opts)
721 timer, fm = gettimer(ui, opts)
711 def moonwalk():
722 def moonwalk():
712 for i in xrange(len(repo), -1, -1):
723 for i in xrange(len(repo), -1, -1):
713 ctx = repo[i]
724 ctx = repo[i]
714 ctx.branch() # read changelog data (in addition to the index)
725 ctx.branch() # read changelog data (in addition to the index)
715 timer(moonwalk)
726 timer(moonwalk)
716 fm.end()
727 fm.end()
717
728
718 @command('perftemplating', formatteropts)
729 @command('perftemplating', formatteropts)
719 def perftemplating(ui, repo, rev=None, **opts):
730 def perftemplating(ui, repo, rev=None, **opts):
720 if rev is None:
731 if rev is None:
721 rev=[]
732 rev=[]
722 timer, fm = gettimer(ui, opts)
733 timer, fm = gettimer(ui, opts)
723 ui.pushbuffer()
734 ui.pushbuffer()
724 timer(lambda: commands.log(ui, repo, rev=rev, date='', user='',
735 timer(lambda: commands.log(ui, repo, rev=rev, date='', user='',
725 template='{date|shortdate} [{rev}:{node|short}]'
736 template='{date|shortdate} [{rev}:{node|short}]'
726 ' {author|person}: {desc|firstline}\n'))
737 ' {author|person}: {desc|firstline}\n'))
727 ui.popbuffer()
738 ui.popbuffer()
728 fm.end()
739 fm.end()
729
740
730 @command('perfcca', formatteropts)
741 @command('perfcca', formatteropts)
731 def perfcca(ui, repo, **opts):
742 def perfcca(ui, repo, **opts):
732 timer, fm = gettimer(ui, opts)
743 timer, fm = gettimer(ui, opts)
733 timer(lambda: scmutil.casecollisionauditor(ui, False, repo.dirstate))
744 timer(lambda: scmutil.casecollisionauditor(ui, False, repo.dirstate))
734 fm.end()
745 fm.end()
735
746
736 @command('perffncacheload', formatteropts)
747 @command('perffncacheload', formatteropts)
737 def perffncacheload(ui, repo, **opts):
748 def perffncacheload(ui, repo, **opts):
738 timer, fm = gettimer(ui, opts)
749 timer, fm = gettimer(ui, opts)
739 s = repo.store
750 s = repo.store
740 def d():
751 def d():
741 s.fncache._load()
752 s.fncache._load()
742 timer(d)
753 timer(d)
743 fm.end()
754 fm.end()
744
755
745 @command('perffncachewrite', formatteropts)
756 @command('perffncachewrite', formatteropts)
746 def perffncachewrite(ui, repo, **opts):
757 def perffncachewrite(ui, repo, **opts):
747 timer, fm = gettimer(ui, opts)
758 timer, fm = gettimer(ui, opts)
748 s = repo.store
759 s = repo.store
749 s.fncache._load()
760 s.fncache._load()
750 lock = repo.lock()
761 lock = repo.lock()
751 tr = repo.transaction('perffncachewrite')
762 tr = repo.transaction('perffncachewrite')
752 def d():
763 def d():
753 s.fncache._dirty = True
764 s.fncache._dirty = True
754 s.fncache.write(tr)
765 s.fncache.write(tr)
755 timer(d)
766 timer(d)
756 tr.close()
767 tr.close()
757 lock.release()
768 lock.release()
758 fm.end()
769 fm.end()
759
770
760 @command('perffncacheencode', formatteropts)
771 @command('perffncacheencode', formatteropts)
761 def perffncacheencode(ui, repo, **opts):
772 def perffncacheencode(ui, repo, **opts):
762 timer, fm = gettimer(ui, opts)
773 timer, fm = gettimer(ui, opts)
763 s = repo.store
774 s = repo.store
764 s.fncache._load()
775 s.fncache._load()
765 def d():
776 def d():
766 for p in s.fncache.entries:
777 for p in s.fncache.entries:
767 s.encode(p)
778 s.encode(p)
768 timer(d)
779 timer(d)
769 fm.end()
780 fm.end()
770
781
771 @command('perfbdiff', revlogopts + formatteropts + [
782 @command('perfbdiff', revlogopts + formatteropts + [
772 ('', 'count', 1, 'number of revisions to test (when using --startrev)'),
783 ('', 'count', 1, 'number of revisions to test (when using --startrev)'),
773 ('', 'alldata', False, 'test bdiffs for all associated revisions')],
784 ('', 'alldata', False, 'test bdiffs for all associated revisions')],
774 '-c|-m|FILE REV')
785 '-c|-m|FILE REV')
775 def perfbdiff(ui, repo, file_, rev=None, count=None, **opts):
786 def perfbdiff(ui, repo, file_, rev=None, count=None, **opts):
776 """benchmark a bdiff between revisions
787 """benchmark a bdiff between revisions
777
788
778 By default, benchmark a bdiff between its delta parent and itself.
789 By default, benchmark a bdiff between its delta parent and itself.
779
790
780 With ``--count``, benchmark bdiffs between delta parents and self for N
791 With ``--count``, benchmark bdiffs between delta parents and self for N
781 revisions starting at the specified revision.
792 revisions starting at the specified revision.
782
793
783 With ``--alldata``, assume the requested revision is a changeset and
794 With ``--alldata``, assume the requested revision is a changeset and
784 measure bdiffs for all changes related to that changeset (manifest
795 measure bdiffs for all changes related to that changeset (manifest
785 and filelogs).
796 and filelogs).
786 """
797 """
787 if opts['alldata']:
798 if opts['alldata']:
788 opts['changelog'] = True
799 opts['changelog'] = True
789
800
790 if opts.get('changelog') or opts.get('manifest'):
801 if opts.get('changelog') or opts.get('manifest'):
791 file_, rev = None, file_
802 file_, rev = None, file_
792 elif rev is None:
803 elif rev is None:
793 raise error.CommandError('perfbdiff', 'invalid arguments')
804 raise error.CommandError('perfbdiff', 'invalid arguments')
794
805
795 textpairs = []
806 textpairs = []
796
807
797 r = cmdutil.openrevlog(repo, 'perfbdiff', file_, opts)
808 r = cmdutil.openrevlog(repo, 'perfbdiff', file_, opts)
798
809
799 startrev = r.rev(r.lookup(rev))
810 startrev = r.rev(r.lookup(rev))
800 for rev in range(startrev, min(startrev + count, len(r) - 1)):
811 for rev in range(startrev, min(startrev + count, len(r) - 1)):
801 if opts['alldata']:
812 if opts['alldata']:
802 # Load revisions associated with changeset.
813 # Load revisions associated with changeset.
803 ctx = repo[rev]
814 ctx = repo[rev]
804 mtext = repo.manifestlog._revlog.revision(ctx.manifestnode())
815 mtext = repo.manifestlog._revlog.revision(ctx.manifestnode())
805 for pctx in ctx.parents():
816 for pctx in ctx.parents():
806 pman = repo.manifestlog._revlog.revision(pctx.manifestnode())
817 pman = repo.manifestlog._revlog.revision(pctx.manifestnode())
807 textpairs.append((pman, mtext))
818 textpairs.append((pman, mtext))
808
819
809 # Load filelog revisions by iterating manifest delta.
820 # Load filelog revisions by iterating manifest delta.
810 man = ctx.manifest()
821 man = ctx.manifest()
811 pman = ctx.p1().manifest()
822 pman = ctx.p1().manifest()
812 for filename, change in pman.diff(man).items():
823 for filename, change in pman.diff(man).items():
813 fctx = repo.file(filename)
824 fctx = repo.file(filename)
814 f1 = fctx.revision(change[0][0] or -1)
825 f1 = fctx.revision(change[0][0] or -1)
815 f2 = fctx.revision(change[1][0] or -1)
826 f2 = fctx.revision(change[1][0] or -1)
816 textpairs.append((f1, f2))
827 textpairs.append((f1, f2))
817 else:
828 else:
818 dp = r.deltaparent(rev)
829 dp = r.deltaparent(rev)
819 textpairs.append((r.revision(dp), r.revision(rev)))
830 textpairs.append((r.revision(dp), r.revision(rev)))
820
831
821 def d():
832 def d():
822 for pair in textpairs:
833 for pair in textpairs:
823 mdiff.textdiff(*pair)
834 mdiff.textdiff(*pair)
824
835
825 timer, fm = gettimer(ui, opts)
836 timer, fm = gettimer(ui, opts)
826 timer(d)
837 timer(d)
827 fm.end()
838 fm.end()
828
839
829 @command('perfdiffwd', formatteropts)
840 @command('perfdiffwd', formatteropts)
830 def perfdiffwd(ui, repo, **opts):
841 def perfdiffwd(ui, repo, **opts):
831 """Profile diff of working directory changes"""
842 """Profile diff of working directory changes"""
832 timer, fm = gettimer(ui, opts)
843 timer, fm = gettimer(ui, opts)
833 options = {
844 options = {
834 'w': 'ignore_all_space',
845 'w': 'ignore_all_space',
835 'b': 'ignore_space_change',
846 'b': 'ignore_space_change',
836 'B': 'ignore_blank_lines',
847 'B': 'ignore_blank_lines',
837 }
848 }
838
849
839 for diffopt in ('', 'w', 'b', 'B', 'wB'):
850 for diffopt in ('', 'w', 'b', 'B', 'wB'):
840 opts = dict((options[c], '1') for c in diffopt)
851 opts = dict((options[c], '1') for c in diffopt)
841 def d():
852 def d():
842 ui.pushbuffer()
853 ui.pushbuffer()
843 commands.diff(ui, repo, **opts)
854 commands.diff(ui, repo, **opts)
844 ui.popbuffer()
855 ui.popbuffer()
845 title = 'diffopts: %s' % (diffopt and ('-' + diffopt) or 'none')
856 title = 'diffopts: %s' % (diffopt and ('-' + diffopt) or 'none')
846 timer(d, title)
857 timer(d, title)
847 fm.end()
858 fm.end()
848
859
849 @command('perfrevlog', revlogopts + formatteropts +
860 @command('perfrevlog', revlogopts + formatteropts +
850 [('d', 'dist', 100, 'distance between the revisions'),
861 [('d', 'dist', 100, 'distance between the revisions'),
851 ('s', 'startrev', 0, 'revision to start reading at'),
862 ('s', 'startrev', 0, 'revision to start reading at'),
852 ('', 'reverse', False, 'read in reverse')],
863 ('', 'reverse', False, 'read in reverse')],
853 '-c|-m|FILE')
864 '-c|-m|FILE')
854 def perfrevlog(ui, repo, file_=None, startrev=0, reverse=False, **opts):
865 def perfrevlog(ui, repo, file_=None, startrev=0, reverse=False, **opts):
855 """Benchmark reading a series of revisions from a revlog.
866 """Benchmark reading a series of revisions from a revlog.
856
867
857 By default, we read every ``-d/--dist`` revision from 0 to tip of
868 By default, we read every ``-d/--dist`` revision from 0 to tip of
858 the specified revlog.
869 the specified revlog.
859
870
860 The start revision can be defined via ``-s/--startrev``.
871 The start revision can be defined via ``-s/--startrev``.
861 """
872 """
862 rl = cmdutil.openrevlog(repo, 'perfrevlog', file_, opts)
873 rl = cmdutil.openrevlog(repo, 'perfrevlog', file_, opts)
863 rllen = getlen(ui)(rl)
874 rllen = getlen(ui)(rl)
864
875
865 def d():
876 def d():
866 rl.clearcaches()
877 rl.clearcaches()
867
878
868 beginrev = startrev
879 beginrev = startrev
869 endrev = rllen
880 endrev = rllen
870 dist = opts['dist']
881 dist = opts['dist']
871
882
872 if reverse:
883 if reverse:
873 beginrev, endrev = endrev, beginrev
884 beginrev, endrev = endrev, beginrev
874 dist = -1 * dist
885 dist = -1 * dist
875
886
876 for x in xrange(beginrev, endrev, dist):
887 for x in xrange(beginrev, endrev, dist):
877 # Old revisions don't support passing int.
888 # Old revisions don't support passing int.
878 n = rl.node(x)
889 n = rl.node(x)
879 rl.revision(n)
890 rl.revision(n)
880
891
881 timer, fm = gettimer(ui, opts)
892 timer, fm = gettimer(ui, opts)
882 timer(d)
893 timer(d)
883 fm.end()
894 fm.end()
884
895
885 @command('perfrevlogchunks', revlogopts + formatteropts +
896 @command('perfrevlogchunks', revlogopts + formatteropts +
886 [('e', 'engines', '', 'compression engines to use'),
897 [('e', 'engines', '', 'compression engines to use'),
887 ('s', 'startrev', 0, 'revision to start at')],
898 ('s', 'startrev', 0, 'revision to start at')],
888 '-c|-m|FILE')
899 '-c|-m|FILE')
889 def perfrevlogchunks(ui, repo, file_=None, engines=None, startrev=0, **opts):
900 def perfrevlogchunks(ui, repo, file_=None, engines=None, startrev=0, **opts):
890 """Benchmark operations on revlog chunks.
901 """Benchmark operations on revlog chunks.
891
902
892 Logically, each revlog is a collection of fulltext revisions. However,
903 Logically, each revlog is a collection of fulltext revisions. However,
893 stored within each revlog are "chunks" of possibly compressed data. This
904 stored within each revlog are "chunks" of possibly compressed data. This
894 data needs to be read and decompressed or compressed and written.
905 data needs to be read and decompressed or compressed and written.
895
906
896 This command measures the time it takes to read+decompress and recompress
907 This command measures the time it takes to read+decompress and recompress
897 chunks in a revlog. It effectively isolates I/O and compression performance.
908 chunks in a revlog. It effectively isolates I/O and compression performance.
898 For measurements of higher-level operations like resolving revisions,
909 For measurements of higher-level operations like resolving revisions,
899 see ``perfrevlog`` and ``perfrevlogrevision``.
910 see ``perfrevlog`` and ``perfrevlogrevision``.
900 """
911 """
901 rl = cmdutil.openrevlog(repo, 'perfrevlogchunks', file_, opts)
912 rl = cmdutil.openrevlog(repo, 'perfrevlogchunks', file_, opts)
902
913
903 # _chunkraw was renamed to _getsegmentforrevs.
914 # _chunkraw was renamed to _getsegmentforrevs.
904 try:
915 try:
905 segmentforrevs = rl._getsegmentforrevs
916 segmentforrevs = rl._getsegmentforrevs
906 except AttributeError:
917 except AttributeError:
907 segmentforrevs = rl._chunkraw
918 segmentforrevs = rl._chunkraw
908
919
909 # Verify engines argument.
920 # Verify engines argument.
910 if engines:
921 if engines:
911 engines = set(e.strip() for e in engines.split(','))
922 engines = set(e.strip() for e in engines.split(','))
912 for engine in engines:
923 for engine in engines:
913 try:
924 try:
914 util.compressionengines[engine]
925 util.compressionengines[engine]
915 except KeyError:
926 except KeyError:
916 raise error.Abort('unknown compression engine: %s' % engine)
927 raise error.Abort('unknown compression engine: %s' % engine)
917 else:
928 else:
918 engines = []
929 engines = []
919 for e in util.compengines:
930 for e in util.compengines:
920 engine = util.compengines[e]
931 engine = util.compengines[e]
921 try:
932 try:
922 if engine.available():
933 if engine.available():
923 engine.revlogcompressor().compress('dummy')
934 engine.revlogcompressor().compress('dummy')
924 engines.append(e)
935 engines.append(e)
925 except NotImplementedError:
936 except NotImplementedError:
926 pass
937 pass
927
938
928 revs = list(rl.revs(startrev, len(rl) - 1))
939 revs = list(rl.revs(startrev, len(rl) - 1))
929
940
930 def rlfh(rl):
941 def rlfh(rl):
931 if rl._inline:
942 if rl._inline:
932 return getsvfs(repo)(rl.indexfile)
943 return getsvfs(repo)(rl.indexfile)
933 else:
944 else:
934 return getsvfs(repo)(rl.datafile)
945 return getsvfs(repo)(rl.datafile)
935
946
936 def doread():
947 def doread():
937 rl.clearcaches()
948 rl.clearcaches()
938 for rev in revs:
949 for rev in revs:
939 segmentforrevs(rev, rev)
950 segmentforrevs(rev, rev)
940
951
941 def doreadcachedfh():
952 def doreadcachedfh():
942 rl.clearcaches()
953 rl.clearcaches()
943 fh = rlfh(rl)
954 fh = rlfh(rl)
944 for rev in revs:
955 for rev in revs:
945 segmentforrevs(rev, rev, df=fh)
956 segmentforrevs(rev, rev, df=fh)
946
957
947 def doreadbatch():
958 def doreadbatch():
948 rl.clearcaches()
959 rl.clearcaches()
949 segmentforrevs(revs[0], revs[-1])
960 segmentforrevs(revs[0], revs[-1])
950
961
951 def doreadbatchcachedfh():
962 def doreadbatchcachedfh():
952 rl.clearcaches()
963 rl.clearcaches()
953 fh = rlfh(rl)
964 fh = rlfh(rl)
954 segmentforrevs(revs[0], revs[-1], df=fh)
965 segmentforrevs(revs[0], revs[-1], df=fh)
955
966
956 def dochunk():
967 def dochunk():
957 rl.clearcaches()
968 rl.clearcaches()
958 fh = rlfh(rl)
969 fh = rlfh(rl)
959 for rev in revs:
970 for rev in revs:
960 rl._chunk(rev, df=fh)
971 rl._chunk(rev, df=fh)
961
972
962 chunks = [None]
973 chunks = [None]
963
974
964 def dochunkbatch():
975 def dochunkbatch():
965 rl.clearcaches()
976 rl.clearcaches()
966 fh = rlfh(rl)
977 fh = rlfh(rl)
967 # Save chunks as a side-effect.
978 # Save chunks as a side-effect.
968 chunks[0] = rl._chunks(revs, df=fh)
979 chunks[0] = rl._chunks(revs, df=fh)
969
980
970 def docompress(compressor):
981 def docompress(compressor):
971 rl.clearcaches()
982 rl.clearcaches()
972
983
973 try:
984 try:
974 # Swap in the requested compression engine.
985 # Swap in the requested compression engine.
975 oldcompressor = rl._compressor
986 oldcompressor = rl._compressor
976 rl._compressor = compressor
987 rl._compressor = compressor
977 for chunk in chunks[0]:
988 for chunk in chunks[0]:
978 rl.compress(chunk)
989 rl.compress(chunk)
979 finally:
990 finally:
980 rl._compressor = oldcompressor
991 rl._compressor = oldcompressor
981
992
982 benches = [
993 benches = [
983 (lambda: doread(), 'read'),
994 (lambda: doread(), 'read'),
984 (lambda: doreadcachedfh(), 'read w/ reused fd'),
995 (lambda: doreadcachedfh(), 'read w/ reused fd'),
985 (lambda: doreadbatch(), 'read batch'),
996 (lambda: doreadbatch(), 'read batch'),
986 (lambda: doreadbatchcachedfh(), 'read batch w/ reused fd'),
997 (lambda: doreadbatchcachedfh(), 'read batch w/ reused fd'),
987 (lambda: dochunk(), 'chunk'),
998 (lambda: dochunk(), 'chunk'),
988 (lambda: dochunkbatch(), 'chunk batch'),
999 (lambda: dochunkbatch(), 'chunk batch'),
989 ]
1000 ]
990
1001
991 for engine in sorted(engines):
1002 for engine in sorted(engines):
992 compressor = util.compengines[engine].revlogcompressor()
1003 compressor = util.compengines[engine].revlogcompressor()
993 benches.append((functools.partial(docompress, compressor),
1004 benches.append((functools.partial(docompress, compressor),
994 'compress w/ %s' % engine))
1005 'compress w/ %s' % engine))
995
1006
996 for fn, title in benches:
1007 for fn, title in benches:
997 timer, fm = gettimer(ui, opts)
1008 timer, fm = gettimer(ui, opts)
998 timer(fn, title=title)
1009 timer(fn, title=title)
999 fm.end()
1010 fm.end()
1000
1011
1001 @command('perfrevlogrevision', revlogopts + formatteropts +
1012 @command('perfrevlogrevision', revlogopts + formatteropts +
1002 [('', 'cache', False, 'use caches instead of clearing')],
1013 [('', 'cache', False, 'use caches instead of clearing')],
1003 '-c|-m|FILE REV')
1014 '-c|-m|FILE REV')
1004 def perfrevlogrevision(ui, repo, file_, rev=None, cache=None, **opts):
1015 def perfrevlogrevision(ui, repo, file_, rev=None, cache=None, **opts):
1005 """Benchmark obtaining a revlog revision.
1016 """Benchmark obtaining a revlog revision.
1006
1017
1007 Obtaining a revlog revision consists of roughly the following steps:
1018 Obtaining a revlog revision consists of roughly the following steps:
1008
1019
1009 1. Compute the delta chain
1020 1. Compute the delta chain
1010 2. Obtain the raw chunks for that delta chain
1021 2. Obtain the raw chunks for that delta chain
1011 3. Decompress each raw chunk
1022 3. Decompress each raw chunk
1012 4. Apply binary patches to obtain fulltext
1023 4. Apply binary patches to obtain fulltext
1013 5. Verify hash of fulltext
1024 5. Verify hash of fulltext
1014
1025
1015 This command measures the time spent in each of these phases.
1026 This command measures the time spent in each of these phases.
1016 """
1027 """
1017 if opts.get('changelog') or opts.get('manifest'):
1028 if opts.get('changelog') or opts.get('manifest'):
1018 file_, rev = None, file_
1029 file_, rev = None, file_
1019 elif rev is None:
1030 elif rev is None:
1020 raise error.CommandError('perfrevlogrevision', 'invalid arguments')
1031 raise error.CommandError('perfrevlogrevision', 'invalid arguments')
1021
1032
1022 r = cmdutil.openrevlog(repo, 'perfrevlogrevision', file_, opts)
1033 r = cmdutil.openrevlog(repo, 'perfrevlogrevision', file_, opts)
1023
1034
1024 # _chunkraw was renamed to _getsegmentforrevs.
1035 # _chunkraw was renamed to _getsegmentforrevs.
1025 try:
1036 try:
1026 segmentforrevs = r._getsegmentforrevs
1037 segmentforrevs = r._getsegmentforrevs
1027 except AttributeError:
1038 except AttributeError:
1028 segmentforrevs = r._chunkraw
1039 segmentforrevs = r._chunkraw
1029
1040
1030 node = r.lookup(rev)
1041 node = r.lookup(rev)
1031 rev = r.rev(node)
1042 rev = r.rev(node)
1032
1043
1033 def getrawchunks(data, chain):
1044 def getrawchunks(data, chain):
1034 start = r.start
1045 start = r.start
1035 length = r.length
1046 length = r.length
1036 inline = r._inline
1047 inline = r._inline
1037 iosize = r._io.size
1048 iosize = r._io.size
1038 buffer = util.buffer
1049 buffer = util.buffer
1039 offset = start(chain[0])
1050 offset = start(chain[0])
1040
1051
1041 chunks = []
1052 chunks = []
1042 ladd = chunks.append
1053 ladd = chunks.append
1043
1054
1044 for rev in chain:
1055 for rev in chain:
1045 chunkstart = start(rev)
1056 chunkstart = start(rev)
1046 if inline:
1057 if inline:
1047 chunkstart += (rev + 1) * iosize
1058 chunkstart += (rev + 1) * iosize
1048 chunklength = length(rev)
1059 chunklength = length(rev)
1049 ladd(buffer(data, chunkstart - offset, chunklength))
1060 ladd(buffer(data, chunkstart - offset, chunklength))
1050
1061
1051 return chunks
1062 return chunks
1052
1063
1053 def dodeltachain(rev):
1064 def dodeltachain(rev):
1054 if not cache:
1065 if not cache:
1055 r.clearcaches()
1066 r.clearcaches()
1056 r._deltachain(rev)
1067 r._deltachain(rev)
1057
1068
1058 def doread(chain):
1069 def doread(chain):
1059 if not cache:
1070 if not cache:
1060 r.clearcaches()
1071 r.clearcaches()
1061 segmentforrevs(chain[0], chain[-1])
1072 segmentforrevs(chain[0], chain[-1])
1062
1073
1063 def dorawchunks(data, chain):
1074 def dorawchunks(data, chain):
1064 if not cache:
1075 if not cache:
1065 r.clearcaches()
1076 r.clearcaches()
1066 getrawchunks(data, chain)
1077 getrawchunks(data, chain)
1067
1078
1068 def dodecompress(chunks):
1079 def dodecompress(chunks):
1069 decomp = r.decompress
1080 decomp = r.decompress
1070 for chunk in chunks:
1081 for chunk in chunks:
1071 decomp(chunk)
1082 decomp(chunk)
1072
1083
1073 def dopatch(text, bins):
1084 def dopatch(text, bins):
1074 if not cache:
1085 if not cache:
1075 r.clearcaches()
1086 r.clearcaches()
1076 mdiff.patches(text, bins)
1087 mdiff.patches(text, bins)
1077
1088
1078 def dohash(text):
1089 def dohash(text):
1079 if not cache:
1090 if not cache:
1080 r.clearcaches()
1091 r.clearcaches()
1081 r.checkhash(text, node, rev=rev)
1092 r.checkhash(text, node, rev=rev)
1082
1093
1083 def dorevision():
1094 def dorevision():
1084 if not cache:
1095 if not cache:
1085 r.clearcaches()
1096 r.clearcaches()
1086 r.revision(node)
1097 r.revision(node)
1087
1098
1088 chain = r._deltachain(rev)[0]
1099 chain = r._deltachain(rev)[0]
1089 data = segmentforrevs(chain[0], chain[-1])[1]
1100 data = segmentforrevs(chain[0], chain[-1])[1]
1090 rawchunks = getrawchunks(data, chain)
1101 rawchunks = getrawchunks(data, chain)
1091 bins = r._chunks(chain)
1102 bins = r._chunks(chain)
1092 text = str(bins[0])
1103 text = str(bins[0])
1093 bins = bins[1:]
1104 bins = bins[1:]
1094 text = mdiff.patches(text, bins)
1105 text = mdiff.patches(text, bins)
1095
1106
1096 benches = [
1107 benches = [
1097 (lambda: dorevision(), 'full'),
1108 (lambda: dorevision(), 'full'),
1098 (lambda: dodeltachain(rev), 'deltachain'),
1109 (lambda: dodeltachain(rev), 'deltachain'),
1099 (lambda: doread(chain), 'read'),
1110 (lambda: doread(chain), 'read'),
1100 (lambda: dorawchunks(data, chain), 'rawchunks'),
1111 (lambda: dorawchunks(data, chain), 'rawchunks'),
1101 (lambda: dodecompress(rawchunks), 'decompress'),
1112 (lambda: dodecompress(rawchunks), 'decompress'),
1102 (lambda: dopatch(text, bins), 'patch'),
1113 (lambda: dopatch(text, bins), 'patch'),
1103 (lambda: dohash(text), 'hash'),
1114 (lambda: dohash(text), 'hash'),
1104 ]
1115 ]
1105
1116
1106 for fn, title in benches:
1117 for fn, title in benches:
1107 timer, fm = gettimer(ui, opts)
1118 timer, fm = gettimer(ui, opts)
1108 timer(fn, title=title)
1119 timer(fn, title=title)
1109 fm.end()
1120 fm.end()
1110
1121
1111 @command('perfrevset',
1122 @command('perfrevset',
1112 [('C', 'clear', False, 'clear volatile cache between each call.'),
1123 [('C', 'clear', False, 'clear volatile cache between each call.'),
1113 ('', 'contexts', False, 'obtain changectx for each revision')]
1124 ('', 'contexts', False, 'obtain changectx for each revision')]
1114 + formatteropts, "REVSET")
1125 + formatteropts, "REVSET")
1115 def perfrevset(ui, repo, expr, clear=False, contexts=False, **opts):
1126 def perfrevset(ui, repo, expr, clear=False, contexts=False, **opts):
1116 """benchmark the execution time of a revset
1127 """benchmark the execution time of a revset
1117
1128
1118 Use the --clean option if need to evaluate the impact of build volatile
1129 Use the --clean option if need to evaluate the impact of build volatile
1119 revisions set cache on the revset execution. Volatile cache hold filtered
1130 revisions set cache on the revset execution. Volatile cache hold filtered
1120 and obsolete related cache."""
1131 and obsolete related cache."""
1121 timer, fm = gettimer(ui, opts)
1132 timer, fm = gettimer(ui, opts)
1122 def d():
1133 def d():
1123 if clear:
1134 if clear:
1124 repo.invalidatevolatilesets()
1135 repo.invalidatevolatilesets()
1125 if contexts:
1136 if contexts:
1126 for ctx in repo.set(expr): pass
1137 for ctx in repo.set(expr): pass
1127 else:
1138 else:
1128 for r in repo.revs(expr): pass
1139 for r in repo.revs(expr): pass
1129 timer(d)
1140 timer(d)
1130 fm.end()
1141 fm.end()
1131
1142
1132 def _clearobsstore(repo):
1143 def _clearobsstore(repo):
1133 unfi = repo.unfiltered()
1144 unfi = repo.unfiltered()
1134 if 'obsstore' in vars(unfi):
1145 if 'obsstore' in vars(unfi):
1135 del unfi.obsstore
1146 del unfi.obsstore
1136 del unfi._filecache['obsstore']
1147 del unfi._filecache['obsstore']
1137
1148
1138 @command('perfvolatilesets',
1149 @command('perfvolatilesets',
1139 [('', 'clear-obsstore', False, 'drop obsstore between each call.'),
1150 [('', 'clear-obsstore', False, 'drop obsstore between each call.'),
1140 ] + formatteropts)
1151 ] + formatteropts)
1141 def perfvolatilesets(ui, repo, *names, **opts):
1152 def perfvolatilesets(ui, repo, *names, **opts):
1142 """benchmark the computation of various volatile set
1153 """benchmark the computation of various volatile set
1143
1154
1144 Volatile set computes element related to filtering and obsolescence."""
1155 Volatile set computes element related to filtering and obsolescence."""
1145 timer, fm = gettimer(ui, opts)
1156 timer, fm = gettimer(ui, opts)
1146 repo = repo.unfiltered()
1157 repo = repo.unfiltered()
1147
1158
1148 def getobs(name):
1159 def getobs(name):
1149 def d():
1160 def d():
1150 repo.invalidatevolatilesets()
1161 repo.invalidatevolatilesets()
1151 if opts['clear_obsstore']:
1162 if opts['clear_obsstore']:
1152 _clearobsstore(repo)
1163 _clearobsstore(repo)
1153 obsolete.getrevs(repo, name)
1164 obsolete.getrevs(repo, name)
1154 return d
1165 return d
1155
1166
1156 allobs = sorted(obsolete.cachefuncs)
1167 allobs = sorted(obsolete.cachefuncs)
1157 if names:
1168 if names:
1158 allobs = [n for n in allobs if n in names]
1169 allobs = [n for n in allobs if n in names]
1159
1170
1160 for name in allobs:
1171 for name in allobs:
1161 timer(getobs(name), title=name)
1172 timer(getobs(name), title=name)
1162
1173
1163 def getfiltered(name):
1174 def getfiltered(name):
1164 def d():
1175 def d():
1165 repo.invalidatevolatilesets()
1176 repo.invalidatevolatilesets()
1166 if opts['clear_obsstore']:
1177 if opts['clear_obsstore']:
1167 _clearobsstore(repo)
1178 _clearobsstore(repo)
1168 repoview.filterrevs(repo, name)
1179 repoview.filterrevs(repo, name)
1169 return d
1180 return d
1170
1181
1171 allfilter = sorted(repoview.filtertable)
1182 allfilter = sorted(repoview.filtertable)
1172 if names:
1183 if names:
1173 allfilter = [n for n in allfilter if n in names]
1184 allfilter = [n for n in allfilter if n in names]
1174
1185
1175 for name in allfilter:
1186 for name in allfilter:
1176 timer(getfiltered(name), title=name)
1187 timer(getfiltered(name), title=name)
1177 fm.end()
1188 fm.end()
1178
1189
1179 @command('perfbranchmap',
1190 @command('perfbranchmap',
1180 [('f', 'full', False,
1191 [('f', 'full', False,
1181 'Includes build time of subset'),
1192 'Includes build time of subset'),
1182 ] + formatteropts)
1193 ] + formatteropts)
1183 def perfbranchmap(ui, repo, full=False, **opts):
1194 def perfbranchmap(ui, repo, full=False, **opts):
1184 """benchmark the update of a branchmap
1195 """benchmark the update of a branchmap
1185
1196
1186 This benchmarks the full repo.branchmap() call with read and write disabled
1197 This benchmarks the full repo.branchmap() call with read and write disabled
1187 """
1198 """
1188 timer, fm = gettimer(ui, opts)
1199 timer, fm = gettimer(ui, opts)
1189 def getbranchmap(filtername):
1200 def getbranchmap(filtername):
1190 """generate a benchmark function for the filtername"""
1201 """generate a benchmark function for the filtername"""
1191 if filtername is None:
1202 if filtername is None:
1192 view = repo
1203 view = repo
1193 else:
1204 else:
1194 view = repo.filtered(filtername)
1205 view = repo.filtered(filtername)
1195 def d():
1206 def d():
1196 if full:
1207 if full:
1197 view._branchcaches.clear()
1208 view._branchcaches.clear()
1198 else:
1209 else:
1199 view._branchcaches.pop(filtername, None)
1210 view._branchcaches.pop(filtername, None)
1200 view.branchmap()
1211 view.branchmap()
1201 return d
1212 return d
1202 # add filter in smaller subset to bigger subset
1213 # add filter in smaller subset to bigger subset
1203 possiblefilters = set(repoview.filtertable)
1214 possiblefilters = set(repoview.filtertable)
1204 subsettable = getbranchmapsubsettable()
1215 subsettable = getbranchmapsubsettable()
1205 allfilters = []
1216 allfilters = []
1206 while possiblefilters:
1217 while possiblefilters:
1207 for name in possiblefilters:
1218 for name in possiblefilters:
1208 subset = subsettable.get(name)
1219 subset = subsettable.get(name)
1209 if subset not in possiblefilters:
1220 if subset not in possiblefilters:
1210 break
1221 break
1211 else:
1222 else:
1212 assert False, 'subset cycle %s!' % possiblefilters
1223 assert False, 'subset cycle %s!' % possiblefilters
1213 allfilters.append(name)
1224 allfilters.append(name)
1214 possiblefilters.remove(name)
1225 possiblefilters.remove(name)
1215
1226
1216 # warm the cache
1227 # warm the cache
1217 if not full:
1228 if not full:
1218 for name in allfilters:
1229 for name in allfilters:
1219 repo.filtered(name).branchmap()
1230 repo.filtered(name).branchmap()
1220 # add unfiltered
1231 # add unfiltered
1221 allfilters.append(None)
1232 allfilters.append(None)
1222
1233
1223 branchcacheread = safeattrsetter(branchmap, 'read')
1234 branchcacheread = safeattrsetter(branchmap, 'read')
1224 branchcachewrite = safeattrsetter(branchmap.branchcache, 'write')
1235 branchcachewrite = safeattrsetter(branchmap.branchcache, 'write')
1225 branchcacheread.set(lambda repo: None)
1236 branchcacheread.set(lambda repo: None)
1226 branchcachewrite.set(lambda bc, repo: None)
1237 branchcachewrite.set(lambda bc, repo: None)
1227 try:
1238 try:
1228 for name in allfilters:
1239 for name in allfilters:
1229 timer(getbranchmap(name), title=str(name))
1240 timer(getbranchmap(name), title=str(name))
1230 finally:
1241 finally:
1231 branchcacheread.restore()
1242 branchcacheread.restore()
1232 branchcachewrite.restore()
1243 branchcachewrite.restore()
1233 fm.end()
1244 fm.end()
1234
1245
1235 @command('perfloadmarkers')
1246 @command('perfloadmarkers')
1236 def perfloadmarkers(ui, repo):
1247 def perfloadmarkers(ui, repo):
1237 """benchmark the time to parse the on-disk markers for a repo
1248 """benchmark the time to parse the on-disk markers for a repo
1238
1249
1239 Result is the number of markers in the repo."""
1250 Result is the number of markers in the repo."""
1240 timer, fm = gettimer(ui)
1251 timer, fm = gettimer(ui)
1241 svfs = getsvfs(repo)
1252 svfs = getsvfs(repo)
1242 timer(lambda: len(obsolete.obsstore(svfs)))
1253 timer(lambda: len(obsolete.obsstore(svfs)))
1243 fm.end()
1254 fm.end()
1244
1255
1245 @command('perflrucachedict', formatteropts +
1256 @command('perflrucachedict', formatteropts +
1246 [('', 'size', 4, 'size of cache'),
1257 [('', 'size', 4, 'size of cache'),
1247 ('', 'gets', 10000, 'number of key lookups'),
1258 ('', 'gets', 10000, 'number of key lookups'),
1248 ('', 'sets', 10000, 'number of key sets'),
1259 ('', 'sets', 10000, 'number of key sets'),
1249 ('', 'mixed', 10000, 'number of mixed mode operations'),
1260 ('', 'mixed', 10000, 'number of mixed mode operations'),
1250 ('', 'mixedgetfreq', 50, 'frequency of get vs set ops in mixed mode')],
1261 ('', 'mixedgetfreq', 50, 'frequency of get vs set ops in mixed mode')],
1251 norepo=True)
1262 norepo=True)
1252 def perflrucache(ui, size=4, gets=10000, sets=10000, mixed=10000,
1263 def perflrucache(ui, size=4, gets=10000, sets=10000, mixed=10000,
1253 mixedgetfreq=50, **opts):
1264 mixedgetfreq=50, **opts):
1254 def doinit():
1265 def doinit():
1255 for i in xrange(10000):
1266 for i in xrange(10000):
1256 util.lrucachedict(size)
1267 util.lrucachedict(size)
1257
1268
1258 values = []
1269 values = []
1259 for i in xrange(size):
1270 for i in xrange(size):
1260 values.append(random.randint(0, sys.maxint))
1271 values.append(random.randint(0, sys.maxint))
1261
1272
1262 # Get mode fills the cache and tests raw lookup performance with no
1273 # Get mode fills the cache and tests raw lookup performance with no
1263 # eviction.
1274 # eviction.
1264 getseq = []
1275 getseq = []
1265 for i in xrange(gets):
1276 for i in xrange(gets):
1266 getseq.append(random.choice(values))
1277 getseq.append(random.choice(values))
1267
1278
1268 def dogets():
1279 def dogets():
1269 d = util.lrucachedict(size)
1280 d = util.lrucachedict(size)
1270 for v in values:
1281 for v in values:
1271 d[v] = v
1282 d[v] = v
1272 for key in getseq:
1283 for key in getseq:
1273 value = d[key]
1284 value = d[key]
1274 value # silence pyflakes warning
1285 value # silence pyflakes warning
1275
1286
1276 # Set mode tests insertion speed with cache eviction.
1287 # Set mode tests insertion speed with cache eviction.
1277 setseq = []
1288 setseq = []
1278 for i in xrange(sets):
1289 for i in xrange(sets):
1279 setseq.append(random.randint(0, sys.maxint))
1290 setseq.append(random.randint(0, sys.maxint))
1280
1291
1281 def dosets():
1292 def dosets():
1282 d = util.lrucachedict(size)
1293 d = util.lrucachedict(size)
1283 for v in setseq:
1294 for v in setseq:
1284 d[v] = v
1295 d[v] = v
1285
1296
1286 # Mixed mode randomly performs gets and sets with eviction.
1297 # Mixed mode randomly performs gets and sets with eviction.
1287 mixedops = []
1298 mixedops = []
1288 for i in xrange(mixed):
1299 for i in xrange(mixed):
1289 r = random.randint(0, 100)
1300 r = random.randint(0, 100)
1290 if r < mixedgetfreq:
1301 if r < mixedgetfreq:
1291 op = 0
1302 op = 0
1292 else:
1303 else:
1293 op = 1
1304 op = 1
1294
1305
1295 mixedops.append((op, random.randint(0, size * 2)))
1306 mixedops.append((op, random.randint(0, size * 2)))
1296
1307
1297 def domixed():
1308 def domixed():
1298 d = util.lrucachedict(size)
1309 d = util.lrucachedict(size)
1299
1310
1300 for op, v in mixedops:
1311 for op, v in mixedops:
1301 if op == 0:
1312 if op == 0:
1302 try:
1313 try:
1303 d[v]
1314 d[v]
1304 except KeyError:
1315 except KeyError:
1305 pass
1316 pass
1306 else:
1317 else:
1307 d[v] = v
1318 d[v] = v
1308
1319
1309 benches = [
1320 benches = [
1310 (doinit, 'init'),
1321 (doinit, 'init'),
1311 (dogets, 'gets'),
1322 (dogets, 'gets'),
1312 (dosets, 'sets'),
1323 (dosets, 'sets'),
1313 (domixed, 'mixed')
1324 (domixed, 'mixed')
1314 ]
1325 ]
1315
1326
1316 for fn, title in benches:
1327 for fn, title in benches:
1317 timer, fm = gettimer(ui, opts)
1328 timer, fm = gettimer(ui, opts)
1318 timer(fn, title=title)
1329 timer(fn, title=title)
1319 fm.end()
1330 fm.end()
1320
1331
1321 @command('perfwrite', formatteropts)
1332 @command('perfwrite', formatteropts)
1322 def perfwrite(ui, repo, **opts):
1333 def perfwrite(ui, repo, **opts):
1323 """microbenchmark ui.write
1334 """microbenchmark ui.write
1324 """
1335 """
1325 timer, fm = gettimer(ui, opts)
1336 timer, fm = gettimer(ui, opts)
1326 def write():
1337 def write():
1327 for i in range(100000):
1338 for i in range(100000):
1328 ui.write(('Testing write performance\n'))
1339 ui.write(('Testing write performance\n'))
1329 timer(write)
1340 timer(write)
1330 fm.end()
1341 fm.end()
1331
1342
1332 def uisetup(ui):
1343 def uisetup(ui):
1333 if (util.safehasattr(cmdutil, 'openrevlog') and
1344 if (util.safehasattr(cmdutil, 'openrevlog') and
1334 not util.safehasattr(commands, 'debugrevlogopts')):
1345 not util.safehasattr(commands, 'debugrevlogopts')):
1335 # for "historical portability":
1346 # for "historical portability":
1336 # In this case, Mercurial should be 1.9 (or a79fea6b3e77) -
1347 # In this case, Mercurial should be 1.9 (or a79fea6b3e77) -
1337 # 3.7 (or 5606f7d0d063). Therefore, '--dir' option for
1348 # 3.7 (or 5606f7d0d063). Therefore, '--dir' option for
1338 # openrevlog() should cause failure, because it has been
1349 # openrevlog() should cause failure, because it has been
1339 # available since 3.5 (or 49c583ca48c4).
1350 # available since 3.5 (or 49c583ca48c4).
1340 def openrevlog(orig, repo, cmd, file_, opts):
1351 def openrevlog(orig, repo, cmd, file_, opts):
1341 if opts.get('dir') and not util.safehasattr(repo, 'dirlog'):
1352 if opts.get('dir') and not util.safehasattr(repo, 'dirlog'):
1342 raise error.Abort("This version doesn't support --dir option",
1353 raise error.Abort("This version doesn't support --dir option",
1343 hint="use 3.5 or later")
1354 hint="use 3.5 or later")
1344 return orig(repo, cmd, file_, opts)
1355 return orig(repo, cmd, file_, opts)
1345 extensions.wrapfunction(cmdutil, 'openrevlog', openrevlog)
1356 extensions.wrapfunction(cmdutil, 'openrevlog', openrevlog)
@@ -1,167 +1,168
1 #require test-repo
1 #require test-repo
2
2
3 Set vars:
3 Set vars:
4
4
5 $ . "$TESTDIR/helpers-testrepo.sh"
5 $ . "$TESTDIR/helpers-testrepo.sh"
6 $ CONTRIBDIR="$TESTDIR/../contrib"
6 $ CONTRIBDIR="$TESTDIR/../contrib"
7
7
8 Prepare repo:
8 Prepare repo:
9
9
10 $ hg init
10 $ hg init
11
11
12 $ echo this is file a > a
12 $ echo this is file a > a
13 $ hg add a
13 $ hg add a
14 $ hg commit -m first
14 $ hg commit -m first
15
15
16 $ echo adding to file a >> a
16 $ echo adding to file a >> a
17 $ hg commit -m second
17 $ hg commit -m second
18
18
19 $ echo adding more to file a >> a
19 $ echo adding more to file a >> a
20 $ hg commit -m third
20 $ hg commit -m third
21
21
22 $ hg up -r 0
22 $ hg up -r 0
23 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
23 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
24 $ echo merge-this >> a
24 $ echo merge-this >> a
25 $ hg commit -m merge-able
25 $ hg commit -m merge-able
26 created new head
26 created new head
27
27
28 $ hg up -r 2
28 $ hg up -r 2
29 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
29 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
30
30
31 perfstatus
31 perfstatus
32
32
33 $ cat >> $HGRCPATH << EOF
33 $ cat >> $HGRCPATH << EOF
34 > [extensions]
34 > [extensions]
35 > perfstatusext=$CONTRIBDIR/perf.py
35 > perfstatusext=$CONTRIBDIR/perf.py
36 > [perf]
36 > [perf]
37 > presleep=0
37 > presleep=0
38 > stub=on
38 > stub=on
39 > parentscount=1
39 > parentscount=1
40 > EOF
40 > EOF
41 $ hg help perfstatusext
41 $ hg help perfstatusext
42 perfstatusext extension - helper extension to measure performance
42 perfstatusext extension - helper extension to measure performance
43
43
44 list of commands:
44 list of commands:
45
45
46 perfaddremove
46 perfaddremove
47 (no help text available)
47 (no help text available)
48 perfancestors
48 perfancestors
49 (no help text available)
49 (no help text available)
50 perfancestorset
50 perfancestorset
51 (no help text available)
51 (no help text available)
52 perfannotate (no help text available)
52 perfannotate (no help text available)
53 perfbdiff benchmark a bdiff between revisions
53 perfbdiff benchmark a bdiff between revisions
54 perfbranchmap
54 perfbranchmap
55 benchmark the update of a branchmap
55 benchmark the update of a branchmap
56 perfcca (no help text available)
56 perfcca (no help text available)
57 perfchangegroupchangelog
57 perfchangegroupchangelog
58 Benchmark producing a changelog group for a changegroup.
58 Benchmark producing a changelog group for a changegroup.
59 perfchangeset
59 perfchangeset
60 (no help text available)
60 (no help text available)
61 perfctxfiles (no help text available)
61 perfctxfiles (no help text available)
62 perfdiffwd Profile diff of working directory changes
62 perfdiffwd Profile diff of working directory changes
63 perfdirfoldmap
63 perfdirfoldmap
64 (no help text available)
64 (no help text available)
65 perfdirs (no help text available)
65 perfdirs (no help text available)
66 perfdirstate (no help text available)
66 perfdirstate (no help text available)
67 perfdirstatedirs
67 perfdirstatedirs
68 (no help text available)
68 (no help text available)
69 perfdirstatefoldmap
69 perfdirstatefoldmap
70 (no help text available)
70 (no help text available)
71 perfdirstatewrite
71 perfdirstatewrite
72 (no help text available)
72 (no help text available)
73 perffncacheencode
73 perffncacheencode
74 (no help text available)
74 (no help text available)
75 perffncacheload
75 perffncacheload
76 (no help text available)
76 (no help text available)
77 perffncachewrite
77 perffncachewrite
78 (no help text available)
78 (no help text available)
79 perfheads (no help text available)
79 perfheads (no help text available)
80 perfindex (no help text available)
80 perfindex (no help text available)
81 perfloadmarkers
81 perfloadmarkers
82 benchmark the time to parse the on-disk markers for a repo
82 benchmark the time to parse the on-disk markers for a repo
83 perflog (no help text available)
83 perflog (no help text available)
84 perflookup (no help text available)
84 perflookup (no help text available)
85 perflrucachedict
85 perflrucachedict
86 (no help text available)
86 (no help text available)
87 perfmanifest (no help text available)
87 perfmanifest (no help text available)
88 perfmergecalculate
88 perfmergecalculate
89 (no help text available)
89 (no help text available)
90 perfmoonwalk benchmark walking the changelog backwards
90 perfmoonwalk benchmark walking the changelog backwards
91 perfnodelookup
91 perfnodelookup
92 (no help text available)
92 (no help text available)
93 perfparents (no help text available)
93 perfparents (no help text available)
94 perfpathcopies
94 perfpathcopies
95 (no help text available)
95 (no help text available)
96 perfphases benchmark phasesets computation
96 perfrawfiles (no help text available)
97 perfrawfiles (no help text available)
97 perfrevlog Benchmark reading a series of revisions from a revlog.
98 perfrevlog Benchmark reading a series of revisions from a revlog.
98 perfrevlogchunks
99 perfrevlogchunks
99 Benchmark operations on revlog chunks.
100 Benchmark operations on revlog chunks.
100 perfrevlogrevision
101 perfrevlogrevision
101 Benchmark obtaining a revlog revision.
102 Benchmark obtaining a revlog revision.
102 perfrevrange (no help text available)
103 perfrevrange (no help text available)
103 perfrevset benchmark the execution time of a revset
104 perfrevset benchmark the execution time of a revset
104 perfstartup (no help text available)
105 perfstartup (no help text available)
105 perfstatus (no help text available)
106 perfstatus (no help text available)
106 perftags (no help text available)
107 perftags (no help text available)
107 perftemplating
108 perftemplating
108 (no help text available)
109 (no help text available)
109 perfvolatilesets
110 perfvolatilesets
110 benchmark the computation of various volatile set
111 benchmark the computation of various volatile set
111 perfwalk (no help text available)
112 perfwalk (no help text available)
112 perfwrite microbenchmark ui.write
113 perfwrite microbenchmark ui.write
113
114
114 (use 'hg help -v perfstatusext' to show built-in aliases and global options)
115 (use 'hg help -v perfstatusext' to show built-in aliases and global options)
115 $ hg perfaddremove
116 $ hg perfaddremove
116 $ hg perfancestors
117 $ hg perfancestors
117 $ hg perfancestorset 2
118 $ hg perfancestorset 2
118 $ hg perfannotate a
119 $ hg perfannotate a
119 $ hg perfbdiff -c 1
120 $ hg perfbdiff -c 1
120 $ hg perfbdiff --alldata 1
121 $ hg perfbdiff --alldata 1
121 $ hg perfbranchmap
122 $ hg perfbranchmap
122 $ hg perfcca
123 $ hg perfcca
123 $ hg perfchangegroupchangelog
124 $ hg perfchangegroupchangelog
124 $ hg perfchangeset 2
125 $ hg perfchangeset 2
125 $ hg perfctxfiles 2
126 $ hg perfctxfiles 2
126 $ hg perfdiffwd
127 $ hg perfdiffwd
127 $ hg perfdirfoldmap
128 $ hg perfdirfoldmap
128 $ hg perfdirs
129 $ hg perfdirs
129 $ hg perfdirstate
130 $ hg perfdirstate
130 $ hg perfdirstatedirs
131 $ hg perfdirstatedirs
131 $ hg perfdirstatefoldmap
132 $ hg perfdirstatefoldmap
132 $ hg perfdirstatewrite
133 $ hg perfdirstatewrite
133 $ hg perffncacheencode
134 $ hg perffncacheencode
134 $ hg perffncacheload
135 $ hg perffncacheload
135 $ hg perffncachewrite
136 $ hg perffncachewrite
136 $ hg perfheads
137 $ hg perfheads
137 $ hg perfindex
138 $ hg perfindex
138 $ hg perfloadmarkers
139 $ hg perfloadmarkers
139 $ hg perflog
140 $ hg perflog
140 $ hg perflookup 2
141 $ hg perflookup 2
141 $ hg perflrucache
142 $ hg perflrucache
142 $ hg perfmanifest 2
143 $ hg perfmanifest 2
143 $ hg perfmergecalculate -r 3
144 $ hg perfmergecalculate -r 3
144 $ hg perfmoonwalk
145 $ hg perfmoonwalk
145 $ hg perfnodelookup 2
146 $ hg perfnodelookup 2
146 $ hg perfpathcopies 1 2
147 $ hg perfpathcopies 1 2
147 $ hg perfrawfiles 2
148 $ hg perfrawfiles 2
148 $ hg perfrevlog .hg/store/data/a.i
149 $ hg perfrevlog .hg/store/data/a.i
149 $ hg perfrevlogrevision -m 0
150 $ hg perfrevlogrevision -m 0
150 $ hg perfrevlogchunks -c
151 $ hg perfrevlogchunks -c
151 $ hg perfrevrange
152 $ hg perfrevrange
152 $ hg perfrevset 'all()'
153 $ hg perfrevset 'all()'
153 $ hg perfstartup
154 $ hg perfstartup
154 $ hg perfstatus
155 $ hg perfstatus
155 $ hg perftags
156 $ hg perftags
156 $ hg perftemplating
157 $ hg perftemplating
157 $ hg perfvolatilesets
158 $ hg perfvolatilesets
158 $ hg perfwalk
159 $ hg perfwalk
159 $ hg perfparents
160 $ hg perfparents
160
161
161 Check perf.py for historical portability
162 Check perf.py for historical portability
162
163
163 $ cd "$TESTDIR/.."
164 $ cd "$TESTDIR/.."
164
165
165 $ (hg files -r 1.2 glob:mercurial/*.c glob:mercurial/*.py;
166 $ (hg files -r 1.2 glob:mercurial/*.c glob:mercurial/*.py;
166 > hg files -r tip glob:mercurial/*.c glob:mercurial/*.py) |
167 > hg files -r tip glob:mercurial/*.c glob:mercurial/*.py) |
167 > "$TESTDIR"/check-perf-code.py contrib/perf.py
168 > "$TESTDIR"/check-perf-code.py contrib/perf.py
General Comments 0
You need to be logged in to leave comments. Login now