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