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