##// END OF EJS Templates
py3: make test-contrib-perf.t work on python 3...
Pulkit Goyal -
r40250:b456b2e0 default
parent child Browse files
Show More
@@ -1,2123 +1,2126 b''
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 contextlib
22 import contextlib
23 import functools
23 import functools
24 import gc
24 import gc
25 import os
25 import os
26 import random
26 import random
27 import struct
27 import struct
28 import sys
28 import sys
29 import threading
29 import threading
30 import time
30 import time
31 from mercurial import (
31 from mercurial import (
32 changegroup,
32 changegroup,
33 cmdutil,
33 cmdutil,
34 commands,
34 commands,
35 copies,
35 copies,
36 error,
36 error,
37 extensions,
37 extensions,
38 mdiff,
38 mdiff,
39 merge,
39 merge,
40 revlog,
40 revlog,
41 util,
41 util,
42 )
42 )
43
43
44 # for "historical portability":
44 # for "historical portability":
45 # try to import modules separately (in dict order), and ignore
45 # try to import modules separately (in dict order), and ignore
46 # failure, because these aren't available with early Mercurial
46 # failure, because these aren't available with early Mercurial
47 try:
47 try:
48 from mercurial import branchmap # since 2.5 (or bcee63733aad)
48 from mercurial import branchmap # since 2.5 (or bcee63733aad)
49 except ImportError:
49 except ImportError:
50 pass
50 pass
51 try:
51 try:
52 from mercurial import obsolete # since 2.3 (or ad0d6c2b3279)
52 from mercurial import obsolete # since 2.3 (or ad0d6c2b3279)
53 except ImportError:
53 except ImportError:
54 pass
54 pass
55 try:
55 try:
56 from mercurial import registrar # since 3.7 (or 37d50250b696)
56 from mercurial import registrar # since 3.7 (or 37d50250b696)
57 dir(registrar) # forcibly load it
57 dir(registrar) # forcibly load it
58 except ImportError:
58 except ImportError:
59 registrar = None
59 registrar = None
60 try:
60 try:
61 from mercurial import repoview # since 2.5 (or 3a6ddacb7198)
61 from mercurial import repoview # since 2.5 (or 3a6ddacb7198)
62 except ImportError:
62 except ImportError:
63 pass
63 pass
64 try:
64 try:
65 from mercurial import scmutil # since 1.9 (or 8b252e826c68)
65 from mercurial import scmutil # since 1.9 (or 8b252e826c68)
66 except ImportError:
66 except ImportError:
67 pass
67 pass
68
68
69 def identity(a):
69 def identity(a):
70 return a
70 return a
71
71
72 try:
72 try:
73 from mercurial import pycompat
73 from mercurial import pycompat
74 getargspec = pycompat.getargspec # added to module after 4.5
74 getargspec = pycompat.getargspec # added to module after 4.5
75 _byteskwargs = pycompat.byteskwargs # since 4.1 (or fbc3f73dc802)
75 _byteskwargs = pycompat.byteskwargs # since 4.1 (or fbc3f73dc802)
76 _sysstr = pycompat.sysstr # since 4.0 (or 2219f4f82ede)
76 _sysstr = pycompat.sysstr # since 4.0 (or 2219f4f82ede)
77 _xrange = pycompat.xrange # since 4.8 (or 7eba8f83129b)
77 _xrange = pycompat.xrange # since 4.8 (or 7eba8f83129b)
78 fsencode = pycompat.fsencode # since 3.9 (or f4a5e0e86a7e)
78 if pycompat.ispy3:
79 if pycompat.ispy3:
79 _maxint = sys.maxsize # per py3 docs for replacing maxint
80 _maxint = sys.maxsize # per py3 docs for replacing maxint
80 else:
81 else:
81 _maxint = sys.maxint
82 _maxint = sys.maxint
82 except (ImportError, AttributeError):
83 except (ImportError, AttributeError):
83 import inspect
84 import inspect
84 getargspec = inspect.getargspec
85 getargspec = inspect.getargspec
85 _byteskwargs = identity
86 _byteskwargs = identity
87 fsencode = identity # no py3 support
86 _maxint = sys.maxint # no py3 support
88 _maxint = sys.maxint # no py3 support
87 _sysstr = lambda x: x # no py3 support
89 _sysstr = lambda x: x # no py3 support
88 _xrange = xrange
90 _xrange = xrange
89
91
90 try:
92 try:
91 # 4.7+
93 # 4.7+
92 queue = pycompat.queue.Queue
94 queue = pycompat.queue.Queue
93 except (AttributeError, ImportError):
95 except (AttributeError, ImportError):
94 # <4.7.
96 # <4.7.
95 try:
97 try:
96 queue = pycompat.queue
98 queue = pycompat.queue
97 except (AttributeError, ImportError):
99 except (AttributeError, ImportError):
98 queue = util.queue
100 queue = util.queue
99
101
100 try:
102 try:
101 from mercurial import logcmdutil
103 from mercurial import logcmdutil
102 makelogtemplater = logcmdutil.maketemplater
104 makelogtemplater = logcmdutil.maketemplater
103 except (AttributeError, ImportError):
105 except (AttributeError, ImportError):
104 try:
106 try:
105 makelogtemplater = cmdutil.makelogtemplater
107 makelogtemplater = cmdutil.makelogtemplater
106 except (AttributeError, ImportError):
108 except (AttributeError, ImportError):
107 makelogtemplater = None
109 makelogtemplater = None
108
110
109 # for "historical portability":
111 # for "historical portability":
110 # define util.safehasattr forcibly, because util.safehasattr has been
112 # define util.safehasattr forcibly, because util.safehasattr has been
111 # available since 1.9.3 (or 94b200a11cf7)
113 # available since 1.9.3 (or 94b200a11cf7)
112 _undefined = object()
114 _undefined = object()
113 def safehasattr(thing, attr):
115 def safehasattr(thing, attr):
114 return getattr(thing, _sysstr(attr), _undefined) is not _undefined
116 return getattr(thing, _sysstr(attr), _undefined) is not _undefined
115 setattr(util, 'safehasattr', safehasattr)
117 setattr(util, 'safehasattr', safehasattr)
116
118
117 # for "historical portability":
119 # for "historical portability":
118 # define util.timer forcibly, because util.timer has been available
120 # define util.timer forcibly, because util.timer has been available
119 # since ae5d60bb70c9
121 # since ae5d60bb70c9
120 if safehasattr(time, 'perf_counter'):
122 if safehasattr(time, 'perf_counter'):
121 util.timer = time.perf_counter
123 util.timer = time.perf_counter
122 elif os.name == b'nt':
124 elif os.name == b'nt':
123 util.timer = time.clock
125 util.timer = time.clock
124 else:
126 else:
125 util.timer = time.time
127 util.timer = time.time
126
128
127 # for "historical portability":
129 # for "historical portability":
128 # use locally defined empty option list, if formatteropts isn't
130 # use locally defined empty option list, if formatteropts isn't
129 # available, because commands.formatteropts has been available since
131 # available, because commands.formatteropts has been available since
130 # 3.2 (or 7a7eed5176a4), even though formatting itself has been
132 # 3.2 (or 7a7eed5176a4), even though formatting itself has been
131 # available since 2.2 (or ae5f92e154d3)
133 # available since 2.2 (or ae5f92e154d3)
132 formatteropts = getattr(cmdutil, "formatteropts",
134 formatteropts = getattr(cmdutil, "formatteropts",
133 getattr(commands, "formatteropts", []))
135 getattr(commands, "formatteropts", []))
134
136
135 # for "historical portability":
137 # for "historical portability":
136 # use locally defined option list, if debugrevlogopts isn't available,
138 # use locally defined option list, if debugrevlogopts isn't available,
137 # because commands.debugrevlogopts has been available since 3.7 (or
139 # because commands.debugrevlogopts has been available since 3.7 (or
138 # 5606f7d0d063), even though cmdutil.openrevlog() has been available
140 # 5606f7d0d063), even though cmdutil.openrevlog() has been available
139 # since 1.9 (or a79fea6b3e77).
141 # since 1.9 (or a79fea6b3e77).
140 revlogopts = getattr(cmdutil, "debugrevlogopts",
142 revlogopts = getattr(cmdutil, "debugrevlogopts",
141 getattr(commands, "debugrevlogopts", [
143 getattr(commands, "debugrevlogopts", [
142 (b'c', b'changelog', False, (b'open changelog')),
144 (b'c', b'changelog', False, (b'open changelog')),
143 (b'm', b'manifest', False, (b'open manifest')),
145 (b'm', b'manifest', False, (b'open manifest')),
144 (b'', b'dir', False, (b'open directory manifest')),
146 (b'', b'dir', False, (b'open directory manifest')),
145 ]))
147 ]))
146
148
147 cmdtable = {}
149 cmdtable = {}
148
150
149 # for "historical portability":
151 # for "historical portability":
150 # define parsealiases locally, because cmdutil.parsealiases has been
152 # define parsealiases locally, because cmdutil.parsealiases has been
151 # available since 1.5 (or 6252852b4332)
153 # available since 1.5 (or 6252852b4332)
152 def parsealiases(cmd):
154 def parsealiases(cmd):
153 return cmd.lstrip(b"^").split(b"|")
155 return cmd.lstrip(b"^").split(b"|")
154
156
155 if safehasattr(registrar, 'command'):
157 if safehasattr(registrar, 'command'):
156 command = registrar.command(cmdtable)
158 command = registrar.command(cmdtable)
157 elif safehasattr(cmdutil, 'command'):
159 elif safehasattr(cmdutil, 'command'):
158 command = cmdutil.command(cmdtable)
160 command = cmdutil.command(cmdtable)
159 if b'norepo' not in getargspec(command).args:
161 if b'norepo' not in getargspec(command).args:
160 # for "historical portability":
162 # for "historical portability":
161 # wrap original cmdutil.command, because "norepo" option has
163 # wrap original cmdutil.command, because "norepo" option has
162 # been available since 3.1 (or 75a96326cecb)
164 # been available since 3.1 (or 75a96326cecb)
163 _command = command
165 _command = command
164 def command(name, options=(), synopsis=None, norepo=False):
166 def command(name, options=(), synopsis=None, norepo=False):
165 if norepo:
167 if norepo:
166 commands.norepo += b' %s' % b' '.join(parsealiases(name))
168 commands.norepo += b' %s' % b' '.join(parsealiases(name))
167 return _command(name, list(options), synopsis)
169 return _command(name, list(options), synopsis)
168 else:
170 else:
169 # for "historical portability":
171 # for "historical portability":
170 # define "@command" annotation locally, because cmdutil.command
172 # define "@command" annotation locally, because cmdutil.command
171 # has been available since 1.9 (or 2daa5179e73f)
173 # has been available since 1.9 (or 2daa5179e73f)
172 def command(name, options=(), synopsis=None, norepo=False):
174 def command(name, options=(), synopsis=None, norepo=False):
173 def decorator(func):
175 def decorator(func):
174 if synopsis:
176 if synopsis:
175 cmdtable[name] = func, list(options), synopsis
177 cmdtable[name] = func, list(options), synopsis
176 else:
178 else:
177 cmdtable[name] = func, list(options)
179 cmdtable[name] = func, list(options)
178 if norepo:
180 if norepo:
179 commands.norepo += b' %s' % b' '.join(parsealiases(name))
181 commands.norepo += b' %s' % b' '.join(parsealiases(name))
180 return func
182 return func
181 return decorator
183 return decorator
182
184
183 try:
185 try:
184 import mercurial.registrar
186 import mercurial.registrar
185 import mercurial.configitems
187 import mercurial.configitems
186 configtable = {}
188 configtable = {}
187 configitem = mercurial.registrar.configitem(configtable)
189 configitem = mercurial.registrar.configitem(configtable)
188 configitem(b'perf', b'presleep',
190 configitem(b'perf', b'presleep',
189 default=mercurial.configitems.dynamicdefault,
191 default=mercurial.configitems.dynamicdefault,
190 )
192 )
191 configitem(b'perf', b'stub',
193 configitem(b'perf', b'stub',
192 default=mercurial.configitems.dynamicdefault,
194 default=mercurial.configitems.dynamicdefault,
193 )
195 )
194 configitem(b'perf', b'parentscount',
196 configitem(b'perf', b'parentscount',
195 default=mercurial.configitems.dynamicdefault,
197 default=mercurial.configitems.dynamicdefault,
196 )
198 )
197 configitem(b'perf', b'all-timing',
199 configitem(b'perf', b'all-timing',
198 default=mercurial.configitems.dynamicdefault,
200 default=mercurial.configitems.dynamicdefault,
199 )
201 )
200 except (ImportError, AttributeError):
202 except (ImportError, AttributeError):
201 pass
203 pass
202
204
203 def getlen(ui):
205 def getlen(ui):
204 if ui.configbool(b"perf", b"stub", False):
206 if ui.configbool(b"perf", b"stub", False):
205 return lambda x: 1
207 return lambda x: 1
206 return len
208 return len
207
209
208 def gettimer(ui, opts=None):
210 def gettimer(ui, opts=None):
209 """return a timer function and formatter: (timer, formatter)
211 """return a timer function and formatter: (timer, formatter)
210
212
211 This function exists to gather the creation of formatter in a single
213 This function exists to gather the creation of formatter in a single
212 place instead of duplicating it in all performance commands."""
214 place instead of duplicating it in all performance commands."""
213
215
214 # enforce an idle period before execution to counteract power management
216 # enforce an idle period before execution to counteract power management
215 # experimental config: perf.presleep
217 # experimental config: perf.presleep
216 time.sleep(getint(ui, b"perf", b"presleep", 1))
218 time.sleep(getint(ui, b"perf", b"presleep", 1))
217
219
218 if opts is None:
220 if opts is None:
219 opts = {}
221 opts = {}
220 # redirect all to stderr unless buffer api is in use
222 # redirect all to stderr unless buffer api is in use
221 if not ui._buffers:
223 if not ui._buffers:
222 ui = ui.copy()
224 ui = ui.copy()
223 uifout = safeattrsetter(ui, b'fout', ignoremissing=True)
225 uifout = safeattrsetter(ui, b'fout', ignoremissing=True)
224 if uifout:
226 if uifout:
225 # for "historical portability":
227 # for "historical portability":
226 # ui.fout/ferr have been available since 1.9 (or 4e1ccd4c2b6d)
228 # ui.fout/ferr have been available since 1.9 (or 4e1ccd4c2b6d)
227 uifout.set(ui.ferr)
229 uifout.set(ui.ferr)
228
230
229 # get a formatter
231 # get a formatter
230 uiformatter = getattr(ui, 'formatter', None)
232 uiformatter = getattr(ui, 'formatter', None)
231 if uiformatter:
233 if uiformatter:
232 fm = uiformatter(b'perf', opts)
234 fm = uiformatter(b'perf', opts)
233 else:
235 else:
234 # for "historical portability":
236 # for "historical portability":
235 # define formatter locally, because ui.formatter has been
237 # define formatter locally, because ui.formatter has been
236 # available since 2.2 (or ae5f92e154d3)
238 # available since 2.2 (or ae5f92e154d3)
237 from mercurial import node
239 from mercurial import node
238 class defaultformatter(object):
240 class defaultformatter(object):
239 """Minimized composition of baseformatter and plainformatter
241 """Minimized composition of baseformatter and plainformatter
240 """
242 """
241 def __init__(self, ui, topic, opts):
243 def __init__(self, ui, topic, opts):
242 self._ui = ui
244 self._ui = ui
243 if ui.debugflag:
245 if ui.debugflag:
244 self.hexfunc = node.hex
246 self.hexfunc = node.hex
245 else:
247 else:
246 self.hexfunc = node.short
248 self.hexfunc = node.short
247 def __nonzero__(self):
249 def __nonzero__(self):
248 return False
250 return False
249 __bool__ = __nonzero__
251 __bool__ = __nonzero__
250 def startitem(self):
252 def startitem(self):
251 pass
253 pass
252 def data(self, **data):
254 def data(self, **data):
253 pass
255 pass
254 def write(self, fields, deftext, *fielddata, **opts):
256 def write(self, fields, deftext, *fielddata, **opts):
255 self._ui.write(deftext % fielddata, **opts)
257 self._ui.write(deftext % fielddata, **opts)
256 def condwrite(self, cond, fields, deftext, *fielddata, **opts):
258 def condwrite(self, cond, fields, deftext, *fielddata, **opts):
257 if cond:
259 if cond:
258 self._ui.write(deftext % fielddata, **opts)
260 self._ui.write(deftext % fielddata, **opts)
259 def plain(self, text, **opts):
261 def plain(self, text, **opts):
260 self._ui.write(text, **opts)
262 self._ui.write(text, **opts)
261 def end(self):
263 def end(self):
262 pass
264 pass
263 fm = defaultformatter(ui, b'perf', opts)
265 fm = defaultformatter(ui, b'perf', opts)
264
266
265 # stub function, runs code only once instead of in a loop
267 # stub function, runs code only once instead of in a loop
266 # experimental config: perf.stub
268 # experimental config: perf.stub
267 if ui.configbool(b"perf", b"stub", False):
269 if ui.configbool(b"perf", b"stub", False):
268 return functools.partial(stub_timer, fm), fm
270 return functools.partial(stub_timer, fm), fm
269
271
270 # experimental config: perf.all-timing
272 # experimental config: perf.all-timing
271 displayall = ui.configbool(b"perf", b"all-timing", False)
273 displayall = ui.configbool(b"perf", b"all-timing", False)
272 return functools.partial(_timer, fm, displayall=displayall), fm
274 return functools.partial(_timer, fm, displayall=displayall), fm
273
275
274 def stub_timer(fm, func, title=None):
276 def stub_timer(fm, func, title=None):
275 func()
277 func()
276
278
277 @contextlib.contextmanager
279 @contextlib.contextmanager
278 def timeone():
280 def timeone():
279 r = []
281 r = []
280 ostart = os.times()
282 ostart = os.times()
281 cstart = util.timer()
283 cstart = util.timer()
282 yield r
284 yield r
283 cstop = util.timer()
285 cstop = util.timer()
284 ostop = os.times()
286 ostop = os.times()
285 a, b = ostart, ostop
287 a, b = ostart, ostop
286 r.append((cstop - cstart, b[0] - a[0], b[1]-a[1]))
288 r.append((cstop - cstart, b[0] - a[0], b[1]-a[1]))
287
289
288 def _timer(fm, func, title=None, displayall=False):
290 def _timer(fm, func, title=None, displayall=False):
289 gc.collect()
291 gc.collect()
290 results = []
292 results = []
291 begin = util.timer()
293 begin = util.timer()
292 count = 0
294 count = 0
293 while True:
295 while True:
294 with timeone() as item:
296 with timeone() as item:
295 r = func()
297 r = func()
296 count += 1
298 count += 1
297 results.append(item[0])
299 results.append(item[0])
298 cstop = util.timer()
300 cstop = util.timer()
299 if cstop - begin > 3 and count >= 100:
301 if cstop - begin > 3 and count >= 100:
300 break
302 break
301 if cstop - begin > 10 and count >= 3:
303 if cstop - begin > 10 and count >= 3:
302 break
304 break
303
305
304 formatone(fm, results, title=title, result=r,
306 formatone(fm, results, title=title, result=r,
305 displayall=displayall)
307 displayall=displayall)
306
308
307 def formatone(fm, timings, title=None, result=None, displayall=False):
309 def formatone(fm, timings, title=None, result=None, displayall=False):
308
310
309 count = len(timings)
311 count = len(timings)
310
312
311 fm.startitem()
313 fm.startitem()
312
314
313 if title:
315 if title:
314 fm.write(b'title', b'! %s\n', title)
316 fm.write(b'title', b'! %s\n', title)
315 if result:
317 if result:
316 fm.write(b'result', b'! result: %s\n', result)
318 fm.write(b'result', b'! result: %s\n', result)
317 def display(role, entry):
319 def display(role, entry):
318 prefix = b''
320 prefix = b''
319 if role != b'best':
321 if role != b'best':
320 prefix = b'%s.' % role
322 prefix = b'%s.' % role
321 fm.plain(b'!')
323 fm.plain(b'!')
322 fm.write(prefix + b'wall', b' wall %f', entry[0])
324 fm.write(prefix + b'wall', b' wall %f', entry[0])
323 fm.write(prefix + b'comb', b' comb %f', entry[1] + entry[2])
325 fm.write(prefix + b'comb', b' comb %f', entry[1] + entry[2])
324 fm.write(prefix + b'user', b' user %f', entry[1])
326 fm.write(prefix + b'user', b' user %f', entry[1])
325 fm.write(prefix + b'sys', b' sys %f', entry[2])
327 fm.write(prefix + b'sys', b' sys %f', entry[2])
326 fm.write(prefix + b'count', b' (%s of %%d)' % role, count)
328 fm.write(prefix + b'count', b' (%s of %%d)' % role, count)
327 fm.plain(b'\n')
329 fm.plain(b'\n')
328 timings.sort()
330 timings.sort()
329 min_val = timings[0]
331 min_val = timings[0]
330 display(b'best', min_val)
332 display(b'best', min_val)
331 if displayall:
333 if displayall:
332 max_val = timings[-1]
334 max_val = timings[-1]
333 display(b'max', max_val)
335 display(b'max', max_val)
334 avg = tuple([sum(x) / count for x in zip(*timings)])
336 avg = tuple([sum(x) / count for x in zip(*timings)])
335 display(b'avg', avg)
337 display(b'avg', avg)
336 median = timings[len(timings) // 2]
338 median = timings[len(timings) // 2]
337 display(b'median', median)
339 display(b'median', median)
338
340
339 # utilities for historical portability
341 # utilities for historical portability
340
342
341 def getint(ui, section, name, default):
343 def getint(ui, section, name, default):
342 # for "historical portability":
344 # for "historical portability":
343 # ui.configint has been available since 1.9 (or fa2b596db182)
345 # ui.configint has been available since 1.9 (or fa2b596db182)
344 v = ui.config(section, name, None)
346 v = ui.config(section, name, None)
345 if v is None:
347 if v is None:
346 return default
348 return default
347 try:
349 try:
348 return int(v)
350 return int(v)
349 except ValueError:
351 except ValueError:
350 raise error.ConfigError((b"%s.%s is not an integer ('%s')")
352 raise error.ConfigError((b"%s.%s is not an integer ('%s')")
351 % (section, name, v))
353 % (section, name, v))
352
354
353 def safeattrsetter(obj, name, ignoremissing=False):
355 def safeattrsetter(obj, name, ignoremissing=False):
354 """Ensure that 'obj' has 'name' attribute before subsequent setattr
356 """Ensure that 'obj' has 'name' attribute before subsequent setattr
355
357
356 This function is aborted, if 'obj' doesn't have 'name' attribute
358 This function is aborted, if 'obj' doesn't have 'name' attribute
357 at runtime. This avoids overlooking removal of an attribute, which
359 at runtime. This avoids overlooking removal of an attribute, which
358 breaks assumption of performance measurement, in the future.
360 breaks assumption of performance measurement, in the future.
359
361
360 This function returns the object to (1) assign a new value, and
362 This function returns the object to (1) assign a new value, and
361 (2) restore an original value to the attribute.
363 (2) restore an original value to the attribute.
362
364
363 If 'ignoremissing' is true, missing 'name' attribute doesn't cause
365 If 'ignoremissing' is true, missing 'name' attribute doesn't cause
364 abortion, and this function returns None. This is useful to
366 abortion, and this function returns None. This is useful to
365 examine an attribute, which isn't ensured in all Mercurial
367 examine an attribute, which isn't ensured in all Mercurial
366 versions.
368 versions.
367 """
369 """
368 if not util.safehasattr(obj, name):
370 if not util.safehasattr(obj, name):
369 if ignoremissing:
371 if ignoremissing:
370 return None
372 return None
371 raise error.Abort((b"missing attribute %s of %s might break assumption"
373 raise error.Abort((b"missing attribute %s of %s might break assumption"
372 b" of performance measurement") % (name, obj))
374 b" of performance measurement") % (name, obj))
373
375
374 origvalue = getattr(obj, _sysstr(name))
376 origvalue = getattr(obj, _sysstr(name))
375 class attrutil(object):
377 class attrutil(object):
376 def set(self, newvalue):
378 def set(self, newvalue):
377 setattr(obj, _sysstr(name), newvalue)
379 setattr(obj, _sysstr(name), newvalue)
378 def restore(self):
380 def restore(self):
379 setattr(obj, _sysstr(name), origvalue)
381 setattr(obj, _sysstr(name), origvalue)
380
382
381 return attrutil()
383 return attrutil()
382
384
383 # utilities to examine each internal API changes
385 # utilities to examine each internal API changes
384
386
385 def getbranchmapsubsettable():
387 def getbranchmapsubsettable():
386 # for "historical portability":
388 # for "historical portability":
387 # subsettable is defined in:
389 # subsettable is defined in:
388 # - branchmap since 2.9 (or 175c6fd8cacc)
390 # - branchmap since 2.9 (or 175c6fd8cacc)
389 # - repoview since 2.5 (or 59a9f18d4587)
391 # - repoview since 2.5 (or 59a9f18d4587)
390 for mod in (branchmap, repoview):
392 for mod in (branchmap, repoview):
391 subsettable = getattr(mod, 'subsettable', None)
393 subsettable = getattr(mod, 'subsettable', None)
392 if subsettable:
394 if subsettable:
393 return subsettable
395 return subsettable
394
396
395 # bisecting in bcee63733aad::59a9f18d4587 can reach here (both
397 # bisecting in bcee63733aad::59a9f18d4587 can reach here (both
396 # branchmap and repoview modules exist, but subsettable attribute
398 # branchmap and repoview modules exist, but subsettable attribute
397 # doesn't)
399 # doesn't)
398 raise error.Abort((b"perfbranchmap not available with this Mercurial"),
400 raise error.Abort((b"perfbranchmap not available with this Mercurial"),
399 hint=b"use 2.5 or later")
401 hint=b"use 2.5 or later")
400
402
401 def getsvfs(repo):
403 def getsvfs(repo):
402 """Return appropriate object to access files under .hg/store
404 """Return appropriate object to access files under .hg/store
403 """
405 """
404 # for "historical portability":
406 # for "historical portability":
405 # repo.svfs has been available since 2.3 (or 7034365089bf)
407 # repo.svfs has been available since 2.3 (or 7034365089bf)
406 svfs = getattr(repo, 'svfs', None)
408 svfs = getattr(repo, 'svfs', None)
407 if svfs:
409 if svfs:
408 return svfs
410 return svfs
409 else:
411 else:
410 return getattr(repo, 'sopener')
412 return getattr(repo, 'sopener')
411
413
412 def getvfs(repo):
414 def getvfs(repo):
413 """Return appropriate object to access files under .hg
415 """Return appropriate object to access files under .hg
414 """
416 """
415 # for "historical portability":
417 # for "historical portability":
416 # repo.vfs has been available since 2.3 (or 7034365089bf)
418 # repo.vfs has been available since 2.3 (or 7034365089bf)
417 vfs = getattr(repo, 'vfs', None)
419 vfs = getattr(repo, 'vfs', None)
418 if vfs:
420 if vfs:
419 return vfs
421 return vfs
420 else:
422 else:
421 return getattr(repo, 'opener')
423 return getattr(repo, 'opener')
422
424
423 def repocleartagscachefunc(repo):
425 def repocleartagscachefunc(repo):
424 """Return the function to clear tags cache according to repo internal API
426 """Return the function to clear tags cache according to repo internal API
425 """
427 """
426 if util.safehasattr(repo, b'_tagscache'): # since 2.0 (or 9dca7653b525)
428 if util.safehasattr(repo, b'_tagscache'): # since 2.0 (or 9dca7653b525)
427 # in this case, setattr(repo, '_tagscache', None) or so isn't
429 # in this case, setattr(repo, '_tagscache', None) or so isn't
428 # correct way to clear tags cache, because existing code paths
430 # correct way to clear tags cache, because existing code paths
429 # expect _tagscache to be a structured object.
431 # expect _tagscache to be a structured object.
430 def clearcache():
432 def clearcache():
431 # _tagscache has been filteredpropertycache since 2.5 (or
433 # _tagscache has been filteredpropertycache since 2.5 (or
432 # 98c867ac1330), and delattr() can't work in such case
434 # 98c867ac1330), and delattr() can't work in such case
433 if b'_tagscache' in vars(repo):
435 if b'_tagscache' in vars(repo):
434 del repo.__dict__[b'_tagscache']
436 del repo.__dict__[b'_tagscache']
435 return clearcache
437 return clearcache
436
438
437 repotags = safeattrsetter(repo, b'_tags', ignoremissing=True)
439 repotags = safeattrsetter(repo, b'_tags', ignoremissing=True)
438 if repotags: # since 1.4 (or 5614a628d173)
440 if repotags: # since 1.4 (or 5614a628d173)
439 return lambda : repotags.set(None)
441 return lambda : repotags.set(None)
440
442
441 repotagscache = safeattrsetter(repo, b'tagscache', ignoremissing=True)
443 repotagscache = safeattrsetter(repo, b'tagscache', ignoremissing=True)
442 if repotagscache: # since 0.6 (or d7df759d0e97)
444 if repotagscache: # since 0.6 (or d7df759d0e97)
443 return lambda : repotagscache.set(None)
445 return lambda : repotagscache.set(None)
444
446
445 # Mercurial earlier than 0.6 (or d7df759d0e97) logically reaches
447 # Mercurial earlier than 0.6 (or d7df759d0e97) logically reaches
446 # this point, but it isn't so problematic, because:
448 # this point, but it isn't so problematic, because:
447 # - repo.tags of such Mercurial isn't "callable", and repo.tags()
449 # - repo.tags of such Mercurial isn't "callable", and repo.tags()
448 # in perftags() causes failure soon
450 # in perftags() causes failure soon
449 # - perf.py itself has been available since 1.1 (or eb240755386d)
451 # - perf.py itself has been available since 1.1 (or eb240755386d)
450 raise error.Abort((b"tags API of this hg command is unknown"))
452 raise error.Abort((b"tags API of this hg command is unknown"))
451
453
452 # utilities to clear cache
454 # utilities to clear cache
453
455
454 def clearfilecache(repo, attrname):
456 def clearfilecache(repo, attrname):
455 unfi = repo.unfiltered()
457 unfi = repo.unfiltered()
456 if attrname in vars(unfi):
458 if attrname in vars(unfi):
457 delattr(unfi, attrname)
459 delattr(unfi, attrname)
458 unfi._filecache.pop(attrname, None)
460 unfi._filecache.pop(attrname, None)
459
461
460 # perf commands
462 # perf commands
461
463
462 @command(b'perfwalk', formatteropts)
464 @command(b'perfwalk', formatteropts)
463 def perfwalk(ui, repo, *pats, **opts):
465 def perfwalk(ui, repo, *pats, **opts):
464 opts = _byteskwargs(opts)
466 opts = _byteskwargs(opts)
465 timer, fm = gettimer(ui, opts)
467 timer, fm = gettimer(ui, opts)
466 m = scmutil.match(repo[None], pats, {})
468 m = scmutil.match(repo[None], pats, {})
467 timer(lambda: len(list(repo.dirstate.walk(m, subrepos=[], unknown=True,
469 timer(lambda: len(list(repo.dirstate.walk(m, subrepos=[], unknown=True,
468 ignored=False))))
470 ignored=False))))
469 fm.end()
471 fm.end()
470
472
471 @command(b'perfannotate', formatteropts)
473 @command(b'perfannotate', formatteropts)
472 def perfannotate(ui, repo, f, **opts):
474 def perfannotate(ui, repo, f, **opts):
473 opts = _byteskwargs(opts)
475 opts = _byteskwargs(opts)
474 timer, fm = gettimer(ui, opts)
476 timer, fm = gettimer(ui, opts)
475 fc = repo[b'.'][f]
477 fc = repo[b'.'][f]
476 timer(lambda: len(fc.annotate(True)))
478 timer(lambda: len(fc.annotate(True)))
477 fm.end()
479 fm.end()
478
480
479 @command(b'perfstatus',
481 @command(b'perfstatus',
480 [(b'u', b'unknown', False,
482 [(b'u', b'unknown', False,
481 b'ask status to look for unknown files')] + formatteropts)
483 b'ask status to look for unknown files')] + formatteropts)
482 def perfstatus(ui, repo, **opts):
484 def perfstatus(ui, repo, **opts):
483 opts = _byteskwargs(opts)
485 opts = _byteskwargs(opts)
484 #m = match.always(repo.root, repo.getcwd())
486 #m = match.always(repo.root, repo.getcwd())
485 #timer(lambda: sum(map(len, repo.dirstate.status(m, [], False, False,
487 #timer(lambda: sum(map(len, repo.dirstate.status(m, [], False, False,
486 # False))))
488 # False))))
487 timer, fm = gettimer(ui, opts)
489 timer, fm = gettimer(ui, opts)
488 timer(lambda: sum(map(len, repo.status(unknown=opts[b'unknown']))))
490 timer(lambda: sum(map(len, repo.status(unknown=opts[b'unknown']))))
489 fm.end()
491 fm.end()
490
492
491 @command(b'perfaddremove', formatteropts)
493 @command(b'perfaddremove', formatteropts)
492 def perfaddremove(ui, repo, **opts):
494 def perfaddremove(ui, repo, **opts):
493 opts = _byteskwargs(opts)
495 opts = _byteskwargs(opts)
494 timer, fm = gettimer(ui, opts)
496 timer, fm = gettimer(ui, opts)
495 try:
497 try:
496 oldquiet = repo.ui.quiet
498 oldquiet = repo.ui.quiet
497 repo.ui.quiet = True
499 repo.ui.quiet = True
498 matcher = scmutil.match(repo[None])
500 matcher = scmutil.match(repo[None])
499 opts[b'dry_run'] = True
501 opts[b'dry_run'] = True
500 timer(lambda: scmutil.addremove(repo, matcher, b"", opts))
502 timer(lambda: scmutil.addremove(repo, matcher, b"", opts))
501 finally:
503 finally:
502 repo.ui.quiet = oldquiet
504 repo.ui.quiet = oldquiet
503 fm.end()
505 fm.end()
504
506
505 def clearcaches(cl):
507 def clearcaches(cl):
506 # behave somewhat consistently across internal API changes
508 # behave somewhat consistently across internal API changes
507 if util.safehasattr(cl, b'clearcaches'):
509 if util.safehasattr(cl, b'clearcaches'):
508 cl.clearcaches()
510 cl.clearcaches()
509 elif util.safehasattr(cl, b'_nodecache'):
511 elif util.safehasattr(cl, b'_nodecache'):
510 from mercurial.node import nullid, nullrev
512 from mercurial.node import nullid, nullrev
511 cl._nodecache = {nullid: nullrev}
513 cl._nodecache = {nullid: nullrev}
512 cl._nodepos = None
514 cl._nodepos = None
513
515
514 @command(b'perfheads', formatteropts)
516 @command(b'perfheads', formatteropts)
515 def perfheads(ui, repo, **opts):
517 def perfheads(ui, repo, **opts):
516 opts = _byteskwargs(opts)
518 opts = _byteskwargs(opts)
517 timer, fm = gettimer(ui, opts)
519 timer, fm = gettimer(ui, opts)
518 cl = repo.changelog
520 cl = repo.changelog
519 def d():
521 def d():
520 len(cl.headrevs())
522 len(cl.headrevs())
521 clearcaches(cl)
523 clearcaches(cl)
522 timer(d)
524 timer(d)
523 fm.end()
525 fm.end()
524
526
525 @command(b'perftags', formatteropts)
527 @command(b'perftags', formatteropts)
526 def perftags(ui, repo, **opts):
528 def perftags(ui, repo, **opts):
527 import mercurial.changelog
529 import mercurial.changelog
528 import mercurial.manifest
530 import mercurial.manifest
529
531
530 opts = _byteskwargs(opts)
532 opts = _byteskwargs(opts)
531 timer, fm = gettimer(ui, opts)
533 timer, fm = gettimer(ui, opts)
532 svfs = getsvfs(repo)
534 svfs = getsvfs(repo)
533 repocleartagscache = repocleartagscachefunc(repo)
535 repocleartagscache = repocleartagscachefunc(repo)
534 def t():
536 def t():
535 repo.changelog = mercurial.changelog.changelog(svfs)
537 repo.changelog = mercurial.changelog.changelog(svfs)
536 rootmanifest = mercurial.manifest.manifestrevlog(svfs)
538 rootmanifest = mercurial.manifest.manifestrevlog(svfs)
537 repo.manifestlog = mercurial.manifest.manifestlog(svfs, repo,
539 repo.manifestlog = mercurial.manifest.manifestlog(svfs, repo,
538 rootmanifest)
540 rootmanifest)
539 repocleartagscache()
541 repocleartagscache()
540 return len(repo.tags())
542 return len(repo.tags())
541 timer(t)
543 timer(t)
542 fm.end()
544 fm.end()
543
545
544 @command(b'perfancestors', formatteropts)
546 @command(b'perfancestors', formatteropts)
545 def perfancestors(ui, repo, **opts):
547 def perfancestors(ui, repo, **opts):
546 opts = _byteskwargs(opts)
548 opts = _byteskwargs(opts)
547 timer, fm = gettimer(ui, opts)
549 timer, fm = gettimer(ui, opts)
548 heads = repo.changelog.headrevs()
550 heads = repo.changelog.headrevs()
549 def d():
551 def d():
550 for a in repo.changelog.ancestors(heads):
552 for a in repo.changelog.ancestors(heads):
551 pass
553 pass
552 timer(d)
554 timer(d)
553 fm.end()
555 fm.end()
554
556
555 @command(b'perfancestorset', formatteropts)
557 @command(b'perfancestorset', formatteropts)
556 def perfancestorset(ui, repo, revset, **opts):
558 def perfancestorset(ui, repo, revset, **opts):
557 opts = _byteskwargs(opts)
559 opts = _byteskwargs(opts)
558 timer, fm = gettimer(ui, opts)
560 timer, fm = gettimer(ui, opts)
559 revs = repo.revs(revset)
561 revs = repo.revs(revset)
560 heads = repo.changelog.headrevs()
562 heads = repo.changelog.headrevs()
561 def d():
563 def d():
562 s = repo.changelog.ancestors(heads)
564 s = repo.changelog.ancestors(heads)
563 for rev in revs:
565 for rev in revs:
564 rev in s
566 rev in s
565 timer(d)
567 timer(d)
566 fm.end()
568 fm.end()
567
569
568 @command(b'perfbookmarks', formatteropts)
570 @command(b'perfbookmarks', formatteropts)
569 def perfbookmarks(ui, repo, **opts):
571 def perfbookmarks(ui, repo, **opts):
570 """benchmark parsing bookmarks from disk to memory"""
572 """benchmark parsing bookmarks from disk to memory"""
571 opts = _byteskwargs(opts)
573 opts = _byteskwargs(opts)
572 timer, fm = gettimer(ui, opts)
574 timer, fm = gettimer(ui, opts)
573 def d():
575 def d():
574 clearfilecache(repo, b'_bookmarks')
576 clearfilecache(repo, b'_bookmarks')
575 repo._bookmarks
577 repo._bookmarks
576 timer(d)
578 timer(d)
577 fm.end()
579 fm.end()
578
580
579 @command(b'perfbundleread', formatteropts, b'BUNDLE')
581 @command(b'perfbundleread', formatteropts, b'BUNDLE')
580 def perfbundleread(ui, repo, bundlepath, **opts):
582 def perfbundleread(ui, repo, bundlepath, **opts):
581 """Benchmark reading of bundle files.
583 """Benchmark reading of bundle files.
582
584
583 This command is meant to isolate the I/O part of bundle reading as
585 This command is meant to isolate the I/O part of bundle reading as
584 much as possible.
586 much as possible.
585 """
587 """
586 from mercurial import (
588 from mercurial import (
587 bundle2,
589 bundle2,
588 exchange,
590 exchange,
589 streamclone,
591 streamclone,
590 )
592 )
591
593
592 opts = _byteskwargs(opts)
594 opts = _byteskwargs(opts)
593
595
594 def makebench(fn):
596 def makebench(fn):
595 def run():
597 def run():
596 with open(bundlepath, b'rb') as fh:
598 with open(bundlepath, b'rb') as fh:
597 bundle = exchange.readbundle(ui, fh, bundlepath)
599 bundle = exchange.readbundle(ui, fh, bundlepath)
598 fn(bundle)
600 fn(bundle)
599
601
600 return run
602 return run
601
603
602 def makereadnbytes(size):
604 def makereadnbytes(size):
603 def run():
605 def run():
604 with open(bundlepath, b'rb') as fh:
606 with open(bundlepath, b'rb') as fh:
605 bundle = exchange.readbundle(ui, fh, bundlepath)
607 bundle = exchange.readbundle(ui, fh, bundlepath)
606 while bundle.read(size):
608 while bundle.read(size):
607 pass
609 pass
608
610
609 return run
611 return run
610
612
611 def makestdioread(size):
613 def makestdioread(size):
612 def run():
614 def run():
613 with open(bundlepath, b'rb') as fh:
615 with open(bundlepath, b'rb') as fh:
614 while fh.read(size):
616 while fh.read(size):
615 pass
617 pass
616
618
617 return run
619 return run
618
620
619 # bundle1
621 # bundle1
620
622
621 def deltaiter(bundle):
623 def deltaiter(bundle):
622 for delta in bundle.deltaiter():
624 for delta in bundle.deltaiter():
623 pass
625 pass
624
626
625 def iterchunks(bundle):
627 def iterchunks(bundle):
626 for chunk in bundle.getchunks():
628 for chunk in bundle.getchunks():
627 pass
629 pass
628
630
629 # bundle2
631 # bundle2
630
632
631 def forwardchunks(bundle):
633 def forwardchunks(bundle):
632 for chunk in bundle._forwardchunks():
634 for chunk in bundle._forwardchunks():
633 pass
635 pass
634
636
635 def iterparts(bundle):
637 def iterparts(bundle):
636 for part in bundle.iterparts():
638 for part in bundle.iterparts():
637 pass
639 pass
638
640
639 def iterpartsseekable(bundle):
641 def iterpartsseekable(bundle):
640 for part in bundle.iterparts(seekable=True):
642 for part in bundle.iterparts(seekable=True):
641 pass
643 pass
642
644
643 def seek(bundle):
645 def seek(bundle):
644 for part in bundle.iterparts(seekable=True):
646 for part in bundle.iterparts(seekable=True):
645 part.seek(0, os.SEEK_END)
647 part.seek(0, os.SEEK_END)
646
648
647 def makepartreadnbytes(size):
649 def makepartreadnbytes(size):
648 def run():
650 def run():
649 with open(bundlepath, b'rb') as fh:
651 with open(bundlepath, b'rb') as fh:
650 bundle = exchange.readbundle(ui, fh, bundlepath)
652 bundle = exchange.readbundle(ui, fh, bundlepath)
651 for part in bundle.iterparts():
653 for part in bundle.iterparts():
652 while part.read(size):
654 while part.read(size):
653 pass
655 pass
654
656
655 return run
657 return run
656
658
657 benches = [
659 benches = [
658 (makestdioread(8192), b'read(8k)'),
660 (makestdioread(8192), b'read(8k)'),
659 (makestdioread(16384), b'read(16k)'),
661 (makestdioread(16384), b'read(16k)'),
660 (makestdioread(32768), b'read(32k)'),
662 (makestdioread(32768), b'read(32k)'),
661 (makestdioread(131072), b'read(128k)'),
663 (makestdioread(131072), b'read(128k)'),
662 ]
664 ]
663
665
664 with open(bundlepath, b'rb') as fh:
666 with open(bundlepath, b'rb') as fh:
665 bundle = exchange.readbundle(ui, fh, bundlepath)
667 bundle = exchange.readbundle(ui, fh, bundlepath)
666
668
667 if isinstance(bundle, changegroup.cg1unpacker):
669 if isinstance(bundle, changegroup.cg1unpacker):
668 benches.extend([
670 benches.extend([
669 (makebench(deltaiter), b'cg1 deltaiter()'),
671 (makebench(deltaiter), b'cg1 deltaiter()'),
670 (makebench(iterchunks), b'cg1 getchunks()'),
672 (makebench(iterchunks), b'cg1 getchunks()'),
671 (makereadnbytes(8192), b'cg1 read(8k)'),
673 (makereadnbytes(8192), b'cg1 read(8k)'),
672 (makereadnbytes(16384), b'cg1 read(16k)'),
674 (makereadnbytes(16384), b'cg1 read(16k)'),
673 (makereadnbytes(32768), b'cg1 read(32k)'),
675 (makereadnbytes(32768), b'cg1 read(32k)'),
674 (makereadnbytes(131072), b'cg1 read(128k)'),
676 (makereadnbytes(131072), b'cg1 read(128k)'),
675 ])
677 ])
676 elif isinstance(bundle, bundle2.unbundle20):
678 elif isinstance(bundle, bundle2.unbundle20):
677 benches.extend([
679 benches.extend([
678 (makebench(forwardchunks), b'bundle2 forwardchunks()'),
680 (makebench(forwardchunks), b'bundle2 forwardchunks()'),
679 (makebench(iterparts), b'bundle2 iterparts()'),
681 (makebench(iterparts), b'bundle2 iterparts()'),
680 (makebench(iterpartsseekable), b'bundle2 iterparts() seekable'),
682 (makebench(iterpartsseekable), b'bundle2 iterparts() seekable'),
681 (makebench(seek), b'bundle2 part seek()'),
683 (makebench(seek), b'bundle2 part seek()'),
682 (makepartreadnbytes(8192), b'bundle2 part read(8k)'),
684 (makepartreadnbytes(8192), b'bundle2 part read(8k)'),
683 (makepartreadnbytes(16384), b'bundle2 part read(16k)'),
685 (makepartreadnbytes(16384), b'bundle2 part read(16k)'),
684 (makepartreadnbytes(32768), b'bundle2 part read(32k)'),
686 (makepartreadnbytes(32768), b'bundle2 part read(32k)'),
685 (makepartreadnbytes(131072), b'bundle2 part read(128k)'),
687 (makepartreadnbytes(131072), b'bundle2 part read(128k)'),
686 ])
688 ])
687 elif isinstance(bundle, streamclone.streamcloneapplier):
689 elif isinstance(bundle, streamclone.streamcloneapplier):
688 raise error.Abort(b'stream clone bundles not supported')
690 raise error.Abort(b'stream clone bundles not supported')
689 else:
691 else:
690 raise error.Abort(b'unhandled bundle type: %s' % type(bundle))
692 raise error.Abort(b'unhandled bundle type: %s' % type(bundle))
691
693
692 for fn, title in benches:
694 for fn, title in benches:
693 timer, fm = gettimer(ui, opts)
695 timer, fm = gettimer(ui, opts)
694 timer(fn, title=title)
696 timer(fn, title=title)
695 fm.end()
697 fm.end()
696
698
697 @command(b'perfchangegroupchangelog', formatteropts +
699 @command(b'perfchangegroupchangelog', formatteropts +
698 [(b'', b'version', b'02', b'changegroup version'),
700 [(b'', b'version', b'02', b'changegroup version'),
699 (b'r', b'rev', b'', b'revisions to add to changegroup')])
701 (b'r', b'rev', b'', b'revisions to add to changegroup')])
700 def perfchangegroupchangelog(ui, repo, version=b'02', rev=None, **opts):
702 def perfchangegroupchangelog(ui, repo, version=b'02', rev=None, **opts):
701 """Benchmark producing a changelog group for a changegroup.
703 """Benchmark producing a changelog group for a changegroup.
702
704
703 This measures the time spent processing the changelog during a
705 This measures the time spent processing the changelog during a
704 bundle operation. This occurs during `hg bundle` and on a server
706 bundle operation. This occurs during `hg bundle` and on a server
705 processing a `getbundle` wire protocol request (handles clones
707 processing a `getbundle` wire protocol request (handles clones
706 and pull requests).
708 and pull requests).
707
709
708 By default, all revisions are added to the changegroup.
710 By default, all revisions are added to the changegroup.
709 """
711 """
710 opts = _byteskwargs(opts)
712 opts = _byteskwargs(opts)
711 cl = repo.changelog
713 cl = repo.changelog
712 nodes = [cl.lookup(r) for r in repo.revs(rev or b'all()')]
714 nodes = [cl.lookup(r) for r in repo.revs(rev or b'all()')]
713 bundler = changegroup.getbundler(version, repo)
715 bundler = changegroup.getbundler(version, repo)
714
716
715 def d():
717 def d():
716 state, chunks = bundler._generatechangelog(cl, nodes)
718 state, chunks = bundler._generatechangelog(cl, nodes)
717 for chunk in chunks:
719 for chunk in chunks:
718 pass
720 pass
719
721
720 timer, fm = gettimer(ui, opts)
722 timer, fm = gettimer(ui, opts)
721
723
722 # Terminal printing can interfere with timing. So disable it.
724 # Terminal printing can interfere with timing. So disable it.
723 with ui.configoverride({(b'progress', b'disable'): True}):
725 with ui.configoverride({(b'progress', b'disable'): True}):
724 timer(d)
726 timer(d)
725
727
726 fm.end()
728 fm.end()
727
729
728 @command(b'perfdirs', formatteropts)
730 @command(b'perfdirs', formatteropts)
729 def perfdirs(ui, repo, **opts):
731 def perfdirs(ui, repo, **opts):
730 opts = _byteskwargs(opts)
732 opts = _byteskwargs(opts)
731 timer, fm = gettimer(ui, opts)
733 timer, fm = gettimer(ui, opts)
732 dirstate = repo.dirstate
734 dirstate = repo.dirstate
733 b'a' in dirstate
735 b'a' in dirstate
734 def d():
736 def d():
735 dirstate.hasdir(b'a')
737 dirstate.hasdir(b'a')
736 del dirstate._map._dirs
738 del dirstate._map._dirs
737 timer(d)
739 timer(d)
738 fm.end()
740 fm.end()
739
741
740 @command(b'perfdirstate', formatteropts)
742 @command(b'perfdirstate', formatteropts)
741 def perfdirstate(ui, repo, **opts):
743 def perfdirstate(ui, repo, **opts):
742 opts = _byteskwargs(opts)
744 opts = _byteskwargs(opts)
743 timer, fm = gettimer(ui, opts)
745 timer, fm = gettimer(ui, opts)
744 b"a" in repo.dirstate
746 b"a" in repo.dirstate
745 def d():
747 def d():
746 repo.dirstate.invalidate()
748 repo.dirstate.invalidate()
747 b"a" in repo.dirstate
749 b"a" in repo.dirstate
748 timer(d)
750 timer(d)
749 fm.end()
751 fm.end()
750
752
751 @command(b'perfdirstatedirs', formatteropts)
753 @command(b'perfdirstatedirs', formatteropts)
752 def perfdirstatedirs(ui, repo, **opts):
754 def perfdirstatedirs(ui, repo, **opts):
753 opts = _byteskwargs(opts)
755 opts = _byteskwargs(opts)
754 timer, fm = gettimer(ui, opts)
756 timer, fm = gettimer(ui, opts)
755 b"a" in repo.dirstate
757 b"a" in repo.dirstate
756 def d():
758 def d():
757 repo.dirstate.hasdir(b"a")
759 repo.dirstate.hasdir(b"a")
758 del repo.dirstate._map._dirs
760 del repo.dirstate._map._dirs
759 timer(d)
761 timer(d)
760 fm.end()
762 fm.end()
761
763
762 @command(b'perfdirstatefoldmap', formatteropts)
764 @command(b'perfdirstatefoldmap', formatteropts)
763 def perfdirstatefoldmap(ui, repo, **opts):
765 def perfdirstatefoldmap(ui, repo, **opts):
764 opts = _byteskwargs(opts)
766 opts = _byteskwargs(opts)
765 timer, fm = gettimer(ui, opts)
767 timer, fm = gettimer(ui, opts)
766 dirstate = repo.dirstate
768 dirstate = repo.dirstate
767 b'a' in dirstate
769 b'a' in dirstate
768 def d():
770 def d():
769 dirstate._map.filefoldmap.get(b'a')
771 dirstate._map.filefoldmap.get(b'a')
770 del dirstate._map.filefoldmap
772 del dirstate._map.filefoldmap
771 timer(d)
773 timer(d)
772 fm.end()
774 fm.end()
773
775
774 @command(b'perfdirfoldmap', formatteropts)
776 @command(b'perfdirfoldmap', formatteropts)
775 def perfdirfoldmap(ui, repo, **opts):
777 def perfdirfoldmap(ui, repo, **opts):
776 opts = _byteskwargs(opts)
778 opts = _byteskwargs(opts)
777 timer, fm = gettimer(ui, opts)
779 timer, fm = gettimer(ui, opts)
778 dirstate = repo.dirstate
780 dirstate = repo.dirstate
779 b'a' in dirstate
781 b'a' in dirstate
780 def d():
782 def d():
781 dirstate._map.dirfoldmap.get(b'a')
783 dirstate._map.dirfoldmap.get(b'a')
782 del dirstate._map.dirfoldmap
784 del dirstate._map.dirfoldmap
783 del dirstate._map._dirs
785 del dirstate._map._dirs
784 timer(d)
786 timer(d)
785 fm.end()
787 fm.end()
786
788
787 @command(b'perfdirstatewrite', formatteropts)
789 @command(b'perfdirstatewrite', formatteropts)
788 def perfdirstatewrite(ui, repo, **opts):
790 def perfdirstatewrite(ui, repo, **opts):
789 opts = _byteskwargs(opts)
791 opts = _byteskwargs(opts)
790 timer, fm = gettimer(ui, opts)
792 timer, fm = gettimer(ui, opts)
791 ds = repo.dirstate
793 ds = repo.dirstate
792 b"a" in ds
794 b"a" in ds
793 def d():
795 def d():
794 ds._dirty = True
796 ds._dirty = True
795 ds.write(repo.currenttransaction())
797 ds.write(repo.currenttransaction())
796 timer(d)
798 timer(d)
797 fm.end()
799 fm.end()
798
800
799 @command(b'perfmergecalculate',
801 @command(b'perfmergecalculate',
800 [(b'r', b'rev', b'.', b'rev to merge against')] + formatteropts)
802 [(b'r', b'rev', b'.', b'rev to merge against')] + formatteropts)
801 def perfmergecalculate(ui, repo, rev, **opts):
803 def perfmergecalculate(ui, repo, rev, **opts):
802 opts = _byteskwargs(opts)
804 opts = _byteskwargs(opts)
803 timer, fm = gettimer(ui, opts)
805 timer, fm = gettimer(ui, opts)
804 wctx = repo[None]
806 wctx = repo[None]
805 rctx = scmutil.revsingle(repo, rev, rev)
807 rctx = scmutil.revsingle(repo, rev, rev)
806 ancestor = wctx.ancestor(rctx)
808 ancestor = wctx.ancestor(rctx)
807 # we don't want working dir files to be stat'd in the benchmark, so prime
809 # we don't want working dir files to be stat'd in the benchmark, so prime
808 # that cache
810 # that cache
809 wctx.dirty()
811 wctx.dirty()
810 def d():
812 def d():
811 # acceptremote is True because we don't want prompts in the middle of
813 # acceptremote is True because we don't want prompts in the middle of
812 # our benchmark
814 # our benchmark
813 merge.calculateupdates(repo, wctx, rctx, [ancestor], False, False,
815 merge.calculateupdates(repo, wctx, rctx, [ancestor], False, False,
814 acceptremote=True, followcopies=True)
816 acceptremote=True, followcopies=True)
815 timer(d)
817 timer(d)
816 fm.end()
818 fm.end()
817
819
818 @command(b'perfpathcopies', [], b"REV REV")
820 @command(b'perfpathcopies', [], b"REV REV")
819 def perfpathcopies(ui, repo, rev1, rev2, **opts):
821 def perfpathcopies(ui, repo, rev1, rev2, **opts):
820 opts = _byteskwargs(opts)
822 opts = _byteskwargs(opts)
821 timer, fm = gettimer(ui, opts)
823 timer, fm = gettimer(ui, opts)
822 ctx1 = scmutil.revsingle(repo, rev1, rev1)
824 ctx1 = scmutil.revsingle(repo, rev1, rev1)
823 ctx2 = scmutil.revsingle(repo, rev2, rev2)
825 ctx2 = scmutil.revsingle(repo, rev2, rev2)
824 def d():
826 def d():
825 copies.pathcopies(ctx1, ctx2)
827 copies.pathcopies(ctx1, ctx2)
826 timer(d)
828 timer(d)
827 fm.end()
829 fm.end()
828
830
829 @command(b'perfphases',
831 @command(b'perfphases',
830 [(b'', b'full', False, b'include file reading time too'),
832 [(b'', b'full', False, b'include file reading time too'),
831 ], b"")
833 ], b"")
832 def perfphases(ui, repo, **opts):
834 def perfphases(ui, repo, **opts):
833 """benchmark phasesets computation"""
835 """benchmark phasesets computation"""
834 opts = _byteskwargs(opts)
836 opts = _byteskwargs(opts)
835 timer, fm = gettimer(ui, opts)
837 timer, fm = gettimer(ui, opts)
836 _phases = repo._phasecache
838 _phases = repo._phasecache
837 full = opts.get(b'full')
839 full = opts.get(b'full')
838 def d():
840 def d():
839 phases = _phases
841 phases = _phases
840 if full:
842 if full:
841 clearfilecache(repo, b'_phasecache')
843 clearfilecache(repo, b'_phasecache')
842 phases = repo._phasecache
844 phases = repo._phasecache
843 phases.invalidate()
845 phases.invalidate()
844 phases.loadphaserevs(repo)
846 phases.loadphaserevs(repo)
845 timer(d)
847 timer(d)
846 fm.end()
848 fm.end()
847
849
848 @command(b'perfphasesremote',
850 @command(b'perfphasesremote',
849 [], b"[DEST]")
851 [], b"[DEST]")
850 def perfphasesremote(ui, repo, dest=None, **opts):
852 def perfphasesremote(ui, repo, dest=None, **opts):
851 """benchmark time needed to analyse phases of the remote server"""
853 """benchmark time needed to analyse phases of the remote server"""
852 from mercurial.node import (
854 from mercurial.node import (
853 bin,
855 bin,
854 )
856 )
855 from mercurial import (
857 from mercurial import (
856 exchange,
858 exchange,
857 hg,
859 hg,
858 phases,
860 phases,
859 )
861 )
860 opts = _byteskwargs(opts)
862 opts = _byteskwargs(opts)
861 timer, fm = gettimer(ui, opts)
863 timer, fm = gettimer(ui, opts)
862
864
863 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
865 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
864 if not path:
866 if not path:
865 raise error.Abort((b'default repository not configured!'),
867 raise error.Abort((b'default repository not configured!'),
866 hint=(b"see 'hg help config.paths'"))
868 hint=(b"see 'hg help config.paths'"))
867 dest = path.pushloc or path.loc
869 dest = path.pushloc or path.loc
868 branches = (path.branch, opts.get(b'branch') or [])
870 branches = (path.branch, opts.get(b'branch') or [])
869 ui.status((b'analysing phase of %s\n') % util.hidepassword(dest))
871 ui.status((b'analysing phase of %s\n') % util.hidepassword(dest))
870 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get(b'rev'))
872 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get(b'rev'))
871 other = hg.peer(repo, opts, dest)
873 other = hg.peer(repo, opts, dest)
872
874
873 # easier to perform discovery through the operation
875 # easier to perform discovery through the operation
874 op = exchange.pushoperation(repo, other)
876 op = exchange.pushoperation(repo, other)
875 exchange._pushdiscoverychangeset(op)
877 exchange._pushdiscoverychangeset(op)
876
878
877 remotesubset = op.fallbackheads
879 remotesubset = op.fallbackheads
878
880
879 with other.commandexecutor() as e:
881 with other.commandexecutor() as e:
880 remotephases = e.callcommand(b'listkeys',
882 remotephases = e.callcommand(b'listkeys',
881 {b'namespace': b'phases'}).result()
883 {b'namespace': b'phases'}).result()
882 del other
884 del other
883 publishing = remotephases.get(b'publishing', False)
885 publishing = remotephases.get(b'publishing', False)
884 if publishing:
886 if publishing:
885 ui.status((b'publishing: yes\n'))
887 ui.status((b'publishing: yes\n'))
886 else:
888 else:
887 ui.status((b'publishing: no\n'))
889 ui.status((b'publishing: no\n'))
888
890
889 nodemap = repo.changelog.nodemap
891 nodemap = repo.changelog.nodemap
890 nonpublishroots = 0
892 nonpublishroots = 0
891 for nhex, phase in remotephases.iteritems():
893 for nhex, phase in remotephases.iteritems():
892 if nhex == b'publishing': # ignore data related to publish option
894 if nhex == b'publishing': # ignore data related to publish option
893 continue
895 continue
894 node = bin(nhex)
896 node = bin(nhex)
895 if node in nodemap and int(phase):
897 if node in nodemap and int(phase):
896 nonpublishroots += 1
898 nonpublishroots += 1
897 ui.status((b'number of roots: %d\n') % len(remotephases))
899 ui.status((b'number of roots: %d\n') % len(remotephases))
898 ui.status((b'number of known non public roots: %d\n') % nonpublishroots)
900 ui.status((b'number of known non public roots: %d\n') % nonpublishroots)
899 def d():
901 def d():
900 phases.remotephasessummary(repo,
902 phases.remotephasessummary(repo,
901 remotesubset,
903 remotesubset,
902 remotephases)
904 remotephases)
903 timer(d)
905 timer(d)
904 fm.end()
906 fm.end()
905
907
906 @command(b'perfmanifest',[
908 @command(b'perfmanifest',[
907 (b'm', b'manifest-rev', False, b'Look up a manifest node revision'),
909 (b'm', b'manifest-rev', False, b'Look up a manifest node revision'),
908 (b'', b'clear-disk', False, b'clear on-disk caches too'),
910 (b'', b'clear-disk', False, b'clear on-disk caches too'),
909 ] + formatteropts, b'REV|NODE')
911 ] + formatteropts, b'REV|NODE')
910 def perfmanifest(ui, repo, rev, manifest_rev=False, clear_disk=False, **opts):
912 def perfmanifest(ui, repo, rev, manifest_rev=False, clear_disk=False, **opts):
911 """benchmark the time to read a manifest from disk and return a usable
913 """benchmark the time to read a manifest from disk and return a usable
912 dict-like object
914 dict-like object
913
915
914 Manifest caches are cleared before retrieval."""
916 Manifest caches are cleared before retrieval."""
915 opts = _byteskwargs(opts)
917 opts = _byteskwargs(opts)
916 timer, fm = gettimer(ui, opts)
918 timer, fm = gettimer(ui, opts)
917 if not manifest_rev:
919 if not manifest_rev:
918 ctx = scmutil.revsingle(repo, rev, rev)
920 ctx = scmutil.revsingle(repo, rev, rev)
919 t = ctx.manifestnode()
921 t = ctx.manifestnode()
920 else:
922 else:
921 from mercurial.node import bin
923 from mercurial.node import bin
922
924
923 if len(rev) == 40:
925 if len(rev) == 40:
924 t = bin(rev)
926 t = bin(rev)
925 else:
927 else:
926 try:
928 try:
927 rev = int(rev)
929 rev = int(rev)
928
930
929 if util.safehasattr(repo.manifestlog, b'getstorage'):
931 if util.safehasattr(repo.manifestlog, b'getstorage'):
930 t = repo.manifestlog.getstorage(b'').node(rev)
932 t = repo.manifestlog.getstorage(b'').node(rev)
931 else:
933 else:
932 t = repo.manifestlog._revlog.lookup(rev)
934 t = repo.manifestlog._revlog.lookup(rev)
933 except ValueError:
935 except ValueError:
934 raise error.Abort(b'manifest revision must be integer or full '
936 raise error.Abort(b'manifest revision must be integer or full '
935 b'node')
937 b'node')
936 def d():
938 def d():
937 repo.manifestlog.clearcaches(clear_persisted_data=clear_disk)
939 repo.manifestlog.clearcaches(clear_persisted_data=clear_disk)
938 repo.manifestlog[t].read()
940 repo.manifestlog[t].read()
939 timer(d)
941 timer(d)
940 fm.end()
942 fm.end()
941
943
942 @command(b'perfchangeset', formatteropts)
944 @command(b'perfchangeset', formatteropts)
943 def perfchangeset(ui, repo, rev, **opts):
945 def perfchangeset(ui, repo, rev, **opts):
944 opts = _byteskwargs(opts)
946 opts = _byteskwargs(opts)
945 timer, fm = gettimer(ui, opts)
947 timer, fm = gettimer(ui, opts)
946 n = scmutil.revsingle(repo, rev).node()
948 n = scmutil.revsingle(repo, rev).node()
947 def d():
949 def d():
948 repo.changelog.read(n)
950 repo.changelog.read(n)
949 #repo.changelog._cache = None
951 #repo.changelog._cache = None
950 timer(d)
952 timer(d)
951 fm.end()
953 fm.end()
952
954
953 @command(b'perfindex', formatteropts)
955 @command(b'perfindex', formatteropts)
954 def perfindex(ui, repo, **opts):
956 def perfindex(ui, repo, **opts):
955 import mercurial.revlog
957 import mercurial.revlog
956 opts = _byteskwargs(opts)
958 opts = _byteskwargs(opts)
957 timer, fm = gettimer(ui, opts)
959 timer, fm = gettimer(ui, opts)
958 mercurial.revlog._prereadsize = 2**24 # disable lazy parser in old hg
960 mercurial.revlog._prereadsize = 2**24 # disable lazy parser in old hg
959 n = repo[b"tip"].node()
961 n = repo[b"tip"].node()
960 svfs = getsvfs(repo)
962 svfs = getsvfs(repo)
961 def d():
963 def d():
962 cl = mercurial.revlog.revlog(svfs, b"00changelog.i")
964 cl = mercurial.revlog.revlog(svfs, b"00changelog.i")
963 cl.rev(n)
965 cl.rev(n)
964 timer(d)
966 timer(d)
965 fm.end()
967 fm.end()
966
968
967 @command(b'perfstartup', formatteropts)
969 @command(b'perfstartup', formatteropts)
968 def perfstartup(ui, repo, **opts):
970 def perfstartup(ui, repo, **opts):
969 opts = _byteskwargs(opts)
971 opts = _byteskwargs(opts)
970 timer, fm = gettimer(ui, opts)
972 timer, fm = gettimer(ui, opts)
971 cmd = sys.argv[0]
973 cmd = fsencode(sys.argv[0])
972 def d():
974 def d():
973 if os.name != r'nt':
975 if os.name != r'nt':
974 os.system(b"HGRCPATH= %s version -q > /dev/null" % cmd)
976 os.system(b"HGRCPATH= %s version -q > /dev/null" % cmd)
975 else:
977 else:
976 os.environ[r'HGRCPATH'] = r' '
978 os.environ[r'HGRCPATH'] = r' '
977 os.system(r"%s version -q > NUL" % cmd)
979 os.system(r"%s version -q > NUL" % cmd)
978 timer(d)
980 timer(d)
979 fm.end()
981 fm.end()
980
982
981 @command(b'perfparents', formatteropts)
983 @command(b'perfparents', formatteropts)
982 def perfparents(ui, repo, **opts):
984 def perfparents(ui, repo, **opts):
983 opts = _byteskwargs(opts)
985 opts = _byteskwargs(opts)
984 timer, fm = gettimer(ui, opts)
986 timer, fm = gettimer(ui, opts)
985 # control the number of commits perfparents iterates over
987 # control the number of commits perfparents iterates over
986 # experimental config: perf.parentscount
988 # experimental config: perf.parentscount
987 count = getint(ui, b"perf", b"parentscount", 1000)
989 count = getint(ui, b"perf", b"parentscount", 1000)
988 if len(repo.changelog) < count:
990 if len(repo.changelog) < count:
989 raise error.Abort(b"repo needs %d commits for this test" % count)
991 raise error.Abort(b"repo needs %d commits for this test" % count)
990 repo = repo.unfiltered()
992 repo = repo.unfiltered()
991 nl = [repo.changelog.node(i) for i in _xrange(count)]
993 nl = [repo.changelog.node(i) for i in _xrange(count)]
992 def d():
994 def d():
993 for n in nl:
995 for n in nl:
994 repo.changelog.parents(n)
996 repo.changelog.parents(n)
995 timer(d)
997 timer(d)
996 fm.end()
998 fm.end()
997
999
998 @command(b'perfctxfiles', formatteropts)
1000 @command(b'perfctxfiles', formatteropts)
999 def perfctxfiles(ui, repo, x, **opts):
1001 def perfctxfiles(ui, repo, x, **opts):
1000 opts = _byteskwargs(opts)
1002 opts = _byteskwargs(opts)
1001 x = int(x)
1003 x = int(x)
1002 timer, fm = gettimer(ui, opts)
1004 timer, fm = gettimer(ui, opts)
1003 def d():
1005 def d():
1004 len(repo[x].files())
1006 len(repo[x].files())
1005 timer(d)
1007 timer(d)
1006 fm.end()
1008 fm.end()
1007
1009
1008 @command(b'perfrawfiles', formatteropts)
1010 @command(b'perfrawfiles', formatteropts)
1009 def perfrawfiles(ui, repo, x, **opts):
1011 def perfrawfiles(ui, repo, x, **opts):
1010 opts = _byteskwargs(opts)
1012 opts = _byteskwargs(opts)
1011 x = int(x)
1013 x = int(x)
1012 timer, fm = gettimer(ui, opts)
1014 timer, fm = gettimer(ui, opts)
1013 cl = repo.changelog
1015 cl = repo.changelog
1014 def d():
1016 def d():
1015 len(cl.read(x)[3])
1017 len(cl.read(x)[3])
1016 timer(d)
1018 timer(d)
1017 fm.end()
1019 fm.end()
1018
1020
1019 @command(b'perflookup', formatteropts)
1021 @command(b'perflookup', formatteropts)
1020 def perflookup(ui, repo, rev, **opts):
1022 def perflookup(ui, repo, rev, **opts):
1021 opts = _byteskwargs(opts)
1023 opts = _byteskwargs(opts)
1022 timer, fm = gettimer(ui, opts)
1024 timer, fm = gettimer(ui, opts)
1023 timer(lambda: len(repo.lookup(rev)))
1025 timer(lambda: len(repo.lookup(rev)))
1024 fm.end()
1026 fm.end()
1025
1027
1026 @command(b'perflinelogedits',
1028 @command(b'perflinelogedits',
1027 [(b'n', b'edits', 10000, b'number of edits'),
1029 [(b'n', b'edits', 10000, b'number of edits'),
1028 (b'', b'max-hunk-lines', 10, b'max lines in a hunk'),
1030 (b'', b'max-hunk-lines', 10, b'max lines in a hunk'),
1029 ], norepo=True)
1031 ], norepo=True)
1030 def perflinelogedits(ui, **opts):
1032 def perflinelogedits(ui, **opts):
1031 from mercurial import linelog
1033 from mercurial import linelog
1032
1034
1033 opts = _byteskwargs(opts)
1035 opts = _byteskwargs(opts)
1034
1036
1035 edits = opts[b'edits']
1037 edits = opts[b'edits']
1036 maxhunklines = opts[b'max_hunk_lines']
1038 maxhunklines = opts[b'max_hunk_lines']
1037
1039
1038 maxb1 = 100000
1040 maxb1 = 100000
1039 random.seed(0)
1041 random.seed(0)
1040 randint = random.randint
1042 randint = random.randint
1041 currentlines = 0
1043 currentlines = 0
1042 arglist = []
1044 arglist = []
1043 for rev in _xrange(edits):
1045 for rev in _xrange(edits):
1044 a1 = randint(0, currentlines)
1046 a1 = randint(0, currentlines)
1045 a2 = randint(a1, min(currentlines, a1 + maxhunklines))
1047 a2 = randint(a1, min(currentlines, a1 + maxhunklines))
1046 b1 = randint(0, maxb1)
1048 b1 = randint(0, maxb1)
1047 b2 = randint(b1, b1 + maxhunklines)
1049 b2 = randint(b1, b1 + maxhunklines)
1048 currentlines += (b2 - b1) - (a2 - a1)
1050 currentlines += (b2 - b1) - (a2 - a1)
1049 arglist.append((rev, a1, a2, b1, b2))
1051 arglist.append((rev, a1, a2, b1, b2))
1050
1052
1051 def d():
1053 def d():
1052 ll = linelog.linelog()
1054 ll = linelog.linelog()
1053 for args in arglist:
1055 for args in arglist:
1054 ll.replacelines(*args)
1056 ll.replacelines(*args)
1055
1057
1056 timer, fm = gettimer(ui, opts)
1058 timer, fm = gettimer(ui, opts)
1057 timer(d)
1059 timer(d)
1058 fm.end()
1060 fm.end()
1059
1061
1060 @command(b'perfrevrange', formatteropts)
1062 @command(b'perfrevrange', formatteropts)
1061 def perfrevrange(ui, repo, *specs, **opts):
1063 def perfrevrange(ui, repo, *specs, **opts):
1062 opts = _byteskwargs(opts)
1064 opts = _byteskwargs(opts)
1063 timer, fm = gettimer(ui, opts)
1065 timer, fm = gettimer(ui, opts)
1064 revrange = scmutil.revrange
1066 revrange = scmutil.revrange
1065 timer(lambda: len(revrange(repo, specs)))
1067 timer(lambda: len(revrange(repo, specs)))
1066 fm.end()
1068 fm.end()
1067
1069
1068 @command(b'perfnodelookup', formatteropts)
1070 @command(b'perfnodelookup', formatteropts)
1069 def perfnodelookup(ui, repo, rev, **opts):
1071 def perfnodelookup(ui, repo, rev, **opts):
1070 opts = _byteskwargs(opts)
1072 opts = _byteskwargs(opts)
1071 timer, fm = gettimer(ui, opts)
1073 timer, fm = gettimer(ui, opts)
1072 import mercurial.revlog
1074 import mercurial.revlog
1073 mercurial.revlog._prereadsize = 2**24 # disable lazy parser in old hg
1075 mercurial.revlog._prereadsize = 2**24 # disable lazy parser in old hg
1074 n = scmutil.revsingle(repo, rev).node()
1076 n = scmutil.revsingle(repo, rev).node()
1075 cl = mercurial.revlog.revlog(getsvfs(repo), b"00changelog.i")
1077 cl = mercurial.revlog.revlog(getsvfs(repo), b"00changelog.i")
1076 def d():
1078 def d():
1077 cl.rev(n)
1079 cl.rev(n)
1078 clearcaches(cl)
1080 clearcaches(cl)
1079 timer(d)
1081 timer(d)
1080 fm.end()
1082 fm.end()
1081
1083
1082 @command(b'perflog',
1084 @command(b'perflog',
1083 [(b'', b'rename', False, b'ask log to follow renames')
1085 [(b'', b'rename', False, b'ask log to follow renames')
1084 ] + formatteropts)
1086 ] + formatteropts)
1085 def perflog(ui, repo, rev=None, **opts):
1087 def perflog(ui, repo, rev=None, **opts):
1086 opts = _byteskwargs(opts)
1088 opts = _byteskwargs(opts)
1087 if rev is None:
1089 if rev is None:
1088 rev=[]
1090 rev=[]
1089 timer, fm = gettimer(ui, opts)
1091 timer, fm = gettimer(ui, opts)
1090 ui.pushbuffer()
1092 ui.pushbuffer()
1091 timer(lambda: commands.log(ui, repo, rev=rev, date=b'', user=b'',
1093 timer(lambda: commands.log(ui, repo, rev=rev, date=b'', user=b'',
1092 copies=opts.get(b'rename')))
1094 copies=opts.get(b'rename')))
1093 ui.popbuffer()
1095 ui.popbuffer()
1094 fm.end()
1096 fm.end()
1095
1097
1096 @command(b'perfmoonwalk', formatteropts)
1098 @command(b'perfmoonwalk', formatteropts)
1097 def perfmoonwalk(ui, repo, **opts):
1099 def perfmoonwalk(ui, repo, **opts):
1098 """benchmark walking the changelog backwards
1100 """benchmark walking the changelog backwards
1099
1101
1100 This also loads the changelog data for each revision in the changelog.
1102 This also loads the changelog data for each revision in the changelog.
1101 """
1103 """
1102 opts = _byteskwargs(opts)
1104 opts = _byteskwargs(opts)
1103 timer, fm = gettimer(ui, opts)
1105 timer, fm = gettimer(ui, opts)
1104 def moonwalk():
1106 def moonwalk():
1105 for i in repo.changelog.revs(start=(len(repo) - 1), stop=-1):
1107 for i in repo.changelog.revs(start=(len(repo) - 1), stop=-1):
1106 ctx = repo[i]
1108 ctx = repo[i]
1107 ctx.branch() # read changelog data (in addition to the index)
1109 ctx.branch() # read changelog data (in addition to the index)
1108 timer(moonwalk)
1110 timer(moonwalk)
1109 fm.end()
1111 fm.end()
1110
1112
1111 @command(b'perftemplating',
1113 @command(b'perftemplating',
1112 [(b'r', b'rev', [], b'revisions to run the template on'),
1114 [(b'r', b'rev', [], b'revisions to run the template on'),
1113 ] + formatteropts)
1115 ] + formatteropts)
1114 def perftemplating(ui, repo, testedtemplate=None, **opts):
1116 def perftemplating(ui, repo, testedtemplate=None, **opts):
1115 """test the rendering time of a given template"""
1117 """test the rendering time of a given template"""
1116 if makelogtemplater is None:
1118 if makelogtemplater is None:
1117 raise error.Abort((b"perftemplating not available with this Mercurial"),
1119 raise error.Abort((b"perftemplating not available with this Mercurial"),
1118 hint=b"use 4.3 or later")
1120 hint=b"use 4.3 or later")
1119
1121
1120 opts = _byteskwargs(opts)
1122 opts = _byteskwargs(opts)
1121
1123
1122 nullui = ui.copy()
1124 nullui = ui.copy()
1123 nullui.fout = open(os.devnull, r'wb')
1125 nullui.fout = open(os.devnull, r'wb')
1124 nullui.disablepager()
1126 nullui.disablepager()
1125 revs = opts.get(b'rev')
1127 revs = opts.get(b'rev')
1126 if not revs:
1128 if not revs:
1127 revs = [b'all()']
1129 revs = [b'all()']
1128 revs = list(scmutil.revrange(repo, revs))
1130 revs = list(scmutil.revrange(repo, revs))
1129
1131
1130 defaulttemplate = (b'{date|shortdate} [{rev}:{node|short}]'
1132 defaulttemplate = (b'{date|shortdate} [{rev}:{node|short}]'
1131 b' {author|person}: {desc|firstline}\n')
1133 b' {author|person}: {desc|firstline}\n')
1132 if testedtemplate is None:
1134 if testedtemplate is None:
1133 testedtemplate = defaulttemplate
1135 testedtemplate = defaulttemplate
1134 displayer = makelogtemplater(nullui, repo, testedtemplate)
1136 displayer = makelogtemplater(nullui, repo, testedtemplate)
1135 def format():
1137 def format():
1136 for r in revs:
1138 for r in revs:
1137 ctx = repo[r]
1139 ctx = repo[r]
1138 displayer.show(ctx)
1140 displayer.show(ctx)
1139 displayer.flush(ctx)
1141 displayer.flush(ctx)
1140
1142
1141 timer, fm = gettimer(ui, opts)
1143 timer, fm = gettimer(ui, opts)
1142 timer(format)
1144 timer(format)
1143 fm.end()
1145 fm.end()
1144
1146
1145 @command(b'perfcca', formatteropts)
1147 @command(b'perfcca', formatteropts)
1146 def perfcca(ui, repo, **opts):
1148 def perfcca(ui, repo, **opts):
1147 opts = _byteskwargs(opts)
1149 opts = _byteskwargs(opts)
1148 timer, fm = gettimer(ui, opts)
1150 timer, fm = gettimer(ui, opts)
1149 timer(lambda: scmutil.casecollisionauditor(ui, False, repo.dirstate))
1151 timer(lambda: scmutil.casecollisionauditor(ui, False, repo.dirstate))
1150 fm.end()
1152 fm.end()
1151
1153
1152 @command(b'perffncacheload', formatteropts)
1154 @command(b'perffncacheload', formatteropts)
1153 def perffncacheload(ui, repo, **opts):
1155 def perffncacheload(ui, repo, **opts):
1154 opts = _byteskwargs(opts)
1156 opts = _byteskwargs(opts)
1155 timer, fm = gettimer(ui, opts)
1157 timer, fm = gettimer(ui, opts)
1156 s = repo.store
1158 s = repo.store
1157 def d():
1159 def d():
1158 s.fncache._load()
1160 s.fncache._load()
1159 timer(d)
1161 timer(d)
1160 fm.end()
1162 fm.end()
1161
1163
1162 @command(b'perffncachewrite', formatteropts)
1164 @command(b'perffncachewrite', formatteropts)
1163 def perffncachewrite(ui, repo, **opts):
1165 def perffncachewrite(ui, repo, **opts):
1164 opts = _byteskwargs(opts)
1166 opts = _byteskwargs(opts)
1165 timer, fm = gettimer(ui, opts)
1167 timer, fm = gettimer(ui, opts)
1166 s = repo.store
1168 s = repo.store
1167 lock = repo.lock()
1169 lock = repo.lock()
1168 s.fncache._load()
1170 s.fncache._load()
1169 tr = repo.transaction(b'perffncachewrite')
1171 tr = repo.transaction(b'perffncachewrite')
1170 tr.addbackup(b'fncache')
1172 tr.addbackup(b'fncache')
1171 def d():
1173 def d():
1172 s.fncache._dirty = True
1174 s.fncache._dirty = True
1173 s.fncache.write(tr)
1175 s.fncache.write(tr)
1174 timer(d)
1176 timer(d)
1175 tr.close()
1177 tr.close()
1176 lock.release()
1178 lock.release()
1177 fm.end()
1179 fm.end()
1178
1180
1179 @command(b'perffncacheencode', formatteropts)
1181 @command(b'perffncacheencode', formatteropts)
1180 def perffncacheencode(ui, repo, **opts):
1182 def perffncacheencode(ui, repo, **opts):
1181 opts = _byteskwargs(opts)
1183 opts = _byteskwargs(opts)
1182 timer, fm = gettimer(ui, opts)
1184 timer, fm = gettimer(ui, opts)
1183 s = repo.store
1185 s = repo.store
1184 s.fncache._load()
1186 s.fncache._load()
1185 def d():
1187 def d():
1186 for p in s.fncache.entries:
1188 for p in s.fncache.entries:
1187 s.encode(p)
1189 s.encode(p)
1188 timer(d)
1190 timer(d)
1189 fm.end()
1191 fm.end()
1190
1192
1191 def _bdiffworker(q, blocks, xdiff, ready, done):
1193 def _bdiffworker(q, blocks, xdiff, ready, done):
1192 while not done.is_set():
1194 while not done.is_set():
1193 pair = q.get()
1195 pair = q.get()
1194 while pair is not None:
1196 while pair is not None:
1195 if xdiff:
1197 if xdiff:
1196 mdiff.bdiff.xdiffblocks(*pair)
1198 mdiff.bdiff.xdiffblocks(*pair)
1197 elif blocks:
1199 elif blocks:
1198 mdiff.bdiff.blocks(*pair)
1200 mdiff.bdiff.blocks(*pair)
1199 else:
1201 else:
1200 mdiff.textdiff(*pair)
1202 mdiff.textdiff(*pair)
1201 q.task_done()
1203 q.task_done()
1202 pair = q.get()
1204 pair = q.get()
1203 q.task_done() # for the None one
1205 q.task_done() # for the None one
1204 with ready:
1206 with ready:
1205 ready.wait()
1207 ready.wait()
1206
1208
1207 def _manifestrevision(repo, mnode):
1209 def _manifestrevision(repo, mnode):
1208 ml = repo.manifestlog
1210 ml = repo.manifestlog
1209
1211
1210 if util.safehasattr(ml, b'getstorage'):
1212 if util.safehasattr(ml, b'getstorage'):
1211 store = ml.getstorage(b'')
1213 store = ml.getstorage(b'')
1212 else:
1214 else:
1213 store = ml._revlog
1215 store = ml._revlog
1214
1216
1215 return store.revision(mnode)
1217 return store.revision(mnode)
1216
1218
1217 @command(b'perfbdiff', revlogopts + formatteropts + [
1219 @command(b'perfbdiff', revlogopts + formatteropts + [
1218 (b'', b'count', 1, b'number of revisions to test (when using --startrev)'),
1220 (b'', b'count', 1, b'number of revisions to test (when using --startrev)'),
1219 (b'', b'alldata', False, b'test bdiffs for all associated revisions'),
1221 (b'', b'alldata', False, b'test bdiffs for all associated revisions'),
1220 (b'', b'threads', 0, b'number of thread to use (disable with 0)'),
1222 (b'', b'threads', 0, b'number of thread to use (disable with 0)'),
1221 (b'', b'blocks', False, b'test computing diffs into blocks'),
1223 (b'', b'blocks', False, b'test computing diffs into blocks'),
1222 (b'', b'xdiff', False, b'use xdiff algorithm'),
1224 (b'', b'xdiff', False, b'use xdiff algorithm'),
1223 ],
1225 ],
1224
1226
1225 b'-c|-m|FILE REV')
1227 b'-c|-m|FILE REV')
1226 def perfbdiff(ui, repo, file_, rev=None, count=None, threads=0, **opts):
1228 def perfbdiff(ui, repo, file_, rev=None, count=None, threads=0, **opts):
1227 """benchmark a bdiff between revisions
1229 """benchmark a bdiff between revisions
1228
1230
1229 By default, benchmark a bdiff between its delta parent and itself.
1231 By default, benchmark a bdiff between its delta parent and itself.
1230
1232
1231 With ``--count``, benchmark bdiffs between delta parents and self for N
1233 With ``--count``, benchmark bdiffs between delta parents and self for N
1232 revisions starting at the specified revision.
1234 revisions starting at the specified revision.
1233
1235
1234 With ``--alldata``, assume the requested revision is a changeset and
1236 With ``--alldata``, assume the requested revision is a changeset and
1235 measure bdiffs for all changes related to that changeset (manifest
1237 measure bdiffs for all changes related to that changeset (manifest
1236 and filelogs).
1238 and filelogs).
1237 """
1239 """
1238 opts = _byteskwargs(opts)
1240 opts = _byteskwargs(opts)
1239
1241
1240 if opts[b'xdiff'] and not opts[b'blocks']:
1242 if opts[b'xdiff'] and not opts[b'blocks']:
1241 raise error.CommandError(b'perfbdiff', b'--xdiff requires --blocks')
1243 raise error.CommandError(b'perfbdiff', b'--xdiff requires --blocks')
1242
1244
1243 if opts[b'alldata']:
1245 if opts[b'alldata']:
1244 opts[b'changelog'] = True
1246 opts[b'changelog'] = True
1245
1247
1246 if opts.get(b'changelog') or opts.get(b'manifest'):
1248 if opts.get(b'changelog') or opts.get(b'manifest'):
1247 file_, rev = None, file_
1249 file_, rev = None, file_
1248 elif rev is None:
1250 elif rev is None:
1249 raise error.CommandError(b'perfbdiff', b'invalid arguments')
1251 raise error.CommandError(b'perfbdiff', b'invalid arguments')
1250
1252
1251 blocks = opts[b'blocks']
1253 blocks = opts[b'blocks']
1252 xdiff = opts[b'xdiff']
1254 xdiff = opts[b'xdiff']
1253 textpairs = []
1255 textpairs = []
1254
1256
1255 r = cmdutil.openrevlog(repo, b'perfbdiff', file_, opts)
1257 r = cmdutil.openrevlog(repo, b'perfbdiff', file_, opts)
1256
1258
1257 startrev = r.rev(r.lookup(rev))
1259 startrev = r.rev(r.lookup(rev))
1258 for rev in range(startrev, min(startrev + count, len(r) - 1)):
1260 for rev in range(startrev, min(startrev + count, len(r) - 1)):
1259 if opts[b'alldata']:
1261 if opts[b'alldata']:
1260 # Load revisions associated with changeset.
1262 # Load revisions associated with changeset.
1261 ctx = repo[rev]
1263 ctx = repo[rev]
1262 mtext = _manifestrevision(repo, ctx.manifestnode())
1264 mtext = _manifestrevision(repo, ctx.manifestnode())
1263 for pctx in ctx.parents():
1265 for pctx in ctx.parents():
1264 pman = _manifestrevision(repo, pctx.manifestnode())
1266 pman = _manifestrevision(repo, pctx.manifestnode())
1265 textpairs.append((pman, mtext))
1267 textpairs.append((pman, mtext))
1266
1268
1267 # Load filelog revisions by iterating manifest delta.
1269 # Load filelog revisions by iterating manifest delta.
1268 man = ctx.manifest()
1270 man = ctx.manifest()
1269 pman = ctx.p1().manifest()
1271 pman = ctx.p1().manifest()
1270 for filename, change in pman.diff(man).items():
1272 for filename, change in pman.diff(man).items():
1271 fctx = repo.file(filename)
1273 fctx = repo.file(filename)
1272 f1 = fctx.revision(change[0][0] or -1)
1274 f1 = fctx.revision(change[0][0] or -1)
1273 f2 = fctx.revision(change[1][0] or -1)
1275 f2 = fctx.revision(change[1][0] or -1)
1274 textpairs.append((f1, f2))
1276 textpairs.append((f1, f2))
1275 else:
1277 else:
1276 dp = r.deltaparent(rev)
1278 dp = r.deltaparent(rev)
1277 textpairs.append((r.revision(dp), r.revision(rev)))
1279 textpairs.append((r.revision(dp), r.revision(rev)))
1278
1280
1279 withthreads = threads > 0
1281 withthreads = threads > 0
1280 if not withthreads:
1282 if not withthreads:
1281 def d():
1283 def d():
1282 for pair in textpairs:
1284 for pair in textpairs:
1283 if xdiff:
1285 if xdiff:
1284 mdiff.bdiff.xdiffblocks(*pair)
1286 mdiff.bdiff.xdiffblocks(*pair)
1285 elif blocks:
1287 elif blocks:
1286 mdiff.bdiff.blocks(*pair)
1288 mdiff.bdiff.blocks(*pair)
1287 else:
1289 else:
1288 mdiff.textdiff(*pair)
1290 mdiff.textdiff(*pair)
1289 else:
1291 else:
1290 q = queue()
1292 q = queue()
1291 for i in _xrange(threads):
1293 for i in _xrange(threads):
1292 q.put(None)
1294 q.put(None)
1293 ready = threading.Condition()
1295 ready = threading.Condition()
1294 done = threading.Event()
1296 done = threading.Event()
1295 for i in _xrange(threads):
1297 for i in _xrange(threads):
1296 threading.Thread(target=_bdiffworker,
1298 threading.Thread(target=_bdiffworker,
1297 args=(q, blocks, xdiff, ready, done)).start()
1299 args=(q, blocks, xdiff, ready, done)).start()
1298 q.join()
1300 q.join()
1299 def d():
1301 def d():
1300 for pair in textpairs:
1302 for pair in textpairs:
1301 q.put(pair)
1303 q.put(pair)
1302 for i in _xrange(threads):
1304 for i in _xrange(threads):
1303 q.put(None)
1305 q.put(None)
1304 with ready:
1306 with ready:
1305 ready.notify_all()
1307 ready.notify_all()
1306 q.join()
1308 q.join()
1307 timer, fm = gettimer(ui, opts)
1309 timer, fm = gettimer(ui, opts)
1308 timer(d)
1310 timer(d)
1309 fm.end()
1311 fm.end()
1310
1312
1311 if withthreads:
1313 if withthreads:
1312 done.set()
1314 done.set()
1313 for i in _xrange(threads):
1315 for i in _xrange(threads):
1314 q.put(None)
1316 q.put(None)
1315 with ready:
1317 with ready:
1316 ready.notify_all()
1318 ready.notify_all()
1317
1319
1318 @command(b'perfunidiff', revlogopts + formatteropts + [
1320 @command(b'perfunidiff', revlogopts + formatteropts + [
1319 (b'', b'count', 1, b'number of revisions to test (when using --startrev)'),
1321 (b'', b'count', 1, b'number of revisions to test (when using --startrev)'),
1320 (b'', b'alldata', False, b'test unidiffs for all associated revisions'),
1322 (b'', b'alldata', False, b'test unidiffs for all associated revisions'),
1321 ], b'-c|-m|FILE REV')
1323 ], b'-c|-m|FILE REV')
1322 def perfunidiff(ui, repo, file_, rev=None, count=None, **opts):
1324 def perfunidiff(ui, repo, file_, rev=None, count=None, **opts):
1323 """benchmark a unified diff between revisions
1325 """benchmark a unified diff between revisions
1324
1326
1325 This doesn't include any copy tracing - it's just a unified diff
1327 This doesn't include any copy tracing - it's just a unified diff
1326 of the texts.
1328 of the texts.
1327
1329
1328 By default, benchmark a diff between its delta parent and itself.
1330 By default, benchmark a diff between its delta parent and itself.
1329
1331
1330 With ``--count``, benchmark diffs between delta parents and self for N
1332 With ``--count``, benchmark diffs between delta parents and self for N
1331 revisions starting at the specified revision.
1333 revisions starting at the specified revision.
1332
1334
1333 With ``--alldata``, assume the requested revision is a changeset and
1335 With ``--alldata``, assume the requested revision is a changeset and
1334 measure diffs for all changes related to that changeset (manifest
1336 measure diffs for all changes related to that changeset (manifest
1335 and filelogs).
1337 and filelogs).
1336 """
1338 """
1337 opts = _byteskwargs(opts)
1339 opts = _byteskwargs(opts)
1338 if opts[b'alldata']:
1340 if opts[b'alldata']:
1339 opts[b'changelog'] = True
1341 opts[b'changelog'] = True
1340
1342
1341 if opts.get(b'changelog') or opts.get(b'manifest'):
1343 if opts.get(b'changelog') or opts.get(b'manifest'):
1342 file_, rev = None, file_
1344 file_, rev = None, file_
1343 elif rev is None:
1345 elif rev is None:
1344 raise error.CommandError(b'perfunidiff', b'invalid arguments')
1346 raise error.CommandError(b'perfunidiff', b'invalid arguments')
1345
1347
1346 textpairs = []
1348 textpairs = []
1347
1349
1348 r = cmdutil.openrevlog(repo, b'perfunidiff', file_, opts)
1350 r = cmdutil.openrevlog(repo, b'perfunidiff', file_, opts)
1349
1351
1350 startrev = r.rev(r.lookup(rev))
1352 startrev = r.rev(r.lookup(rev))
1351 for rev in range(startrev, min(startrev + count, len(r) - 1)):
1353 for rev in range(startrev, min(startrev + count, len(r) - 1)):
1352 if opts[b'alldata']:
1354 if opts[b'alldata']:
1353 # Load revisions associated with changeset.
1355 # Load revisions associated with changeset.
1354 ctx = repo[rev]
1356 ctx = repo[rev]
1355 mtext = _manifestrevision(repo, ctx.manifestnode())
1357 mtext = _manifestrevision(repo, ctx.manifestnode())
1356 for pctx in ctx.parents():
1358 for pctx in ctx.parents():
1357 pman = _manifestrevision(repo, pctx.manifestnode())
1359 pman = _manifestrevision(repo, pctx.manifestnode())
1358 textpairs.append((pman, mtext))
1360 textpairs.append((pman, mtext))
1359
1361
1360 # Load filelog revisions by iterating manifest delta.
1362 # Load filelog revisions by iterating manifest delta.
1361 man = ctx.manifest()
1363 man = ctx.manifest()
1362 pman = ctx.p1().manifest()
1364 pman = ctx.p1().manifest()
1363 for filename, change in pman.diff(man).items():
1365 for filename, change in pman.diff(man).items():
1364 fctx = repo.file(filename)
1366 fctx = repo.file(filename)
1365 f1 = fctx.revision(change[0][0] or -1)
1367 f1 = fctx.revision(change[0][0] or -1)
1366 f2 = fctx.revision(change[1][0] or -1)
1368 f2 = fctx.revision(change[1][0] or -1)
1367 textpairs.append((f1, f2))
1369 textpairs.append((f1, f2))
1368 else:
1370 else:
1369 dp = r.deltaparent(rev)
1371 dp = r.deltaparent(rev)
1370 textpairs.append((r.revision(dp), r.revision(rev)))
1372 textpairs.append((r.revision(dp), r.revision(rev)))
1371
1373
1372 def d():
1374 def d():
1373 for left, right in textpairs:
1375 for left, right in textpairs:
1374 # The date strings don't matter, so we pass empty strings.
1376 # The date strings don't matter, so we pass empty strings.
1375 headerlines, hunks = mdiff.unidiff(
1377 headerlines, hunks = mdiff.unidiff(
1376 left, b'', right, b'', b'left', b'right', binary=False)
1378 left, b'', right, b'', b'left', b'right', binary=False)
1377 # consume iterators in roughly the way patch.py does
1379 # consume iterators in roughly the way patch.py does
1378 b'\n'.join(headerlines)
1380 b'\n'.join(headerlines)
1379 b''.join(sum((list(hlines) for hrange, hlines in hunks), []))
1381 b''.join(sum((list(hlines) for hrange, hlines in hunks), []))
1380 timer, fm = gettimer(ui, opts)
1382 timer, fm = gettimer(ui, opts)
1381 timer(d)
1383 timer(d)
1382 fm.end()
1384 fm.end()
1383
1385
1384 @command(b'perfdiffwd', formatteropts)
1386 @command(b'perfdiffwd', formatteropts)
1385 def perfdiffwd(ui, repo, **opts):
1387 def perfdiffwd(ui, repo, **opts):
1386 """Profile diff of working directory changes"""
1388 """Profile diff of working directory changes"""
1387 opts = _byteskwargs(opts)
1389 opts = _byteskwargs(opts)
1388 timer, fm = gettimer(ui, opts)
1390 timer, fm = gettimer(ui, opts)
1389 options = {
1391 options = {
1390 b'w': b'ignore_all_space',
1392 'w': 'ignore_all_space',
1391 b'b': b'ignore_space_change',
1393 'b': 'ignore_space_change',
1392 b'B': b'ignore_blank_lines',
1394 'B': 'ignore_blank_lines',
1393 }
1395 }
1394
1396
1395 for diffopt in (b'', b'w', b'b', b'B', b'wB'):
1397 for diffopt in ('', 'w', 'b', 'B', 'wB'):
1396 opts = dict((options[c], b'1') for c in diffopt)
1398 opts = dict((options[c], b'1') for c in diffopt)
1397 def d():
1399 def d():
1398 ui.pushbuffer()
1400 ui.pushbuffer()
1399 commands.diff(ui, repo, **opts)
1401 commands.diff(ui, repo, **opts)
1400 ui.popbuffer()
1402 ui.popbuffer()
1403 diffopt = diffopt.encode('ascii')
1401 title = b'diffopts: %s' % (diffopt and (b'-' + diffopt) or b'none')
1404 title = b'diffopts: %s' % (diffopt and (b'-' + diffopt) or b'none')
1402 timer(d, title)
1405 timer(d, title)
1403 fm.end()
1406 fm.end()
1404
1407
1405 @command(b'perfrevlogindex', revlogopts + formatteropts,
1408 @command(b'perfrevlogindex', revlogopts + formatteropts,
1406 b'-c|-m|FILE')
1409 b'-c|-m|FILE')
1407 def perfrevlogindex(ui, repo, file_=None, **opts):
1410 def perfrevlogindex(ui, repo, file_=None, **opts):
1408 """Benchmark operations against a revlog index.
1411 """Benchmark operations against a revlog index.
1409
1412
1410 This tests constructing a revlog instance, reading index data,
1413 This tests constructing a revlog instance, reading index data,
1411 parsing index data, and performing various operations related to
1414 parsing index data, and performing various operations related to
1412 index data.
1415 index data.
1413 """
1416 """
1414
1417
1415 opts = _byteskwargs(opts)
1418 opts = _byteskwargs(opts)
1416
1419
1417 rl = cmdutil.openrevlog(repo, b'perfrevlogindex', file_, opts)
1420 rl = cmdutil.openrevlog(repo, b'perfrevlogindex', file_, opts)
1418
1421
1419 opener = getattr(rl, 'opener') # trick linter
1422 opener = getattr(rl, 'opener') # trick linter
1420 indexfile = rl.indexfile
1423 indexfile = rl.indexfile
1421 data = opener.read(indexfile)
1424 data = opener.read(indexfile)
1422
1425
1423 header = struct.unpack(b'>I', data[0:4])[0]
1426 header = struct.unpack(b'>I', data[0:4])[0]
1424 version = header & 0xFFFF
1427 version = header & 0xFFFF
1425 if version == 1:
1428 if version == 1:
1426 revlogio = revlog.revlogio()
1429 revlogio = revlog.revlogio()
1427 inline = header & (1 << 16)
1430 inline = header & (1 << 16)
1428 else:
1431 else:
1429 raise error.Abort((b'unsupported revlog version: %d') % version)
1432 raise error.Abort((b'unsupported revlog version: %d') % version)
1430
1433
1431 rllen = len(rl)
1434 rllen = len(rl)
1432
1435
1433 node0 = rl.node(0)
1436 node0 = rl.node(0)
1434 node25 = rl.node(rllen // 4)
1437 node25 = rl.node(rllen // 4)
1435 node50 = rl.node(rllen // 2)
1438 node50 = rl.node(rllen // 2)
1436 node75 = rl.node(rllen // 4 * 3)
1439 node75 = rl.node(rllen // 4 * 3)
1437 node100 = rl.node(rllen - 1)
1440 node100 = rl.node(rllen - 1)
1438
1441
1439 allrevs = range(rllen)
1442 allrevs = range(rllen)
1440 allrevsrev = list(reversed(allrevs))
1443 allrevsrev = list(reversed(allrevs))
1441 allnodes = [rl.node(rev) for rev in range(rllen)]
1444 allnodes = [rl.node(rev) for rev in range(rllen)]
1442 allnodesrev = list(reversed(allnodes))
1445 allnodesrev = list(reversed(allnodes))
1443
1446
1444 def constructor():
1447 def constructor():
1445 revlog.revlog(opener, indexfile)
1448 revlog.revlog(opener, indexfile)
1446
1449
1447 def read():
1450 def read():
1448 with opener(indexfile) as fh:
1451 with opener(indexfile) as fh:
1449 fh.read()
1452 fh.read()
1450
1453
1451 def parseindex():
1454 def parseindex():
1452 revlogio.parseindex(data, inline)
1455 revlogio.parseindex(data, inline)
1453
1456
1454 def getentry(revornode):
1457 def getentry(revornode):
1455 index = revlogio.parseindex(data, inline)[0]
1458 index = revlogio.parseindex(data, inline)[0]
1456 index[revornode]
1459 index[revornode]
1457
1460
1458 def getentries(revs, count=1):
1461 def getentries(revs, count=1):
1459 index = revlogio.parseindex(data, inline)[0]
1462 index = revlogio.parseindex(data, inline)[0]
1460
1463
1461 for i in range(count):
1464 for i in range(count):
1462 for rev in revs:
1465 for rev in revs:
1463 index[rev]
1466 index[rev]
1464
1467
1465 def resolvenode(node):
1468 def resolvenode(node):
1466 nodemap = revlogio.parseindex(data, inline)[1]
1469 nodemap = revlogio.parseindex(data, inline)[1]
1467 # This only works for the C code.
1470 # This only works for the C code.
1468 if nodemap is None:
1471 if nodemap is None:
1469 return
1472 return
1470
1473
1471 try:
1474 try:
1472 nodemap[node]
1475 nodemap[node]
1473 except error.RevlogError:
1476 except error.RevlogError:
1474 pass
1477 pass
1475
1478
1476 def resolvenodes(nodes, count=1):
1479 def resolvenodes(nodes, count=1):
1477 nodemap = revlogio.parseindex(data, inline)[1]
1480 nodemap = revlogio.parseindex(data, inline)[1]
1478 if nodemap is None:
1481 if nodemap is None:
1479 return
1482 return
1480
1483
1481 for i in range(count):
1484 for i in range(count):
1482 for node in nodes:
1485 for node in nodes:
1483 try:
1486 try:
1484 nodemap[node]
1487 nodemap[node]
1485 except error.RevlogError:
1488 except error.RevlogError:
1486 pass
1489 pass
1487
1490
1488 benches = [
1491 benches = [
1489 (constructor, b'revlog constructor'),
1492 (constructor, b'revlog constructor'),
1490 (read, b'read'),
1493 (read, b'read'),
1491 (parseindex, b'create index object'),
1494 (parseindex, b'create index object'),
1492 (lambda: getentry(0), b'retrieve index entry for rev 0'),
1495 (lambda: getentry(0), b'retrieve index entry for rev 0'),
1493 (lambda: resolvenode(b'a' * 20), b'look up missing node'),
1496 (lambda: resolvenode(b'a' * 20), b'look up missing node'),
1494 (lambda: resolvenode(node0), b'look up node at rev 0'),
1497 (lambda: resolvenode(node0), b'look up node at rev 0'),
1495 (lambda: resolvenode(node25), b'look up node at 1/4 len'),
1498 (lambda: resolvenode(node25), b'look up node at 1/4 len'),
1496 (lambda: resolvenode(node50), b'look up node at 1/2 len'),
1499 (lambda: resolvenode(node50), b'look up node at 1/2 len'),
1497 (lambda: resolvenode(node75), b'look up node at 3/4 len'),
1500 (lambda: resolvenode(node75), b'look up node at 3/4 len'),
1498 (lambda: resolvenode(node100), b'look up node at tip'),
1501 (lambda: resolvenode(node100), b'look up node at tip'),
1499 # 2x variation is to measure caching impact.
1502 # 2x variation is to measure caching impact.
1500 (lambda: resolvenodes(allnodes),
1503 (lambda: resolvenodes(allnodes),
1501 b'look up all nodes (forward)'),
1504 b'look up all nodes (forward)'),
1502 (lambda: resolvenodes(allnodes, 2),
1505 (lambda: resolvenodes(allnodes, 2),
1503 b'look up all nodes 2x (forward)'),
1506 b'look up all nodes 2x (forward)'),
1504 (lambda: resolvenodes(allnodesrev),
1507 (lambda: resolvenodes(allnodesrev),
1505 b'look up all nodes (reverse)'),
1508 b'look up all nodes (reverse)'),
1506 (lambda: resolvenodes(allnodesrev, 2),
1509 (lambda: resolvenodes(allnodesrev, 2),
1507 b'look up all nodes 2x (reverse)'),
1510 b'look up all nodes 2x (reverse)'),
1508 (lambda: getentries(allrevs),
1511 (lambda: getentries(allrevs),
1509 b'retrieve all index entries (forward)'),
1512 b'retrieve all index entries (forward)'),
1510 (lambda: getentries(allrevs, 2),
1513 (lambda: getentries(allrevs, 2),
1511 b'retrieve all index entries 2x (forward)'),
1514 b'retrieve all index entries 2x (forward)'),
1512 (lambda: getentries(allrevsrev),
1515 (lambda: getentries(allrevsrev),
1513 b'retrieve all index entries (reverse)'),
1516 b'retrieve all index entries (reverse)'),
1514 (lambda: getentries(allrevsrev, 2),
1517 (lambda: getentries(allrevsrev, 2),
1515 b'retrieve all index entries 2x (reverse)'),
1518 b'retrieve all index entries 2x (reverse)'),
1516 ]
1519 ]
1517
1520
1518 for fn, title in benches:
1521 for fn, title in benches:
1519 timer, fm = gettimer(ui, opts)
1522 timer, fm = gettimer(ui, opts)
1520 timer(fn, title=title)
1523 timer(fn, title=title)
1521 fm.end()
1524 fm.end()
1522
1525
1523 @command(b'perfrevlogrevisions', revlogopts + formatteropts +
1526 @command(b'perfrevlogrevisions', revlogopts + formatteropts +
1524 [(b'd', b'dist', 100, b'distance between the revisions'),
1527 [(b'd', b'dist', 100, b'distance between the revisions'),
1525 (b's', b'startrev', 0, b'revision to start reading at'),
1528 (b's', b'startrev', 0, b'revision to start reading at'),
1526 (b'', b'reverse', False, b'read in reverse')],
1529 (b'', b'reverse', False, b'read in reverse')],
1527 b'-c|-m|FILE')
1530 b'-c|-m|FILE')
1528 def perfrevlogrevisions(ui, repo, file_=None, startrev=0, reverse=False,
1531 def perfrevlogrevisions(ui, repo, file_=None, startrev=0, reverse=False,
1529 **opts):
1532 **opts):
1530 """Benchmark reading a series of revisions from a revlog.
1533 """Benchmark reading a series of revisions from a revlog.
1531
1534
1532 By default, we read every ``-d/--dist`` revision from 0 to tip of
1535 By default, we read every ``-d/--dist`` revision from 0 to tip of
1533 the specified revlog.
1536 the specified revlog.
1534
1537
1535 The start revision can be defined via ``-s/--startrev``.
1538 The start revision can be defined via ``-s/--startrev``.
1536 """
1539 """
1537 opts = _byteskwargs(opts)
1540 opts = _byteskwargs(opts)
1538
1541
1539 rl = cmdutil.openrevlog(repo, b'perfrevlogrevisions', file_, opts)
1542 rl = cmdutil.openrevlog(repo, b'perfrevlogrevisions', file_, opts)
1540 rllen = getlen(ui)(rl)
1543 rllen = getlen(ui)(rl)
1541
1544
1542 if startrev < 0:
1545 if startrev < 0:
1543 startrev = rllen + startrev
1546 startrev = rllen + startrev
1544
1547
1545 def d():
1548 def d():
1546 rl.clearcaches()
1549 rl.clearcaches()
1547
1550
1548 beginrev = startrev
1551 beginrev = startrev
1549 endrev = rllen
1552 endrev = rllen
1550 dist = opts[b'dist']
1553 dist = opts[b'dist']
1551
1554
1552 if reverse:
1555 if reverse:
1553 beginrev, endrev = endrev, beginrev
1556 beginrev, endrev = endrev, beginrev
1554 dist = -1 * dist
1557 dist = -1 * dist
1555
1558
1556 for x in _xrange(beginrev, endrev, dist):
1559 for x in _xrange(beginrev, endrev, dist):
1557 # Old revisions don't support passing int.
1560 # Old revisions don't support passing int.
1558 n = rl.node(x)
1561 n = rl.node(x)
1559 rl.revision(n)
1562 rl.revision(n)
1560
1563
1561 timer, fm = gettimer(ui, opts)
1564 timer, fm = gettimer(ui, opts)
1562 timer(d)
1565 timer(d)
1563 fm.end()
1566 fm.end()
1564
1567
1565 @command(b'perfrevlogchunks', revlogopts + formatteropts +
1568 @command(b'perfrevlogchunks', revlogopts + formatteropts +
1566 [(b'e', b'engines', b'', b'compression engines to use'),
1569 [(b'e', b'engines', b'', b'compression engines to use'),
1567 (b's', b'startrev', 0, b'revision to start at')],
1570 (b's', b'startrev', 0, b'revision to start at')],
1568 b'-c|-m|FILE')
1571 b'-c|-m|FILE')
1569 def perfrevlogchunks(ui, repo, file_=None, engines=None, startrev=0, **opts):
1572 def perfrevlogchunks(ui, repo, file_=None, engines=None, startrev=0, **opts):
1570 """Benchmark operations on revlog chunks.
1573 """Benchmark operations on revlog chunks.
1571
1574
1572 Logically, each revlog is a collection of fulltext revisions. However,
1575 Logically, each revlog is a collection of fulltext revisions. However,
1573 stored within each revlog are "chunks" of possibly compressed data. This
1576 stored within each revlog are "chunks" of possibly compressed data. This
1574 data needs to be read and decompressed or compressed and written.
1577 data needs to be read and decompressed or compressed and written.
1575
1578
1576 This command measures the time it takes to read+decompress and recompress
1579 This command measures the time it takes to read+decompress and recompress
1577 chunks in a revlog. It effectively isolates I/O and compression performance.
1580 chunks in a revlog. It effectively isolates I/O and compression performance.
1578 For measurements of higher-level operations like resolving revisions,
1581 For measurements of higher-level operations like resolving revisions,
1579 see ``perfrevlogrevisions`` and ``perfrevlogrevision``.
1582 see ``perfrevlogrevisions`` and ``perfrevlogrevision``.
1580 """
1583 """
1581 opts = _byteskwargs(opts)
1584 opts = _byteskwargs(opts)
1582
1585
1583 rl = cmdutil.openrevlog(repo, b'perfrevlogchunks', file_, opts)
1586 rl = cmdutil.openrevlog(repo, b'perfrevlogchunks', file_, opts)
1584
1587
1585 # _chunkraw was renamed to _getsegmentforrevs.
1588 # _chunkraw was renamed to _getsegmentforrevs.
1586 try:
1589 try:
1587 segmentforrevs = rl._getsegmentforrevs
1590 segmentforrevs = rl._getsegmentforrevs
1588 except AttributeError:
1591 except AttributeError:
1589 segmentforrevs = rl._chunkraw
1592 segmentforrevs = rl._chunkraw
1590
1593
1591 # Verify engines argument.
1594 # Verify engines argument.
1592 if engines:
1595 if engines:
1593 engines = set(e.strip() for e in engines.split(b','))
1596 engines = set(e.strip() for e in engines.split(b','))
1594 for engine in engines:
1597 for engine in engines:
1595 try:
1598 try:
1596 util.compressionengines[engine]
1599 util.compressionengines[engine]
1597 except KeyError:
1600 except KeyError:
1598 raise error.Abort(b'unknown compression engine: %s' % engine)
1601 raise error.Abort(b'unknown compression engine: %s' % engine)
1599 else:
1602 else:
1600 engines = []
1603 engines = []
1601 for e in util.compengines:
1604 for e in util.compengines:
1602 engine = util.compengines[e]
1605 engine = util.compengines[e]
1603 try:
1606 try:
1604 if engine.available():
1607 if engine.available():
1605 engine.revlogcompressor().compress(b'dummy')
1608 engine.revlogcompressor().compress(b'dummy')
1606 engines.append(e)
1609 engines.append(e)
1607 except NotImplementedError:
1610 except NotImplementedError:
1608 pass
1611 pass
1609
1612
1610 revs = list(rl.revs(startrev, len(rl) - 1))
1613 revs = list(rl.revs(startrev, len(rl) - 1))
1611
1614
1612 def rlfh(rl):
1615 def rlfh(rl):
1613 if rl._inline:
1616 if rl._inline:
1614 return getsvfs(repo)(rl.indexfile)
1617 return getsvfs(repo)(rl.indexfile)
1615 else:
1618 else:
1616 return getsvfs(repo)(rl.datafile)
1619 return getsvfs(repo)(rl.datafile)
1617
1620
1618 def doread():
1621 def doread():
1619 rl.clearcaches()
1622 rl.clearcaches()
1620 for rev in revs:
1623 for rev in revs:
1621 segmentforrevs(rev, rev)
1624 segmentforrevs(rev, rev)
1622
1625
1623 def doreadcachedfh():
1626 def doreadcachedfh():
1624 rl.clearcaches()
1627 rl.clearcaches()
1625 fh = rlfh(rl)
1628 fh = rlfh(rl)
1626 for rev in revs:
1629 for rev in revs:
1627 segmentforrevs(rev, rev, df=fh)
1630 segmentforrevs(rev, rev, df=fh)
1628
1631
1629 def doreadbatch():
1632 def doreadbatch():
1630 rl.clearcaches()
1633 rl.clearcaches()
1631 segmentforrevs(revs[0], revs[-1])
1634 segmentforrevs(revs[0], revs[-1])
1632
1635
1633 def doreadbatchcachedfh():
1636 def doreadbatchcachedfh():
1634 rl.clearcaches()
1637 rl.clearcaches()
1635 fh = rlfh(rl)
1638 fh = rlfh(rl)
1636 segmentforrevs(revs[0], revs[-1], df=fh)
1639 segmentforrevs(revs[0], revs[-1], df=fh)
1637
1640
1638 def dochunk():
1641 def dochunk():
1639 rl.clearcaches()
1642 rl.clearcaches()
1640 fh = rlfh(rl)
1643 fh = rlfh(rl)
1641 for rev in revs:
1644 for rev in revs:
1642 rl._chunk(rev, df=fh)
1645 rl._chunk(rev, df=fh)
1643
1646
1644 chunks = [None]
1647 chunks = [None]
1645
1648
1646 def dochunkbatch():
1649 def dochunkbatch():
1647 rl.clearcaches()
1650 rl.clearcaches()
1648 fh = rlfh(rl)
1651 fh = rlfh(rl)
1649 # Save chunks as a side-effect.
1652 # Save chunks as a side-effect.
1650 chunks[0] = rl._chunks(revs, df=fh)
1653 chunks[0] = rl._chunks(revs, df=fh)
1651
1654
1652 def docompress(compressor):
1655 def docompress(compressor):
1653 rl.clearcaches()
1656 rl.clearcaches()
1654
1657
1655 try:
1658 try:
1656 # Swap in the requested compression engine.
1659 # Swap in the requested compression engine.
1657 oldcompressor = rl._compressor
1660 oldcompressor = rl._compressor
1658 rl._compressor = compressor
1661 rl._compressor = compressor
1659 for chunk in chunks[0]:
1662 for chunk in chunks[0]:
1660 rl.compress(chunk)
1663 rl.compress(chunk)
1661 finally:
1664 finally:
1662 rl._compressor = oldcompressor
1665 rl._compressor = oldcompressor
1663
1666
1664 benches = [
1667 benches = [
1665 (lambda: doread(), b'read'),
1668 (lambda: doread(), b'read'),
1666 (lambda: doreadcachedfh(), b'read w/ reused fd'),
1669 (lambda: doreadcachedfh(), b'read w/ reused fd'),
1667 (lambda: doreadbatch(), b'read batch'),
1670 (lambda: doreadbatch(), b'read batch'),
1668 (lambda: doreadbatchcachedfh(), b'read batch w/ reused fd'),
1671 (lambda: doreadbatchcachedfh(), b'read batch w/ reused fd'),
1669 (lambda: dochunk(), b'chunk'),
1672 (lambda: dochunk(), b'chunk'),
1670 (lambda: dochunkbatch(), b'chunk batch'),
1673 (lambda: dochunkbatch(), b'chunk batch'),
1671 ]
1674 ]
1672
1675
1673 for engine in sorted(engines):
1676 for engine in sorted(engines):
1674 compressor = util.compengines[engine].revlogcompressor()
1677 compressor = util.compengines[engine].revlogcompressor()
1675 benches.append((functools.partial(docompress, compressor),
1678 benches.append((functools.partial(docompress, compressor),
1676 b'compress w/ %s' % engine))
1679 b'compress w/ %s' % engine))
1677
1680
1678 for fn, title in benches:
1681 for fn, title in benches:
1679 timer, fm = gettimer(ui, opts)
1682 timer, fm = gettimer(ui, opts)
1680 timer(fn, title=title)
1683 timer(fn, title=title)
1681 fm.end()
1684 fm.end()
1682
1685
1683 @command(b'perfrevlogrevision', revlogopts + formatteropts +
1686 @command(b'perfrevlogrevision', revlogopts + formatteropts +
1684 [(b'', b'cache', False, b'use caches instead of clearing')],
1687 [(b'', b'cache', False, b'use caches instead of clearing')],
1685 b'-c|-m|FILE REV')
1688 b'-c|-m|FILE REV')
1686 def perfrevlogrevision(ui, repo, file_, rev=None, cache=None, **opts):
1689 def perfrevlogrevision(ui, repo, file_, rev=None, cache=None, **opts):
1687 """Benchmark obtaining a revlog revision.
1690 """Benchmark obtaining a revlog revision.
1688
1691
1689 Obtaining a revlog revision consists of roughly the following steps:
1692 Obtaining a revlog revision consists of roughly the following steps:
1690
1693
1691 1. Compute the delta chain
1694 1. Compute the delta chain
1692 2. Obtain the raw chunks for that delta chain
1695 2. Obtain the raw chunks for that delta chain
1693 3. Decompress each raw chunk
1696 3. Decompress each raw chunk
1694 4. Apply binary patches to obtain fulltext
1697 4. Apply binary patches to obtain fulltext
1695 5. Verify hash of fulltext
1698 5. Verify hash of fulltext
1696
1699
1697 This command measures the time spent in each of these phases.
1700 This command measures the time spent in each of these phases.
1698 """
1701 """
1699 opts = _byteskwargs(opts)
1702 opts = _byteskwargs(opts)
1700
1703
1701 if opts.get(b'changelog') or opts.get(b'manifest'):
1704 if opts.get(b'changelog') or opts.get(b'manifest'):
1702 file_, rev = None, file_
1705 file_, rev = None, file_
1703 elif rev is None:
1706 elif rev is None:
1704 raise error.CommandError(b'perfrevlogrevision', b'invalid arguments')
1707 raise error.CommandError(b'perfrevlogrevision', b'invalid arguments')
1705
1708
1706 r = cmdutil.openrevlog(repo, b'perfrevlogrevision', file_, opts)
1709 r = cmdutil.openrevlog(repo, b'perfrevlogrevision', file_, opts)
1707
1710
1708 # _chunkraw was renamed to _getsegmentforrevs.
1711 # _chunkraw was renamed to _getsegmentforrevs.
1709 try:
1712 try:
1710 segmentforrevs = r._getsegmentforrevs
1713 segmentforrevs = r._getsegmentforrevs
1711 except AttributeError:
1714 except AttributeError:
1712 segmentforrevs = r._chunkraw
1715 segmentforrevs = r._chunkraw
1713
1716
1714 node = r.lookup(rev)
1717 node = r.lookup(rev)
1715 rev = r.rev(node)
1718 rev = r.rev(node)
1716
1719
1717 def getrawchunks(data, chain):
1720 def getrawchunks(data, chain):
1718 start = r.start
1721 start = r.start
1719 length = r.length
1722 length = r.length
1720 inline = r._inline
1723 inline = r._inline
1721 iosize = r._io.size
1724 iosize = r._io.size
1722 buffer = util.buffer
1725 buffer = util.buffer
1723 offset = start(chain[0])
1726 offset = start(chain[0])
1724
1727
1725 chunks = []
1728 chunks = []
1726 ladd = chunks.append
1729 ladd = chunks.append
1727
1730
1728 for rev in chain:
1731 for rev in chain:
1729 chunkstart = start(rev)
1732 chunkstart = start(rev)
1730 if inline:
1733 if inline:
1731 chunkstart += (rev + 1) * iosize
1734 chunkstart += (rev + 1) * iosize
1732 chunklength = length(rev)
1735 chunklength = length(rev)
1733 ladd(buffer(data, chunkstart - offset, chunklength))
1736 ladd(buffer(data, chunkstart - offset, chunklength))
1734
1737
1735 return chunks
1738 return chunks
1736
1739
1737 def dodeltachain(rev):
1740 def dodeltachain(rev):
1738 if not cache:
1741 if not cache:
1739 r.clearcaches()
1742 r.clearcaches()
1740 r._deltachain(rev)
1743 r._deltachain(rev)
1741
1744
1742 def doread(chain):
1745 def doread(chain):
1743 if not cache:
1746 if not cache:
1744 r.clearcaches()
1747 r.clearcaches()
1745 segmentforrevs(chain[0], chain[-1])
1748 segmentforrevs(chain[0], chain[-1])
1746
1749
1747 def dorawchunks(data, chain):
1750 def dorawchunks(data, chain):
1748 if not cache:
1751 if not cache:
1749 r.clearcaches()
1752 r.clearcaches()
1750 getrawchunks(data, chain)
1753 getrawchunks(data, chain)
1751
1754
1752 def dodecompress(chunks):
1755 def dodecompress(chunks):
1753 decomp = r.decompress
1756 decomp = r.decompress
1754 for chunk in chunks:
1757 for chunk in chunks:
1755 decomp(chunk)
1758 decomp(chunk)
1756
1759
1757 def dopatch(text, bins):
1760 def dopatch(text, bins):
1758 if not cache:
1761 if not cache:
1759 r.clearcaches()
1762 r.clearcaches()
1760 mdiff.patches(text, bins)
1763 mdiff.patches(text, bins)
1761
1764
1762 def dohash(text):
1765 def dohash(text):
1763 if not cache:
1766 if not cache:
1764 r.clearcaches()
1767 r.clearcaches()
1765 r.checkhash(text, node, rev=rev)
1768 r.checkhash(text, node, rev=rev)
1766
1769
1767 def dorevision():
1770 def dorevision():
1768 if not cache:
1771 if not cache:
1769 r.clearcaches()
1772 r.clearcaches()
1770 r.revision(node)
1773 r.revision(node)
1771
1774
1772 chain = r._deltachain(rev)[0]
1775 chain = r._deltachain(rev)[0]
1773 data = segmentforrevs(chain[0], chain[-1])[1]
1776 data = segmentforrevs(chain[0], chain[-1])[1]
1774 rawchunks = getrawchunks(data, chain)
1777 rawchunks = getrawchunks(data, chain)
1775 bins = r._chunks(chain)
1778 bins = r._chunks(chain)
1776 text = str(bins[0])
1779 text = bytes(bins[0])
1777 bins = bins[1:]
1780 bins = bins[1:]
1778 text = mdiff.patches(text, bins)
1781 text = mdiff.patches(text, bins)
1779
1782
1780 benches = [
1783 benches = [
1781 (lambda: dorevision(), b'full'),
1784 (lambda: dorevision(), b'full'),
1782 (lambda: dodeltachain(rev), b'deltachain'),
1785 (lambda: dodeltachain(rev), b'deltachain'),
1783 (lambda: doread(chain), b'read'),
1786 (lambda: doread(chain), b'read'),
1784 (lambda: dorawchunks(data, chain), b'rawchunks'),
1787 (lambda: dorawchunks(data, chain), b'rawchunks'),
1785 (lambda: dodecompress(rawchunks), b'decompress'),
1788 (lambda: dodecompress(rawchunks), b'decompress'),
1786 (lambda: dopatch(text, bins), b'patch'),
1789 (lambda: dopatch(text, bins), b'patch'),
1787 (lambda: dohash(text), b'hash'),
1790 (lambda: dohash(text), b'hash'),
1788 ]
1791 ]
1789
1792
1790 for fn, title in benches:
1793 for fn, title in benches:
1791 timer, fm = gettimer(ui, opts)
1794 timer, fm = gettimer(ui, opts)
1792 timer(fn, title=title)
1795 timer(fn, title=title)
1793 fm.end()
1796 fm.end()
1794
1797
1795 @command(b'perfrevset',
1798 @command(b'perfrevset',
1796 [(b'C', b'clear', False, b'clear volatile cache between each call.'),
1799 [(b'C', b'clear', False, b'clear volatile cache between each call.'),
1797 (b'', b'contexts', False, b'obtain changectx for each revision')]
1800 (b'', b'contexts', False, b'obtain changectx for each revision')]
1798 + formatteropts, b"REVSET")
1801 + formatteropts, b"REVSET")
1799 def perfrevset(ui, repo, expr, clear=False, contexts=False, **opts):
1802 def perfrevset(ui, repo, expr, clear=False, contexts=False, **opts):
1800 """benchmark the execution time of a revset
1803 """benchmark the execution time of a revset
1801
1804
1802 Use the --clean option if need to evaluate the impact of build volatile
1805 Use the --clean option if need to evaluate the impact of build volatile
1803 revisions set cache on the revset execution. Volatile cache hold filtered
1806 revisions set cache on the revset execution. Volatile cache hold filtered
1804 and obsolete related cache."""
1807 and obsolete related cache."""
1805 opts = _byteskwargs(opts)
1808 opts = _byteskwargs(opts)
1806
1809
1807 timer, fm = gettimer(ui, opts)
1810 timer, fm = gettimer(ui, opts)
1808 def d():
1811 def d():
1809 if clear:
1812 if clear:
1810 repo.invalidatevolatilesets()
1813 repo.invalidatevolatilesets()
1811 if contexts:
1814 if contexts:
1812 for ctx in repo.set(expr): pass
1815 for ctx in repo.set(expr): pass
1813 else:
1816 else:
1814 for r in repo.revs(expr): pass
1817 for r in repo.revs(expr): pass
1815 timer(d)
1818 timer(d)
1816 fm.end()
1819 fm.end()
1817
1820
1818 @command(b'perfvolatilesets',
1821 @command(b'perfvolatilesets',
1819 [(b'', b'clear-obsstore', False, b'drop obsstore between each call.'),
1822 [(b'', b'clear-obsstore', False, b'drop obsstore between each call.'),
1820 ] + formatteropts)
1823 ] + formatteropts)
1821 def perfvolatilesets(ui, repo, *names, **opts):
1824 def perfvolatilesets(ui, repo, *names, **opts):
1822 """benchmark the computation of various volatile set
1825 """benchmark the computation of various volatile set
1823
1826
1824 Volatile set computes element related to filtering and obsolescence."""
1827 Volatile set computes element related to filtering and obsolescence."""
1825 opts = _byteskwargs(opts)
1828 opts = _byteskwargs(opts)
1826 timer, fm = gettimer(ui, opts)
1829 timer, fm = gettimer(ui, opts)
1827 repo = repo.unfiltered()
1830 repo = repo.unfiltered()
1828
1831
1829 def getobs(name):
1832 def getobs(name):
1830 def d():
1833 def d():
1831 repo.invalidatevolatilesets()
1834 repo.invalidatevolatilesets()
1832 if opts[b'clear_obsstore']:
1835 if opts[b'clear_obsstore']:
1833 clearfilecache(repo, b'obsstore')
1836 clearfilecache(repo, b'obsstore')
1834 obsolete.getrevs(repo, name)
1837 obsolete.getrevs(repo, name)
1835 return d
1838 return d
1836
1839
1837 allobs = sorted(obsolete.cachefuncs)
1840 allobs = sorted(obsolete.cachefuncs)
1838 if names:
1841 if names:
1839 allobs = [n for n in allobs if n in names]
1842 allobs = [n for n in allobs if n in names]
1840
1843
1841 for name in allobs:
1844 for name in allobs:
1842 timer(getobs(name), title=name)
1845 timer(getobs(name), title=name)
1843
1846
1844 def getfiltered(name):
1847 def getfiltered(name):
1845 def d():
1848 def d():
1846 repo.invalidatevolatilesets()
1849 repo.invalidatevolatilesets()
1847 if opts[b'clear_obsstore']:
1850 if opts[b'clear_obsstore']:
1848 clearfilecache(repo, b'obsstore')
1851 clearfilecache(repo, b'obsstore')
1849 repoview.filterrevs(repo, name)
1852 repoview.filterrevs(repo, name)
1850 return d
1853 return d
1851
1854
1852 allfilter = sorted(repoview.filtertable)
1855 allfilter = sorted(repoview.filtertable)
1853 if names:
1856 if names:
1854 allfilter = [n for n in allfilter if n in names]
1857 allfilter = [n for n in allfilter if n in names]
1855
1858
1856 for name in allfilter:
1859 for name in allfilter:
1857 timer(getfiltered(name), title=name)
1860 timer(getfiltered(name), title=name)
1858 fm.end()
1861 fm.end()
1859
1862
1860 @command(b'perfbranchmap',
1863 @command(b'perfbranchmap',
1861 [(b'f', b'full', False,
1864 [(b'f', b'full', False,
1862 b'Includes build time of subset'),
1865 b'Includes build time of subset'),
1863 (b'', b'clear-revbranch', False,
1866 (b'', b'clear-revbranch', False,
1864 b'purge the revbranch cache between computation'),
1867 b'purge the revbranch cache between computation'),
1865 ] + formatteropts)
1868 ] + formatteropts)
1866 def perfbranchmap(ui, repo, *filternames, **opts):
1869 def perfbranchmap(ui, repo, *filternames, **opts):
1867 """benchmark the update of a branchmap
1870 """benchmark the update of a branchmap
1868
1871
1869 This benchmarks the full repo.branchmap() call with read and write disabled
1872 This benchmarks the full repo.branchmap() call with read and write disabled
1870 """
1873 """
1871 opts = _byteskwargs(opts)
1874 opts = _byteskwargs(opts)
1872 full = opts.get(b"full", False)
1875 full = opts.get(b"full", False)
1873 clear_revbranch = opts.get(b"clear_revbranch", False)
1876 clear_revbranch = opts.get(b"clear_revbranch", False)
1874 timer, fm = gettimer(ui, opts)
1877 timer, fm = gettimer(ui, opts)
1875 def getbranchmap(filtername):
1878 def getbranchmap(filtername):
1876 """generate a benchmark function for the filtername"""
1879 """generate a benchmark function for the filtername"""
1877 if filtername is None:
1880 if filtername is None:
1878 view = repo
1881 view = repo
1879 else:
1882 else:
1880 view = repo.filtered(filtername)
1883 view = repo.filtered(filtername)
1881 def d():
1884 def d():
1882 if clear_revbranch:
1885 if clear_revbranch:
1883 repo.revbranchcache()._clear()
1886 repo.revbranchcache()._clear()
1884 if full:
1887 if full:
1885 view._branchcaches.clear()
1888 view._branchcaches.clear()
1886 else:
1889 else:
1887 view._branchcaches.pop(filtername, None)
1890 view._branchcaches.pop(filtername, None)
1888 view.branchmap()
1891 view.branchmap()
1889 return d
1892 return d
1890 # add filter in smaller subset to bigger subset
1893 # add filter in smaller subset to bigger subset
1891 possiblefilters = set(repoview.filtertable)
1894 possiblefilters = set(repoview.filtertable)
1892 if filternames:
1895 if filternames:
1893 possiblefilters &= set(filternames)
1896 possiblefilters &= set(filternames)
1894 subsettable = getbranchmapsubsettable()
1897 subsettable = getbranchmapsubsettable()
1895 allfilters = []
1898 allfilters = []
1896 while possiblefilters:
1899 while possiblefilters:
1897 for name in possiblefilters:
1900 for name in possiblefilters:
1898 subset = subsettable.get(name)
1901 subset = subsettable.get(name)
1899 if subset not in possiblefilters:
1902 if subset not in possiblefilters:
1900 break
1903 break
1901 else:
1904 else:
1902 assert False, b'subset cycle %s!' % possiblefilters
1905 assert False, b'subset cycle %s!' % possiblefilters
1903 allfilters.append(name)
1906 allfilters.append(name)
1904 possiblefilters.remove(name)
1907 possiblefilters.remove(name)
1905
1908
1906 # warm the cache
1909 # warm the cache
1907 if not full:
1910 if not full:
1908 for name in allfilters:
1911 for name in allfilters:
1909 repo.filtered(name).branchmap()
1912 repo.filtered(name).branchmap()
1910 if not filternames or b'unfiltered' in filternames:
1913 if not filternames or b'unfiltered' in filternames:
1911 # add unfiltered
1914 # add unfiltered
1912 allfilters.append(None)
1915 allfilters.append(None)
1913
1916
1914 branchcacheread = safeattrsetter(branchmap, b'read')
1917 branchcacheread = safeattrsetter(branchmap, b'read')
1915 branchcachewrite = safeattrsetter(branchmap.branchcache, b'write')
1918 branchcachewrite = safeattrsetter(branchmap.branchcache, b'write')
1916 branchcacheread.set(lambda repo: None)
1919 branchcacheread.set(lambda repo: None)
1917 branchcachewrite.set(lambda bc, repo: None)
1920 branchcachewrite.set(lambda bc, repo: None)
1918 try:
1921 try:
1919 for name in allfilters:
1922 for name in allfilters:
1920 printname = name
1923 printname = name
1921 if name is None:
1924 if name is None:
1922 printname = b'unfiltered'
1925 printname = b'unfiltered'
1923 timer(getbranchmap(name), title=str(printname))
1926 timer(getbranchmap(name), title=str(printname))
1924 finally:
1927 finally:
1925 branchcacheread.restore()
1928 branchcacheread.restore()
1926 branchcachewrite.restore()
1929 branchcachewrite.restore()
1927 fm.end()
1930 fm.end()
1928
1931
1929 @command(b'perfbranchmapload', [
1932 @command(b'perfbranchmapload', [
1930 (b'f', b'filter', b'', b'Specify repoview filter'),
1933 (b'f', b'filter', b'', b'Specify repoview filter'),
1931 (b'', b'list', False, b'List brachmap filter caches'),
1934 (b'', b'list', False, b'List brachmap filter caches'),
1932 ] + formatteropts)
1935 ] + formatteropts)
1933 def perfbranchmapread(ui, repo, filter=b'', list=False, **opts):
1936 def perfbranchmapread(ui, repo, filter=b'', list=False, **opts):
1934 """benchmark reading the branchmap"""
1937 """benchmark reading the branchmap"""
1935 opts = _byteskwargs(opts)
1938 opts = _byteskwargs(opts)
1936
1939
1937 if list:
1940 if list:
1938 for name, kind, st in repo.cachevfs.readdir(stat=True):
1941 for name, kind, st in repo.cachevfs.readdir(stat=True):
1939 if name.startswith(b'branch2'):
1942 if name.startswith(b'branch2'):
1940 filtername = name.partition(b'-')[2] or b'unfiltered'
1943 filtername = name.partition(b'-')[2] or b'unfiltered'
1941 ui.status(b'%s - %s\n'
1944 ui.status(b'%s - %s\n'
1942 % (filtername, util.bytecount(st.st_size)))
1945 % (filtername, util.bytecount(st.st_size)))
1943 return
1946 return
1944 if filter:
1947 if filter:
1945 repo = repoview.repoview(repo, filter)
1948 repo = repoview.repoview(repo, filter)
1946 else:
1949 else:
1947 repo = repo.unfiltered()
1950 repo = repo.unfiltered()
1948 # try once without timer, the filter may not be cached
1951 # try once without timer, the filter may not be cached
1949 if branchmap.read(repo) is None:
1952 if branchmap.read(repo) is None:
1950 raise error.Abort(b'No brachmap cached for %s repo'
1953 raise error.Abort(b'No brachmap cached for %s repo'
1951 % (filter or b'unfiltered'))
1954 % (filter or b'unfiltered'))
1952 timer, fm = gettimer(ui, opts)
1955 timer, fm = gettimer(ui, opts)
1953 timer(lambda: branchmap.read(repo) and None)
1956 timer(lambda: branchmap.read(repo) and None)
1954 fm.end()
1957 fm.end()
1955
1958
1956 @command(b'perfloadmarkers')
1959 @command(b'perfloadmarkers')
1957 def perfloadmarkers(ui, repo):
1960 def perfloadmarkers(ui, repo):
1958 """benchmark the time to parse the on-disk markers for a repo
1961 """benchmark the time to parse the on-disk markers for a repo
1959
1962
1960 Result is the number of markers in the repo."""
1963 Result is the number of markers in the repo."""
1961 timer, fm = gettimer(ui)
1964 timer, fm = gettimer(ui)
1962 svfs = getsvfs(repo)
1965 svfs = getsvfs(repo)
1963 timer(lambda: len(obsolete.obsstore(svfs)))
1966 timer(lambda: len(obsolete.obsstore(svfs)))
1964 fm.end()
1967 fm.end()
1965
1968
1966 @command(b'perflrucachedict', formatteropts +
1969 @command(b'perflrucachedict', formatteropts +
1967 [(b'', b'costlimit', 0, b'maximum total cost of items in cache'),
1970 [(b'', b'costlimit', 0, b'maximum total cost of items in cache'),
1968 (b'', b'mincost', 0, b'smallest cost of items in cache'),
1971 (b'', b'mincost', 0, b'smallest cost of items in cache'),
1969 (b'', b'maxcost', 100, b'maximum cost of items in cache'),
1972 (b'', b'maxcost', 100, b'maximum cost of items in cache'),
1970 (b'', b'size', 4, b'size of cache'),
1973 (b'', b'size', 4, b'size of cache'),
1971 (b'', b'gets', 10000, b'number of key lookups'),
1974 (b'', b'gets', 10000, b'number of key lookups'),
1972 (b'', b'sets', 10000, b'number of key sets'),
1975 (b'', b'sets', 10000, b'number of key sets'),
1973 (b'', b'mixed', 10000, b'number of mixed mode operations'),
1976 (b'', b'mixed', 10000, b'number of mixed mode operations'),
1974 (b'', b'mixedgetfreq', 50, b'frequency of get vs set ops in mixed mode')],
1977 (b'', b'mixedgetfreq', 50, b'frequency of get vs set ops in mixed mode')],
1975 norepo=True)
1978 norepo=True)
1976 def perflrucache(ui, mincost=0, maxcost=100, costlimit=0, size=4,
1979 def perflrucache(ui, mincost=0, maxcost=100, costlimit=0, size=4,
1977 gets=10000, sets=10000, mixed=10000, mixedgetfreq=50, **opts):
1980 gets=10000, sets=10000, mixed=10000, mixedgetfreq=50, **opts):
1978 opts = _byteskwargs(opts)
1981 opts = _byteskwargs(opts)
1979
1982
1980 def doinit():
1983 def doinit():
1981 for i in _xrange(10000):
1984 for i in _xrange(10000):
1982 util.lrucachedict(size)
1985 util.lrucachedict(size)
1983
1986
1984 costrange = list(range(mincost, maxcost + 1))
1987 costrange = list(range(mincost, maxcost + 1))
1985
1988
1986 values = []
1989 values = []
1987 for i in _xrange(size):
1990 for i in _xrange(size):
1988 values.append(random.randint(0, _maxint))
1991 values.append(random.randint(0, _maxint))
1989
1992
1990 # Get mode fills the cache and tests raw lookup performance with no
1993 # Get mode fills the cache and tests raw lookup performance with no
1991 # eviction.
1994 # eviction.
1992 getseq = []
1995 getseq = []
1993 for i in _xrange(gets):
1996 for i in _xrange(gets):
1994 getseq.append(random.choice(values))
1997 getseq.append(random.choice(values))
1995
1998
1996 def dogets():
1999 def dogets():
1997 d = util.lrucachedict(size)
2000 d = util.lrucachedict(size)
1998 for v in values:
2001 for v in values:
1999 d[v] = v
2002 d[v] = v
2000 for key in getseq:
2003 for key in getseq:
2001 value = d[key]
2004 value = d[key]
2002 value # silence pyflakes warning
2005 value # silence pyflakes warning
2003
2006
2004 def dogetscost():
2007 def dogetscost():
2005 d = util.lrucachedict(size, maxcost=costlimit)
2008 d = util.lrucachedict(size, maxcost=costlimit)
2006 for i, v in enumerate(values):
2009 for i, v in enumerate(values):
2007 d.insert(v, v, cost=costs[i])
2010 d.insert(v, v, cost=costs[i])
2008 for key in getseq:
2011 for key in getseq:
2009 try:
2012 try:
2010 value = d[key]
2013 value = d[key]
2011 value # silence pyflakes warning
2014 value # silence pyflakes warning
2012 except KeyError:
2015 except KeyError:
2013 pass
2016 pass
2014
2017
2015 # Set mode tests insertion speed with cache eviction.
2018 # Set mode tests insertion speed with cache eviction.
2016 setseq = []
2019 setseq = []
2017 costs = []
2020 costs = []
2018 for i in _xrange(sets):
2021 for i in _xrange(sets):
2019 setseq.append(random.randint(0, _maxint))
2022 setseq.append(random.randint(0, _maxint))
2020 costs.append(random.choice(costrange))
2023 costs.append(random.choice(costrange))
2021
2024
2022 def doinserts():
2025 def doinserts():
2023 d = util.lrucachedict(size)
2026 d = util.lrucachedict(size)
2024 for v in setseq:
2027 for v in setseq:
2025 d.insert(v, v)
2028 d.insert(v, v)
2026
2029
2027 def doinsertscost():
2030 def doinsertscost():
2028 d = util.lrucachedict(size, maxcost=costlimit)
2031 d = util.lrucachedict(size, maxcost=costlimit)
2029 for i, v in enumerate(setseq):
2032 for i, v in enumerate(setseq):
2030 d.insert(v, v, cost=costs[i])
2033 d.insert(v, v, cost=costs[i])
2031
2034
2032 def dosets():
2035 def dosets():
2033 d = util.lrucachedict(size)
2036 d = util.lrucachedict(size)
2034 for v in setseq:
2037 for v in setseq:
2035 d[v] = v
2038 d[v] = v
2036
2039
2037 # Mixed mode randomly performs gets and sets with eviction.
2040 # Mixed mode randomly performs gets and sets with eviction.
2038 mixedops = []
2041 mixedops = []
2039 for i in _xrange(mixed):
2042 for i in _xrange(mixed):
2040 r = random.randint(0, 100)
2043 r = random.randint(0, 100)
2041 if r < mixedgetfreq:
2044 if r < mixedgetfreq:
2042 op = 0
2045 op = 0
2043 else:
2046 else:
2044 op = 1
2047 op = 1
2045
2048
2046 mixedops.append((op,
2049 mixedops.append((op,
2047 random.randint(0, size * 2),
2050 random.randint(0, size * 2),
2048 random.choice(costrange)))
2051 random.choice(costrange)))
2049
2052
2050 def domixed():
2053 def domixed():
2051 d = util.lrucachedict(size)
2054 d = util.lrucachedict(size)
2052
2055
2053 for op, v, cost in mixedops:
2056 for op, v, cost in mixedops:
2054 if op == 0:
2057 if op == 0:
2055 try:
2058 try:
2056 d[v]
2059 d[v]
2057 except KeyError:
2060 except KeyError:
2058 pass
2061 pass
2059 else:
2062 else:
2060 d[v] = v
2063 d[v] = v
2061
2064
2062 def domixedcost():
2065 def domixedcost():
2063 d = util.lrucachedict(size, maxcost=costlimit)
2066 d = util.lrucachedict(size, maxcost=costlimit)
2064
2067
2065 for op, v, cost in mixedops:
2068 for op, v, cost in mixedops:
2066 if op == 0:
2069 if op == 0:
2067 try:
2070 try:
2068 d[v]
2071 d[v]
2069 except KeyError:
2072 except KeyError:
2070 pass
2073 pass
2071 else:
2074 else:
2072 d.insert(v, v, cost=cost)
2075 d.insert(v, v, cost=cost)
2073
2076
2074 benches = [
2077 benches = [
2075 (doinit, b'init'),
2078 (doinit, b'init'),
2076 ]
2079 ]
2077
2080
2078 if costlimit:
2081 if costlimit:
2079 benches.extend([
2082 benches.extend([
2080 (dogetscost, b'gets w/ cost limit'),
2083 (dogetscost, b'gets w/ cost limit'),
2081 (doinsertscost, b'inserts w/ cost limit'),
2084 (doinsertscost, b'inserts w/ cost limit'),
2082 (domixedcost, b'mixed w/ cost limit'),
2085 (domixedcost, b'mixed w/ cost limit'),
2083 ])
2086 ])
2084 else:
2087 else:
2085 benches.extend([
2088 benches.extend([
2086 (dogets, b'gets'),
2089 (dogets, b'gets'),
2087 (doinserts, b'inserts'),
2090 (doinserts, b'inserts'),
2088 (dosets, b'sets'),
2091 (dosets, b'sets'),
2089 (domixed, b'mixed')
2092 (domixed, b'mixed')
2090 ])
2093 ])
2091
2094
2092 for fn, title in benches:
2095 for fn, title in benches:
2093 timer, fm = gettimer(ui, opts)
2096 timer, fm = gettimer(ui, opts)
2094 timer(fn, title=title)
2097 timer(fn, title=title)
2095 fm.end()
2098 fm.end()
2096
2099
2097 @command(b'perfwrite', formatteropts)
2100 @command(b'perfwrite', formatteropts)
2098 def perfwrite(ui, repo, **opts):
2101 def perfwrite(ui, repo, **opts):
2099 """microbenchmark ui.write
2102 """microbenchmark ui.write
2100 """
2103 """
2101 opts = _byteskwargs(opts)
2104 opts = _byteskwargs(opts)
2102
2105
2103 timer, fm = gettimer(ui, opts)
2106 timer, fm = gettimer(ui, opts)
2104 def write():
2107 def write():
2105 for i in range(100000):
2108 for i in range(100000):
2106 ui.write((b'Testing write performance\n'))
2109 ui.write((b'Testing write performance\n'))
2107 timer(write)
2110 timer(write)
2108 fm.end()
2111 fm.end()
2109
2112
2110 def uisetup(ui):
2113 def uisetup(ui):
2111 if (util.safehasattr(cmdutil, b'openrevlog') and
2114 if (util.safehasattr(cmdutil, b'openrevlog') and
2112 not util.safehasattr(commands, b'debugrevlogopts')):
2115 not util.safehasattr(commands, b'debugrevlogopts')):
2113 # for "historical portability":
2116 # for "historical portability":
2114 # In this case, Mercurial should be 1.9 (or a79fea6b3e77) -
2117 # In this case, Mercurial should be 1.9 (or a79fea6b3e77) -
2115 # 3.7 (or 5606f7d0d063). Therefore, '--dir' option for
2118 # 3.7 (or 5606f7d0d063). Therefore, '--dir' option for
2116 # openrevlog() should cause failure, because it has been
2119 # openrevlog() should cause failure, because it has been
2117 # available since 3.5 (or 49c583ca48c4).
2120 # available since 3.5 (or 49c583ca48c4).
2118 def openrevlog(orig, repo, cmd, file_, opts):
2121 def openrevlog(orig, repo, cmd, file_, opts):
2119 if opts.get(b'dir') and not util.safehasattr(repo, b'dirlog'):
2122 if opts.get(b'dir') and not util.safehasattr(repo, b'dirlog'):
2120 raise error.Abort(b"This version doesn't support --dir option",
2123 raise error.Abort(b"This version doesn't support --dir option",
2121 hint=b"use 3.5 or later")
2124 hint=b"use 3.5 or later")
2122 return orig(repo, cmd, file_, opts)
2125 return orig(repo, cmd, file_, opts)
2123 extensions.wrapfunction(cmdutil, b'openrevlog', openrevlog)
2126 extensions.wrapfunction(cmdutil, b'openrevlog', openrevlog)
@@ -1,599 +1,600 b''
1 test-abort-checkin.t
1 test-abort-checkin.t
2 test-absorb-filefixupstate.py
2 test-absorb-filefixupstate.py
3 test-absorb-phase.t
3 test-absorb-phase.t
4 test-absorb-rename.t
4 test-absorb-rename.t
5 test-absorb-strip.t
5 test-absorb-strip.t
6 test-absorb.t
6 test-absorb.t
7 test-add.t
7 test-add.t
8 test-addremove-similar.t
8 test-addremove-similar.t
9 test-addremove.t
9 test-addremove.t
10 test-alias.t
10 test-alias.t
11 test-amend-subrepo.t
11 test-amend-subrepo.t
12 test-amend.t
12 test-amend.t
13 test-ancestor.py
13 test-ancestor.py
14 test-annotate.py
14 test-annotate.py
15 test-annotate.t
15 test-annotate.t
16 test-archive-symlinks.t
16 test-archive-symlinks.t
17 test-atomictempfile.py
17 test-atomictempfile.py
18 test-audit-path.t
18 test-audit-path.t
19 test-audit-subrepo.t
19 test-audit-subrepo.t
20 test-automv.t
20 test-automv.t
21 test-backout.t
21 test-backout.t
22 test-backwards-remove.t
22 test-backwards-remove.t
23 test-bad-pull.t
23 test-bad-pull.t
24 test-basic.t
24 test-basic.t
25 test-bdiff.py
25 test-bdiff.py
26 test-bheads.t
26 test-bheads.t
27 test-bisect.t
27 test-bisect.t
28 test-bisect2.t
28 test-bisect2.t
29 test-bisect3.t
29 test-bisect3.t
30 test-blackbox.t
30 test-blackbox.t
31 test-bookmarks-current.t
31 test-bookmarks-current.t
32 test-bookmarks-merge.t
32 test-bookmarks-merge.t
33 test-bookmarks-pushpull.t
33 test-bookmarks-pushpull.t
34 test-bookmarks-rebase.t
34 test-bookmarks-rebase.t
35 test-bookmarks-strip.t
35 test-bookmarks-strip.t
36 test-bookmarks.t
36 test-bookmarks.t
37 test-branch-change.t
37 test-branch-change.t
38 test-branch-option.t
38 test-branch-option.t
39 test-branch-tag-confict.t
39 test-branch-tag-confict.t
40 test-branches.t
40 test-branches.t
41 test-bundle-phases.t
41 test-bundle-phases.t
42 test-bundle-r.t
42 test-bundle-r.t
43 test-bundle-type.t
43 test-bundle-type.t
44 test-bundle-vs-outgoing.t
44 test-bundle-vs-outgoing.t
45 test-bundle.t
45 test-bundle.t
46 test-bundle2-exchange.t
46 test-bundle2-exchange.t
47 test-bundle2-format.t
47 test-bundle2-format.t
48 test-bundle2-multiple-changegroups.t
48 test-bundle2-multiple-changegroups.t
49 test-bundle2-pushback.t
49 test-bundle2-pushback.t
50 test-bundle2-remote-changegroup.t
50 test-bundle2-remote-changegroup.t
51 test-cappedreader.py
51 test-cappedreader.py
52 test-casecollision.t
52 test-casecollision.t
53 test-cat.t
53 test-cat.t
54 test-cbor.py
54 test-cbor.py
55 test-censor.t
55 test-censor.t
56 test-changelog-exec.t
56 test-changelog-exec.t
57 test-check-code.t
57 test-check-code.t
58 test-check-commit.t
58 test-check-commit.t
59 test-check-execute.t
59 test-check-execute.t
60 test-check-interfaces.py
60 test-check-interfaces.py
61 test-check-module-imports.t
61 test-check-module-imports.t
62 test-check-py3-compat.t
62 test-check-py3-compat.t
63 test-check-pyflakes.t
63 test-check-pyflakes.t
64 test-check-pylint.t
64 test-check-pylint.t
65 test-check-shbang.t
65 test-check-shbang.t
66 test-children.t
66 test-children.t
67 test-clone-cgi.t
67 test-clone-cgi.t
68 test-clone-pull-corruption.t
68 test-clone-pull-corruption.t
69 test-clone-r.t
69 test-clone-r.t
70 test-clone-uncompressed.t
70 test-clone-uncompressed.t
71 test-clone-update-order.t
71 test-clone-update-order.t
72 test-clonebundles.t
72 test-clonebundles.t
73 test-commit-amend.t
73 test-commit-amend.t
74 test-commit-interactive.t
74 test-commit-interactive.t
75 test-commit-multiple.t
75 test-commit-multiple.t
76 test-commit-unresolved.t
76 test-commit-unresolved.t
77 test-commit.t
77 test-commit.t
78 test-committer.t
78 test-committer.t
79 test-completion.t
79 test-completion.t
80 test-config-env.py
80 test-config-env.py
81 test-config.t
81 test-config.t
82 test-conflict.t
82 test-conflict.t
83 test-confused-revert.t
83 test-confused-revert.t
84 test-context.py
84 test-context.py
85 test-contrib-check-code.t
85 test-contrib-check-code.t
86 test-contrib-check-commit.t
86 test-contrib-check-commit.t
87 test-contrib-dumprevlog.t
87 test-contrib-dumprevlog.t
88 test-contrib-perf.t
88 test-contrib-testparseutil.t
89 test-contrib-testparseutil.t
89 test-convert-authormap.t
90 test-convert-authormap.t
90 test-convert-clonebranches.t
91 test-convert-clonebranches.t
91 test-convert-cvs-branch.t
92 test-convert-cvs-branch.t
92 test-convert-cvs-detectmerge.t
93 test-convert-cvs-detectmerge.t
93 test-convert-cvs-synthetic.t
94 test-convert-cvs-synthetic.t
94 test-convert-cvs.t
95 test-convert-cvs.t
95 test-convert-cvsnt-mergepoints.t
96 test-convert-cvsnt-mergepoints.t
96 test-convert-datesort.t
97 test-convert-datesort.t
97 test-convert-filemap.t
98 test-convert-filemap.t
98 test-convert-hg-sink.t
99 test-convert-hg-sink.t
99 test-convert-hg-source.t
100 test-convert-hg-source.t
100 test-convert-hg-startrev.t
101 test-convert-hg-startrev.t
101 test-convert-splicemap.t
102 test-convert-splicemap.t
102 test-convert-tagsbranch-topology.t
103 test-convert-tagsbranch-topology.t
103 test-copy-move-merge.t
104 test-copy-move-merge.t
104 test-copy.t
105 test-copy.t
105 test-copytrace-heuristics.t
106 test-copytrace-heuristics.t
106 test-debugbuilddag.t
107 test-debugbuilddag.t
107 test-debugbundle.t
108 test-debugbundle.t
108 test-debugcommands.t
109 test-debugcommands.t
109 test-debugextensions.t
110 test-debugextensions.t
110 test-debugindexdot.t
111 test-debugindexdot.t
111 test-debugrename.t
112 test-debugrename.t
112 test-default-push.t
113 test-default-push.t
113 test-diff-antipatience.t
114 test-diff-antipatience.t
114 test-diff-binary-file.t
115 test-diff-binary-file.t
115 test-diff-change.t
116 test-diff-change.t
116 test-diff-copy-depth.t
117 test-diff-copy-depth.t
117 test-diff-hashes.t
118 test-diff-hashes.t
118 test-diff-ignore-whitespace.t
119 test-diff-ignore-whitespace.t
119 test-diff-indent-heuristic.t
120 test-diff-indent-heuristic.t
120 test-diff-issue2761.t
121 test-diff-issue2761.t
121 test-diff-newlines.t
122 test-diff-newlines.t
122 test-diff-reverse.t
123 test-diff-reverse.t
123 test-diff-subdir.t
124 test-diff-subdir.t
124 test-diff-unified.t
125 test-diff-unified.t
125 test-diff-upgrade.t
126 test-diff-upgrade.t
126 test-diffdir.t
127 test-diffdir.t
127 test-diffstat.t
128 test-diffstat.t
128 test-directaccess.t
129 test-directaccess.t
129 test-dirstate-backup.t
130 test-dirstate-backup.t
130 test-dirstate-nonnormalset.t
131 test-dirstate-nonnormalset.t
131 test-dirstate.t
132 test-dirstate.t
132 test-dispatch.py
133 test-dispatch.py
133 test-doctest.py
134 test-doctest.py
134 test-double-merge.t
135 test-double-merge.t
135 test-drawdag.t
136 test-drawdag.t
136 test-duplicateoptions.py
137 test-duplicateoptions.py
137 test-editor-filename.t
138 test-editor-filename.t
138 test-empty-dir.t
139 test-empty-dir.t
139 test-empty-file.t
140 test-empty-file.t
140 test-empty-group.t
141 test-empty-group.t
141 test-empty.t
142 test-empty.t
142 test-encode.t
143 test-encode.t
143 test-encoding-func.py
144 test-encoding-func.py
144 test-encoding.t
145 test-encoding.t
145 test-eol-add.t
146 test-eol-add.t
146 test-eol-clone.t
147 test-eol-clone.t
147 test-eol-hook.t
148 test-eol-hook.t
148 test-eol-patch.t
149 test-eol-patch.t
149 test-eol-tag.t
150 test-eol-tag.t
150 test-eol-update.t
151 test-eol-update.t
151 test-eol.t
152 test-eol.t
152 test-eolfilename.t
153 test-eolfilename.t
153 test-excessive-merge.t
154 test-excessive-merge.t
154 test-exchange-obsmarkers-case-A1.t
155 test-exchange-obsmarkers-case-A1.t
155 test-exchange-obsmarkers-case-A2.t
156 test-exchange-obsmarkers-case-A2.t
156 test-exchange-obsmarkers-case-A3.t
157 test-exchange-obsmarkers-case-A3.t
157 test-exchange-obsmarkers-case-A4.t
158 test-exchange-obsmarkers-case-A4.t
158 test-exchange-obsmarkers-case-A5.t
159 test-exchange-obsmarkers-case-A5.t
159 test-exchange-obsmarkers-case-A6.t
160 test-exchange-obsmarkers-case-A6.t
160 test-exchange-obsmarkers-case-A7.t
161 test-exchange-obsmarkers-case-A7.t
161 test-exchange-obsmarkers-case-B1.t
162 test-exchange-obsmarkers-case-B1.t
162 test-exchange-obsmarkers-case-B2.t
163 test-exchange-obsmarkers-case-B2.t
163 test-exchange-obsmarkers-case-B3.t
164 test-exchange-obsmarkers-case-B3.t
164 test-exchange-obsmarkers-case-B4.t
165 test-exchange-obsmarkers-case-B4.t
165 test-exchange-obsmarkers-case-B5.t
166 test-exchange-obsmarkers-case-B5.t
166 test-exchange-obsmarkers-case-B6.t
167 test-exchange-obsmarkers-case-B6.t
167 test-exchange-obsmarkers-case-B7.t
168 test-exchange-obsmarkers-case-B7.t
168 test-exchange-obsmarkers-case-C1.t
169 test-exchange-obsmarkers-case-C1.t
169 test-exchange-obsmarkers-case-C2.t
170 test-exchange-obsmarkers-case-C2.t
170 test-exchange-obsmarkers-case-C3.t
171 test-exchange-obsmarkers-case-C3.t
171 test-exchange-obsmarkers-case-C4.t
172 test-exchange-obsmarkers-case-C4.t
172 test-exchange-obsmarkers-case-D1.t
173 test-exchange-obsmarkers-case-D1.t
173 test-exchange-obsmarkers-case-D2.t
174 test-exchange-obsmarkers-case-D2.t
174 test-exchange-obsmarkers-case-D3.t
175 test-exchange-obsmarkers-case-D3.t
175 test-exchange-obsmarkers-case-D4.t
176 test-exchange-obsmarkers-case-D4.t
176 test-execute-bit.t
177 test-execute-bit.t
177 test-export.t
178 test-export.t
178 test-extdata.t
179 test-extdata.t
179 test-extdiff.t
180 test-extdiff.t
180 test-extensions-afterloaded.t
181 test-extensions-afterloaded.t
181 test-extensions-wrapfunction.py
182 test-extensions-wrapfunction.py
182 test-extra-filelog-entry.t
183 test-extra-filelog-entry.t
183 test-fetch.t
184 test-fetch.t
184 test-filebranch.t
185 test-filebranch.t
185 test-filecache.py
186 test-filecache.py
186 test-filelog.py
187 test-filelog.py
187 test-fileset-generated.t
188 test-fileset-generated.t
188 test-fileset.t
189 test-fileset.t
189 test-fix-topology.t
190 test-fix-topology.t
190 test-flags.t
191 test-flags.t
191 test-generaldelta.t
192 test-generaldelta.t
192 test-getbundle.t
193 test-getbundle.t
193 test-git-export.t
194 test-git-export.t
194 test-glog-beautifygraph.t
195 test-glog-beautifygraph.t
195 test-glog-topological.t
196 test-glog-topological.t
196 test-glog.t
197 test-glog.t
197 test-gpg.t
198 test-gpg.t
198 test-graft.t
199 test-graft.t
199 test-grep.t
200 test-grep.t
200 test-hg-parseurl.py
201 test-hg-parseurl.py
201 test-hghave.t
202 test-hghave.t
202 test-hgignore.t
203 test-hgignore.t
203 test-hgk.t
204 test-hgk.t
204 test-hgrc.t
205 test-hgrc.t
205 test-hgweb-annotate-whitespace.t
206 test-hgweb-annotate-whitespace.t
206 test-hgweb-bundle.t
207 test-hgweb-bundle.t
207 test-hgweb-csp.t
208 test-hgweb-csp.t
208 test-hgweb-descend-empties.t
209 test-hgweb-descend-empties.t
209 test-hgweb-diffs.t
210 test-hgweb-diffs.t
210 test-hgweb-empty.t
211 test-hgweb-empty.t
211 test-hgweb-filelog.t
212 test-hgweb-filelog.t
212 test-hgweb-non-interactive.t
213 test-hgweb-non-interactive.t
213 test-hgweb-raw.t
214 test-hgweb-raw.t
214 test-hgweb-removed.t
215 test-hgweb-removed.t
215 test-hgweb.t
216 test-hgweb.t
216 test-hgwebdir-paths.py
217 test-hgwebdir-paths.py
217 test-hgwebdirsym.t
218 test-hgwebdirsym.t
218 test-histedit-arguments.t
219 test-histedit-arguments.t
219 test-histedit-base.t
220 test-histedit-base.t
220 test-histedit-bookmark-motion.t
221 test-histedit-bookmark-motion.t
221 test-histedit-commute.t
222 test-histedit-commute.t
222 test-histedit-drop.t
223 test-histedit-drop.t
223 test-histedit-edit.t
224 test-histedit-edit.t
224 test-histedit-fold-non-commute.t
225 test-histedit-fold-non-commute.t
225 test-histedit-fold.t
226 test-histedit-fold.t
226 test-histedit-no-backup.t
227 test-histedit-no-backup.t
227 test-histedit-no-change.t
228 test-histedit-no-change.t
228 test-histedit-non-commute-abort.t
229 test-histedit-non-commute-abort.t
229 test-histedit-non-commute.t
230 test-histedit-non-commute.t
230 test-histedit-obsolete.t
231 test-histedit-obsolete.t
231 test-histedit-outgoing.t
232 test-histedit-outgoing.t
232 test-histedit-templates.t
233 test-histedit-templates.t
233 test-http-branchmap.t
234 test-http-branchmap.t
234 test-http-bundle1.t
235 test-http-bundle1.t
235 test-http-clone-r.t
236 test-http-clone-r.t
236 test-http-permissions.t
237 test-http-permissions.t
237 test-http.t
238 test-http.t
238 test-hybridencode.py
239 test-hybridencode.py
239 test-i18n.t
240 test-i18n.t
240 test-identify.t
241 test-identify.t
241 test-impexp-branch.t
242 test-impexp-branch.t
242 test-import-bypass.t
243 test-import-bypass.t
243 test-import-eol.t
244 test-import-eol.t
244 test-import-merge.t
245 test-import-merge.t
245 test-import-unknown.t
246 test-import-unknown.t
246 test-import.t
247 test-import.t
247 test-imports-checker.t
248 test-imports-checker.t
248 test-incoming-outgoing.t
249 test-incoming-outgoing.t
249 test-inherit-mode.t
250 test-inherit-mode.t
250 test-init.t
251 test-init.t
251 test-issue1089.t
252 test-issue1089.t
252 test-issue1102.t
253 test-issue1102.t
253 test-issue1175.t
254 test-issue1175.t
254 test-issue1306.t
255 test-issue1306.t
255 test-issue1438.t
256 test-issue1438.t
256 test-issue1502.t
257 test-issue1502.t
257 test-issue1802.t
258 test-issue1802.t
258 test-issue1877.t
259 test-issue1877.t
259 test-issue1993.t
260 test-issue1993.t
260 test-issue2137.t
261 test-issue2137.t
261 test-issue3084.t
262 test-issue3084.t
262 test-issue4074.t
263 test-issue4074.t
263 test-issue522.t
264 test-issue522.t
264 test-issue586.t
265 test-issue586.t
265 test-issue5979.t
266 test-issue5979.t
266 test-issue612.t
267 test-issue612.t
267 test-issue619.t
268 test-issue619.t
268 test-issue660.t
269 test-issue660.t
269 test-issue672.t
270 test-issue672.t
270 test-issue842.t
271 test-issue842.t
271 test-journal-exists.t
272 test-journal-exists.t
272 test-journal-share.t
273 test-journal-share.t
273 test-journal.t
274 test-journal.t
274 test-known.t
275 test-known.t
275 test-largefiles-cache.t
276 test-largefiles-cache.t
276 test-largefiles-misc.t
277 test-largefiles-misc.t
277 test-largefiles-small-disk.t
278 test-largefiles-small-disk.t
278 test-largefiles-update.t
279 test-largefiles-update.t
279 test-largefiles.t
280 test-largefiles.t
280 test-lfs-largefiles.t
281 test-lfs-largefiles.t
281 test-lfs-pointer.py
282 test-lfs-pointer.py
282 test-linelog.py
283 test-linelog.py
283 test-linerange.py
284 test-linerange.py
284 test-locate.t
285 test-locate.t
285 test-lock-badness.t
286 test-lock-badness.t
286 test-log-linerange.t
287 test-log-linerange.t
287 test-log.t
288 test-log.t
288 test-logexchange.t
289 test-logexchange.t
289 test-lrucachedict.py
290 test-lrucachedict.py
290 test-mactext.t
291 test-mactext.t
291 test-mailmap.t
292 test-mailmap.t
292 test-manifest-merging.t
293 test-manifest-merging.t
293 test-manifest.py
294 test-manifest.py
294 test-manifest.t
295 test-manifest.t
295 test-match.py
296 test-match.py
296 test-mdiff.py
297 test-mdiff.py
297 test-merge-changedelete.t
298 test-merge-changedelete.t
298 test-merge-closedheads.t
299 test-merge-closedheads.t
299 test-merge-commit.t
300 test-merge-commit.t
300 test-merge-criss-cross.t
301 test-merge-criss-cross.t
301 test-merge-default.t
302 test-merge-default.t
302 test-merge-force.t
303 test-merge-force.t
303 test-merge-halt.t
304 test-merge-halt.t
304 test-merge-internal-tools-pattern.t
305 test-merge-internal-tools-pattern.t
305 test-merge-local.t
306 test-merge-local.t
306 test-merge-no-file-change.t
307 test-merge-no-file-change.t
307 test-merge-remove.t
308 test-merge-remove.t
308 test-merge-revert.t
309 test-merge-revert.t
309 test-merge-revert2.t
310 test-merge-revert2.t
310 test-merge-subrepos.t
311 test-merge-subrepos.t
311 test-merge-symlinks.t
312 test-merge-symlinks.t
312 test-merge-tools.t
313 test-merge-tools.t
313 test-merge-types.t
314 test-merge-types.t
314 test-merge1.t
315 test-merge1.t
315 test-merge10.t
316 test-merge10.t
316 test-merge2.t
317 test-merge2.t
317 test-merge4.t
318 test-merge4.t
318 test-merge5.t
319 test-merge5.t
319 test-merge6.t
320 test-merge6.t
320 test-merge7.t
321 test-merge7.t
321 test-merge8.t
322 test-merge8.t
322 test-merge9.t
323 test-merge9.t
323 test-minifileset.py
324 test-minifileset.py
324 test-minirst.py
325 test-minirst.py
325 test-mq-git.t
326 test-mq-git.t
326 test-mq-guards.t
327 test-mq-guards.t
327 test-mq-header-date.t
328 test-mq-header-date.t
328 test-mq-header-from.t
329 test-mq-header-from.t
329 test-mq-merge.t
330 test-mq-merge.t
330 test-mq-pull-from-bundle.t
331 test-mq-pull-from-bundle.t
331 test-mq-qclone-http.t
332 test-mq-qclone-http.t
332 test-mq-qdelete.t
333 test-mq-qdelete.t
333 test-mq-qdiff.t
334 test-mq-qdiff.t
334 test-mq-qfold.t
335 test-mq-qfold.t
335 test-mq-qgoto.t
336 test-mq-qgoto.t
336 test-mq-qimport-fail-cleanup.t
337 test-mq-qimport-fail-cleanup.t
337 test-mq-qnew.t
338 test-mq-qnew.t
338 test-mq-qpush-exact.t
339 test-mq-qpush-exact.t
339 test-mq-qpush-fail.t
340 test-mq-qpush-fail.t
340 test-mq-qqueue.t
341 test-mq-qqueue.t
341 test-mq-qrefresh-interactive.t
342 test-mq-qrefresh-interactive.t
342 test-mq-qrefresh-replace-log-message.t
343 test-mq-qrefresh-replace-log-message.t
343 test-mq-qrefresh.t
344 test-mq-qrefresh.t
344 test-mq-qrename.t
345 test-mq-qrename.t
345 test-mq-qsave.t
346 test-mq-qsave.t
346 test-mq-safety.t
347 test-mq-safety.t
347 test-mq-subrepo.t
348 test-mq-subrepo.t
348 test-mq-symlinks.t
349 test-mq-symlinks.t
349 test-mq.t
350 test-mq.t
350 test-mv-cp-st-diff.t
351 test-mv-cp-st-diff.t
351 test-narrow-acl.t
352 test-narrow-acl.t
352 test-narrow-archive.t
353 test-narrow-archive.t
353 test-narrow-clone-no-ellipsis.t
354 test-narrow-clone-no-ellipsis.t
354 test-narrow-clone-non-narrow-server.t
355 test-narrow-clone-non-narrow-server.t
355 test-narrow-clone-nonlinear.t
356 test-narrow-clone-nonlinear.t
356 test-narrow-clone.t
357 test-narrow-clone.t
357 test-narrow-commit.t
358 test-narrow-commit.t
358 test-narrow-copies.t
359 test-narrow-copies.t
359 test-narrow-debugcommands.t
360 test-narrow-debugcommands.t
360 test-narrow-debugrebuilddirstate.t
361 test-narrow-debugrebuilddirstate.t
361 test-narrow-exchange-merges.t
362 test-narrow-exchange-merges.t
362 test-narrow-exchange.t
363 test-narrow-exchange.t
363 test-narrow-expanddirstate.t
364 test-narrow-expanddirstate.t
364 test-narrow-merge.t
365 test-narrow-merge.t
365 test-narrow-patch.t
366 test-narrow-patch.t
366 test-narrow-patterns.t
367 test-narrow-patterns.t
367 test-narrow-pull.t
368 test-narrow-pull.t
368 test-narrow-rebase.t
369 test-narrow-rebase.t
369 test-narrow-shallow-merges.t
370 test-narrow-shallow-merges.t
370 test-narrow-shallow.t
371 test-narrow-shallow.t
371 test-narrow-strip.t
372 test-narrow-strip.t
372 test-narrow-trackedcmd.t
373 test-narrow-trackedcmd.t
373 test-narrow-update.t
374 test-narrow-update.t
374 test-narrow-widen-no-ellipsis.t
375 test-narrow-widen-no-ellipsis.t
375 test-narrow-widen.t
376 test-narrow-widen.t
376 test-narrow.t
377 test-narrow.t
377 test-nested-repo.t
378 test-nested-repo.t
378 test-newbranch.t
379 test-newbranch.t
379 test-newercgi.t
380 test-newercgi.t
380 test-nointerrupt.t
381 test-nointerrupt.t
381 test-obshistory.t
382 test-obshistory.t
382 test-obsmarker-template.t
383 test-obsmarker-template.t
383 test-obsmarkers-effectflag.t
384 test-obsmarkers-effectflag.t
384 test-obsolete-bounds-checking.t
385 test-obsolete-bounds-checking.t
385 test-obsolete-bundle-strip.t
386 test-obsolete-bundle-strip.t
386 test-obsolete-changeset-exchange.t
387 test-obsolete-changeset-exchange.t
387 test-obsolete-checkheads.t
388 test-obsolete-checkheads.t
388 test-obsolete-distributed.t
389 test-obsolete-distributed.t
389 test-obsolete-divergent.t
390 test-obsolete-divergent.t
390 test-obsolete-tag-cache.t
391 test-obsolete-tag-cache.t
391 test-obsolete.t
392 test-obsolete.t
392 test-pager.t
393 test-pager.t
393 test-parents.t
394 test-parents.t
394 test-parseindex2.py
395 test-parseindex2.py
395 test-patch-offset.t
396 test-patch-offset.t
396 test-patch.t
397 test-patch.t
397 test-patchbomb-bookmark.t
398 test-patchbomb-bookmark.t
398 test-patchbomb-tls.t
399 test-patchbomb-tls.t
399 test-patchbomb.t
400 test-patchbomb.t
400 test-pathconflicts-merge.t
401 test-pathconflicts-merge.t
401 test-pathconflicts-update.t
402 test-pathconflicts-update.t
402 test-pathencode.py
403 test-pathencode.py
403 test-pending.t
404 test-pending.t
404 test-permissions.t
405 test-permissions.t
405 test-phases-exchange.t
406 test-phases-exchange.t
406 test-phases.t
407 test-phases.t
407 test-pull-branch.t
408 test-pull-branch.t
408 test-pull-http.t
409 test-pull-http.t
409 test-pull-permission.t
410 test-pull-permission.t
410 test-pull-pull-corruption.t
411 test-pull-pull-corruption.t
411 test-pull-r.t
412 test-pull-r.t
412 test-pull-update.t
413 test-pull-update.t
413 test-pull.t
414 test-pull.t
414 test-purge.t
415 test-purge.t
415 test-push-cgi.t
416 test-push-cgi.t
416 test-push-checkheads-partial-C1.t
417 test-push-checkheads-partial-C1.t
417 test-push-checkheads-partial-C2.t
418 test-push-checkheads-partial-C2.t
418 test-push-checkheads-partial-C3.t
419 test-push-checkheads-partial-C3.t
419 test-push-checkheads-partial-C4.t
420 test-push-checkheads-partial-C4.t
420 test-push-checkheads-pruned-B1.t
421 test-push-checkheads-pruned-B1.t
421 test-push-checkheads-pruned-B2.t
422 test-push-checkheads-pruned-B2.t
422 test-push-checkheads-pruned-B3.t
423 test-push-checkheads-pruned-B3.t
423 test-push-checkheads-pruned-B4.t
424 test-push-checkheads-pruned-B4.t
424 test-push-checkheads-pruned-B5.t
425 test-push-checkheads-pruned-B5.t
425 test-push-checkheads-pruned-B6.t
426 test-push-checkheads-pruned-B6.t
426 test-push-checkheads-pruned-B7.t
427 test-push-checkheads-pruned-B7.t
427 test-push-checkheads-pruned-B8.t
428 test-push-checkheads-pruned-B8.t
428 test-push-checkheads-superceed-A1.t
429 test-push-checkheads-superceed-A1.t
429 test-push-checkheads-superceed-A2.t
430 test-push-checkheads-superceed-A2.t
430 test-push-checkheads-superceed-A3.t
431 test-push-checkheads-superceed-A3.t
431 test-push-checkheads-superceed-A4.t
432 test-push-checkheads-superceed-A4.t
432 test-push-checkheads-superceed-A5.t
433 test-push-checkheads-superceed-A5.t
433 test-push-checkheads-superceed-A6.t
434 test-push-checkheads-superceed-A6.t
434 test-push-checkheads-superceed-A7.t
435 test-push-checkheads-superceed-A7.t
435 test-push-checkheads-superceed-A8.t
436 test-push-checkheads-superceed-A8.t
436 test-push-checkheads-unpushed-D1.t
437 test-push-checkheads-unpushed-D1.t
437 test-push-checkheads-unpushed-D2.t
438 test-push-checkheads-unpushed-D2.t
438 test-push-checkheads-unpushed-D3.t
439 test-push-checkheads-unpushed-D3.t
439 test-push-checkheads-unpushed-D4.t
440 test-push-checkheads-unpushed-D4.t
440 test-push-checkheads-unpushed-D5.t
441 test-push-checkheads-unpushed-D5.t
441 test-push-checkheads-unpushed-D6.t
442 test-push-checkheads-unpushed-D6.t
442 test-push-checkheads-unpushed-D7.t
443 test-push-checkheads-unpushed-D7.t
443 test-push-http.t
444 test-push-http.t
444 test-push-warn.t
445 test-push-warn.t
445 test-push.t
446 test-push.t
446 test-pushvars.t
447 test-pushvars.t
447 test-qrecord.t
448 test-qrecord.t
448 test-rebase-abort.t
449 test-rebase-abort.t
449 test-rebase-backup.t
450 test-rebase-backup.t
450 test-rebase-base-flag.t
451 test-rebase-base-flag.t
451 test-rebase-bookmarks.t
452 test-rebase-bookmarks.t
452 test-rebase-brute-force.t
453 test-rebase-brute-force.t
453 test-rebase-cache.t
454 test-rebase-cache.t
454 test-rebase-check-restore.t
455 test-rebase-check-restore.t
455 test-rebase-collapse.t
456 test-rebase-collapse.t
456 test-rebase-conflicts.t
457 test-rebase-conflicts.t
457 test-rebase-dest.t
458 test-rebase-dest.t
458 test-rebase-detach.t
459 test-rebase-detach.t
459 test-rebase-emptycommit.t
460 test-rebase-emptycommit.t
460 test-rebase-inmemory.t
461 test-rebase-inmemory.t
461 test-rebase-interruptions.t
462 test-rebase-interruptions.t
462 test-rebase-issue-noparam-single-rev.t
463 test-rebase-issue-noparam-single-rev.t
463 test-rebase-legacy.t
464 test-rebase-legacy.t
464 test-rebase-mq-skip.t
465 test-rebase-mq-skip.t
465 test-rebase-mq.t
466 test-rebase-mq.t
466 test-rebase-named-branches.t
467 test-rebase-named-branches.t
467 test-rebase-newancestor.t
468 test-rebase-newancestor.t
468 test-rebase-obsolete.t
469 test-rebase-obsolete.t
469 test-rebase-parameters.t
470 test-rebase-parameters.t
470 test-rebase-partial.t
471 test-rebase-partial.t
471 test-rebase-pull.t
472 test-rebase-pull.t
472 test-rebase-rename.t
473 test-rebase-rename.t
473 test-rebase-scenario-global.t
474 test-rebase-scenario-global.t
474 test-rebase-templates.t
475 test-rebase-templates.t
475 test-rebase-transaction.t
476 test-rebase-transaction.t
476 test-rebuildstate.t
477 test-rebuildstate.t
477 test-record.t
478 test-record.t
478 test-relink.t
479 test-relink.t
479 test-remove.t
480 test-remove.t
480 test-removeemptydirs.t
481 test-removeemptydirs.t
481 test-rename-after-merge.t
482 test-rename-after-merge.t
482 test-rename-dir-merge.t
483 test-rename-dir-merge.t
483 test-rename-merge1.t
484 test-rename-merge1.t
484 test-rename-merge2.t
485 test-rename-merge2.t
485 test-rename.t
486 test-rename.t
486 test-repair-strip.t
487 test-repair-strip.t
487 test-repo-compengines.t
488 test-repo-compengines.t
488 test-resolve.t
489 test-resolve.t
489 test-revert-flags.t
490 test-revert-flags.t
490 test-revert-interactive.t
491 test-revert-interactive.t
491 test-revert-unknown.t
492 test-revert-unknown.t
492 test-revert.t
493 test-revert.t
493 test-revisions.t
494 test-revisions.t
494 test-revlog-ancestry.py
495 test-revlog-ancestry.py
495 test-revlog-group-emptyiter.t
496 test-revlog-group-emptyiter.t
496 test-revlog-mmapindex.t
497 test-revlog-mmapindex.t
497 test-revlog-packentry.t
498 test-revlog-packentry.t
498 test-revlog-raw.py
499 test-revlog-raw.py
499 test-revlog-v2.t
500 test-revlog-v2.t
500 test-revset-dirstate-parents.t
501 test-revset-dirstate-parents.t
501 test-revset-legacy-lookup.t
502 test-revset-legacy-lookup.t
502 test-revset-outgoing.t
503 test-revset-outgoing.t
503 test-rollback.t
504 test-rollback.t
504 test-run-tests.py
505 test-run-tests.py
505 test-run-tests.t
506 test-run-tests.t
506 test-schemes.t
507 test-schemes.t
507 test-serve.t
508 test-serve.t
508 test-setdiscovery.t
509 test-setdiscovery.t
509 test-share.t
510 test-share.t
510 test-shelve.t
511 test-shelve.t
511 test-show-stack.t
512 test-show-stack.t
512 test-show-work.t
513 test-show-work.t
513 test-show.t
514 test-show.t
514 test-simple-update.t
515 test-simple-update.t
515 test-simplekeyvaluefile.py
516 test-simplekeyvaluefile.py
516 test-simplemerge.py
517 test-simplemerge.py
517 test-single-head.t
518 test-single-head.t
518 test-sparse-clear.t
519 test-sparse-clear.t
519 test-sparse-clone.t
520 test-sparse-clone.t
520 test-sparse-import.t
521 test-sparse-import.t
521 test-sparse-merges.t
522 test-sparse-merges.t
522 test-sparse-profiles.t
523 test-sparse-profiles.t
523 test-sparse-requirement.t
524 test-sparse-requirement.t
524 test-sparse-verbose-json.t
525 test-sparse-verbose-json.t
525 test-sparse.t
526 test-sparse.t
526 test-split.t
527 test-split.t
527 test-ssh-bundle1.t
528 test-ssh-bundle1.t
528 test-ssh-clone-r.t
529 test-ssh-clone-r.t
529 test-ssh-proto-unbundle.t
530 test-ssh-proto-unbundle.t
530 test-ssh-proto.t
531 test-ssh-proto.t
531 test-ssh.t
532 test-ssh.t
532 test-sshserver.py
533 test-sshserver.py
533 test-stack.t
534 test-stack.t
534 test-status-inprocess.py
535 test-status-inprocess.py
535 test-status-rev.t
536 test-status-rev.t
536 test-status-terse.t
537 test-status-terse.t
537 test-storage.py
538 test-storage.py
538 test-stream-bundle-v2.t
539 test-stream-bundle-v2.t
539 test-strict.t
540 test-strict.t
540 test-strip-cross.t
541 test-strip-cross.t
541 test-strip.t
542 test-strip.t
542 test-subrepo-deep-nested-change.t
543 test-subrepo-deep-nested-change.t
543 test-subrepo-missing.t
544 test-subrepo-missing.t
544 test-subrepo-paths.t
545 test-subrepo-paths.t
545 test-subrepo-recursion.t
546 test-subrepo-recursion.t
546 test-subrepo-relative-path.t
547 test-subrepo-relative-path.t
547 test-subrepo.t
548 test-subrepo.t
548 test-symlink-os-yes-fs-no.py
549 test-symlink-os-yes-fs-no.py
549 test-symlink-placeholder.t
550 test-symlink-placeholder.t
550 test-symlinks.t
551 test-symlinks.t
551 test-tag.t
552 test-tag.t
552 test-tags.t
553 test-tags.t
553 test-template-basic.t
554 test-template-basic.t
554 test-template-functions.t
555 test-template-functions.t
555 test-template-keywords.t
556 test-template-keywords.t
556 test-template-map.t
557 test-template-map.t
557 test-transplant.t
558 test-transplant.t
558 test-treemanifest.t
559 test-treemanifest.t
559 test-ui-color.py
560 test-ui-color.py
560 test-ui-config.py
561 test-ui-config.py
561 test-ui-verbosity.py
562 test-ui-verbosity.py
562 test-unamend.t
563 test-unamend.t
563 test-unbundlehash.t
564 test-unbundlehash.t
564 test-uncommit.t
565 test-uncommit.t
565 test-unified-test.t
566 test-unified-test.t
566 test-unionrepo.t
567 test-unionrepo.t
567 test-unrelated-pull.t
568 test-unrelated-pull.t
568 test-up-local-change.t
569 test-up-local-change.t
569 test-update-branches.t
570 test-update-branches.t
570 test-update-dest.t
571 test-update-dest.t
571 test-update-issue1456.t
572 test-update-issue1456.t
572 test-update-names.t
573 test-update-names.t
573 test-update-reverse.t
574 test-update-reverse.t
574 test-upgrade-repo.t
575 test-upgrade-repo.t
575 test-url-download.t
576 test-url-download.t
576 test-url-rev.t
577 test-url-rev.t
577 test-url.py
578 test-url.py
578 test-username-newline.t
579 test-username-newline.t
579 test-util.py
580 test-util.py
580 test-verify.t
581 test-verify.t
581 test-walk.t
582 test-walk.t
582 test-walkrepo.py
583 test-walkrepo.py
583 test-websub.t
584 test-websub.t
584 test-win32text.t
585 test-win32text.t
585 test-wireproto-clientreactor.py
586 test-wireproto-clientreactor.py
586 test-wireproto-command-branchmap.t
587 test-wireproto-command-branchmap.t
587 test-wireproto-command-changesetdata.t
588 test-wireproto-command-changesetdata.t
588 test-wireproto-command-filedata.t
589 test-wireproto-command-filedata.t
589 test-wireproto-command-filesdata.t
590 test-wireproto-command-filesdata.t
590 test-wireproto-command-heads.t
591 test-wireproto-command-heads.t
591 test-wireproto-command-listkeys.t
592 test-wireproto-command-listkeys.t
592 test-wireproto-command-lookup.t
593 test-wireproto-command-lookup.t
593 test-wireproto-command-manifestdata.t
594 test-wireproto-command-manifestdata.t
594 test-wireproto-command-pushkey.t
595 test-wireproto-command-pushkey.t
595 test-wireproto-framing.py
596 test-wireproto-framing.py
596 test-wireproto-serverreactor.py
597 test-wireproto-serverreactor.py
597 test-wireproto.py
598 test-wireproto.py
598 test-wsgirequest.py
599 test-wsgirequest.py
599 test-xdg.t
600 test-xdg.t
General Comments 0
You need to be logged in to leave comments. Login now