##// END OF EJS Templates
perf: add perfbranchmap command...
Pierre-Yves David -
r18304:9b6ae29d default
parent child Browse files
Show More
@@ -1,311 +1,366 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, match, commands, obsolete
4 from mercurial import cmdutil, scmutil, util, match, commands, obsolete
5 from mercurial import repoview
5 from mercurial import repoview, branchmap
6 import time, os, sys
6 import time, os, sys
7
7
8 cmdtable = {}
8 cmdtable = {}
9 command = cmdutil.command(cmdtable)
9 command = cmdutil.command(cmdtable)
10
10
11 def timer(func, title=None):
11 def timer(func, title=None):
12 results = []
12 results = []
13 begin = time.time()
13 begin = time.time()
14 count = 0
14 count = 0
15 while True:
15 while True:
16 ostart = os.times()
16 ostart = os.times()
17 cstart = time.time()
17 cstart = time.time()
18 r = func()
18 r = func()
19 cstop = time.time()
19 cstop = time.time()
20 ostop = os.times()
20 ostop = os.times()
21 count += 1
21 count += 1
22 a, b = ostart, ostop
22 a, b = ostart, ostop
23 results.append((cstop - cstart, b[0] - a[0], b[1]-a[1]))
23 results.append((cstop - cstart, b[0] - a[0], b[1]-a[1]))
24 if cstop - begin > 3 and count >= 100:
24 if cstop - begin > 3 and count >= 100:
25 break
25 break
26 if cstop - begin > 10 and count >= 3:
26 if cstop - begin > 10 and count >= 3:
27 break
27 break
28 if title:
28 if title:
29 sys.stderr.write("! %s\n" % title)
29 sys.stderr.write("! %s\n" % title)
30 if r:
30 if r:
31 sys.stderr.write("! result: %s\n" % r)
31 sys.stderr.write("! result: %s\n" % r)
32 m = min(results)
32 m = min(results)
33 sys.stderr.write("! wall %f comb %f user %f sys %f (best of %d)\n"
33 sys.stderr.write("! wall %f comb %f user %f sys %f (best of %d)\n"
34 % (m[0], m[1] + m[2], m[1], m[2], count))
34 % (m[0], m[1] + m[2], m[1], m[2], count))
35
35
36 @command('perfwalk')
36 @command('perfwalk')
37 def perfwalk(ui, repo, *pats):
37 def perfwalk(ui, repo, *pats):
38 try:
38 try:
39 m = scmutil.match(repo[None], pats, {})
39 m = scmutil.match(repo[None], pats, {})
40 timer(lambda: len(list(repo.dirstate.walk(m, [], True, False))))
40 timer(lambda: len(list(repo.dirstate.walk(m, [], True, False))))
41 except Exception:
41 except Exception:
42 try:
42 try:
43 m = scmutil.match(repo[None], pats, {})
43 m = scmutil.match(repo[None], pats, {})
44 timer(lambda: len([b for a, b, c in repo.dirstate.statwalk([], m)]))
44 timer(lambda: len([b for a, b, c in repo.dirstate.statwalk([], m)]))
45 except Exception:
45 except Exception:
46 timer(lambda: len(list(cmdutil.walk(repo, pats, {}))))
46 timer(lambda: len(list(cmdutil.walk(repo, pats, {}))))
47
47
48 @command('perfstatus',
48 @command('perfstatus',
49 [('u', 'unknown', False,
49 [('u', 'unknown', False,
50 'ask status to look for unknown files')])
50 'ask status to look for unknown files')])
51 def perfstatus(ui, repo, **opts):
51 def perfstatus(ui, repo, **opts):
52 #m = match.always(repo.root, repo.getcwd())
52 #m = match.always(repo.root, repo.getcwd())
53 #timer(lambda: sum(map(len, repo.dirstate.status(m, [], False, False,
53 #timer(lambda: sum(map(len, repo.dirstate.status(m, [], False, False,
54 # False))))
54 # False))))
55 timer(lambda: sum(map(len, repo.status(**opts))))
55 timer(lambda: sum(map(len, repo.status(**opts))))
56
56
57 def clearcaches(cl):
57 def clearcaches(cl):
58 # behave somewhat consistently across internal API changes
58 # behave somewhat consistently across internal API changes
59 if util.safehasattr(cl, 'clearcaches'):
59 if util.safehasattr(cl, 'clearcaches'):
60 cl.clearcaches()
60 cl.clearcaches()
61 elif util.safehasattr(cl, '_nodecache'):
61 elif util.safehasattr(cl, '_nodecache'):
62 from mercurial.node import nullid, nullrev
62 from mercurial.node import nullid, nullrev
63 cl._nodecache = {nullid: nullrev}
63 cl._nodecache = {nullid: nullrev}
64 cl._nodepos = None
64 cl._nodepos = None
65
65
66 @command('perfheads')
66 @command('perfheads')
67 def perfheads(ui, repo):
67 def perfheads(ui, repo):
68 cl = repo.changelog
68 cl = repo.changelog
69 def d():
69 def d():
70 len(cl.headrevs())
70 len(cl.headrevs())
71 clearcaches(cl)
71 clearcaches(cl)
72 timer(d)
72 timer(d)
73
73
74 @command('perftags')
74 @command('perftags')
75 def perftags(ui, repo):
75 def perftags(ui, repo):
76 import mercurial.changelog, mercurial.manifest
76 import mercurial.changelog, mercurial.manifest
77 def t():
77 def t():
78 repo.changelog = mercurial.changelog.changelog(repo.sopener)
78 repo.changelog = mercurial.changelog.changelog(repo.sopener)
79 repo.manifest = mercurial.manifest.manifest(repo.sopener)
79 repo.manifest = mercurial.manifest.manifest(repo.sopener)
80 repo._tags = None
80 repo._tags = None
81 return len(repo.tags())
81 return len(repo.tags())
82 timer(t)
82 timer(t)
83
83
84 @command('perfancestors')
84 @command('perfancestors')
85 def perfancestors(ui, repo):
85 def perfancestors(ui, repo):
86 heads = repo.changelog.headrevs()
86 heads = repo.changelog.headrevs()
87 def d():
87 def d():
88 for a in repo.changelog.ancestors(heads):
88 for a in repo.changelog.ancestors(heads):
89 pass
89 pass
90 timer(d)
90 timer(d)
91
91
92 @command('perfancestorset')
92 @command('perfancestorset')
93 def perfancestorset(ui, repo, revset):
93 def perfancestorset(ui, repo, revset):
94 revs = repo.revs(revset)
94 revs = repo.revs(revset)
95 heads = repo.changelog.headrevs()
95 heads = repo.changelog.headrevs()
96 def d():
96 def d():
97 s = repo.changelog.ancestors(heads)
97 s = repo.changelog.ancestors(heads)
98 for rev in revs:
98 for rev in revs:
99 rev in s
99 rev in s
100 timer(d)
100 timer(d)
101
101
102 @command('perfdirstate')
102 @command('perfdirstate')
103 def perfdirstate(ui, repo):
103 def perfdirstate(ui, repo):
104 "a" in repo.dirstate
104 "a" in repo.dirstate
105 def d():
105 def d():
106 repo.dirstate.invalidate()
106 repo.dirstate.invalidate()
107 "a" in repo.dirstate
107 "a" in repo.dirstate
108 timer(d)
108 timer(d)
109
109
110 @command('perfdirstatedirs')
110 @command('perfdirstatedirs')
111 def perfdirstatedirs(ui, repo):
111 def perfdirstatedirs(ui, repo):
112 "a" in repo.dirstate
112 "a" in repo.dirstate
113 def d():
113 def d():
114 "a" in repo.dirstate._dirs
114 "a" in repo.dirstate._dirs
115 del repo.dirstate._dirs
115 del repo.dirstate._dirs
116 timer(d)
116 timer(d)
117
117
118 @command('perfdirstatewrite')
118 @command('perfdirstatewrite')
119 def perfdirstatewrite(ui, repo):
119 def perfdirstatewrite(ui, repo):
120 ds = repo.dirstate
120 ds = repo.dirstate
121 "a" in ds
121 "a" in ds
122 def d():
122 def d():
123 ds._dirty = True
123 ds._dirty = True
124 ds.write()
124 ds.write()
125 timer(d)
125 timer(d)
126
126
127 @command('perfmanifest')
127 @command('perfmanifest')
128 def perfmanifest(ui, repo):
128 def perfmanifest(ui, repo):
129 def d():
129 def d():
130 t = repo.manifest.tip()
130 t = repo.manifest.tip()
131 m = repo.manifest.read(t)
131 m = repo.manifest.read(t)
132 repo.manifest.mapcache = None
132 repo.manifest.mapcache = None
133 repo.manifest._cache = None
133 repo.manifest._cache = None
134 timer(d)
134 timer(d)
135
135
136 @command('perfchangeset')
136 @command('perfchangeset')
137 def perfchangeset(ui, repo, rev):
137 def perfchangeset(ui, repo, rev):
138 n = repo[rev].node()
138 n = repo[rev].node()
139 def d():
139 def d():
140 c = repo.changelog.read(n)
140 c = repo.changelog.read(n)
141 #repo.changelog._cache = None
141 #repo.changelog._cache = None
142 timer(d)
142 timer(d)
143
143
144 @command('perfindex')
144 @command('perfindex')
145 def perfindex(ui, repo):
145 def perfindex(ui, repo):
146 import mercurial.revlog
146 import mercurial.revlog
147 mercurial.revlog._prereadsize = 2**24 # disable lazy parser in old hg
147 mercurial.revlog._prereadsize = 2**24 # disable lazy parser in old hg
148 n = repo["tip"].node()
148 n = repo["tip"].node()
149 def d():
149 def d():
150 cl = mercurial.revlog.revlog(repo.sopener, "00changelog.i")
150 cl = mercurial.revlog.revlog(repo.sopener, "00changelog.i")
151 cl.rev(n)
151 cl.rev(n)
152 timer(d)
152 timer(d)
153
153
154 @command('perfstartup')
154 @command('perfstartup')
155 def perfstartup(ui, repo):
155 def perfstartup(ui, repo):
156 cmd = sys.argv[0]
156 cmd = sys.argv[0]
157 def d():
157 def d():
158 os.system("HGRCPATH= %s version -q > /dev/null" % cmd)
158 os.system("HGRCPATH= %s version -q > /dev/null" % cmd)
159 timer(d)
159 timer(d)
160
160
161 @command('perfparents')
161 @command('perfparents')
162 def perfparents(ui, repo):
162 def perfparents(ui, repo):
163 nl = [repo.changelog.node(i) for i in xrange(1000)]
163 nl = [repo.changelog.node(i) for i in xrange(1000)]
164 def d():
164 def d():
165 for n in nl:
165 for n in nl:
166 repo.changelog.parents(n)
166 repo.changelog.parents(n)
167 timer(d)
167 timer(d)
168
168
169 @command('perflookup')
169 @command('perflookup')
170 def perflookup(ui, repo, rev):
170 def perflookup(ui, repo, rev):
171 timer(lambda: len(repo.lookup(rev)))
171 timer(lambda: len(repo.lookup(rev)))
172
172
173 @command('perfrevrange')
173 @command('perfrevrange')
174 def perfrevrange(ui, repo, *specs):
174 def perfrevrange(ui, repo, *specs):
175 revrange = scmutil.revrange
175 revrange = scmutil.revrange
176 timer(lambda: len(revrange(repo, specs)))
176 timer(lambda: len(revrange(repo, specs)))
177
177
178 @command('perfnodelookup')
178 @command('perfnodelookup')
179 def perfnodelookup(ui, repo, rev):
179 def perfnodelookup(ui, repo, rev):
180 import mercurial.revlog
180 import mercurial.revlog
181 mercurial.revlog._prereadsize = 2**24 # disable lazy parser in old hg
181 mercurial.revlog._prereadsize = 2**24 # disable lazy parser in old hg
182 n = repo[rev].node()
182 n = repo[rev].node()
183 cl = mercurial.revlog.revlog(repo.sopener, "00changelog.i")
183 cl = mercurial.revlog.revlog(repo.sopener, "00changelog.i")
184 def d():
184 def d():
185 cl.rev(n)
185 cl.rev(n)
186 clearcaches(cl)
186 clearcaches(cl)
187 timer(d)
187 timer(d)
188
188
189 @command('perflog',
189 @command('perflog',
190 [('', 'rename', False, 'ask log to follow renames')])
190 [('', 'rename', False, 'ask log to follow renames')])
191 def perflog(ui, repo, **opts):
191 def perflog(ui, repo, **opts):
192 ui.pushbuffer()
192 ui.pushbuffer()
193 timer(lambda: commands.log(ui, repo, rev=[], date='', user='',
193 timer(lambda: commands.log(ui, repo, rev=[], date='', user='',
194 copies=opts.get('rename')))
194 copies=opts.get('rename')))
195 ui.popbuffer()
195 ui.popbuffer()
196
196
197 @command('perftemplating')
197 @command('perftemplating')
198 def perftemplating(ui, repo):
198 def perftemplating(ui, repo):
199 ui.pushbuffer()
199 ui.pushbuffer()
200 timer(lambda: commands.log(ui, repo, rev=[], date='', user='',
200 timer(lambda: commands.log(ui, repo, rev=[], date='', user='',
201 template='{date|shortdate} [{rev}:{node|short}]'
201 template='{date|shortdate} [{rev}:{node|short}]'
202 ' {author|person}: {desc|firstline}\n'))
202 ' {author|person}: {desc|firstline}\n'))
203 ui.popbuffer()
203 ui.popbuffer()
204
204
205 @command('perfcca')
205 @command('perfcca')
206 def perfcca(ui, repo):
206 def perfcca(ui, repo):
207 timer(lambda: scmutil.casecollisionauditor(ui, False, repo.dirstate))
207 timer(lambda: scmutil.casecollisionauditor(ui, False, repo.dirstate))
208
208
209 @command('perffncacheload')
209 @command('perffncacheload')
210 def perffncacheload(ui, repo):
210 def perffncacheload(ui, repo):
211 s = repo.store
211 s = repo.store
212 def d():
212 def d():
213 s.fncache._load()
213 s.fncache._load()
214 timer(d)
214 timer(d)
215
215
216 @command('perffncachewrite')
216 @command('perffncachewrite')
217 def perffncachewrite(ui, repo):
217 def perffncachewrite(ui, repo):
218 s = repo.store
218 s = repo.store
219 s.fncache._load()
219 s.fncache._load()
220 def d():
220 def d():
221 s.fncache._dirty = True
221 s.fncache._dirty = True
222 s.fncache.write()
222 s.fncache.write()
223 timer(d)
223 timer(d)
224
224
225 @command('perffncacheencode')
225 @command('perffncacheencode')
226 def perffncacheencode(ui, repo):
226 def perffncacheencode(ui, repo):
227 s = repo.store
227 s = repo.store
228 s.fncache._load()
228 s.fncache._load()
229 def d():
229 def d():
230 for p in s.fncache.entries:
230 for p in s.fncache.entries:
231 s.encode(p)
231 s.encode(p)
232 timer(d)
232 timer(d)
233
233
234 @command('perfdiffwd')
234 @command('perfdiffwd')
235 def perfdiffwd(ui, repo):
235 def perfdiffwd(ui, repo):
236 """Profile diff of working directory changes"""
236 """Profile diff of working directory changes"""
237 options = {
237 options = {
238 'w': 'ignore_all_space',
238 'w': 'ignore_all_space',
239 'b': 'ignore_space_change',
239 'b': 'ignore_space_change',
240 'B': 'ignore_blank_lines',
240 'B': 'ignore_blank_lines',
241 }
241 }
242
242
243 for diffopt in ('', 'w', 'b', 'B', 'wB'):
243 for diffopt in ('', 'w', 'b', 'B', 'wB'):
244 opts = dict((options[c], '1') for c in diffopt)
244 opts = dict((options[c], '1') for c in diffopt)
245 def d():
245 def d():
246 ui.pushbuffer()
246 ui.pushbuffer()
247 commands.diff(ui, repo, **opts)
247 commands.diff(ui, repo, **opts)
248 ui.popbuffer()
248 ui.popbuffer()
249 title = 'diffopts: %s' % (diffopt and ('-' + diffopt) or 'none')
249 title = 'diffopts: %s' % (diffopt and ('-' + diffopt) or 'none')
250 timer(d, title)
250 timer(d, title)
251
251
252 @command('perfrevlog',
252 @command('perfrevlog',
253 [('d', 'dist', 100, 'distance between the revisions')],
253 [('d', 'dist', 100, 'distance between the revisions')],
254 "[INDEXFILE]")
254 "[INDEXFILE]")
255 def perfrevlog(ui, repo, file_, **opts):
255 def perfrevlog(ui, repo, file_, **opts):
256 from mercurial import revlog
256 from mercurial import revlog
257 dist = opts['dist']
257 dist = opts['dist']
258 def d():
258 def d():
259 r = revlog.revlog(lambda fn: open(fn, 'rb'), file_)
259 r = revlog.revlog(lambda fn: open(fn, 'rb'), file_)
260 for x in xrange(0, len(r), dist):
260 for x in xrange(0, len(r), dist):
261 r.revision(r.node(x))
261 r.revision(r.node(x))
262
262
263 timer(d)
263 timer(d)
264
264
265 @command('perfrevset',
265 @command('perfrevset',
266 [('C', 'clear', False, 'clear volatile cache between each call.')],
266 [('C', 'clear', False, 'clear volatile cache between each call.')],
267 "REVSET")
267 "REVSET")
268 def perfrevset(ui, repo, expr, clear=False):
268 def perfrevset(ui, repo, expr, clear=False):
269 """benchmark the execution time of a revset
269 """benchmark the execution time of a revset
270
270
271 Use the --clean option if need to evaluate the impact of build volative
271 Use the --clean option if need to evaluate the impact of build volative
272 revisions set cache on the revset execution. Volatile cache hold filtered
272 revisions set cache on the revset execution. Volatile cache hold filtered
273 and obsolete related cache."""
273 and obsolete related cache."""
274 def d():
274 def d():
275 if clear:
275 if clear:
276 repo.invalidatevolatilesets()
276 repo.invalidatevolatilesets()
277 repo.revs(expr)
277 repo.revs(expr)
278 timer(d)
278 timer(d)
279
279
280 @command('perfvolatilesets')
280 @command('perfvolatilesets')
281 def perfvolatilesets(ui, repo, *names):
281 def perfvolatilesets(ui, repo, *names):
282 """benchmark the computation of various volatile set
282 """benchmark the computation of various volatile set
283
283
284 Volatile set computes element related to filtering and obsolescence."""
284 Volatile set computes element related to filtering and obsolescence."""
285 repo = repo.unfiltered()
285 repo = repo.unfiltered()
286
286
287 def getobs(name):
287 def getobs(name):
288 def d():
288 def d():
289 repo.invalidatevolatilesets()
289 repo.invalidatevolatilesets()
290 obsolete.getrevs(repo, name)
290 obsolete.getrevs(repo, name)
291 return d
291 return d
292
292
293 allobs = sorted(obsolete.cachefuncs)
293 allobs = sorted(obsolete.cachefuncs)
294 if names:
294 if names:
295 allobs = [n for n in allobs if n in names]
295 allobs = [n for n in allobs if n in names]
296
296
297 for name in allobs:
297 for name in allobs:
298 timer(getobs(name), title=name)
298 timer(getobs(name), title=name)
299
299
300 def getfiltered(name):
300 def getfiltered(name):
301 def d():
301 def d():
302 repo.invalidatevolatilesets()
302 repo.invalidatevolatilesets()
303 repoview.filteredrevs(repo, name)
303 repoview.filteredrevs(repo, name)
304 return d
304 return d
305
305
306 allfilter = sorted(repoview.filtertable)
306 allfilter = sorted(repoview.filtertable)
307 if names:
307 if names:
308 allfilter = [n for n in allfilter if n in names]
308 allfilter = [n for n in allfilter if n in names]
309
309
310 for name in allfilter:
310 for name in allfilter:
311 timer(getfiltered(name), title=name)
311 timer(getfiltered(name), title=name)
312
313 @command('perfbranchmap',
314 [('f', 'full', False,
315 'Includes build time of subset'),
316 ])
317 def perfbranchmap(ui, repo, full=False):
318 """benchmark the update of a branchmap
319
320 This benchmarks the full repo.branchmap() call with read and write disabled
321 """
322 def getbranchmap(filtername):
323 """generate a benchmark function for the filtername"""
324 if filtername is None:
325 view = repo
326 else:
327 view = repo.filtered(filtername)
328 def d():
329 if full:
330 view._branchcaches.clear()
331 else:
332 view._branchcaches.pop(filtername, None)
333 view.branchmap()
334 return d
335 # add filter in smaller subset to bigger subset
336 possiblefilters = set(repoview.filtertable)
337 allfilters = []
338 while possiblefilters:
339 for name in possiblefilters:
340 subset = repoview.subsettable.get(name)
341 if subset not in possiblefilters:
342 break
343 else:
344 assert False, 'subset cycle %s!' % possiblefilters
345 allfilters.append(name)
346 possiblefilters.remove(name)
347
348 # warm the cache
349 if not full:
350 for name in allfilters:
351 repo.filtered(name).branchmap()
352 # add unfiltered
353 allfilters.append(None)
354 oldread = branchmap.read
355 oldwrite = branchmap.branchcache.write
356 try:
357 branchmap.read = lambda repo: None
358 branchmap.write = lambda repo: None
359 for name in allfilters:
360 timer(getbranchmap(name), title=str(name))
361 finally:
362 branchmap.read = oldread
363 branchmap.branchcache.write = oldwrite
364
365
366
General Comments 0
You need to be logged in to leave comments. Login now