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