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