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