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