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