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