##// END OF EJS Templates
perf: define command annotation locally for Mercurial earlier than 3.1...
FUJIWARA Katsunori -
r29497:ee202719 default
parent child Browse files
Show More
@@ -1,854 +1,886 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 branchmap,
28 branchmap,
29 cmdutil,
29 cmdutil,
30 commands,
30 commands,
31 copies,
31 copies,
32 error,
32 error,
33 extensions,
33 extensions,
34 mdiff,
34 mdiff,
35 merge,
35 merge,
36 obsolete,
36 obsolete,
37 repoview,
37 repoview,
38 revlog,
38 revlog,
39 scmutil,
39 scmutil,
40 util,
40 util,
41 )
41 )
42
42
43 # for "historical portability":
43 # for "historical portability":
44 # define util.safehasattr forcibly, because util.safehasattr has been
44 # define util.safehasattr forcibly, because util.safehasattr has been
45 # available since 1.9.3 (or 94b200a11cf7)
45 # available since 1.9.3 (or 94b200a11cf7)
46 _undefined = object()
46 _undefined = object()
47 def safehasattr(thing, attr):
47 def safehasattr(thing, attr):
48 return getattr(thing, attr, _undefined) is not _undefined
48 return getattr(thing, attr, _undefined) is not _undefined
49 setattr(util, 'safehasattr', safehasattr)
49 setattr(util, 'safehasattr', safehasattr)
50
50
51 # for "historical portability":
51 # for "historical portability":
52 # use locally defined empty option list, if formatteropts isn't
52 # use locally defined empty option list, if formatteropts isn't
53 # available, because commands.formatteropts has been available since
53 # available, because commands.formatteropts has been available since
54 # 3.2 (or 7a7eed5176a4), even though formatting itself has been
54 # 3.2 (or 7a7eed5176a4), even though formatting itself has been
55 # available since 2.2 (or ae5f92e154d3)
55 # available since 2.2 (or ae5f92e154d3)
56 formatteropts = getattr(commands, "formatteropts", [])
56 formatteropts = getattr(commands, "formatteropts", [])
57
57
58 # for "historical portability":
58 # for "historical portability":
59 # use locally defined option list, if debugrevlogopts isn't available,
59 # use locally defined option list, if debugrevlogopts isn't available,
60 # because commands.debugrevlogopts has been available since 3.7 (or
60 # because commands.debugrevlogopts has been available since 3.7 (or
61 # 5606f7d0d063), even though cmdutil.openrevlog() has been available
61 # 5606f7d0d063), even though cmdutil.openrevlog() has been available
62 # since 1.9 (or a79fea6b3e77).
62 # since 1.9 (or a79fea6b3e77).
63 revlogopts = getattr(commands, "debugrevlogopts", [
63 revlogopts = getattr(commands, "debugrevlogopts", [
64 ('c', 'changelog', False, ('open changelog')),
64 ('c', 'changelog', False, ('open changelog')),
65 ('m', 'manifest', False, ('open manifest')),
65 ('m', 'manifest', False, ('open manifest')),
66 ('', 'dir', False, ('open directory manifest')),
66 ('', 'dir', False, ('open directory manifest')),
67 ])
67 ])
68
68
69 cmdtable = {}
69 cmdtable = {}
70 command = cmdutil.command(cmdtable)
70
71 # for "historical portability":
72 # define parsealiases locally, because cmdutil.parsealiases has been
73 # available since 1.5 (or 6252852b4332)
74 def parsealiases(cmd):
75 return cmd.lstrip("^").split("|")
76
77 if safehasattr(cmdutil, 'command'):
78 import inspect
79 command = cmdutil.command(cmdtable)
80 if 'norepo' not in inspect.getargspec(command)[0]:
81 # for "historical portability":
82 # wrap original cmdutil.command, because "norepo" option has
83 # been available since 3.1 (or 75a96326cecb)
84 _command = command
85 def command(name, options=(), synopsis=None, norepo=False):
86 if norepo:
87 commands.norepo += ' %s' % ' '.join(parsealiases(name))
88 return _command(name, list(options), synopsis)
89 else:
90 # for "historical portability":
91 # define "@command" annotation locally, because cmdutil.command
92 # has been available since 1.9 (or 2daa5179e73f)
93 def command(name, options=(), synopsis=None, norepo=False):
94 def decorator(func):
95 if synopsis:
96 cmdtable[name] = func, list(options), synopsis
97 else:
98 cmdtable[name] = func, list(options)
99 if norepo:
100 commands.norepo += ' %s' % ' '.join(parsealiases(name))
101 return func
102 return decorator
71
103
72 def getlen(ui):
104 def getlen(ui):
73 if ui.configbool("perf", "stub"):
105 if ui.configbool("perf", "stub"):
74 return lambda x: 1
106 return lambda x: 1
75 return len
107 return len
76
108
77 def gettimer(ui, opts=None):
109 def gettimer(ui, opts=None):
78 """return a timer function and formatter: (timer, formatter)
110 """return a timer function and formatter: (timer, formatter)
79
111
80 This function exists to gather the creation of formatter in a single
112 This function exists to gather the creation of formatter in a single
81 place instead of duplicating it in all performance commands."""
113 place instead of duplicating it in all performance commands."""
82
114
83 # enforce an idle period before execution to counteract power management
115 # enforce an idle period before execution to counteract power management
84 # experimental config: perf.presleep
116 # experimental config: perf.presleep
85 time.sleep(ui.configint("perf", "presleep", 1))
117 time.sleep(ui.configint("perf", "presleep", 1))
86
118
87 if opts is None:
119 if opts is None:
88 opts = {}
120 opts = {}
89 # redirect all to stderr
121 # redirect all to stderr
90 ui = ui.copy()
122 ui = ui.copy()
91 ui.fout = ui.ferr
123 ui.fout = ui.ferr
92 # get a formatter
124 # get a formatter
93 fm = ui.formatter('perf', opts)
125 fm = ui.formatter('perf', opts)
94 # stub function, runs code only once instead of in a loop
126 # stub function, runs code only once instead of in a loop
95 # experimental config: perf.stub
127 # experimental config: perf.stub
96 if ui.configbool("perf", "stub"):
128 if ui.configbool("perf", "stub"):
97 return functools.partial(stub_timer, fm), fm
129 return functools.partial(stub_timer, fm), fm
98 return functools.partial(_timer, fm), fm
130 return functools.partial(_timer, fm), fm
99
131
100 def stub_timer(fm, func, title=None):
132 def stub_timer(fm, func, title=None):
101 func()
133 func()
102
134
103 def _timer(fm, func, title=None):
135 def _timer(fm, func, title=None):
104 results = []
136 results = []
105 begin = time.time()
137 begin = time.time()
106 count = 0
138 count = 0
107 while True:
139 while True:
108 ostart = os.times()
140 ostart = os.times()
109 cstart = time.time()
141 cstart = time.time()
110 r = func()
142 r = func()
111 cstop = time.time()
143 cstop = time.time()
112 ostop = os.times()
144 ostop = os.times()
113 count += 1
145 count += 1
114 a, b = ostart, ostop
146 a, b = ostart, ostop
115 results.append((cstop - cstart, b[0] - a[0], b[1]-a[1]))
147 results.append((cstop - cstart, b[0] - a[0], b[1]-a[1]))
116 if cstop - begin > 3 and count >= 100:
148 if cstop - begin > 3 and count >= 100:
117 break
149 break
118 if cstop - begin > 10 and count >= 3:
150 if cstop - begin > 10 and count >= 3:
119 break
151 break
120
152
121 fm.startitem()
153 fm.startitem()
122
154
123 if title:
155 if title:
124 fm.write('title', '! %s\n', title)
156 fm.write('title', '! %s\n', title)
125 if r:
157 if r:
126 fm.write('result', '! result: %s\n', r)
158 fm.write('result', '! result: %s\n', r)
127 m = min(results)
159 m = min(results)
128 fm.plain('!')
160 fm.plain('!')
129 fm.write('wall', ' wall %f', m[0])
161 fm.write('wall', ' wall %f', m[0])
130 fm.write('comb', ' comb %f', m[1] + m[2])
162 fm.write('comb', ' comb %f', m[1] + m[2])
131 fm.write('user', ' user %f', m[1])
163 fm.write('user', ' user %f', m[1])
132 fm.write('sys', ' sys %f', m[2])
164 fm.write('sys', ' sys %f', m[2])
133 fm.write('count', ' (best of %d)', count)
165 fm.write('count', ' (best of %d)', count)
134 fm.plain('\n')
166 fm.plain('\n')
135
167
136 @command('perfwalk', formatteropts)
168 @command('perfwalk', formatteropts)
137 def perfwalk(ui, repo, *pats, **opts):
169 def perfwalk(ui, repo, *pats, **opts):
138 timer, fm = gettimer(ui, opts)
170 timer, fm = gettimer(ui, opts)
139 try:
171 try:
140 m = scmutil.match(repo[None], pats, {})
172 m = scmutil.match(repo[None], pats, {})
141 timer(lambda: len(list(repo.dirstate.walk(m, [], True, False))))
173 timer(lambda: len(list(repo.dirstate.walk(m, [], True, False))))
142 except Exception:
174 except Exception:
143 try:
175 try:
144 m = scmutil.match(repo[None], pats, {})
176 m = scmutil.match(repo[None], pats, {})
145 timer(lambda: len([b for a, b, c in repo.dirstate.statwalk([], m)]))
177 timer(lambda: len([b for a, b, c in repo.dirstate.statwalk([], m)]))
146 except Exception:
178 except Exception:
147 timer(lambda: len(list(cmdutil.walk(repo, pats, {}))))
179 timer(lambda: len(list(cmdutil.walk(repo, pats, {}))))
148 fm.end()
180 fm.end()
149
181
150 @command('perfannotate', formatteropts)
182 @command('perfannotate', formatteropts)
151 def perfannotate(ui, repo, f, **opts):
183 def perfannotate(ui, repo, f, **opts):
152 timer, fm = gettimer(ui, opts)
184 timer, fm = gettimer(ui, opts)
153 fc = repo['.'][f]
185 fc = repo['.'][f]
154 timer(lambda: len(fc.annotate(True)))
186 timer(lambda: len(fc.annotate(True)))
155 fm.end()
187 fm.end()
156
188
157 @command('perfstatus',
189 @command('perfstatus',
158 [('u', 'unknown', False,
190 [('u', 'unknown', False,
159 'ask status to look for unknown files')] + formatteropts)
191 'ask status to look for unknown files')] + formatteropts)
160 def perfstatus(ui, repo, **opts):
192 def perfstatus(ui, repo, **opts):
161 #m = match.always(repo.root, repo.getcwd())
193 #m = match.always(repo.root, repo.getcwd())
162 #timer(lambda: sum(map(len, repo.dirstate.status(m, [], False, False,
194 #timer(lambda: sum(map(len, repo.dirstate.status(m, [], False, False,
163 # False))))
195 # False))))
164 timer, fm = gettimer(ui, opts)
196 timer, fm = gettimer(ui, opts)
165 timer(lambda: sum(map(len, repo.status(unknown=opts['unknown']))))
197 timer(lambda: sum(map(len, repo.status(unknown=opts['unknown']))))
166 fm.end()
198 fm.end()
167
199
168 @command('perfaddremove', formatteropts)
200 @command('perfaddremove', formatteropts)
169 def perfaddremove(ui, repo, **opts):
201 def perfaddremove(ui, repo, **opts):
170 timer, fm = gettimer(ui, opts)
202 timer, fm = gettimer(ui, opts)
171 try:
203 try:
172 oldquiet = repo.ui.quiet
204 oldquiet = repo.ui.quiet
173 repo.ui.quiet = True
205 repo.ui.quiet = True
174 matcher = scmutil.match(repo[None])
206 matcher = scmutil.match(repo[None])
175 timer(lambda: scmutil.addremove(repo, matcher, "", dry_run=True))
207 timer(lambda: scmutil.addremove(repo, matcher, "", dry_run=True))
176 finally:
208 finally:
177 repo.ui.quiet = oldquiet
209 repo.ui.quiet = oldquiet
178 fm.end()
210 fm.end()
179
211
180 def clearcaches(cl):
212 def clearcaches(cl):
181 # behave somewhat consistently across internal API changes
213 # behave somewhat consistently across internal API changes
182 if util.safehasattr(cl, 'clearcaches'):
214 if util.safehasattr(cl, 'clearcaches'):
183 cl.clearcaches()
215 cl.clearcaches()
184 elif util.safehasattr(cl, '_nodecache'):
216 elif util.safehasattr(cl, '_nodecache'):
185 from mercurial.node import nullid, nullrev
217 from mercurial.node import nullid, nullrev
186 cl._nodecache = {nullid: nullrev}
218 cl._nodecache = {nullid: nullrev}
187 cl._nodepos = None
219 cl._nodepos = None
188
220
189 @command('perfheads', formatteropts)
221 @command('perfheads', formatteropts)
190 def perfheads(ui, repo, **opts):
222 def perfheads(ui, repo, **opts):
191 timer, fm = gettimer(ui, opts)
223 timer, fm = gettimer(ui, opts)
192 cl = repo.changelog
224 cl = repo.changelog
193 def d():
225 def d():
194 len(cl.headrevs())
226 len(cl.headrevs())
195 clearcaches(cl)
227 clearcaches(cl)
196 timer(d)
228 timer(d)
197 fm.end()
229 fm.end()
198
230
199 @command('perftags', formatteropts)
231 @command('perftags', formatteropts)
200 def perftags(ui, repo, **opts):
232 def perftags(ui, repo, **opts):
201 import mercurial.changelog
233 import mercurial.changelog
202 import mercurial.manifest
234 import mercurial.manifest
203 timer, fm = gettimer(ui, opts)
235 timer, fm = gettimer(ui, opts)
204 def t():
236 def t():
205 repo.changelog = mercurial.changelog.changelog(repo.svfs)
237 repo.changelog = mercurial.changelog.changelog(repo.svfs)
206 repo.manifest = mercurial.manifest.manifest(repo.svfs)
238 repo.manifest = mercurial.manifest.manifest(repo.svfs)
207 repo._tags = None
239 repo._tags = None
208 return len(repo.tags())
240 return len(repo.tags())
209 timer(t)
241 timer(t)
210 fm.end()
242 fm.end()
211
243
212 @command('perfancestors', formatteropts)
244 @command('perfancestors', formatteropts)
213 def perfancestors(ui, repo, **opts):
245 def perfancestors(ui, repo, **opts):
214 timer, fm = gettimer(ui, opts)
246 timer, fm = gettimer(ui, opts)
215 heads = repo.changelog.headrevs()
247 heads = repo.changelog.headrevs()
216 def d():
248 def d():
217 for a in repo.changelog.ancestors(heads):
249 for a in repo.changelog.ancestors(heads):
218 pass
250 pass
219 timer(d)
251 timer(d)
220 fm.end()
252 fm.end()
221
253
222 @command('perfancestorset', formatteropts)
254 @command('perfancestorset', formatteropts)
223 def perfancestorset(ui, repo, revset, **opts):
255 def perfancestorset(ui, repo, revset, **opts):
224 timer, fm = gettimer(ui, opts)
256 timer, fm = gettimer(ui, opts)
225 revs = repo.revs(revset)
257 revs = repo.revs(revset)
226 heads = repo.changelog.headrevs()
258 heads = repo.changelog.headrevs()
227 def d():
259 def d():
228 s = repo.changelog.ancestors(heads)
260 s = repo.changelog.ancestors(heads)
229 for rev in revs:
261 for rev in revs:
230 rev in s
262 rev in s
231 timer(d)
263 timer(d)
232 fm.end()
264 fm.end()
233
265
234 @command('perfdirs', formatteropts)
266 @command('perfdirs', formatteropts)
235 def perfdirs(ui, repo, **opts):
267 def perfdirs(ui, repo, **opts):
236 timer, fm = gettimer(ui, opts)
268 timer, fm = gettimer(ui, opts)
237 dirstate = repo.dirstate
269 dirstate = repo.dirstate
238 'a' in dirstate
270 'a' in dirstate
239 def d():
271 def d():
240 dirstate.dirs()
272 dirstate.dirs()
241 del dirstate._dirs
273 del dirstate._dirs
242 timer(d)
274 timer(d)
243 fm.end()
275 fm.end()
244
276
245 @command('perfdirstate', formatteropts)
277 @command('perfdirstate', formatteropts)
246 def perfdirstate(ui, repo, **opts):
278 def perfdirstate(ui, repo, **opts):
247 timer, fm = gettimer(ui, opts)
279 timer, fm = gettimer(ui, opts)
248 "a" in repo.dirstate
280 "a" in repo.dirstate
249 def d():
281 def d():
250 repo.dirstate.invalidate()
282 repo.dirstate.invalidate()
251 "a" in repo.dirstate
283 "a" in repo.dirstate
252 timer(d)
284 timer(d)
253 fm.end()
285 fm.end()
254
286
255 @command('perfdirstatedirs', formatteropts)
287 @command('perfdirstatedirs', formatteropts)
256 def perfdirstatedirs(ui, repo, **opts):
288 def perfdirstatedirs(ui, repo, **opts):
257 timer, fm = gettimer(ui, opts)
289 timer, fm = gettimer(ui, opts)
258 "a" in repo.dirstate
290 "a" in repo.dirstate
259 def d():
291 def d():
260 "a" in repo.dirstate._dirs
292 "a" in repo.dirstate._dirs
261 del repo.dirstate._dirs
293 del repo.dirstate._dirs
262 timer(d)
294 timer(d)
263 fm.end()
295 fm.end()
264
296
265 @command('perfdirstatefoldmap', formatteropts)
297 @command('perfdirstatefoldmap', formatteropts)
266 def perfdirstatefoldmap(ui, repo, **opts):
298 def perfdirstatefoldmap(ui, repo, **opts):
267 timer, fm = gettimer(ui, opts)
299 timer, fm = gettimer(ui, opts)
268 dirstate = repo.dirstate
300 dirstate = repo.dirstate
269 'a' in dirstate
301 'a' in dirstate
270 def d():
302 def d():
271 dirstate._filefoldmap.get('a')
303 dirstate._filefoldmap.get('a')
272 del dirstate._filefoldmap
304 del dirstate._filefoldmap
273 timer(d)
305 timer(d)
274 fm.end()
306 fm.end()
275
307
276 @command('perfdirfoldmap', formatteropts)
308 @command('perfdirfoldmap', formatteropts)
277 def perfdirfoldmap(ui, repo, **opts):
309 def perfdirfoldmap(ui, repo, **opts):
278 timer, fm = gettimer(ui, opts)
310 timer, fm = gettimer(ui, opts)
279 dirstate = repo.dirstate
311 dirstate = repo.dirstate
280 'a' in dirstate
312 'a' in dirstate
281 def d():
313 def d():
282 dirstate._dirfoldmap.get('a')
314 dirstate._dirfoldmap.get('a')
283 del dirstate._dirfoldmap
315 del dirstate._dirfoldmap
284 del dirstate._dirs
316 del dirstate._dirs
285 timer(d)
317 timer(d)
286 fm.end()
318 fm.end()
287
319
288 @command('perfdirstatewrite', formatteropts)
320 @command('perfdirstatewrite', formatteropts)
289 def perfdirstatewrite(ui, repo, **opts):
321 def perfdirstatewrite(ui, repo, **opts):
290 timer, fm = gettimer(ui, opts)
322 timer, fm = gettimer(ui, opts)
291 ds = repo.dirstate
323 ds = repo.dirstate
292 "a" in ds
324 "a" in ds
293 def d():
325 def d():
294 ds._dirty = True
326 ds._dirty = True
295 ds.write(repo.currenttransaction())
327 ds.write(repo.currenttransaction())
296 timer(d)
328 timer(d)
297 fm.end()
329 fm.end()
298
330
299 @command('perfmergecalculate',
331 @command('perfmergecalculate',
300 [('r', 'rev', '.', 'rev to merge against')] + formatteropts)
332 [('r', 'rev', '.', 'rev to merge against')] + formatteropts)
301 def perfmergecalculate(ui, repo, rev, **opts):
333 def perfmergecalculate(ui, repo, rev, **opts):
302 timer, fm = gettimer(ui, opts)
334 timer, fm = gettimer(ui, opts)
303 wctx = repo[None]
335 wctx = repo[None]
304 rctx = scmutil.revsingle(repo, rev, rev)
336 rctx = scmutil.revsingle(repo, rev, rev)
305 ancestor = wctx.ancestor(rctx)
337 ancestor = wctx.ancestor(rctx)
306 # we don't want working dir files to be stat'd in the benchmark, so prime
338 # we don't want working dir files to be stat'd in the benchmark, so prime
307 # that cache
339 # that cache
308 wctx.dirty()
340 wctx.dirty()
309 def d():
341 def d():
310 # acceptremote is True because we don't want prompts in the middle of
342 # acceptremote is True because we don't want prompts in the middle of
311 # our benchmark
343 # our benchmark
312 merge.calculateupdates(repo, wctx, rctx, [ancestor], False, False,
344 merge.calculateupdates(repo, wctx, rctx, [ancestor], False, False,
313 acceptremote=True, followcopies=True)
345 acceptremote=True, followcopies=True)
314 timer(d)
346 timer(d)
315 fm.end()
347 fm.end()
316
348
317 @command('perfpathcopies', [], "REV REV")
349 @command('perfpathcopies', [], "REV REV")
318 def perfpathcopies(ui, repo, rev1, rev2, **opts):
350 def perfpathcopies(ui, repo, rev1, rev2, **opts):
319 timer, fm = gettimer(ui, opts)
351 timer, fm = gettimer(ui, opts)
320 ctx1 = scmutil.revsingle(repo, rev1, rev1)
352 ctx1 = scmutil.revsingle(repo, rev1, rev1)
321 ctx2 = scmutil.revsingle(repo, rev2, rev2)
353 ctx2 = scmutil.revsingle(repo, rev2, rev2)
322 def d():
354 def d():
323 copies.pathcopies(ctx1, ctx2)
355 copies.pathcopies(ctx1, ctx2)
324 timer(d)
356 timer(d)
325 fm.end()
357 fm.end()
326
358
327 @command('perfmanifest', [], 'REV')
359 @command('perfmanifest', [], 'REV')
328 def perfmanifest(ui, repo, rev, **opts):
360 def perfmanifest(ui, repo, rev, **opts):
329 timer, fm = gettimer(ui, opts)
361 timer, fm = gettimer(ui, opts)
330 ctx = scmutil.revsingle(repo, rev, rev)
362 ctx = scmutil.revsingle(repo, rev, rev)
331 t = ctx.manifestnode()
363 t = ctx.manifestnode()
332 def d():
364 def d():
333 repo.manifest.clearcaches()
365 repo.manifest.clearcaches()
334 repo.manifest.read(t)
366 repo.manifest.read(t)
335 timer(d)
367 timer(d)
336 fm.end()
368 fm.end()
337
369
338 @command('perfchangeset', formatteropts)
370 @command('perfchangeset', formatteropts)
339 def perfchangeset(ui, repo, rev, **opts):
371 def perfchangeset(ui, repo, rev, **opts):
340 timer, fm = gettimer(ui, opts)
372 timer, fm = gettimer(ui, opts)
341 n = repo[rev].node()
373 n = repo[rev].node()
342 def d():
374 def d():
343 repo.changelog.read(n)
375 repo.changelog.read(n)
344 #repo.changelog._cache = None
376 #repo.changelog._cache = None
345 timer(d)
377 timer(d)
346 fm.end()
378 fm.end()
347
379
348 @command('perfindex', formatteropts)
380 @command('perfindex', formatteropts)
349 def perfindex(ui, repo, **opts):
381 def perfindex(ui, repo, **opts):
350 import mercurial.revlog
382 import mercurial.revlog
351 timer, fm = gettimer(ui, opts)
383 timer, fm = gettimer(ui, opts)
352 mercurial.revlog._prereadsize = 2**24 # disable lazy parser in old hg
384 mercurial.revlog._prereadsize = 2**24 # disable lazy parser in old hg
353 n = repo["tip"].node()
385 n = repo["tip"].node()
354 def d():
386 def d():
355 cl = mercurial.revlog.revlog(repo.svfs, "00changelog.i")
387 cl = mercurial.revlog.revlog(repo.svfs, "00changelog.i")
356 cl.rev(n)
388 cl.rev(n)
357 timer(d)
389 timer(d)
358 fm.end()
390 fm.end()
359
391
360 @command('perfstartup', formatteropts)
392 @command('perfstartup', formatteropts)
361 def perfstartup(ui, repo, **opts):
393 def perfstartup(ui, repo, **opts):
362 timer, fm = gettimer(ui, opts)
394 timer, fm = gettimer(ui, opts)
363 cmd = sys.argv[0]
395 cmd = sys.argv[0]
364 def d():
396 def d():
365 if os.name != 'nt':
397 if os.name != 'nt':
366 os.system("HGRCPATH= %s version -q > /dev/null" % cmd)
398 os.system("HGRCPATH= %s version -q > /dev/null" % cmd)
367 else:
399 else:
368 os.environ['HGRCPATH'] = ''
400 os.environ['HGRCPATH'] = ''
369 os.system("%s version -q > NUL" % cmd)
401 os.system("%s version -q > NUL" % cmd)
370 timer(d)
402 timer(d)
371 fm.end()
403 fm.end()
372
404
373 @command('perfparents', formatteropts)
405 @command('perfparents', formatteropts)
374 def perfparents(ui, repo, **opts):
406 def perfparents(ui, repo, **opts):
375 timer, fm = gettimer(ui, opts)
407 timer, fm = gettimer(ui, opts)
376 # control the number of commits perfparents iterates over
408 # control the number of commits perfparents iterates over
377 # experimental config: perf.parentscount
409 # experimental config: perf.parentscount
378 count = ui.configint("perf", "parentscount", 1000)
410 count = ui.configint("perf", "parentscount", 1000)
379 if len(repo.changelog) < count:
411 if len(repo.changelog) < count:
380 raise error.Abort("repo needs %d commits for this test" % count)
412 raise error.Abort("repo needs %d commits for this test" % count)
381 repo = repo.unfiltered()
413 repo = repo.unfiltered()
382 nl = [repo.changelog.node(i) for i in xrange(count)]
414 nl = [repo.changelog.node(i) for i in xrange(count)]
383 def d():
415 def d():
384 for n in nl:
416 for n in nl:
385 repo.changelog.parents(n)
417 repo.changelog.parents(n)
386 timer(d)
418 timer(d)
387 fm.end()
419 fm.end()
388
420
389 @command('perfctxfiles', formatteropts)
421 @command('perfctxfiles', formatteropts)
390 def perfctxfiles(ui, repo, x, **opts):
422 def perfctxfiles(ui, repo, x, **opts):
391 x = int(x)
423 x = int(x)
392 timer, fm = gettimer(ui, opts)
424 timer, fm = gettimer(ui, opts)
393 def d():
425 def d():
394 len(repo[x].files())
426 len(repo[x].files())
395 timer(d)
427 timer(d)
396 fm.end()
428 fm.end()
397
429
398 @command('perfrawfiles', formatteropts)
430 @command('perfrawfiles', formatteropts)
399 def perfrawfiles(ui, repo, x, **opts):
431 def perfrawfiles(ui, repo, x, **opts):
400 x = int(x)
432 x = int(x)
401 timer, fm = gettimer(ui, opts)
433 timer, fm = gettimer(ui, opts)
402 cl = repo.changelog
434 cl = repo.changelog
403 def d():
435 def d():
404 len(cl.read(x)[3])
436 len(cl.read(x)[3])
405 timer(d)
437 timer(d)
406 fm.end()
438 fm.end()
407
439
408 @command('perflookup', formatteropts)
440 @command('perflookup', formatteropts)
409 def perflookup(ui, repo, rev, **opts):
441 def perflookup(ui, repo, rev, **opts):
410 timer, fm = gettimer(ui, opts)
442 timer, fm = gettimer(ui, opts)
411 timer(lambda: len(repo.lookup(rev)))
443 timer(lambda: len(repo.lookup(rev)))
412 fm.end()
444 fm.end()
413
445
414 @command('perfrevrange', formatteropts)
446 @command('perfrevrange', formatteropts)
415 def perfrevrange(ui, repo, *specs, **opts):
447 def perfrevrange(ui, repo, *specs, **opts):
416 timer, fm = gettimer(ui, opts)
448 timer, fm = gettimer(ui, opts)
417 revrange = scmutil.revrange
449 revrange = scmutil.revrange
418 timer(lambda: len(revrange(repo, specs)))
450 timer(lambda: len(revrange(repo, specs)))
419 fm.end()
451 fm.end()
420
452
421 @command('perfnodelookup', formatteropts)
453 @command('perfnodelookup', formatteropts)
422 def perfnodelookup(ui, repo, rev, **opts):
454 def perfnodelookup(ui, repo, rev, **opts):
423 timer, fm = gettimer(ui, opts)
455 timer, fm = gettimer(ui, opts)
424 import mercurial.revlog
456 import mercurial.revlog
425 mercurial.revlog._prereadsize = 2**24 # disable lazy parser in old hg
457 mercurial.revlog._prereadsize = 2**24 # disable lazy parser in old hg
426 n = repo[rev].node()
458 n = repo[rev].node()
427 cl = mercurial.revlog.revlog(repo.svfs, "00changelog.i")
459 cl = mercurial.revlog.revlog(repo.svfs, "00changelog.i")
428 def d():
460 def d():
429 cl.rev(n)
461 cl.rev(n)
430 clearcaches(cl)
462 clearcaches(cl)
431 timer(d)
463 timer(d)
432 fm.end()
464 fm.end()
433
465
434 @command('perflog',
466 @command('perflog',
435 [('', 'rename', False, 'ask log to follow renames')] + formatteropts)
467 [('', 'rename', False, 'ask log to follow renames')] + formatteropts)
436 def perflog(ui, repo, rev=None, **opts):
468 def perflog(ui, repo, rev=None, **opts):
437 if rev is None:
469 if rev is None:
438 rev=[]
470 rev=[]
439 timer, fm = gettimer(ui, opts)
471 timer, fm = gettimer(ui, opts)
440 ui.pushbuffer()
472 ui.pushbuffer()
441 timer(lambda: commands.log(ui, repo, rev=rev, date='', user='',
473 timer(lambda: commands.log(ui, repo, rev=rev, date='', user='',
442 copies=opts.get('rename')))
474 copies=opts.get('rename')))
443 ui.popbuffer()
475 ui.popbuffer()
444 fm.end()
476 fm.end()
445
477
446 @command('perfmoonwalk', formatteropts)
478 @command('perfmoonwalk', formatteropts)
447 def perfmoonwalk(ui, repo, **opts):
479 def perfmoonwalk(ui, repo, **opts):
448 """benchmark walking the changelog backwards
480 """benchmark walking the changelog backwards
449
481
450 This also loads the changelog data for each revision in the changelog.
482 This also loads the changelog data for each revision in the changelog.
451 """
483 """
452 timer, fm = gettimer(ui, opts)
484 timer, fm = gettimer(ui, opts)
453 def moonwalk():
485 def moonwalk():
454 for i in xrange(len(repo), -1, -1):
486 for i in xrange(len(repo), -1, -1):
455 ctx = repo[i]
487 ctx = repo[i]
456 ctx.branch() # read changelog data (in addition to the index)
488 ctx.branch() # read changelog data (in addition to the index)
457 timer(moonwalk)
489 timer(moonwalk)
458 fm.end()
490 fm.end()
459
491
460 @command('perftemplating', formatteropts)
492 @command('perftemplating', formatteropts)
461 def perftemplating(ui, repo, rev=None, **opts):
493 def perftemplating(ui, repo, rev=None, **opts):
462 if rev is None:
494 if rev is None:
463 rev=[]
495 rev=[]
464 timer, fm = gettimer(ui, opts)
496 timer, fm = gettimer(ui, opts)
465 ui.pushbuffer()
497 ui.pushbuffer()
466 timer(lambda: commands.log(ui, repo, rev=rev, date='', user='',
498 timer(lambda: commands.log(ui, repo, rev=rev, date='', user='',
467 template='{date|shortdate} [{rev}:{node|short}]'
499 template='{date|shortdate} [{rev}:{node|short}]'
468 ' {author|person}: {desc|firstline}\n'))
500 ' {author|person}: {desc|firstline}\n'))
469 ui.popbuffer()
501 ui.popbuffer()
470 fm.end()
502 fm.end()
471
503
472 @command('perfcca', formatteropts)
504 @command('perfcca', formatteropts)
473 def perfcca(ui, repo, **opts):
505 def perfcca(ui, repo, **opts):
474 timer, fm = gettimer(ui, opts)
506 timer, fm = gettimer(ui, opts)
475 timer(lambda: scmutil.casecollisionauditor(ui, False, repo.dirstate))
507 timer(lambda: scmutil.casecollisionauditor(ui, False, repo.dirstate))
476 fm.end()
508 fm.end()
477
509
478 @command('perffncacheload', formatteropts)
510 @command('perffncacheload', formatteropts)
479 def perffncacheload(ui, repo, **opts):
511 def perffncacheload(ui, repo, **opts):
480 timer, fm = gettimer(ui, opts)
512 timer, fm = gettimer(ui, opts)
481 s = repo.store
513 s = repo.store
482 def d():
514 def d():
483 s.fncache._load()
515 s.fncache._load()
484 timer(d)
516 timer(d)
485 fm.end()
517 fm.end()
486
518
487 @command('perffncachewrite', formatteropts)
519 @command('perffncachewrite', formatteropts)
488 def perffncachewrite(ui, repo, **opts):
520 def perffncachewrite(ui, repo, **opts):
489 timer, fm = gettimer(ui, opts)
521 timer, fm = gettimer(ui, opts)
490 s = repo.store
522 s = repo.store
491 s.fncache._load()
523 s.fncache._load()
492 lock = repo.lock()
524 lock = repo.lock()
493 tr = repo.transaction('perffncachewrite')
525 tr = repo.transaction('perffncachewrite')
494 def d():
526 def d():
495 s.fncache._dirty = True
527 s.fncache._dirty = True
496 s.fncache.write(tr)
528 s.fncache.write(tr)
497 timer(d)
529 timer(d)
498 lock.release()
530 lock.release()
499 tr.close()
531 tr.close()
500 fm.end()
532 fm.end()
501
533
502 @command('perffncacheencode', formatteropts)
534 @command('perffncacheencode', formatteropts)
503 def perffncacheencode(ui, repo, **opts):
535 def perffncacheencode(ui, repo, **opts):
504 timer, fm = gettimer(ui, opts)
536 timer, fm = gettimer(ui, opts)
505 s = repo.store
537 s = repo.store
506 s.fncache._load()
538 s.fncache._load()
507 def d():
539 def d():
508 for p in s.fncache.entries:
540 for p in s.fncache.entries:
509 s.encode(p)
541 s.encode(p)
510 timer(d)
542 timer(d)
511 fm.end()
543 fm.end()
512
544
513 @command('perfdiffwd', formatteropts)
545 @command('perfdiffwd', formatteropts)
514 def perfdiffwd(ui, repo, **opts):
546 def perfdiffwd(ui, repo, **opts):
515 """Profile diff of working directory changes"""
547 """Profile diff of working directory changes"""
516 timer, fm = gettimer(ui, opts)
548 timer, fm = gettimer(ui, opts)
517 options = {
549 options = {
518 'w': 'ignore_all_space',
550 'w': 'ignore_all_space',
519 'b': 'ignore_space_change',
551 'b': 'ignore_space_change',
520 'B': 'ignore_blank_lines',
552 'B': 'ignore_blank_lines',
521 }
553 }
522
554
523 for diffopt in ('', 'w', 'b', 'B', 'wB'):
555 for diffopt in ('', 'w', 'b', 'B', 'wB'):
524 opts = dict((options[c], '1') for c in diffopt)
556 opts = dict((options[c], '1') for c in diffopt)
525 def d():
557 def d():
526 ui.pushbuffer()
558 ui.pushbuffer()
527 commands.diff(ui, repo, **opts)
559 commands.diff(ui, repo, **opts)
528 ui.popbuffer()
560 ui.popbuffer()
529 title = 'diffopts: %s' % (diffopt and ('-' + diffopt) or 'none')
561 title = 'diffopts: %s' % (diffopt and ('-' + diffopt) or 'none')
530 timer(d, title)
562 timer(d, title)
531 fm.end()
563 fm.end()
532
564
533 @command('perfrevlog', revlogopts + formatteropts +
565 @command('perfrevlog', revlogopts + formatteropts +
534 [('d', 'dist', 100, 'distance between the revisions'),
566 [('d', 'dist', 100, 'distance between the revisions'),
535 ('s', 'startrev', 0, 'revision to start reading at')],
567 ('s', 'startrev', 0, 'revision to start reading at')],
536 '-c|-m|FILE')
568 '-c|-m|FILE')
537 def perfrevlog(ui, repo, file_=None, startrev=0, **opts):
569 def perfrevlog(ui, repo, file_=None, startrev=0, **opts):
538 """Benchmark reading a series of revisions from a revlog.
570 """Benchmark reading a series of revisions from a revlog.
539
571
540 By default, we read every ``-d/--dist`` revision from 0 to tip of
572 By default, we read every ``-d/--dist`` revision from 0 to tip of
541 the specified revlog.
573 the specified revlog.
542
574
543 The start revision can be defined via ``-s/--startrev``.
575 The start revision can be defined via ``-s/--startrev``.
544 """
576 """
545 timer, fm = gettimer(ui, opts)
577 timer, fm = gettimer(ui, opts)
546 dist = opts['dist']
578 dist = opts['dist']
547 _len = getlen(ui)
579 _len = getlen(ui)
548 def d():
580 def d():
549 r = cmdutil.openrevlog(repo, 'perfrevlog', file_, opts)
581 r = cmdutil.openrevlog(repo, 'perfrevlog', file_, opts)
550 for x in xrange(startrev, _len(r), dist):
582 for x in xrange(startrev, _len(r), dist):
551 r.revision(r.node(x))
583 r.revision(r.node(x))
552
584
553 timer(d)
585 timer(d)
554 fm.end()
586 fm.end()
555
587
556 @command('perfrevlogrevision', revlogopts + formatteropts +
588 @command('perfrevlogrevision', revlogopts + formatteropts +
557 [('', 'cache', False, 'use caches instead of clearing')],
589 [('', 'cache', False, 'use caches instead of clearing')],
558 '-c|-m|FILE REV')
590 '-c|-m|FILE REV')
559 def perfrevlogrevision(ui, repo, file_, rev=None, cache=None, **opts):
591 def perfrevlogrevision(ui, repo, file_, rev=None, cache=None, **opts):
560 """Benchmark obtaining a revlog revision.
592 """Benchmark obtaining a revlog revision.
561
593
562 Obtaining a revlog revision consists of roughly the following steps:
594 Obtaining a revlog revision consists of roughly the following steps:
563
595
564 1. Compute the delta chain
596 1. Compute the delta chain
565 2. Obtain the raw chunks for that delta chain
597 2. Obtain the raw chunks for that delta chain
566 3. Decompress each raw chunk
598 3. Decompress each raw chunk
567 4. Apply binary patches to obtain fulltext
599 4. Apply binary patches to obtain fulltext
568 5. Verify hash of fulltext
600 5. Verify hash of fulltext
569
601
570 This command measures the time spent in each of these phases.
602 This command measures the time spent in each of these phases.
571 """
603 """
572 if opts.get('changelog') or opts.get('manifest'):
604 if opts.get('changelog') or opts.get('manifest'):
573 file_, rev = None, file_
605 file_, rev = None, file_
574 elif rev is None:
606 elif rev is None:
575 raise error.CommandError('perfrevlogrevision', 'invalid arguments')
607 raise error.CommandError('perfrevlogrevision', 'invalid arguments')
576
608
577 r = cmdutil.openrevlog(repo, 'perfrevlogrevision', file_, opts)
609 r = cmdutil.openrevlog(repo, 'perfrevlogrevision', file_, opts)
578 node = r.lookup(rev)
610 node = r.lookup(rev)
579 rev = r.rev(node)
611 rev = r.rev(node)
580
612
581 def dodeltachain(rev):
613 def dodeltachain(rev):
582 if not cache:
614 if not cache:
583 r.clearcaches()
615 r.clearcaches()
584 r._deltachain(rev)
616 r._deltachain(rev)
585
617
586 def doread(chain):
618 def doread(chain):
587 if not cache:
619 if not cache:
588 r.clearcaches()
620 r.clearcaches()
589 r._chunkraw(chain[0], chain[-1])
621 r._chunkraw(chain[0], chain[-1])
590
622
591 def dodecompress(data, chain):
623 def dodecompress(data, chain):
592 if not cache:
624 if not cache:
593 r.clearcaches()
625 r.clearcaches()
594
626
595 start = r.start
627 start = r.start
596 length = r.length
628 length = r.length
597 inline = r._inline
629 inline = r._inline
598 iosize = r._io.size
630 iosize = r._io.size
599 buffer = util.buffer
631 buffer = util.buffer
600 offset = start(chain[0])
632 offset = start(chain[0])
601
633
602 for rev in chain:
634 for rev in chain:
603 chunkstart = start(rev)
635 chunkstart = start(rev)
604 if inline:
636 if inline:
605 chunkstart += (rev + 1) * iosize
637 chunkstart += (rev + 1) * iosize
606 chunklength = length(rev)
638 chunklength = length(rev)
607 b = buffer(data, chunkstart - offset, chunklength)
639 b = buffer(data, chunkstart - offset, chunklength)
608 revlog.decompress(b)
640 revlog.decompress(b)
609
641
610 def dopatch(text, bins):
642 def dopatch(text, bins):
611 if not cache:
643 if not cache:
612 r.clearcaches()
644 r.clearcaches()
613 mdiff.patches(text, bins)
645 mdiff.patches(text, bins)
614
646
615 def dohash(text):
647 def dohash(text):
616 if not cache:
648 if not cache:
617 r.clearcaches()
649 r.clearcaches()
618 r._checkhash(text, node, rev)
650 r._checkhash(text, node, rev)
619
651
620 def dorevision():
652 def dorevision():
621 if not cache:
653 if not cache:
622 r.clearcaches()
654 r.clearcaches()
623 r.revision(node)
655 r.revision(node)
624
656
625 chain = r._deltachain(rev)[0]
657 chain = r._deltachain(rev)[0]
626 data = r._chunkraw(chain[0], chain[-1])[1]
658 data = r._chunkraw(chain[0], chain[-1])[1]
627 bins = r._chunks(chain)
659 bins = r._chunks(chain)
628 text = str(bins[0])
660 text = str(bins[0])
629 bins = bins[1:]
661 bins = bins[1:]
630 text = mdiff.patches(text, bins)
662 text = mdiff.patches(text, bins)
631
663
632 benches = [
664 benches = [
633 (lambda: dorevision(), 'full'),
665 (lambda: dorevision(), 'full'),
634 (lambda: dodeltachain(rev), 'deltachain'),
666 (lambda: dodeltachain(rev), 'deltachain'),
635 (lambda: doread(chain), 'read'),
667 (lambda: doread(chain), 'read'),
636 (lambda: dodecompress(data, chain), 'decompress'),
668 (lambda: dodecompress(data, chain), 'decompress'),
637 (lambda: dopatch(text, bins), 'patch'),
669 (lambda: dopatch(text, bins), 'patch'),
638 (lambda: dohash(text), 'hash'),
670 (lambda: dohash(text), 'hash'),
639 ]
671 ]
640
672
641 for fn, title in benches:
673 for fn, title in benches:
642 timer, fm = gettimer(ui, opts)
674 timer, fm = gettimer(ui, opts)
643 timer(fn, title=title)
675 timer(fn, title=title)
644 fm.end()
676 fm.end()
645
677
646 @command('perfrevset',
678 @command('perfrevset',
647 [('C', 'clear', False, 'clear volatile cache between each call.'),
679 [('C', 'clear', False, 'clear volatile cache between each call.'),
648 ('', 'contexts', False, 'obtain changectx for each revision')]
680 ('', 'contexts', False, 'obtain changectx for each revision')]
649 + formatteropts, "REVSET")
681 + formatteropts, "REVSET")
650 def perfrevset(ui, repo, expr, clear=False, contexts=False, **opts):
682 def perfrevset(ui, repo, expr, clear=False, contexts=False, **opts):
651 """benchmark the execution time of a revset
683 """benchmark the execution time of a revset
652
684
653 Use the --clean option if need to evaluate the impact of build volatile
685 Use the --clean option if need to evaluate the impact of build volatile
654 revisions set cache on the revset execution. Volatile cache hold filtered
686 revisions set cache on the revset execution. Volatile cache hold filtered
655 and obsolete related cache."""
687 and obsolete related cache."""
656 timer, fm = gettimer(ui, opts)
688 timer, fm = gettimer(ui, opts)
657 def d():
689 def d():
658 if clear:
690 if clear:
659 repo.invalidatevolatilesets()
691 repo.invalidatevolatilesets()
660 if contexts:
692 if contexts:
661 for ctx in repo.set(expr): pass
693 for ctx in repo.set(expr): pass
662 else:
694 else:
663 for r in repo.revs(expr): pass
695 for r in repo.revs(expr): pass
664 timer(d)
696 timer(d)
665 fm.end()
697 fm.end()
666
698
667 @command('perfvolatilesets', formatteropts)
699 @command('perfvolatilesets', formatteropts)
668 def perfvolatilesets(ui, repo, *names, **opts):
700 def perfvolatilesets(ui, repo, *names, **opts):
669 """benchmark the computation of various volatile set
701 """benchmark the computation of various volatile set
670
702
671 Volatile set computes element related to filtering and obsolescence."""
703 Volatile set computes element related to filtering and obsolescence."""
672 timer, fm = gettimer(ui, opts)
704 timer, fm = gettimer(ui, opts)
673 repo = repo.unfiltered()
705 repo = repo.unfiltered()
674
706
675 def getobs(name):
707 def getobs(name):
676 def d():
708 def d():
677 repo.invalidatevolatilesets()
709 repo.invalidatevolatilesets()
678 obsolete.getrevs(repo, name)
710 obsolete.getrevs(repo, name)
679 return d
711 return d
680
712
681 allobs = sorted(obsolete.cachefuncs)
713 allobs = sorted(obsolete.cachefuncs)
682 if names:
714 if names:
683 allobs = [n for n in allobs if n in names]
715 allobs = [n for n in allobs if n in names]
684
716
685 for name in allobs:
717 for name in allobs:
686 timer(getobs(name), title=name)
718 timer(getobs(name), title=name)
687
719
688 def getfiltered(name):
720 def getfiltered(name):
689 def d():
721 def d():
690 repo.invalidatevolatilesets()
722 repo.invalidatevolatilesets()
691 repoview.filterrevs(repo, name)
723 repoview.filterrevs(repo, name)
692 return d
724 return d
693
725
694 allfilter = sorted(repoview.filtertable)
726 allfilter = sorted(repoview.filtertable)
695 if names:
727 if names:
696 allfilter = [n for n in allfilter if n in names]
728 allfilter = [n for n in allfilter if n in names]
697
729
698 for name in allfilter:
730 for name in allfilter:
699 timer(getfiltered(name), title=name)
731 timer(getfiltered(name), title=name)
700 fm.end()
732 fm.end()
701
733
702 @command('perfbranchmap',
734 @command('perfbranchmap',
703 [('f', 'full', False,
735 [('f', 'full', False,
704 'Includes build time of subset'),
736 'Includes build time of subset'),
705 ] + formatteropts)
737 ] + formatteropts)
706 def perfbranchmap(ui, repo, full=False, **opts):
738 def perfbranchmap(ui, repo, full=False, **opts):
707 """benchmark the update of a branchmap
739 """benchmark the update of a branchmap
708
740
709 This benchmarks the full repo.branchmap() call with read and write disabled
741 This benchmarks the full repo.branchmap() call with read and write disabled
710 """
742 """
711 timer, fm = gettimer(ui, opts)
743 timer, fm = gettimer(ui, opts)
712 def getbranchmap(filtername):
744 def getbranchmap(filtername):
713 """generate a benchmark function for the filtername"""
745 """generate a benchmark function for the filtername"""
714 if filtername is None:
746 if filtername is None:
715 view = repo
747 view = repo
716 else:
748 else:
717 view = repo.filtered(filtername)
749 view = repo.filtered(filtername)
718 def d():
750 def d():
719 if full:
751 if full:
720 view._branchcaches.clear()
752 view._branchcaches.clear()
721 else:
753 else:
722 view._branchcaches.pop(filtername, None)
754 view._branchcaches.pop(filtername, None)
723 view.branchmap()
755 view.branchmap()
724 return d
756 return d
725 # add filter in smaller subset to bigger subset
757 # add filter in smaller subset to bigger subset
726 possiblefilters = set(repoview.filtertable)
758 possiblefilters = set(repoview.filtertable)
727 allfilters = []
759 allfilters = []
728 while possiblefilters:
760 while possiblefilters:
729 for name in possiblefilters:
761 for name in possiblefilters:
730 subset = branchmap.subsettable.get(name)
762 subset = branchmap.subsettable.get(name)
731 if subset not in possiblefilters:
763 if subset not in possiblefilters:
732 break
764 break
733 else:
765 else:
734 assert False, 'subset cycle %s!' % possiblefilters
766 assert False, 'subset cycle %s!' % possiblefilters
735 allfilters.append(name)
767 allfilters.append(name)
736 possiblefilters.remove(name)
768 possiblefilters.remove(name)
737
769
738 # warm the cache
770 # warm the cache
739 if not full:
771 if not full:
740 for name in allfilters:
772 for name in allfilters:
741 repo.filtered(name).branchmap()
773 repo.filtered(name).branchmap()
742 # add unfiltered
774 # add unfiltered
743 allfilters.append(None)
775 allfilters.append(None)
744 oldread = branchmap.read
776 oldread = branchmap.read
745 oldwrite = branchmap.branchcache.write
777 oldwrite = branchmap.branchcache.write
746 try:
778 try:
747 branchmap.read = lambda repo: None
779 branchmap.read = lambda repo: None
748 branchmap.write = lambda repo: None
780 branchmap.write = lambda repo: None
749 for name in allfilters:
781 for name in allfilters:
750 timer(getbranchmap(name), title=str(name))
782 timer(getbranchmap(name), title=str(name))
751 finally:
783 finally:
752 branchmap.read = oldread
784 branchmap.read = oldread
753 branchmap.branchcache.write = oldwrite
785 branchmap.branchcache.write = oldwrite
754 fm.end()
786 fm.end()
755
787
756 @command('perfloadmarkers')
788 @command('perfloadmarkers')
757 def perfloadmarkers(ui, repo):
789 def perfloadmarkers(ui, repo):
758 """benchmark the time to parse the on-disk markers for a repo
790 """benchmark the time to parse the on-disk markers for a repo
759
791
760 Result is the number of markers in the repo."""
792 Result is the number of markers in the repo."""
761 timer, fm = gettimer(ui)
793 timer, fm = gettimer(ui)
762 timer(lambda: len(obsolete.obsstore(repo.svfs)))
794 timer(lambda: len(obsolete.obsstore(repo.svfs)))
763 fm.end()
795 fm.end()
764
796
765 @command('perflrucachedict', formatteropts +
797 @command('perflrucachedict', formatteropts +
766 [('', 'size', 4, 'size of cache'),
798 [('', 'size', 4, 'size of cache'),
767 ('', 'gets', 10000, 'number of key lookups'),
799 ('', 'gets', 10000, 'number of key lookups'),
768 ('', 'sets', 10000, 'number of key sets'),
800 ('', 'sets', 10000, 'number of key sets'),
769 ('', 'mixed', 10000, 'number of mixed mode operations'),
801 ('', 'mixed', 10000, 'number of mixed mode operations'),
770 ('', 'mixedgetfreq', 50, 'frequency of get vs set ops in mixed mode')],
802 ('', 'mixedgetfreq', 50, 'frequency of get vs set ops in mixed mode')],
771 norepo=True)
803 norepo=True)
772 def perflrucache(ui, size=4, gets=10000, sets=10000, mixed=10000,
804 def perflrucache(ui, size=4, gets=10000, sets=10000, mixed=10000,
773 mixedgetfreq=50, **opts):
805 mixedgetfreq=50, **opts):
774 def doinit():
806 def doinit():
775 for i in xrange(10000):
807 for i in xrange(10000):
776 util.lrucachedict(size)
808 util.lrucachedict(size)
777
809
778 values = []
810 values = []
779 for i in xrange(size):
811 for i in xrange(size):
780 values.append(random.randint(0, sys.maxint))
812 values.append(random.randint(0, sys.maxint))
781
813
782 # Get mode fills the cache and tests raw lookup performance with no
814 # Get mode fills the cache and tests raw lookup performance with no
783 # eviction.
815 # eviction.
784 getseq = []
816 getseq = []
785 for i in xrange(gets):
817 for i in xrange(gets):
786 getseq.append(random.choice(values))
818 getseq.append(random.choice(values))
787
819
788 def dogets():
820 def dogets():
789 d = util.lrucachedict(size)
821 d = util.lrucachedict(size)
790 for v in values:
822 for v in values:
791 d[v] = v
823 d[v] = v
792 for key in getseq:
824 for key in getseq:
793 value = d[key]
825 value = d[key]
794 value # silence pyflakes warning
826 value # silence pyflakes warning
795
827
796 # Set mode tests insertion speed with cache eviction.
828 # Set mode tests insertion speed with cache eviction.
797 setseq = []
829 setseq = []
798 for i in xrange(sets):
830 for i in xrange(sets):
799 setseq.append(random.randint(0, sys.maxint))
831 setseq.append(random.randint(0, sys.maxint))
800
832
801 def dosets():
833 def dosets():
802 d = util.lrucachedict(size)
834 d = util.lrucachedict(size)
803 for v in setseq:
835 for v in setseq:
804 d[v] = v
836 d[v] = v
805
837
806 # Mixed mode randomly performs gets and sets with eviction.
838 # Mixed mode randomly performs gets and sets with eviction.
807 mixedops = []
839 mixedops = []
808 for i in xrange(mixed):
840 for i in xrange(mixed):
809 r = random.randint(0, 100)
841 r = random.randint(0, 100)
810 if r < mixedgetfreq:
842 if r < mixedgetfreq:
811 op = 0
843 op = 0
812 else:
844 else:
813 op = 1
845 op = 1
814
846
815 mixedops.append((op, random.randint(0, size * 2)))
847 mixedops.append((op, random.randint(0, size * 2)))
816
848
817 def domixed():
849 def domixed():
818 d = util.lrucachedict(size)
850 d = util.lrucachedict(size)
819
851
820 for op, v in mixedops:
852 for op, v in mixedops:
821 if op == 0:
853 if op == 0:
822 try:
854 try:
823 d[v]
855 d[v]
824 except KeyError:
856 except KeyError:
825 pass
857 pass
826 else:
858 else:
827 d[v] = v
859 d[v] = v
828
860
829 benches = [
861 benches = [
830 (doinit, 'init'),
862 (doinit, 'init'),
831 (dogets, 'gets'),
863 (dogets, 'gets'),
832 (dosets, 'sets'),
864 (dosets, 'sets'),
833 (domixed, 'mixed')
865 (domixed, 'mixed')
834 ]
866 ]
835
867
836 for fn, title in benches:
868 for fn, title in benches:
837 timer, fm = gettimer(ui, opts)
869 timer, fm = gettimer(ui, opts)
838 timer(fn, title=title)
870 timer(fn, title=title)
839 fm.end()
871 fm.end()
840
872
841 def uisetup(ui):
873 def uisetup(ui):
842 if (util.safehasattr(cmdutil, 'openrevlog') and
874 if (util.safehasattr(cmdutil, 'openrevlog') and
843 not util.safehasattr(commands, 'debugrevlogopts')):
875 not util.safehasattr(commands, 'debugrevlogopts')):
844 # for "historical portability":
876 # for "historical portability":
845 # In this case, Mercurial should be 1.9 (or a79fea6b3e77) -
877 # In this case, Mercurial should be 1.9 (or a79fea6b3e77) -
846 # 3.7 (or 5606f7d0d063). Therefore, '--dir' option for
878 # 3.7 (or 5606f7d0d063). Therefore, '--dir' option for
847 # openrevlog() should cause failure, because it has been
879 # openrevlog() should cause failure, because it has been
848 # available since 3.5 (or 49c583ca48c4).
880 # available since 3.5 (or 49c583ca48c4).
849 def openrevlog(orig, repo, cmd, file_, opts):
881 def openrevlog(orig, repo, cmd, file_, opts):
850 if opts.get('dir') and not util.safehasattr(repo, 'dirlog'):
882 if opts.get('dir') and not util.safehasattr(repo, 'dirlog'):
851 raise error.Abort("This version doesn't support --dir option",
883 raise error.Abort("This version doesn't support --dir option",
852 hint="use 3.5 or later")
884 hint="use 3.5 or later")
853 return orig(repo, cmd, file_, opts)
885 return orig(repo, cmd, file_, opts)
854 extensions.wrapfunction(cmdutil, 'openrevlog', openrevlog)
886 extensions.wrapfunction(cmdutil, 'openrevlog', openrevlog)
General Comments 0
You need to be logged in to leave comments. Login now