##// END OF EJS Templates
perf: call clearcaches() in perfmanifest...
Gregory Szorc -
r27467:fbe292b5 default
parent child Browse files
Show More
@@ -1,685 +1,684 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 acceptremote=True, followcopies=True)
256 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.clearcaches()
277 repo.manifest._cache = None
278 repo.manifest.read(t)
277 repo.manifest.read(t)
279 timer(d)
278 timer(d)
280 fm.end()
279 fm.end()
281
280
282 @command('perfchangeset', formatteropts)
281 @command('perfchangeset', formatteropts)
283 def perfchangeset(ui, repo, rev, **opts):
282 def perfchangeset(ui, repo, rev, **opts):
284 timer, fm = gettimer(ui, opts)
283 timer, fm = gettimer(ui, opts)
285 n = repo[rev].node()
284 n = repo[rev].node()
286 def d():
285 def d():
287 repo.changelog.read(n)
286 repo.changelog.read(n)
288 #repo.changelog._cache = None
287 #repo.changelog._cache = None
289 timer(d)
288 timer(d)
290 fm.end()
289 fm.end()
291
290
292 @command('perfindex', formatteropts)
291 @command('perfindex', formatteropts)
293 def perfindex(ui, repo, **opts):
292 def perfindex(ui, repo, **opts):
294 import mercurial.revlog
293 import mercurial.revlog
295 timer, fm = gettimer(ui, opts)
294 timer, fm = gettimer(ui, opts)
296 mercurial.revlog._prereadsize = 2**24 # disable lazy parser in old hg
295 mercurial.revlog._prereadsize = 2**24 # disable lazy parser in old hg
297 n = repo["tip"].node()
296 n = repo["tip"].node()
298 def d():
297 def d():
299 cl = mercurial.revlog.revlog(repo.svfs, "00changelog.i")
298 cl = mercurial.revlog.revlog(repo.svfs, "00changelog.i")
300 cl.rev(n)
299 cl.rev(n)
301 timer(d)
300 timer(d)
302 fm.end()
301 fm.end()
303
302
304 @command('perfstartup', formatteropts)
303 @command('perfstartup', formatteropts)
305 def perfstartup(ui, repo, **opts):
304 def perfstartup(ui, repo, **opts):
306 timer, fm = gettimer(ui, opts)
305 timer, fm = gettimer(ui, opts)
307 cmd = sys.argv[0]
306 cmd = sys.argv[0]
308 def d():
307 def d():
309 if os.name != 'nt':
308 if os.name != 'nt':
310 os.system("HGRCPATH= %s version -q > /dev/null" % cmd)
309 os.system("HGRCPATH= %s version -q > /dev/null" % cmd)
311 else:
310 else:
312 os.environ['HGRCPATH'] = ''
311 os.environ['HGRCPATH'] = ''
313 os.system("%s version -q > NUL" % cmd)
312 os.system("%s version -q > NUL" % cmd)
314 timer(d)
313 timer(d)
315 fm.end()
314 fm.end()
316
315
317 @command('perfparents', formatteropts)
316 @command('perfparents', formatteropts)
318 def perfparents(ui, repo, **opts):
317 def perfparents(ui, repo, **opts):
319 timer, fm = gettimer(ui, opts)
318 timer, fm = gettimer(ui, opts)
320 # control the number of commits perfparents iterates over
319 # control the number of commits perfparents iterates over
321 # experimental config: perf.parentscount
320 # experimental config: perf.parentscount
322 count = ui.configint("perf", "parentscount", 1000)
321 count = ui.configint("perf", "parentscount", 1000)
323 if len(repo.changelog) < count:
322 if len(repo.changelog) < count:
324 raise error.Abort("repo needs %d commits for this test" % count)
323 raise error.Abort("repo needs %d commits for this test" % count)
325 repo = repo.unfiltered()
324 repo = repo.unfiltered()
326 nl = [repo.changelog.node(i) for i in xrange(count)]
325 nl = [repo.changelog.node(i) for i in xrange(count)]
327 def d():
326 def d():
328 for n in nl:
327 for n in nl:
329 repo.changelog.parents(n)
328 repo.changelog.parents(n)
330 timer(d)
329 timer(d)
331 fm.end()
330 fm.end()
332
331
333 @command('perfctxfiles', formatteropts)
332 @command('perfctxfiles', formatteropts)
334 def perfctxfiles(ui, repo, x, **opts):
333 def perfctxfiles(ui, repo, x, **opts):
335 x = int(x)
334 x = int(x)
336 timer, fm = gettimer(ui, opts)
335 timer, fm = gettimer(ui, opts)
337 def d():
336 def d():
338 len(repo[x].files())
337 len(repo[x].files())
339 timer(d)
338 timer(d)
340 fm.end()
339 fm.end()
341
340
342 @command('perfrawfiles', formatteropts)
341 @command('perfrawfiles', formatteropts)
343 def perfrawfiles(ui, repo, x, **opts):
342 def perfrawfiles(ui, repo, x, **opts):
344 x = int(x)
343 x = int(x)
345 timer, fm = gettimer(ui, opts)
344 timer, fm = gettimer(ui, opts)
346 cl = repo.changelog
345 cl = repo.changelog
347 def d():
346 def d():
348 len(cl.read(x)[3])
347 len(cl.read(x)[3])
349 timer(d)
348 timer(d)
350 fm.end()
349 fm.end()
351
350
352 @command('perflookup', formatteropts)
351 @command('perflookup', formatteropts)
353 def perflookup(ui, repo, rev, **opts):
352 def perflookup(ui, repo, rev, **opts):
354 timer, fm = gettimer(ui, opts)
353 timer, fm = gettimer(ui, opts)
355 timer(lambda: len(repo.lookup(rev)))
354 timer(lambda: len(repo.lookup(rev)))
356 fm.end()
355 fm.end()
357
356
358 @command('perfrevrange', formatteropts)
357 @command('perfrevrange', formatteropts)
359 def perfrevrange(ui, repo, *specs, **opts):
358 def perfrevrange(ui, repo, *specs, **opts):
360 timer, fm = gettimer(ui, opts)
359 timer, fm = gettimer(ui, opts)
361 revrange = scmutil.revrange
360 revrange = scmutil.revrange
362 timer(lambda: len(revrange(repo, specs)))
361 timer(lambda: len(revrange(repo, specs)))
363 fm.end()
362 fm.end()
364
363
365 @command('perfnodelookup', formatteropts)
364 @command('perfnodelookup', formatteropts)
366 def perfnodelookup(ui, repo, rev, **opts):
365 def perfnodelookup(ui, repo, rev, **opts):
367 timer, fm = gettimer(ui, opts)
366 timer, fm = gettimer(ui, opts)
368 import mercurial.revlog
367 import mercurial.revlog
369 mercurial.revlog._prereadsize = 2**24 # disable lazy parser in old hg
368 mercurial.revlog._prereadsize = 2**24 # disable lazy parser in old hg
370 n = repo[rev].node()
369 n = repo[rev].node()
371 cl = mercurial.revlog.revlog(repo.svfs, "00changelog.i")
370 cl = mercurial.revlog.revlog(repo.svfs, "00changelog.i")
372 def d():
371 def d():
373 cl.rev(n)
372 cl.rev(n)
374 clearcaches(cl)
373 clearcaches(cl)
375 timer(d)
374 timer(d)
376 fm.end()
375 fm.end()
377
376
378 @command('perflog',
377 @command('perflog',
379 [('', 'rename', False, 'ask log to follow renames')] + formatteropts)
378 [('', 'rename', False, 'ask log to follow renames')] + formatteropts)
380 def perflog(ui, repo, rev=None, **opts):
379 def perflog(ui, repo, rev=None, **opts):
381 if rev is None:
380 if rev is None:
382 rev=[]
381 rev=[]
383 timer, fm = gettimer(ui, opts)
382 timer, fm = gettimer(ui, opts)
384 ui.pushbuffer()
383 ui.pushbuffer()
385 timer(lambda: commands.log(ui, repo, rev=rev, date='', user='',
384 timer(lambda: commands.log(ui, repo, rev=rev, date='', user='',
386 copies=opts.get('rename')))
385 copies=opts.get('rename')))
387 ui.popbuffer()
386 ui.popbuffer()
388 fm.end()
387 fm.end()
389
388
390 @command('perfmoonwalk', formatteropts)
389 @command('perfmoonwalk', formatteropts)
391 def perfmoonwalk(ui, repo, **opts):
390 def perfmoonwalk(ui, repo, **opts):
392 """benchmark walking the changelog backwards
391 """benchmark walking the changelog backwards
393
392
394 This also loads the changelog data for each revision in the changelog.
393 This also loads the changelog data for each revision in the changelog.
395 """
394 """
396 timer, fm = gettimer(ui, opts)
395 timer, fm = gettimer(ui, opts)
397 def moonwalk():
396 def moonwalk():
398 for i in xrange(len(repo), -1, -1):
397 for i in xrange(len(repo), -1, -1):
399 ctx = repo[i]
398 ctx = repo[i]
400 ctx.branch() # read changelog data (in addition to the index)
399 ctx.branch() # read changelog data (in addition to the index)
401 timer(moonwalk)
400 timer(moonwalk)
402 fm.end()
401 fm.end()
403
402
404 @command('perftemplating', formatteropts)
403 @command('perftemplating', formatteropts)
405 def perftemplating(ui, repo, rev=None, **opts):
404 def perftemplating(ui, repo, rev=None, **opts):
406 if rev is None:
405 if rev is None:
407 rev=[]
406 rev=[]
408 timer, fm = gettimer(ui, opts)
407 timer, fm = gettimer(ui, opts)
409 ui.pushbuffer()
408 ui.pushbuffer()
410 timer(lambda: commands.log(ui, repo, rev=rev, date='', user='',
409 timer(lambda: commands.log(ui, repo, rev=rev, date='', user='',
411 template='{date|shortdate} [{rev}:{node|short}]'
410 template='{date|shortdate} [{rev}:{node|short}]'
412 ' {author|person}: {desc|firstline}\n'))
411 ' {author|person}: {desc|firstline}\n'))
413 ui.popbuffer()
412 ui.popbuffer()
414 fm.end()
413 fm.end()
415
414
416 @command('perfcca', formatteropts)
415 @command('perfcca', formatteropts)
417 def perfcca(ui, repo, **opts):
416 def perfcca(ui, repo, **opts):
418 timer, fm = gettimer(ui, opts)
417 timer, fm = gettimer(ui, opts)
419 timer(lambda: scmutil.casecollisionauditor(ui, False, repo.dirstate))
418 timer(lambda: scmutil.casecollisionauditor(ui, False, repo.dirstate))
420 fm.end()
419 fm.end()
421
420
422 @command('perffncacheload', formatteropts)
421 @command('perffncacheload', formatteropts)
423 def perffncacheload(ui, repo, **opts):
422 def perffncacheload(ui, repo, **opts):
424 timer, fm = gettimer(ui, opts)
423 timer, fm = gettimer(ui, opts)
425 s = repo.store
424 s = repo.store
426 def d():
425 def d():
427 s.fncache._load()
426 s.fncache._load()
428 timer(d)
427 timer(d)
429 fm.end()
428 fm.end()
430
429
431 @command('perffncachewrite', formatteropts)
430 @command('perffncachewrite', formatteropts)
432 def perffncachewrite(ui, repo, **opts):
431 def perffncachewrite(ui, repo, **opts):
433 timer, fm = gettimer(ui, opts)
432 timer, fm = gettimer(ui, opts)
434 s = repo.store
433 s = repo.store
435 s.fncache._load()
434 s.fncache._load()
436 lock = repo.lock()
435 lock = repo.lock()
437 tr = repo.transaction('perffncachewrite')
436 tr = repo.transaction('perffncachewrite')
438 def d():
437 def d():
439 s.fncache._dirty = True
438 s.fncache._dirty = True
440 s.fncache.write(tr)
439 s.fncache.write(tr)
441 timer(d)
440 timer(d)
442 lock.release()
441 lock.release()
443 fm.end()
442 fm.end()
444
443
445 @command('perffncacheencode', formatteropts)
444 @command('perffncacheencode', formatteropts)
446 def perffncacheencode(ui, repo, **opts):
445 def perffncacheencode(ui, repo, **opts):
447 timer, fm = gettimer(ui, opts)
446 timer, fm = gettimer(ui, opts)
448 s = repo.store
447 s = repo.store
449 s.fncache._load()
448 s.fncache._load()
450 def d():
449 def d():
451 for p in s.fncache.entries:
450 for p in s.fncache.entries:
452 s.encode(p)
451 s.encode(p)
453 timer(d)
452 timer(d)
454 fm.end()
453 fm.end()
455
454
456 @command('perfdiffwd', formatteropts)
455 @command('perfdiffwd', formatteropts)
457 def perfdiffwd(ui, repo, **opts):
456 def perfdiffwd(ui, repo, **opts):
458 """Profile diff of working directory changes"""
457 """Profile diff of working directory changes"""
459 timer, fm = gettimer(ui, opts)
458 timer, fm = gettimer(ui, opts)
460 options = {
459 options = {
461 'w': 'ignore_all_space',
460 'w': 'ignore_all_space',
462 'b': 'ignore_space_change',
461 'b': 'ignore_space_change',
463 'B': 'ignore_blank_lines',
462 'B': 'ignore_blank_lines',
464 }
463 }
465
464
466 for diffopt in ('', 'w', 'b', 'B', 'wB'):
465 for diffopt in ('', 'w', 'b', 'B', 'wB'):
467 opts = dict((options[c], '1') for c in diffopt)
466 opts = dict((options[c], '1') for c in diffopt)
468 def d():
467 def d():
469 ui.pushbuffer()
468 ui.pushbuffer()
470 commands.diff(ui, repo, **opts)
469 commands.diff(ui, repo, **opts)
471 ui.popbuffer()
470 ui.popbuffer()
472 title = 'diffopts: %s' % (diffopt and ('-' + diffopt) or 'none')
471 title = 'diffopts: %s' % (diffopt and ('-' + diffopt) or 'none')
473 timer(d, title)
472 timer(d, title)
474 fm.end()
473 fm.end()
475
474
476 @command('perfrevlog',
475 @command('perfrevlog',
477 [('d', 'dist', 100, 'distance between the revisions')] + formatteropts,
476 [('d', 'dist', 100, 'distance between the revisions')] + formatteropts,
478 "[INDEXFILE]")
477 "[INDEXFILE]")
479 def perfrevlog(ui, repo, file_, **opts):
478 def perfrevlog(ui, repo, file_, **opts):
480 timer, fm = gettimer(ui, opts)
479 timer, fm = gettimer(ui, opts)
481 from mercurial import revlog
480 from mercurial import revlog
482 dist = opts['dist']
481 dist = opts['dist']
483 _len = getlen(ui)
482 _len = getlen(ui)
484 def d():
483 def d():
485 r = revlog.revlog(lambda fn: open(fn, 'rb'), file_)
484 r = revlog.revlog(lambda fn: open(fn, 'rb'), file_)
486 for x in xrange(0, _len(r), dist):
485 for x in xrange(0, _len(r), dist):
487 r.revision(r.node(x))
486 r.revision(r.node(x))
488
487
489 timer(d)
488 timer(d)
490 fm.end()
489 fm.end()
491
490
492 @command('perfrevset',
491 @command('perfrevset',
493 [('C', 'clear', False, 'clear volatile cache between each call.'),
492 [('C', 'clear', False, 'clear volatile cache between each call.'),
494 ('', 'contexts', False, 'obtain changectx for each revision')]
493 ('', 'contexts', False, 'obtain changectx for each revision')]
495 + formatteropts, "REVSET")
494 + formatteropts, "REVSET")
496 def perfrevset(ui, repo, expr, clear=False, contexts=False, **opts):
495 def perfrevset(ui, repo, expr, clear=False, contexts=False, **opts):
497 """benchmark the execution time of a revset
496 """benchmark the execution time of a revset
498
497
499 Use the --clean option if need to evaluate the impact of build volatile
498 Use the --clean option if need to evaluate the impact of build volatile
500 revisions set cache on the revset execution. Volatile cache hold filtered
499 revisions set cache on the revset execution. Volatile cache hold filtered
501 and obsolete related cache."""
500 and obsolete related cache."""
502 timer, fm = gettimer(ui, opts)
501 timer, fm = gettimer(ui, opts)
503 def d():
502 def d():
504 if clear:
503 if clear:
505 repo.invalidatevolatilesets()
504 repo.invalidatevolatilesets()
506 if contexts:
505 if contexts:
507 for ctx in repo.set(expr): pass
506 for ctx in repo.set(expr): pass
508 else:
507 else:
509 for r in repo.revs(expr): pass
508 for r in repo.revs(expr): pass
510 timer(d)
509 timer(d)
511 fm.end()
510 fm.end()
512
511
513 @command('perfvolatilesets', formatteropts)
512 @command('perfvolatilesets', formatteropts)
514 def perfvolatilesets(ui, repo, *names, **opts):
513 def perfvolatilesets(ui, repo, *names, **opts):
515 """benchmark the computation of various volatile set
514 """benchmark the computation of various volatile set
516
515
517 Volatile set computes element related to filtering and obsolescence."""
516 Volatile set computes element related to filtering and obsolescence."""
518 timer, fm = gettimer(ui, opts)
517 timer, fm = gettimer(ui, opts)
519 repo = repo.unfiltered()
518 repo = repo.unfiltered()
520
519
521 def getobs(name):
520 def getobs(name):
522 def d():
521 def d():
523 repo.invalidatevolatilesets()
522 repo.invalidatevolatilesets()
524 obsolete.getrevs(repo, name)
523 obsolete.getrevs(repo, name)
525 return d
524 return d
526
525
527 allobs = sorted(obsolete.cachefuncs)
526 allobs = sorted(obsolete.cachefuncs)
528 if names:
527 if names:
529 allobs = [n for n in allobs if n in names]
528 allobs = [n for n in allobs if n in names]
530
529
531 for name in allobs:
530 for name in allobs:
532 timer(getobs(name), title=name)
531 timer(getobs(name), title=name)
533
532
534 def getfiltered(name):
533 def getfiltered(name):
535 def d():
534 def d():
536 repo.invalidatevolatilesets()
535 repo.invalidatevolatilesets()
537 repoview.filterrevs(repo, name)
536 repoview.filterrevs(repo, name)
538 return d
537 return d
539
538
540 allfilter = sorted(repoview.filtertable)
539 allfilter = sorted(repoview.filtertable)
541 if names:
540 if names:
542 allfilter = [n for n in allfilter if n in names]
541 allfilter = [n for n in allfilter if n in names]
543
542
544 for name in allfilter:
543 for name in allfilter:
545 timer(getfiltered(name), title=name)
544 timer(getfiltered(name), title=name)
546 fm.end()
545 fm.end()
547
546
548 @command('perfbranchmap',
547 @command('perfbranchmap',
549 [('f', 'full', False,
548 [('f', 'full', False,
550 'Includes build time of subset'),
549 'Includes build time of subset'),
551 ] + formatteropts)
550 ] + formatteropts)
552 def perfbranchmap(ui, repo, full=False, **opts):
551 def perfbranchmap(ui, repo, full=False, **opts):
553 """benchmark the update of a branchmap
552 """benchmark the update of a branchmap
554
553
555 This benchmarks the full repo.branchmap() call with read and write disabled
554 This benchmarks the full repo.branchmap() call with read and write disabled
556 """
555 """
557 timer, fm = gettimer(ui, opts)
556 timer, fm = gettimer(ui, opts)
558 def getbranchmap(filtername):
557 def getbranchmap(filtername):
559 """generate a benchmark function for the filtername"""
558 """generate a benchmark function for the filtername"""
560 if filtername is None:
559 if filtername is None:
561 view = repo
560 view = repo
562 else:
561 else:
563 view = repo.filtered(filtername)
562 view = repo.filtered(filtername)
564 def d():
563 def d():
565 if full:
564 if full:
566 view._branchcaches.clear()
565 view._branchcaches.clear()
567 else:
566 else:
568 view._branchcaches.pop(filtername, None)
567 view._branchcaches.pop(filtername, None)
569 view.branchmap()
568 view.branchmap()
570 return d
569 return d
571 # add filter in smaller subset to bigger subset
570 # add filter in smaller subset to bigger subset
572 possiblefilters = set(repoview.filtertable)
571 possiblefilters = set(repoview.filtertable)
573 allfilters = []
572 allfilters = []
574 while possiblefilters:
573 while possiblefilters:
575 for name in possiblefilters:
574 for name in possiblefilters:
576 subset = branchmap.subsettable.get(name)
575 subset = branchmap.subsettable.get(name)
577 if subset not in possiblefilters:
576 if subset not in possiblefilters:
578 break
577 break
579 else:
578 else:
580 assert False, 'subset cycle %s!' % possiblefilters
579 assert False, 'subset cycle %s!' % possiblefilters
581 allfilters.append(name)
580 allfilters.append(name)
582 possiblefilters.remove(name)
581 possiblefilters.remove(name)
583
582
584 # warm the cache
583 # warm the cache
585 if not full:
584 if not full:
586 for name in allfilters:
585 for name in allfilters:
587 repo.filtered(name).branchmap()
586 repo.filtered(name).branchmap()
588 # add unfiltered
587 # add unfiltered
589 allfilters.append(None)
588 allfilters.append(None)
590 oldread = branchmap.read
589 oldread = branchmap.read
591 oldwrite = branchmap.branchcache.write
590 oldwrite = branchmap.branchcache.write
592 try:
591 try:
593 branchmap.read = lambda repo: None
592 branchmap.read = lambda repo: None
594 branchmap.write = lambda repo: None
593 branchmap.write = lambda repo: None
595 for name in allfilters:
594 for name in allfilters:
596 timer(getbranchmap(name), title=str(name))
595 timer(getbranchmap(name), title=str(name))
597 finally:
596 finally:
598 branchmap.read = oldread
597 branchmap.read = oldread
599 branchmap.branchcache.write = oldwrite
598 branchmap.branchcache.write = oldwrite
600 fm.end()
599 fm.end()
601
600
602 @command('perfloadmarkers')
601 @command('perfloadmarkers')
603 def perfloadmarkers(ui, repo):
602 def perfloadmarkers(ui, repo):
604 """benchmark the time to parse the on-disk markers for a repo
603 """benchmark the time to parse the on-disk markers for a repo
605
604
606 Result is the number of markers in the repo."""
605 Result is the number of markers in the repo."""
607 timer, fm = gettimer(ui)
606 timer, fm = gettimer(ui)
608 timer(lambda: len(obsolete.obsstore(repo.svfs)))
607 timer(lambda: len(obsolete.obsstore(repo.svfs)))
609 fm.end()
608 fm.end()
610
609
611 @command('perflrucachedict', formatteropts +
610 @command('perflrucachedict', formatteropts +
612 [('', 'size', 4, 'size of cache'),
611 [('', 'size', 4, 'size of cache'),
613 ('', 'gets', 10000, 'number of key lookups'),
612 ('', 'gets', 10000, 'number of key lookups'),
614 ('', 'sets', 10000, 'number of key sets'),
613 ('', 'sets', 10000, 'number of key sets'),
615 ('', 'mixed', 10000, 'number of mixed mode operations'),
614 ('', 'mixed', 10000, 'number of mixed mode operations'),
616 ('', 'mixedgetfreq', 50, 'frequency of get vs set ops in mixed mode')],
615 ('', 'mixedgetfreq', 50, 'frequency of get vs set ops in mixed mode')],
617 norepo=True)
616 norepo=True)
618 def perflrucache(ui, size=4, gets=10000, sets=10000, mixed=10000,
617 def perflrucache(ui, size=4, gets=10000, sets=10000, mixed=10000,
619 mixedgetfreq=50, **opts):
618 mixedgetfreq=50, **opts):
620 def doinit():
619 def doinit():
621 for i in xrange(10000):
620 for i in xrange(10000):
622 util.lrucachedict(size)
621 util.lrucachedict(size)
623
622
624 values = []
623 values = []
625 for i in xrange(size):
624 for i in xrange(size):
626 values.append(random.randint(0, sys.maxint))
625 values.append(random.randint(0, sys.maxint))
627
626
628 # Get mode fills the cache and tests raw lookup performance with no
627 # Get mode fills the cache and tests raw lookup performance with no
629 # eviction.
628 # eviction.
630 getseq = []
629 getseq = []
631 for i in xrange(gets):
630 for i in xrange(gets):
632 getseq.append(random.choice(values))
631 getseq.append(random.choice(values))
633
632
634 def dogets():
633 def dogets():
635 d = util.lrucachedict(size)
634 d = util.lrucachedict(size)
636 for v in values:
635 for v in values:
637 d[v] = v
636 d[v] = v
638 for key in getseq:
637 for key in getseq:
639 value = d[key]
638 value = d[key]
640 value # silence pyflakes warning
639 value # silence pyflakes warning
641
640
642 # Set mode tests insertion speed with cache eviction.
641 # Set mode tests insertion speed with cache eviction.
643 setseq = []
642 setseq = []
644 for i in xrange(sets):
643 for i in xrange(sets):
645 setseq.append(random.randint(0, sys.maxint))
644 setseq.append(random.randint(0, sys.maxint))
646
645
647 def dosets():
646 def dosets():
648 d = util.lrucachedict(size)
647 d = util.lrucachedict(size)
649 for v in setseq:
648 for v in setseq:
650 d[v] = v
649 d[v] = v
651
650
652 # Mixed mode randomly performs gets and sets with eviction.
651 # Mixed mode randomly performs gets and sets with eviction.
653 mixedops = []
652 mixedops = []
654 for i in xrange(mixed):
653 for i in xrange(mixed):
655 r = random.randint(0, 100)
654 r = random.randint(0, 100)
656 if r < mixedgetfreq:
655 if r < mixedgetfreq:
657 op = 0
656 op = 0
658 else:
657 else:
659 op = 1
658 op = 1
660
659
661 mixedops.append((op, random.randint(0, size * 2)))
660 mixedops.append((op, random.randint(0, size * 2)))
662
661
663 def domixed():
662 def domixed():
664 d = util.lrucachedict(size)
663 d = util.lrucachedict(size)
665
664
666 for op, v in mixedops:
665 for op, v in mixedops:
667 if op == 0:
666 if op == 0:
668 try:
667 try:
669 d[v]
668 d[v]
670 except KeyError:
669 except KeyError:
671 pass
670 pass
672 else:
671 else:
673 d[v] = v
672 d[v] = v
674
673
675 benches = [
674 benches = [
676 (doinit, 'init'),
675 (doinit, 'init'),
677 (dogets, 'gets'),
676 (dogets, 'gets'),
678 (dosets, 'sets'),
677 (dosets, 'sets'),
679 (domixed, 'mixed')
678 (domixed, 'mixed')
680 ]
679 ]
681
680
682 for fn, title in benches:
681 for fn, title in benches:
683 timer, fm = gettimer(ui, opts)
682 timer, fm = gettimer(ui, opts)
684 timer(fn, title=title)
683 timer(fn, title=title)
685 fm.end()
684 fm.end()
General Comments 0
You need to be logged in to leave comments. Login now