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