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