##// END OF EJS Templates
perf: add command for measuring revlog chunk operations...
Gregory Szorc -
r30451:94ca0e13 default
parent child Browse files
Show More
@@ -1,1163 +1,1241
1 1 # perf.py - performance test routines
2 2 '''helper extension to measure performance'''
3 3
4 4 # "historical portability" policy of perf.py:
5 5 #
6 6 # We have to do:
7 7 # - make perf.py "loadable" with as wide Mercurial version as possible
8 8 # This doesn't mean that perf commands work correctly with that Mercurial.
9 9 # BTW, perf.py itself has been available since 1.1 (or eb240755386d).
10 10 # - make historical perf command work correctly with as wide Mercurial
11 11 # version as possible
12 12 #
13 13 # We have to do, if possible with reasonable cost:
14 14 # - make recent perf command for historical feature work correctly
15 15 # with early Mercurial
16 16 #
17 17 # We don't have to do:
18 18 # - make perf command for recent feature work correctly with early
19 19 # Mercurial
20 20
21 21 from __future__ import absolute_import
22 22 import functools
23 23 import os
24 24 import random
25 25 import sys
26 26 import time
27 27 from mercurial import (
28 28 bdiff,
29 29 changegroup,
30 30 cmdutil,
31 31 commands,
32 32 copies,
33 33 error,
34 34 extensions,
35 35 mdiff,
36 36 merge,
37 37 revlog,
38 38 util,
39 39 )
40 40
41 41 # for "historical portability":
42 42 # try to import modules separately (in dict order), and ignore
43 43 # failure, because these aren't available with early Mercurial
44 44 try:
45 45 from mercurial import branchmap # since 2.5 (or bcee63733aad)
46 46 except ImportError:
47 47 pass
48 48 try:
49 49 from mercurial import obsolete # since 2.3 (or ad0d6c2b3279)
50 50 except ImportError:
51 51 pass
52 52 try:
53 53 from mercurial import repoview # since 2.5 (or 3a6ddacb7198)
54 54 except ImportError:
55 55 pass
56 56 try:
57 57 from mercurial import scmutil # since 1.9 (or 8b252e826c68)
58 58 except ImportError:
59 59 pass
60 60
61 61 # for "historical portability":
62 62 # define util.safehasattr forcibly, because util.safehasattr has been
63 63 # available since 1.9.3 (or 94b200a11cf7)
64 64 _undefined = object()
65 65 def safehasattr(thing, attr):
66 66 return getattr(thing, attr, _undefined) is not _undefined
67 67 setattr(util, 'safehasattr', safehasattr)
68 68
69 69 # for "historical portability":
70 70 # use locally defined empty option list, if formatteropts isn't
71 71 # available, because commands.formatteropts has been available since
72 72 # 3.2 (or 7a7eed5176a4), even though formatting itself has been
73 73 # available since 2.2 (or ae5f92e154d3)
74 74 formatteropts = getattr(commands, "formatteropts", [])
75 75
76 76 # for "historical portability":
77 77 # use locally defined option list, if debugrevlogopts isn't available,
78 78 # because commands.debugrevlogopts has been available since 3.7 (or
79 79 # 5606f7d0d063), even though cmdutil.openrevlog() has been available
80 80 # since 1.9 (or a79fea6b3e77).
81 81 revlogopts = getattr(commands, "debugrevlogopts", [
82 82 ('c', 'changelog', False, ('open changelog')),
83 83 ('m', 'manifest', False, ('open manifest')),
84 84 ('', 'dir', False, ('open directory manifest')),
85 85 ])
86 86
87 87 cmdtable = {}
88 88
89 89 # for "historical portability":
90 90 # define parsealiases locally, because cmdutil.parsealiases has been
91 91 # available since 1.5 (or 6252852b4332)
92 92 def parsealiases(cmd):
93 93 return cmd.lstrip("^").split("|")
94 94
95 95 if safehasattr(cmdutil, 'command'):
96 96 import inspect
97 97 command = cmdutil.command(cmdtable)
98 98 if 'norepo' not in inspect.getargspec(command)[0]:
99 99 # for "historical portability":
100 100 # wrap original cmdutil.command, because "norepo" option has
101 101 # been available since 3.1 (or 75a96326cecb)
102 102 _command = command
103 103 def command(name, options=(), synopsis=None, norepo=False):
104 104 if norepo:
105 105 commands.norepo += ' %s' % ' '.join(parsealiases(name))
106 106 return _command(name, list(options), synopsis)
107 107 else:
108 108 # for "historical portability":
109 109 # define "@command" annotation locally, because cmdutil.command
110 110 # has been available since 1.9 (or 2daa5179e73f)
111 111 def command(name, options=(), synopsis=None, norepo=False):
112 112 def decorator(func):
113 113 if synopsis:
114 114 cmdtable[name] = func, list(options), synopsis
115 115 else:
116 116 cmdtable[name] = func, list(options)
117 117 if norepo:
118 118 commands.norepo += ' %s' % ' '.join(parsealiases(name))
119 119 return func
120 120 return decorator
121 121
122 122 def getlen(ui):
123 123 if ui.configbool("perf", "stub"):
124 124 return lambda x: 1
125 125 return len
126 126
127 127 def gettimer(ui, opts=None):
128 128 """return a timer function and formatter: (timer, formatter)
129 129
130 130 This function exists to gather the creation of formatter in a single
131 131 place instead of duplicating it in all performance commands."""
132 132
133 133 # enforce an idle period before execution to counteract power management
134 134 # experimental config: perf.presleep
135 135 time.sleep(getint(ui, "perf", "presleep", 1))
136 136
137 137 if opts is None:
138 138 opts = {}
139 139 # redirect all to stderr unless buffer api is in use
140 140 if not ui._buffers:
141 141 ui = ui.copy()
142 142 uifout = safeattrsetter(ui, 'fout', ignoremissing=True)
143 143 if uifout:
144 144 # for "historical portability":
145 145 # ui.fout/ferr have been available since 1.9 (or 4e1ccd4c2b6d)
146 146 uifout.set(ui.ferr)
147 147
148 148 # get a formatter
149 149 uiformatter = getattr(ui, 'formatter', None)
150 150 if uiformatter:
151 151 fm = uiformatter('perf', opts)
152 152 else:
153 153 # for "historical portability":
154 154 # define formatter locally, because ui.formatter has been
155 155 # available since 2.2 (or ae5f92e154d3)
156 156 from mercurial import node
157 157 class defaultformatter(object):
158 158 """Minimized composition of baseformatter and plainformatter
159 159 """
160 160 def __init__(self, ui, topic, opts):
161 161 self._ui = ui
162 162 if ui.debugflag:
163 163 self.hexfunc = node.hex
164 164 else:
165 165 self.hexfunc = node.short
166 166 def __nonzero__(self):
167 167 return False
168 168 def startitem(self):
169 169 pass
170 170 def data(self, **data):
171 171 pass
172 172 def write(self, fields, deftext, *fielddata, **opts):
173 173 self._ui.write(deftext % fielddata, **opts)
174 174 def condwrite(self, cond, fields, deftext, *fielddata, **opts):
175 175 if cond:
176 176 self._ui.write(deftext % fielddata, **opts)
177 177 def plain(self, text, **opts):
178 178 self._ui.write(text, **opts)
179 179 def end(self):
180 180 pass
181 181 fm = defaultformatter(ui, 'perf', opts)
182 182
183 183 # stub function, runs code only once instead of in a loop
184 184 # experimental config: perf.stub
185 185 if ui.configbool("perf", "stub"):
186 186 return functools.partial(stub_timer, fm), fm
187 187 return functools.partial(_timer, fm), fm
188 188
189 189 def stub_timer(fm, func, title=None):
190 190 func()
191 191
192 192 def _timer(fm, func, title=None):
193 193 results = []
194 194 begin = time.time()
195 195 count = 0
196 196 while True:
197 197 ostart = os.times()
198 198 cstart = time.time()
199 199 r = func()
200 200 cstop = time.time()
201 201 ostop = os.times()
202 202 count += 1
203 203 a, b = ostart, ostop
204 204 results.append((cstop - cstart, b[0] - a[0], b[1]-a[1]))
205 205 if cstop - begin > 3 and count >= 100:
206 206 break
207 207 if cstop - begin > 10 and count >= 3:
208 208 break
209 209
210 210 fm.startitem()
211 211
212 212 if title:
213 213 fm.write('title', '! %s\n', title)
214 214 if r:
215 215 fm.write('result', '! result: %s\n', r)
216 216 m = min(results)
217 217 fm.plain('!')
218 218 fm.write('wall', ' wall %f', m[0])
219 219 fm.write('comb', ' comb %f', m[1] + m[2])
220 220 fm.write('user', ' user %f', m[1])
221 221 fm.write('sys', ' sys %f', m[2])
222 222 fm.write('count', ' (best of %d)', count)
223 223 fm.plain('\n')
224 224
225 225 # utilities for historical portability
226 226
227 227 def getint(ui, section, name, default):
228 228 # for "historical portability":
229 229 # ui.configint has been available since 1.9 (or fa2b596db182)
230 230 v = ui.config(section, name, None)
231 231 if v is None:
232 232 return default
233 233 try:
234 234 return int(v)
235 235 except ValueError:
236 236 raise error.ConfigError(("%s.%s is not an integer ('%s')")
237 237 % (section, name, v))
238 238
239 239 def safeattrsetter(obj, name, ignoremissing=False):
240 240 """Ensure that 'obj' has 'name' attribute before subsequent setattr
241 241
242 242 This function is aborted, if 'obj' doesn't have 'name' attribute
243 243 at runtime. This avoids overlooking removal of an attribute, which
244 244 breaks assumption of performance measurement, in the future.
245 245
246 246 This function returns the object to (1) assign a new value, and
247 247 (2) restore an original value to the attribute.
248 248
249 249 If 'ignoremissing' is true, missing 'name' attribute doesn't cause
250 250 abortion, and this function returns None. This is useful to
251 251 examine an attribute, which isn't ensured in all Mercurial
252 252 versions.
253 253 """
254 254 if not util.safehasattr(obj, name):
255 255 if ignoremissing:
256 256 return None
257 257 raise error.Abort(("missing attribute %s of %s might break assumption"
258 258 " of performance measurement") % (name, obj))
259 259
260 260 origvalue = getattr(obj, name)
261 261 class attrutil(object):
262 262 def set(self, newvalue):
263 263 setattr(obj, name, newvalue)
264 264 def restore(self):
265 265 setattr(obj, name, origvalue)
266 266
267 267 return attrutil()
268 268
269 269 # utilities to examine each internal API changes
270 270
271 271 def getbranchmapsubsettable():
272 272 # for "historical portability":
273 273 # subsettable is defined in:
274 274 # - branchmap since 2.9 (or 175c6fd8cacc)
275 275 # - repoview since 2.5 (or 59a9f18d4587)
276 276 for mod in (branchmap, repoview):
277 277 subsettable = getattr(mod, 'subsettable', None)
278 278 if subsettable:
279 279 return subsettable
280 280
281 281 # bisecting in bcee63733aad::59a9f18d4587 can reach here (both
282 282 # branchmap and repoview modules exist, but subsettable attribute
283 283 # doesn't)
284 284 raise error.Abort(("perfbranchmap not available with this Mercurial"),
285 285 hint="use 2.5 or later")
286 286
287 287 def getsvfs(repo):
288 288 """Return appropriate object to access files under .hg/store
289 289 """
290 290 # for "historical portability":
291 291 # repo.svfs has been available since 2.3 (or 7034365089bf)
292 292 svfs = getattr(repo, 'svfs', None)
293 293 if svfs:
294 294 return svfs
295 295 else:
296 296 return getattr(repo, 'sopener')
297 297
298 298 def getvfs(repo):
299 299 """Return appropriate object to access files under .hg
300 300 """
301 301 # for "historical portability":
302 302 # repo.vfs has been available since 2.3 (or 7034365089bf)
303 303 vfs = getattr(repo, 'vfs', None)
304 304 if vfs:
305 305 return vfs
306 306 else:
307 307 return getattr(repo, 'opener')
308 308
309 309 def repocleartagscachefunc(repo):
310 310 """Return the function to clear tags cache according to repo internal API
311 311 """
312 312 if util.safehasattr(repo, '_tagscache'): # since 2.0 (or 9dca7653b525)
313 313 # in this case, setattr(repo, '_tagscache', None) or so isn't
314 314 # correct way to clear tags cache, because existing code paths
315 315 # expect _tagscache to be a structured object.
316 316 def clearcache():
317 317 # _tagscache has been filteredpropertycache since 2.5 (or
318 318 # 98c867ac1330), and delattr() can't work in such case
319 319 if '_tagscache' in vars(repo):
320 320 del repo.__dict__['_tagscache']
321 321 return clearcache
322 322
323 323 repotags = safeattrsetter(repo, '_tags', ignoremissing=True)
324 324 if repotags: # since 1.4 (or 5614a628d173)
325 325 return lambda : repotags.set(None)
326 326
327 327 repotagscache = safeattrsetter(repo, 'tagscache', ignoremissing=True)
328 328 if repotagscache: # since 0.6 (or d7df759d0e97)
329 329 return lambda : repotagscache.set(None)
330 330
331 331 # Mercurial earlier than 0.6 (or d7df759d0e97) logically reaches
332 332 # this point, but it isn't so problematic, because:
333 333 # - repo.tags of such Mercurial isn't "callable", and repo.tags()
334 334 # in perftags() causes failure soon
335 335 # - perf.py itself has been available since 1.1 (or eb240755386d)
336 336 raise error.Abort(("tags API of this hg command is unknown"))
337 337
338 338 # perf commands
339 339
340 340 @command('perfwalk', formatteropts)
341 341 def perfwalk(ui, repo, *pats, **opts):
342 342 timer, fm = gettimer(ui, opts)
343 343 try:
344 344 m = scmutil.match(repo[None], pats, {})
345 345 timer(lambda: len(list(repo.dirstate.walk(m, [], True, False))))
346 346 except Exception:
347 347 try:
348 348 m = scmutil.match(repo[None], pats, {})
349 349 timer(lambda: len([b for a, b, c in repo.dirstate.statwalk([], m)]))
350 350 except Exception:
351 351 timer(lambda: len(list(cmdutil.walk(repo, pats, {}))))
352 352 fm.end()
353 353
354 354 @command('perfannotate', formatteropts)
355 355 def perfannotate(ui, repo, f, **opts):
356 356 timer, fm = gettimer(ui, opts)
357 357 fc = repo['.'][f]
358 358 timer(lambda: len(fc.annotate(True)))
359 359 fm.end()
360 360
361 361 @command('perfstatus',
362 362 [('u', 'unknown', False,
363 363 'ask status to look for unknown files')] + formatteropts)
364 364 def perfstatus(ui, repo, **opts):
365 365 #m = match.always(repo.root, repo.getcwd())
366 366 #timer(lambda: sum(map(len, repo.dirstate.status(m, [], False, False,
367 367 # False))))
368 368 timer, fm = gettimer(ui, opts)
369 369 timer(lambda: sum(map(len, repo.status(unknown=opts['unknown']))))
370 370 fm.end()
371 371
372 372 @command('perfaddremove', formatteropts)
373 373 def perfaddremove(ui, repo, **opts):
374 374 timer, fm = gettimer(ui, opts)
375 375 try:
376 376 oldquiet = repo.ui.quiet
377 377 repo.ui.quiet = True
378 378 matcher = scmutil.match(repo[None])
379 379 timer(lambda: scmutil.addremove(repo, matcher, "", dry_run=True))
380 380 finally:
381 381 repo.ui.quiet = oldquiet
382 382 fm.end()
383 383
384 384 def clearcaches(cl):
385 385 # behave somewhat consistently across internal API changes
386 386 if util.safehasattr(cl, 'clearcaches'):
387 387 cl.clearcaches()
388 388 elif util.safehasattr(cl, '_nodecache'):
389 389 from mercurial.node import nullid, nullrev
390 390 cl._nodecache = {nullid: nullrev}
391 391 cl._nodepos = None
392 392
393 393 @command('perfheads', formatteropts)
394 394 def perfheads(ui, repo, **opts):
395 395 timer, fm = gettimer(ui, opts)
396 396 cl = repo.changelog
397 397 def d():
398 398 len(cl.headrevs())
399 399 clearcaches(cl)
400 400 timer(d)
401 401 fm.end()
402 402
403 403 @command('perftags', formatteropts)
404 404 def perftags(ui, repo, **opts):
405 405 import mercurial.changelog
406 406 import mercurial.manifest
407 407 timer, fm = gettimer(ui, opts)
408 408 svfs = getsvfs(repo)
409 409 repocleartagscache = repocleartagscachefunc(repo)
410 410 def t():
411 411 repo.changelog = mercurial.changelog.changelog(svfs)
412 412 repo.manifestlog = mercurial.manifest.manifestlog(svfs, repo)
413 413 repocleartagscache()
414 414 return len(repo.tags())
415 415 timer(t)
416 416 fm.end()
417 417
418 418 @command('perfancestors', formatteropts)
419 419 def perfancestors(ui, repo, **opts):
420 420 timer, fm = gettimer(ui, opts)
421 421 heads = repo.changelog.headrevs()
422 422 def d():
423 423 for a in repo.changelog.ancestors(heads):
424 424 pass
425 425 timer(d)
426 426 fm.end()
427 427
428 428 @command('perfancestorset', formatteropts)
429 429 def perfancestorset(ui, repo, revset, **opts):
430 430 timer, fm = gettimer(ui, opts)
431 431 revs = repo.revs(revset)
432 432 heads = repo.changelog.headrevs()
433 433 def d():
434 434 s = repo.changelog.ancestors(heads)
435 435 for rev in revs:
436 436 rev in s
437 437 timer(d)
438 438 fm.end()
439 439
440 440 @command('perfchangegroupchangelog', formatteropts +
441 441 [('', 'version', '02', 'changegroup version'),
442 442 ('r', 'rev', '', 'revisions to add to changegroup')])
443 443 def perfchangegroupchangelog(ui, repo, version='02', rev=None, **opts):
444 444 """Benchmark producing a changelog group for a changegroup.
445 445
446 446 This measures the time spent processing the changelog during a
447 447 bundle operation. This occurs during `hg bundle` and on a server
448 448 processing a `getbundle` wire protocol request (handles clones
449 449 and pull requests).
450 450
451 451 By default, all revisions are added to the changegroup.
452 452 """
453 453 cl = repo.changelog
454 454 revs = [cl.lookup(r) for r in repo.revs(rev or 'all()')]
455 455 bundler = changegroup.getbundler(version, repo)
456 456
457 457 def lookup(node):
458 458 # The real bundler reads the revision in order to access the
459 459 # manifest node and files list. Do that here.
460 460 cl.read(node)
461 461 return node
462 462
463 463 def d():
464 464 for chunk in bundler.group(revs, cl, lookup):
465 465 pass
466 466
467 467 timer, fm = gettimer(ui, opts)
468 468 timer(d)
469 469 fm.end()
470 470
471 471 @command('perfdirs', formatteropts)
472 472 def perfdirs(ui, repo, **opts):
473 473 timer, fm = gettimer(ui, opts)
474 474 dirstate = repo.dirstate
475 475 'a' in dirstate
476 476 def d():
477 477 dirstate.dirs()
478 478 del dirstate._dirs
479 479 timer(d)
480 480 fm.end()
481 481
482 482 @command('perfdirstate', formatteropts)
483 483 def perfdirstate(ui, repo, **opts):
484 484 timer, fm = gettimer(ui, opts)
485 485 "a" in repo.dirstate
486 486 def d():
487 487 repo.dirstate.invalidate()
488 488 "a" in repo.dirstate
489 489 timer(d)
490 490 fm.end()
491 491
492 492 @command('perfdirstatedirs', formatteropts)
493 493 def perfdirstatedirs(ui, repo, **opts):
494 494 timer, fm = gettimer(ui, opts)
495 495 "a" in repo.dirstate
496 496 def d():
497 497 "a" in repo.dirstate._dirs
498 498 del repo.dirstate._dirs
499 499 timer(d)
500 500 fm.end()
501 501
502 502 @command('perfdirstatefoldmap', formatteropts)
503 503 def perfdirstatefoldmap(ui, repo, **opts):
504 504 timer, fm = gettimer(ui, opts)
505 505 dirstate = repo.dirstate
506 506 'a' in dirstate
507 507 def d():
508 508 dirstate._filefoldmap.get('a')
509 509 del dirstate._filefoldmap
510 510 timer(d)
511 511 fm.end()
512 512
513 513 @command('perfdirfoldmap', formatteropts)
514 514 def perfdirfoldmap(ui, repo, **opts):
515 515 timer, fm = gettimer(ui, opts)
516 516 dirstate = repo.dirstate
517 517 'a' in dirstate
518 518 def d():
519 519 dirstate._dirfoldmap.get('a')
520 520 del dirstate._dirfoldmap
521 521 del dirstate._dirs
522 522 timer(d)
523 523 fm.end()
524 524
525 525 @command('perfdirstatewrite', formatteropts)
526 526 def perfdirstatewrite(ui, repo, **opts):
527 527 timer, fm = gettimer(ui, opts)
528 528 ds = repo.dirstate
529 529 "a" in ds
530 530 def d():
531 531 ds._dirty = True
532 532 ds.write(repo.currenttransaction())
533 533 timer(d)
534 534 fm.end()
535 535
536 536 @command('perfmergecalculate',
537 537 [('r', 'rev', '.', 'rev to merge against')] + formatteropts)
538 538 def perfmergecalculate(ui, repo, rev, **opts):
539 539 timer, fm = gettimer(ui, opts)
540 540 wctx = repo[None]
541 541 rctx = scmutil.revsingle(repo, rev, rev)
542 542 ancestor = wctx.ancestor(rctx)
543 543 # we don't want working dir files to be stat'd in the benchmark, so prime
544 544 # that cache
545 545 wctx.dirty()
546 546 def d():
547 547 # acceptremote is True because we don't want prompts in the middle of
548 548 # our benchmark
549 549 merge.calculateupdates(repo, wctx, rctx, [ancestor], False, False,
550 550 acceptremote=True, followcopies=True)
551 551 timer(d)
552 552 fm.end()
553 553
554 554 @command('perfpathcopies', [], "REV REV")
555 555 def perfpathcopies(ui, repo, rev1, rev2, **opts):
556 556 timer, fm = gettimer(ui, opts)
557 557 ctx1 = scmutil.revsingle(repo, rev1, rev1)
558 558 ctx2 = scmutil.revsingle(repo, rev2, rev2)
559 559 def d():
560 560 copies.pathcopies(ctx1, ctx2)
561 561 timer(d)
562 562 fm.end()
563 563
564 564 @command('perfmanifest', [], 'REV')
565 565 def perfmanifest(ui, repo, rev, **opts):
566 566 timer, fm = gettimer(ui, opts)
567 567 ctx = scmutil.revsingle(repo, rev, rev)
568 568 t = ctx.manifestnode()
569 569 def d():
570 570 repo.manifestlog.clearcaches()
571 571 repo.manifestlog[t].read()
572 572 timer(d)
573 573 fm.end()
574 574
575 575 @command('perfchangeset', formatteropts)
576 576 def perfchangeset(ui, repo, rev, **opts):
577 577 timer, fm = gettimer(ui, opts)
578 578 n = repo[rev].node()
579 579 def d():
580 580 repo.changelog.read(n)
581 581 #repo.changelog._cache = None
582 582 timer(d)
583 583 fm.end()
584 584
585 585 @command('perfindex', formatteropts)
586 586 def perfindex(ui, repo, **opts):
587 587 import mercurial.revlog
588 588 timer, fm = gettimer(ui, opts)
589 589 mercurial.revlog._prereadsize = 2**24 # disable lazy parser in old hg
590 590 n = repo["tip"].node()
591 591 svfs = getsvfs(repo)
592 592 def d():
593 593 cl = mercurial.revlog.revlog(svfs, "00changelog.i")
594 594 cl.rev(n)
595 595 timer(d)
596 596 fm.end()
597 597
598 598 @command('perfstartup', formatteropts)
599 599 def perfstartup(ui, repo, **opts):
600 600 timer, fm = gettimer(ui, opts)
601 601 cmd = sys.argv[0]
602 602 def d():
603 603 if os.name != 'nt':
604 604 os.system("HGRCPATH= %s version -q > /dev/null" % cmd)
605 605 else:
606 606 os.environ['HGRCPATH'] = ''
607 607 os.system("%s version -q > NUL" % cmd)
608 608 timer(d)
609 609 fm.end()
610 610
611 611 @command('perfparents', formatteropts)
612 612 def perfparents(ui, repo, **opts):
613 613 timer, fm = gettimer(ui, opts)
614 614 # control the number of commits perfparents iterates over
615 615 # experimental config: perf.parentscount
616 616 count = getint(ui, "perf", "parentscount", 1000)
617 617 if len(repo.changelog) < count:
618 618 raise error.Abort("repo needs %d commits for this test" % count)
619 619 repo = repo.unfiltered()
620 620 nl = [repo.changelog.node(i) for i in xrange(count)]
621 621 def d():
622 622 for n in nl:
623 623 repo.changelog.parents(n)
624 624 timer(d)
625 625 fm.end()
626 626
627 627 @command('perfctxfiles', formatteropts)
628 628 def perfctxfiles(ui, repo, x, **opts):
629 629 x = int(x)
630 630 timer, fm = gettimer(ui, opts)
631 631 def d():
632 632 len(repo[x].files())
633 633 timer(d)
634 634 fm.end()
635 635
636 636 @command('perfrawfiles', formatteropts)
637 637 def perfrawfiles(ui, repo, x, **opts):
638 638 x = int(x)
639 639 timer, fm = gettimer(ui, opts)
640 640 cl = repo.changelog
641 641 def d():
642 642 len(cl.read(x)[3])
643 643 timer(d)
644 644 fm.end()
645 645
646 646 @command('perflookup', formatteropts)
647 647 def perflookup(ui, repo, rev, **opts):
648 648 timer, fm = gettimer(ui, opts)
649 649 timer(lambda: len(repo.lookup(rev)))
650 650 fm.end()
651 651
652 652 @command('perfrevrange', formatteropts)
653 653 def perfrevrange(ui, repo, *specs, **opts):
654 654 timer, fm = gettimer(ui, opts)
655 655 revrange = scmutil.revrange
656 656 timer(lambda: len(revrange(repo, specs)))
657 657 fm.end()
658 658
659 659 @command('perfnodelookup', formatteropts)
660 660 def perfnodelookup(ui, repo, rev, **opts):
661 661 timer, fm = gettimer(ui, opts)
662 662 import mercurial.revlog
663 663 mercurial.revlog._prereadsize = 2**24 # disable lazy parser in old hg
664 664 n = repo[rev].node()
665 665 cl = mercurial.revlog.revlog(getsvfs(repo), "00changelog.i")
666 666 def d():
667 667 cl.rev(n)
668 668 clearcaches(cl)
669 669 timer(d)
670 670 fm.end()
671 671
672 672 @command('perflog',
673 673 [('', 'rename', False, 'ask log to follow renames')] + formatteropts)
674 674 def perflog(ui, repo, rev=None, **opts):
675 675 if rev is None:
676 676 rev=[]
677 677 timer, fm = gettimer(ui, opts)
678 678 ui.pushbuffer()
679 679 timer(lambda: commands.log(ui, repo, rev=rev, date='', user='',
680 680 copies=opts.get('rename')))
681 681 ui.popbuffer()
682 682 fm.end()
683 683
684 684 @command('perfmoonwalk', formatteropts)
685 685 def perfmoonwalk(ui, repo, **opts):
686 686 """benchmark walking the changelog backwards
687 687
688 688 This also loads the changelog data for each revision in the changelog.
689 689 """
690 690 timer, fm = gettimer(ui, opts)
691 691 def moonwalk():
692 692 for i in xrange(len(repo), -1, -1):
693 693 ctx = repo[i]
694 694 ctx.branch() # read changelog data (in addition to the index)
695 695 timer(moonwalk)
696 696 fm.end()
697 697
698 698 @command('perftemplating', formatteropts)
699 699 def perftemplating(ui, repo, rev=None, **opts):
700 700 if rev is None:
701 701 rev=[]
702 702 timer, fm = gettimer(ui, opts)
703 703 ui.pushbuffer()
704 704 timer(lambda: commands.log(ui, repo, rev=rev, date='', user='',
705 705 template='{date|shortdate} [{rev}:{node|short}]'
706 706 ' {author|person}: {desc|firstline}\n'))
707 707 ui.popbuffer()
708 708 fm.end()
709 709
710 710 @command('perfcca', formatteropts)
711 711 def perfcca(ui, repo, **opts):
712 712 timer, fm = gettimer(ui, opts)
713 713 timer(lambda: scmutil.casecollisionauditor(ui, False, repo.dirstate))
714 714 fm.end()
715 715
716 716 @command('perffncacheload', formatteropts)
717 717 def perffncacheload(ui, repo, **opts):
718 718 timer, fm = gettimer(ui, opts)
719 719 s = repo.store
720 720 def d():
721 721 s.fncache._load()
722 722 timer(d)
723 723 fm.end()
724 724
725 725 @command('perffncachewrite', formatteropts)
726 726 def perffncachewrite(ui, repo, **opts):
727 727 timer, fm = gettimer(ui, opts)
728 728 s = repo.store
729 729 s.fncache._load()
730 730 lock = repo.lock()
731 731 tr = repo.transaction('perffncachewrite')
732 732 def d():
733 733 s.fncache._dirty = True
734 734 s.fncache.write(tr)
735 735 timer(d)
736 736 tr.close()
737 737 lock.release()
738 738 fm.end()
739 739
740 740 @command('perffncacheencode', formatteropts)
741 741 def perffncacheencode(ui, repo, **opts):
742 742 timer, fm = gettimer(ui, opts)
743 743 s = repo.store
744 744 s.fncache._load()
745 745 def d():
746 746 for p in s.fncache.entries:
747 747 s.encode(p)
748 748 timer(d)
749 749 fm.end()
750 750
751 751 @command('perfbdiff', revlogopts + formatteropts + [
752 752 ('', 'count', 1, 'number of revisions to test (when using --startrev)'),
753 753 ('', 'alldata', False, 'test bdiffs for all associated revisions')],
754 754 '-c|-m|FILE REV')
755 755 def perfbdiff(ui, repo, file_, rev=None, count=None, **opts):
756 756 """benchmark a bdiff between revisions
757 757
758 758 By default, benchmark a bdiff between its delta parent and itself.
759 759
760 760 With ``--count``, benchmark bdiffs between delta parents and self for N
761 761 revisions starting at the specified revision.
762 762
763 763 With ``--alldata``, assume the requested revision is a changeset and
764 764 measure bdiffs for all changes related to that changeset (manifest
765 765 and filelogs).
766 766 """
767 767 if opts['alldata']:
768 768 opts['changelog'] = True
769 769
770 770 if opts.get('changelog') or opts.get('manifest'):
771 771 file_, rev = None, file_
772 772 elif rev is None:
773 773 raise error.CommandError('perfbdiff', 'invalid arguments')
774 774
775 775 textpairs = []
776 776
777 777 r = cmdutil.openrevlog(repo, 'perfbdiff', file_, opts)
778 778
779 779 startrev = r.rev(r.lookup(rev))
780 780 for rev in range(startrev, min(startrev + count, len(r) - 1)):
781 781 if opts['alldata']:
782 782 # Load revisions associated with changeset.
783 783 ctx = repo[rev]
784 784 mtext = repo.manifestlog._revlog.revision(ctx.manifestnode())
785 785 for pctx in ctx.parents():
786 786 pman = repo.manifestlog._revlog.revision(pctx.manifestnode())
787 787 textpairs.append((pman, mtext))
788 788
789 789 # Load filelog revisions by iterating manifest delta.
790 790 man = ctx.manifest()
791 791 pman = ctx.p1().manifest()
792 792 for filename, change in pman.diff(man).items():
793 793 fctx = repo.file(filename)
794 794 f1 = fctx.revision(change[0][0] or -1)
795 795 f2 = fctx.revision(change[1][0] or -1)
796 796 textpairs.append((f1, f2))
797 797 else:
798 798 dp = r.deltaparent(rev)
799 799 textpairs.append((r.revision(dp), r.revision(rev)))
800 800
801 801 def d():
802 802 for pair in textpairs:
803 803 bdiff.bdiff(*pair)
804 804
805 805 timer, fm = gettimer(ui, opts)
806 806 timer(d)
807 807 fm.end()
808 808
809 809 @command('perfdiffwd', formatteropts)
810 810 def perfdiffwd(ui, repo, **opts):
811 811 """Profile diff of working directory changes"""
812 812 timer, fm = gettimer(ui, opts)
813 813 options = {
814 814 'w': 'ignore_all_space',
815 815 'b': 'ignore_space_change',
816 816 'B': 'ignore_blank_lines',
817 817 }
818 818
819 819 for diffopt in ('', 'w', 'b', 'B', 'wB'):
820 820 opts = dict((options[c], '1') for c in diffopt)
821 821 def d():
822 822 ui.pushbuffer()
823 823 commands.diff(ui, repo, **opts)
824 824 ui.popbuffer()
825 825 title = 'diffopts: %s' % (diffopt and ('-' + diffopt) or 'none')
826 826 timer(d, title)
827 827 fm.end()
828 828
829 829 @command('perfrevlog', revlogopts + formatteropts +
830 830 [('d', 'dist', 100, 'distance between the revisions'),
831 831 ('s', 'startrev', 0, 'revision to start reading at'),
832 832 ('', 'reverse', False, 'read in reverse')],
833 833 '-c|-m|FILE')
834 834 def perfrevlog(ui, repo, file_=None, startrev=0, reverse=False, **opts):
835 835 """Benchmark reading a series of revisions from a revlog.
836 836
837 837 By default, we read every ``-d/--dist`` revision from 0 to tip of
838 838 the specified revlog.
839 839
840 840 The start revision can be defined via ``-s/--startrev``.
841 841 """
842 842 timer, fm = gettimer(ui, opts)
843 843 _len = getlen(ui)
844 844
845 845 def d():
846 846 r = cmdutil.openrevlog(repo, 'perfrevlog', file_, opts)
847 847
848 848 startrev = 0
849 849 endrev = _len(r)
850 850 dist = opts['dist']
851 851
852 852 if reverse:
853 853 startrev, endrev = endrev, startrev
854 854 dist = -1 * dist
855 855
856 856 for x in xrange(startrev, endrev, dist):
857 857 r.revision(r.node(x))
858 858
859 859 timer(d)
860 860 fm.end()
861 861
862 @command('perfrevlogchunks', revlogopts + formatteropts +
863 [('s', 'startrev', 0, 'revision to start at')],
864 '-c|-m|FILE')
865 def perfrevlogchunks(ui, repo, file_=None, startrev=0, **opts):
866 """Benchmark operations on revlog chunks.
867
868 Logically, each revlog is a collection of fulltext revisions. However,
869 stored within each revlog are "chunks" of possibly compressed data. This
870 data needs to be read and decompressed or compressed and written.
871
872 This command measures the time it takes to read+decompress and recompress
873 chunks in a revlog. It effectively isolates I/O and compression performance.
874 For measurements of higher-level operations like resolving revisions,
875 see ``perfrevlog`` and ``perfrevlogrevision``.
876 """
877 rl = cmdutil.openrevlog(repo, 'perfrevlogchunks', file_, opts)
878 revs = list(rl.revs(startrev, len(rl) - 1))
879
880 def rlfh(rl):
881 if rl._inline:
882 return getsvfs(repo)(rl.indexfile)
883 else:
884 return getsvfs(repo)(rl.datafile)
885
886 def doread():
887 rl.clearcaches()
888 for rev in revs:
889 rl._chunkraw(rev, rev)
890
891 def doreadcachedfh():
892 rl.clearcaches()
893 fh = rlfh(rl)
894 for rev in revs:
895 rl._chunkraw(rev, rev, df=fh)
896
897 def doreadbatch():
898 rl.clearcaches()
899 rl._chunkraw(revs[0], revs[-1])
900
901 def doreadbatchcachedfh():
902 rl.clearcaches()
903 fh = rlfh(rl)
904 rl._chunkraw(revs[0], revs[-1], df=fh)
905
906 def dochunk():
907 rl.clearcaches()
908 fh = rlfh(rl)
909 for rev in revs:
910 rl._chunk(rev, df=fh)
911
912 chunks = [None]
913
914 def dochunkbatch():
915 rl.clearcaches()
916 fh = rlfh(rl)
917 # Save chunks as a side-effect.
918 chunks[0] = rl._chunks(revs, df=fh)
919
920 def docompress():
921 rl.clearcaches()
922 for chunk in chunks[0]:
923 rl.compress(chunk)
924
925 benches = [
926 (lambda: doread(), 'read'),
927 (lambda: doreadcachedfh(), 'read w/ reused fd'),
928 (lambda: doreadbatch(), 'read batch'),
929 (lambda: doreadbatchcachedfh(), 'read batch w/ reused fd'),
930 (lambda: dochunk(), 'chunk'),
931 (lambda: dochunkbatch(), 'chunk batch'),
932 (lambda: docompress(), 'compress'),
933 ]
934
935 for fn, title in benches:
936 timer, fm = gettimer(ui, opts)
937 timer(fn, title=title)
938 fm.end()
939
862 940 @command('perfrevlogrevision', revlogopts + formatteropts +
863 941 [('', 'cache', False, 'use caches instead of clearing')],
864 942 '-c|-m|FILE REV')
865 943 def perfrevlogrevision(ui, repo, file_, rev=None, cache=None, **opts):
866 944 """Benchmark obtaining a revlog revision.
867 945
868 946 Obtaining a revlog revision consists of roughly the following steps:
869 947
870 948 1. Compute the delta chain
871 949 2. Obtain the raw chunks for that delta chain
872 950 3. Decompress each raw chunk
873 951 4. Apply binary patches to obtain fulltext
874 952 5. Verify hash of fulltext
875 953
876 954 This command measures the time spent in each of these phases.
877 955 """
878 956 if opts.get('changelog') or opts.get('manifest'):
879 957 file_, rev = None, file_
880 958 elif rev is None:
881 959 raise error.CommandError('perfrevlogrevision', 'invalid arguments')
882 960
883 961 r = cmdutil.openrevlog(repo, 'perfrevlogrevision', file_, opts)
884 962 node = r.lookup(rev)
885 963 rev = r.rev(node)
886 964
887 965 def dodeltachain(rev):
888 966 if not cache:
889 967 r.clearcaches()
890 968 r._deltachain(rev)
891 969
892 970 def doread(chain):
893 971 if not cache:
894 972 r.clearcaches()
895 973 r._chunkraw(chain[0], chain[-1])
896 974
897 975 def dodecompress(data, chain):
898 976 if not cache:
899 977 r.clearcaches()
900 978
901 979 start = r.start
902 980 length = r.length
903 981 inline = r._inline
904 982 iosize = r._io.size
905 983 buffer = util.buffer
906 984 offset = start(chain[0])
907 985
908 986 for rev in chain:
909 987 chunkstart = start(rev)
910 988 if inline:
911 989 chunkstart += (rev + 1) * iosize
912 990 chunklength = length(rev)
913 991 b = buffer(data, chunkstart - offset, chunklength)
914 992 revlog.decompress(b)
915 993
916 994 def dopatch(text, bins):
917 995 if not cache:
918 996 r.clearcaches()
919 997 mdiff.patches(text, bins)
920 998
921 999 def dohash(text):
922 1000 if not cache:
923 1001 r.clearcaches()
924 1002 r._checkhash(text, node, rev)
925 1003
926 1004 def dorevision():
927 1005 if not cache:
928 1006 r.clearcaches()
929 1007 r.revision(node)
930 1008
931 1009 chain = r._deltachain(rev)[0]
932 1010 data = r._chunkraw(chain[0], chain[-1])[1]
933 1011 bins = r._chunks(chain)
934 1012 text = str(bins[0])
935 1013 bins = bins[1:]
936 1014 text = mdiff.patches(text, bins)
937 1015
938 1016 benches = [
939 1017 (lambda: dorevision(), 'full'),
940 1018 (lambda: dodeltachain(rev), 'deltachain'),
941 1019 (lambda: doread(chain), 'read'),
942 1020 (lambda: dodecompress(data, chain), 'decompress'),
943 1021 (lambda: dopatch(text, bins), 'patch'),
944 1022 (lambda: dohash(text), 'hash'),
945 1023 ]
946 1024
947 1025 for fn, title in benches:
948 1026 timer, fm = gettimer(ui, opts)
949 1027 timer(fn, title=title)
950 1028 fm.end()
951 1029
952 1030 @command('perfrevset',
953 1031 [('C', 'clear', False, 'clear volatile cache between each call.'),
954 1032 ('', 'contexts', False, 'obtain changectx for each revision')]
955 1033 + formatteropts, "REVSET")
956 1034 def perfrevset(ui, repo, expr, clear=False, contexts=False, **opts):
957 1035 """benchmark the execution time of a revset
958 1036
959 1037 Use the --clean option if need to evaluate the impact of build volatile
960 1038 revisions set cache on the revset execution. Volatile cache hold filtered
961 1039 and obsolete related cache."""
962 1040 timer, fm = gettimer(ui, opts)
963 1041 def d():
964 1042 if clear:
965 1043 repo.invalidatevolatilesets()
966 1044 if contexts:
967 1045 for ctx in repo.set(expr): pass
968 1046 else:
969 1047 for r in repo.revs(expr): pass
970 1048 timer(d)
971 1049 fm.end()
972 1050
973 1051 @command('perfvolatilesets', formatteropts)
974 1052 def perfvolatilesets(ui, repo, *names, **opts):
975 1053 """benchmark the computation of various volatile set
976 1054
977 1055 Volatile set computes element related to filtering and obsolescence."""
978 1056 timer, fm = gettimer(ui, opts)
979 1057 repo = repo.unfiltered()
980 1058
981 1059 def getobs(name):
982 1060 def d():
983 1061 repo.invalidatevolatilesets()
984 1062 obsolete.getrevs(repo, name)
985 1063 return d
986 1064
987 1065 allobs = sorted(obsolete.cachefuncs)
988 1066 if names:
989 1067 allobs = [n for n in allobs if n in names]
990 1068
991 1069 for name in allobs:
992 1070 timer(getobs(name), title=name)
993 1071
994 1072 def getfiltered(name):
995 1073 def d():
996 1074 repo.invalidatevolatilesets()
997 1075 repoview.filterrevs(repo, name)
998 1076 return d
999 1077
1000 1078 allfilter = sorted(repoview.filtertable)
1001 1079 if names:
1002 1080 allfilter = [n for n in allfilter if n in names]
1003 1081
1004 1082 for name in allfilter:
1005 1083 timer(getfiltered(name), title=name)
1006 1084 fm.end()
1007 1085
1008 1086 @command('perfbranchmap',
1009 1087 [('f', 'full', False,
1010 1088 'Includes build time of subset'),
1011 1089 ] + formatteropts)
1012 1090 def perfbranchmap(ui, repo, full=False, **opts):
1013 1091 """benchmark the update of a branchmap
1014 1092
1015 1093 This benchmarks the full repo.branchmap() call with read and write disabled
1016 1094 """
1017 1095 timer, fm = gettimer(ui, opts)
1018 1096 def getbranchmap(filtername):
1019 1097 """generate a benchmark function for the filtername"""
1020 1098 if filtername is None:
1021 1099 view = repo
1022 1100 else:
1023 1101 view = repo.filtered(filtername)
1024 1102 def d():
1025 1103 if full:
1026 1104 view._branchcaches.clear()
1027 1105 else:
1028 1106 view._branchcaches.pop(filtername, None)
1029 1107 view.branchmap()
1030 1108 return d
1031 1109 # add filter in smaller subset to bigger subset
1032 1110 possiblefilters = set(repoview.filtertable)
1033 1111 subsettable = getbranchmapsubsettable()
1034 1112 allfilters = []
1035 1113 while possiblefilters:
1036 1114 for name in possiblefilters:
1037 1115 subset = subsettable.get(name)
1038 1116 if subset not in possiblefilters:
1039 1117 break
1040 1118 else:
1041 1119 assert False, 'subset cycle %s!' % possiblefilters
1042 1120 allfilters.append(name)
1043 1121 possiblefilters.remove(name)
1044 1122
1045 1123 # warm the cache
1046 1124 if not full:
1047 1125 for name in allfilters:
1048 1126 repo.filtered(name).branchmap()
1049 1127 # add unfiltered
1050 1128 allfilters.append(None)
1051 1129
1052 1130 branchcacheread = safeattrsetter(branchmap, 'read')
1053 1131 branchcachewrite = safeattrsetter(branchmap.branchcache, 'write')
1054 1132 branchcacheread.set(lambda repo: None)
1055 1133 branchcachewrite.set(lambda bc, repo: None)
1056 1134 try:
1057 1135 for name in allfilters:
1058 1136 timer(getbranchmap(name), title=str(name))
1059 1137 finally:
1060 1138 branchcacheread.restore()
1061 1139 branchcachewrite.restore()
1062 1140 fm.end()
1063 1141
1064 1142 @command('perfloadmarkers')
1065 1143 def perfloadmarkers(ui, repo):
1066 1144 """benchmark the time to parse the on-disk markers for a repo
1067 1145
1068 1146 Result is the number of markers in the repo."""
1069 1147 timer, fm = gettimer(ui)
1070 1148 svfs = getsvfs(repo)
1071 1149 timer(lambda: len(obsolete.obsstore(svfs)))
1072 1150 fm.end()
1073 1151
1074 1152 @command('perflrucachedict', formatteropts +
1075 1153 [('', 'size', 4, 'size of cache'),
1076 1154 ('', 'gets', 10000, 'number of key lookups'),
1077 1155 ('', 'sets', 10000, 'number of key sets'),
1078 1156 ('', 'mixed', 10000, 'number of mixed mode operations'),
1079 1157 ('', 'mixedgetfreq', 50, 'frequency of get vs set ops in mixed mode')],
1080 1158 norepo=True)
1081 1159 def perflrucache(ui, size=4, gets=10000, sets=10000, mixed=10000,
1082 1160 mixedgetfreq=50, **opts):
1083 1161 def doinit():
1084 1162 for i in xrange(10000):
1085 1163 util.lrucachedict(size)
1086 1164
1087 1165 values = []
1088 1166 for i in xrange(size):
1089 1167 values.append(random.randint(0, sys.maxint))
1090 1168
1091 1169 # Get mode fills the cache and tests raw lookup performance with no
1092 1170 # eviction.
1093 1171 getseq = []
1094 1172 for i in xrange(gets):
1095 1173 getseq.append(random.choice(values))
1096 1174
1097 1175 def dogets():
1098 1176 d = util.lrucachedict(size)
1099 1177 for v in values:
1100 1178 d[v] = v
1101 1179 for key in getseq:
1102 1180 value = d[key]
1103 1181 value # silence pyflakes warning
1104 1182
1105 1183 # Set mode tests insertion speed with cache eviction.
1106 1184 setseq = []
1107 1185 for i in xrange(sets):
1108 1186 setseq.append(random.randint(0, sys.maxint))
1109 1187
1110 1188 def dosets():
1111 1189 d = util.lrucachedict(size)
1112 1190 for v in setseq:
1113 1191 d[v] = v
1114 1192
1115 1193 # Mixed mode randomly performs gets and sets with eviction.
1116 1194 mixedops = []
1117 1195 for i in xrange(mixed):
1118 1196 r = random.randint(0, 100)
1119 1197 if r < mixedgetfreq:
1120 1198 op = 0
1121 1199 else:
1122 1200 op = 1
1123 1201
1124 1202 mixedops.append((op, random.randint(0, size * 2)))
1125 1203
1126 1204 def domixed():
1127 1205 d = util.lrucachedict(size)
1128 1206
1129 1207 for op, v in mixedops:
1130 1208 if op == 0:
1131 1209 try:
1132 1210 d[v]
1133 1211 except KeyError:
1134 1212 pass
1135 1213 else:
1136 1214 d[v] = v
1137 1215
1138 1216 benches = [
1139 1217 (doinit, 'init'),
1140 1218 (dogets, 'gets'),
1141 1219 (dosets, 'sets'),
1142 1220 (domixed, 'mixed')
1143 1221 ]
1144 1222
1145 1223 for fn, title in benches:
1146 1224 timer, fm = gettimer(ui, opts)
1147 1225 timer(fn, title=title)
1148 1226 fm.end()
1149 1227
1150 1228 def uisetup(ui):
1151 1229 if (util.safehasattr(cmdutil, 'openrevlog') and
1152 1230 not util.safehasattr(commands, 'debugrevlogopts')):
1153 1231 # for "historical portability":
1154 1232 # In this case, Mercurial should be 1.9 (or a79fea6b3e77) -
1155 1233 # 3.7 (or 5606f7d0d063). Therefore, '--dir' option for
1156 1234 # openrevlog() should cause failure, because it has been
1157 1235 # available since 3.5 (or 49c583ca48c4).
1158 1236 def openrevlog(orig, repo, cmd, file_, opts):
1159 1237 if opts.get('dir') and not util.safehasattr(repo, 'dirlog'):
1160 1238 raise error.Abort("This version doesn't support --dir option",
1161 1239 hint="use 3.5 or later")
1162 1240 return orig(repo, cmd, file_, opts)
1163 1241 extensions.wrapfunction(cmdutil, 'openrevlog', openrevlog)
@@ -1,163 +1,166
1 1 #require test-repo
2 2
3 3 Set vars:
4 4
5 5 $ . "$TESTDIR/helpers-testrepo.sh"
6 6 $ CONTRIBDIR="$TESTDIR/../contrib"
7 7
8 8 Prepare repo:
9 9
10 10 $ hg init
11 11
12 12 $ echo this is file a > a
13 13 $ hg add a
14 14 $ hg commit -m first
15 15
16 16 $ echo adding to file a >> a
17 17 $ hg commit -m second
18 18
19 19 $ echo adding more to file a >> a
20 20 $ hg commit -m third
21 21
22 22 $ hg up -r 0
23 23 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
24 24 $ echo merge-this >> a
25 25 $ hg commit -m merge-able
26 26 created new head
27 27
28 28 $ hg up -r 2
29 29 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
30 30
31 31 perfstatus
32 32
33 33 $ cat >> $HGRCPATH << EOF
34 34 > [extensions]
35 35 > perfstatusext=$CONTRIBDIR/perf.py
36 36 > [perf]
37 37 > presleep=0
38 38 > stub=on
39 39 > parentscount=1
40 40 > EOF
41 41 $ hg help perfstatusext
42 42 perfstatusext extension - helper extension to measure performance
43 43
44 44 list of commands:
45 45
46 46 perfaddremove
47 47 (no help text available)
48 48 perfancestors
49 49 (no help text available)
50 50 perfancestorset
51 51 (no help text available)
52 52 perfannotate (no help text available)
53 53 perfbdiff benchmark a bdiff between revisions
54 54 perfbranchmap
55 55 benchmark the update of a branchmap
56 56 perfcca (no help text available)
57 57 perfchangegroupchangelog
58 58 Benchmark producing a changelog group for a changegroup.
59 59 perfchangeset
60 60 (no help text available)
61 61 perfctxfiles (no help text available)
62 62 perfdiffwd Profile diff of working directory changes
63 63 perfdirfoldmap
64 64 (no help text available)
65 65 perfdirs (no help text available)
66 66 perfdirstate (no help text available)
67 67 perfdirstatedirs
68 68 (no help text available)
69 69 perfdirstatefoldmap
70 70 (no help text available)
71 71 perfdirstatewrite
72 72 (no help text available)
73 73 perffncacheencode
74 74 (no help text available)
75 75 perffncacheload
76 76 (no help text available)
77 77 perffncachewrite
78 78 (no help text available)
79 79 perfheads (no help text available)
80 80 perfindex (no help text available)
81 81 perfloadmarkers
82 82 benchmark the time to parse the on-disk markers for a repo
83 83 perflog (no help text available)
84 84 perflookup (no help text available)
85 85 perflrucachedict
86 86 (no help text available)
87 87 perfmanifest (no help text available)
88 88 perfmergecalculate
89 89 (no help text available)
90 90 perfmoonwalk benchmark walking the changelog backwards
91 91 perfnodelookup
92 92 (no help text available)
93 93 perfparents (no help text available)
94 94 perfpathcopies
95 95 (no help text available)
96 96 perfrawfiles (no help text available)
97 97 perfrevlog Benchmark reading a series of revisions from a revlog.
98 perfrevlogchunks
99 Benchmark operations on revlog chunks.
98 100 perfrevlogrevision
99 101 Benchmark obtaining a revlog revision.
100 102 perfrevrange (no help text available)
101 103 perfrevset benchmark the execution time of a revset
102 104 perfstartup (no help text available)
103 105 perfstatus (no help text available)
104 106 perftags (no help text available)
105 107 perftemplating
106 108 (no help text available)
107 109 perfvolatilesets
108 110 benchmark the computation of various volatile set
109 111 perfwalk (no help text available)
110 112
111 113 (use 'hg help -v perfstatusext' to show built-in aliases and global options)
112 114 $ hg perfaddremove
113 115 $ hg perfancestors
114 116 $ hg perfancestorset 2
115 117 $ hg perfannotate a
116 118 $ hg perfbdiff -c 1
117 119 $ hg perfbdiff --alldata 1
118 120 $ hg perfbranchmap
119 121 $ hg perfcca
120 122 $ hg perfchangegroupchangelog
121 123 $ hg perfchangeset 2
122 124 $ hg perfctxfiles 2
123 125 $ hg perfdiffwd
124 126 $ hg perfdirfoldmap
125 127 $ hg perfdirs
126 128 $ hg perfdirstate
127 129 $ hg perfdirstatedirs
128 130 $ hg perfdirstatefoldmap
129 131 $ hg perfdirstatewrite
130 132 $ hg perffncacheencode
131 133 $ hg perffncacheload
132 134 $ hg perffncachewrite
133 135 $ hg perfheads
134 136 $ hg perfindex
135 137 $ hg perfloadmarkers
136 138 $ hg perflog
137 139 $ hg perflookup 2
138 140 $ hg perflrucache
139 141 $ hg perfmanifest 2
140 142 $ hg perfmergecalculate -r 3
141 143 $ hg perfmoonwalk
142 144 $ hg perfnodelookup 2
143 145 $ hg perfpathcopies 1 2
144 146 $ hg perfrawfiles 2
145 147 $ hg perfrevlog .hg/store/data/a.i
146 148 $ hg perfrevlogrevision -m 0
149 $ hg perfrevlogchunks -c
147 150 $ hg perfrevrange
148 151 $ hg perfrevset 'all()'
149 152 $ hg perfstartup
150 153 $ hg perfstatus
151 154 $ hg perftags
152 155 $ hg perftemplating
153 156 $ hg perfvolatilesets
154 157 $ hg perfwalk
155 158 $ hg perfparents
156 159
157 160 Check perf.py for historical portability
158 161
159 162 $ cd "$TESTDIR/.."
160 163
161 164 $ (hg files -r 1.2 glob:mercurial/*.c glob:mercurial/*.py;
162 165 > hg files -r tip glob:mercurial/*.c glob:mercurial/*.py) |
163 166 > "$TESTDIR"/check-perf-code.py contrib/perf.py
General Comments 0
You need to be logged in to leave comments. Login now