##// END OF EJS Templates
perf: unbust perfbdiff --alldata...
Gregory Szorc -
r30426:605e3b12 default
parent child Browse files
Show More
@@ -1,1163 +1,1163
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 mtext = repo.manifest.revision(ctx.manifestnode())
784 mtext = repo.manifestlog._revlog.revision(ctx.manifestnode())
785 785 for pctx in ctx.parents():
786 pman = repo.manifest.revision(pctx.manifestnode())
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 862 @command('perfrevlogrevision', revlogopts + formatteropts +
863 863 [('', 'cache', False, 'use caches instead of clearing')],
864 864 '-c|-m|FILE REV')
865 865 def perfrevlogrevision(ui, repo, file_, rev=None, cache=None, **opts):
866 866 """Benchmark obtaining a revlog revision.
867 867
868 868 Obtaining a revlog revision consists of roughly the following steps:
869 869
870 870 1. Compute the delta chain
871 871 2. Obtain the raw chunks for that delta chain
872 872 3. Decompress each raw chunk
873 873 4. Apply binary patches to obtain fulltext
874 874 5. Verify hash of fulltext
875 875
876 876 This command measures the time spent in each of these phases.
877 877 """
878 878 if opts.get('changelog') or opts.get('manifest'):
879 879 file_, rev = None, file_
880 880 elif rev is None:
881 881 raise error.CommandError('perfrevlogrevision', 'invalid arguments')
882 882
883 883 r = cmdutil.openrevlog(repo, 'perfrevlogrevision', file_, opts)
884 884 node = r.lookup(rev)
885 885 rev = r.rev(node)
886 886
887 887 def dodeltachain(rev):
888 888 if not cache:
889 889 r.clearcaches()
890 890 r._deltachain(rev)
891 891
892 892 def doread(chain):
893 893 if not cache:
894 894 r.clearcaches()
895 895 r._chunkraw(chain[0], chain[-1])
896 896
897 897 def dodecompress(data, chain):
898 898 if not cache:
899 899 r.clearcaches()
900 900
901 901 start = r.start
902 902 length = r.length
903 903 inline = r._inline
904 904 iosize = r._io.size
905 905 buffer = util.buffer
906 906 offset = start(chain[0])
907 907
908 908 for rev in chain:
909 909 chunkstart = start(rev)
910 910 if inline:
911 911 chunkstart += (rev + 1) * iosize
912 912 chunklength = length(rev)
913 913 b = buffer(data, chunkstart - offset, chunklength)
914 914 revlog.decompress(b)
915 915
916 916 def dopatch(text, bins):
917 917 if not cache:
918 918 r.clearcaches()
919 919 mdiff.patches(text, bins)
920 920
921 921 def dohash(text):
922 922 if not cache:
923 923 r.clearcaches()
924 924 r._checkhash(text, node, rev)
925 925
926 926 def dorevision():
927 927 if not cache:
928 928 r.clearcaches()
929 929 r.revision(node)
930 930
931 931 chain = r._deltachain(rev)[0]
932 932 data = r._chunkraw(chain[0], chain[-1])[1]
933 933 bins = r._chunks(chain)
934 934 text = str(bins[0])
935 935 bins = bins[1:]
936 936 text = mdiff.patches(text, bins)
937 937
938 938 benches = [
939 939 (lambda: dorevision(), 'full'),
940 940 (lambda: dodeltachain(rev), 'deltachain'),
941 941 (lambda: doread(chain), 'read'),
942 942 (lambda: dodecompress(data, chain), 'decompress'),
943 943 (lambda: dopatch(text, bins), 'patch'),
944 944 (lambda: dohash(text), 'hash'),
945 945 ]
946 946
947 947 for fn, title in benches:
948 948 timer, fm = gettimer(ui, opts)
949 949 timer(fn, title=title)
950 950 fm.end()
951 951
952 952 @command('perfrevset',
953 953 [('C', 'clear', False, 'clear volatile cache between each call.'),
954 954 ('', 'contexts', False, 'obtain changectx for each revision')]
955 955 + formatteropts, "REVSET")
956 956 def perfrevset(ui, repo, expr, clear=False, contexts=False, **opts):
957 957 """benchmark the execution time of a revset
958 958
959 959 Use the --clean option if need to evaluate the impact of build volatile
960 960 revisions set cache on the revset execution. Volatile cache hold filtered
961 961 and obsolete related cache."""
962 962 timer, fm = gettimer(ui, opts)
963 963 def d():
964 964 if clear:
965 965 repo.invalidatevolatilesets()
966 966 if contexts:
967 967 for ctx in repo.set(expr): pass
968 968 else:
969 969 for r in repo.revs(expr): pass
970 970 timer(d)
971 971 fm.end()
972 972
973 973 @command('perfvolatilesets', formatteropts)
974 974 def perfvolatilesets(ui, repo, *names, **opts):
975 975 """benchmark the computation of various volatile set
976 976
977 977 Volatile set computes element related to filtering and obsolescence."""
978 978 timer, fm = gettimer(ui, opts)
979 979 repo = repo.unfiltered()
980 980
981 981 def getobs(name):
982 982 def d():
983 983 repo.invalidatevolatilesets()
984 984 obsolete.getrevs(repo, name)
985 985 return d
986 986
987 987 allobs = sorted(obsolete.cachefuncs)
988 988 if names:
989 989 allobs = [n for n in allobs if n in names]
990 990
991 991 for name in allobs:
992 992 timer(getobs(name), title=name)
993 993
994 994 def getfiltered(name):
995 995 def d():
996 996 repo.invalidatevolatilesets()
997 997 repoview.filterrevs(repo, name)
998 998 return d
999 999
1000 1000 allfilter = sorted(repoview.filtertable)
1001 1001 if names:
1002 1002 allfilter = [n for n in allfilter if n in names]
1003 1003
1004 1004 for name in allfilter:
1005 1005 timer(getfiltered(name), title=name)
1006 1006 fm.end()
1007 1007
1008 1008 @command('perfbranchmap',
1009 1009 [('f', 'full', False,
1010 1010 'Includes build time of subset'),
1011 1011 ] + formatteropts)
1012 1012 def perfbranchmap(ui, repo, full=False, **opts):
1013 1013 """benchmark the update of a branchmap
1014 1014
1015 1015 This benchmarks the full repo.branchmap() call with read and write disabled
1016 1016 """
1017 1017 timer, fm = gettimer(ui, opts)
1018 1018 def getbranchmap(filtername):
1019 1019 """generate a benchmark function for the filtername"""
1020 1020 if filtername is None:
1021 1021 view = repo
1022 1022 else:
1023 1023 view = repo.filtered(filtername)
1024 1024 def d():
1025 1025 if full:
1026 1026 view._branchcaches.clear()
1027 1027 else:
1028 1028 view._branchcaches.pop(filtername, None)
1029 1029 view.branchmap()
1030 1030 return d
1031 1031 # add filter in smaller subset to bigger subset
1032 1032 possiblefilters = set(repoview.filtertable)
1033 1033 subsettable = getbranchmapsubsettable()
1034 1034 allfilters = []
1035 1035 while possiblefilters:
1036 1036 for name in possiblefilters:
1037 1037 subset = subsettable.get(name)
1038 1038 if subset not in possiblefilters:
1039 1039 break
1040 1040 else:
1041 1041 assert False, 'subset cycle %s!' % possiblefilters
1042 1042 allfilters.append(name)
1043 1043 possiblefilters.remove(name)
1044 1044
1045 1045 # warm the cache
1046 1046 if not full:
1047 1047 for name in allfilters:
1048 1048 repo.filtered(name).branchmap()
1049 1049 # add unfiltered
1050 1050 allfilters.append(None)
1051 1051
1052 1052 branchcacheread = safeattrsetter(branchmap, 'read')
1053 1053 branchcachewrite = safeattrsetter(branchmap.branchcache, 'write')
1054 1054 branchcacheread.set(lambda repo: None)
1055 1055 branchcachewrite.set(lambda bc, repo: None)
1056 1056 try:
1057 1057 for name in allfilters:
1058 1058 timer(getbranchmap(name), title=str(name))
1059 1059 finally:
1060 1060 branchcacheread.restore()
1061 1061 branchcachewrite.restore()
1062 1062 fm.end()
1063 1063
1064 1064 @command('perfloadmarkers')
1065 1065 def perfloadmarkers(ui, repo):
1066 1066 """benchmark the time to parse the on-disk markers for a repo
1067 1067
1068 1068 Result is the number of markers in the repo."""
1069 1069 timer, fm = gettimer(ui)
1070 1070 svfs = getsvfs(repo)
1071 1071 timer(lambda: len(obsolete.obsstore(svfs)))
1072 1072 fm.end()
1073 1073
1074 1074 @command('perflrucachedict', formatteropts +
1075 1075 [('', 'size', 4, 'size of cache'),
1076 1076 ('', 'gets', 10000, 'number of key lookups'),
1077 1077 ('', 'sets', 10000, 'number of key sets'),
1078 1078 ('', 'mixed', 10000, 'number of mixed mode operations'),
1079 1079 ('', 'mixedgetfreq', 50, 'frequency of get vs set ops in mixed mode')],
1080 1080 norepo=True)
1081 1081 def perflrucache(ui, size=4, gets=10000, sets=10000, mixed=10000,
1082 1082 mixedgetfreq=50, **opts):
1083 1083 def doinit():
1084 1084 for i in xrange(10000):
1085 1085 util.lrucachedict(size)
1086 1086
1087 1087 values = []
1088 1088 for i in xrange(size):
1089 1089 values.append(random.randint(0, sys.maxint))
1090 1090
1091 1091 # Get mode fills the cache and tests raw lookup performance with no
1092 1092 # eviction.
1093 1093 getseq = []
1094 1094 for i in xrange(gets):
1095 1095 getseq.append(random.choice(values))
1096 1096
1097 1097 def dogets():
1098 1098 d = util.lrucachedict(size)
1099 1099 for v in values:
1100 1100 d[v] = v
1101 1101 for key in getseq:
1102 1102 value = d[key]
1103 1103 value # silence pyflakes warning
1104 1104
1105 1105 # Set mode tests insertion speed with cache eviction.
1106 1106 setseq = []
1107 1107 for i in xrange(sets):
1108 1108 setseq.append(random.randint(0, sys.maxint))
1109 1109
1110 1110 def dosets():
1111 1111 d = util.lrucachedict(size)
1112 1112 for v in setseq:
1113 1113 d[v] = v
1114 1114
1115 1115 # Mixed mode randomly performs gets and sets with eviction.
1116 1116 mixedops = []
1117 1117 for i in xrange(mixed):
1118 1118 r = random.randint(0, 100)
1119 1119 if r < mixedgetfreq:
1120 1120 op = 0
1121 1121 else:
1122 1122 op = 1
1123 1123
1124 1124 mixedops.append((op, random.randint(0, size * 2)))
1125 1125
1126 1126 def domixed():
1127 1127 d = util.lrucachedict(size)
1128 1128
1129 1129 for op, v in mixedops:
1130 1130 if op == 0:
1131 1131 try:
1132 1132 d[v]
1133 1133 except KeyError:
1134 1134 pass
1135 1135 else:
1136 1136 d[v] = v
1137 1137
1138 1138 benches = [
1139 1139 (doinit, 'init'),
1140 1140 (dogets, 'gets'),
1141 1141 (dosets, 'sets'),
1142 1142 (domixed, 'mixed')
1143 1143 ]
1144 1144
1145 1145 for fn, title in benches:
1146 1146 timer, fm = gettimer(ui, opts)
1147 1147 timer(fn, title=title)
1148 1148 fm.end()
1149 1149
1150 1150 def uisetup(ui):
1151 1151 if (util.safehasattr(cmdutil, 'openrevlog') and
1152 1152 not util.safehasattr(commands, 'debugrevlogopts')):
1153 1153 # for "historical portability":
1154 1154 # In this case, Mercurial should be 1.9 (or a79fea6b3e77) -
1155 1155 # 3.7 (or 5606f7d0d063). Therefore, '--dir' option for
1156 1156 # openrevlog() should cause failure, because it has been
1157 1157 # available since 3.5 (or 49c583ca48c4).
1158 1158 def openrevlog(orig, repo, cmd, file_, opts):
1159 1159 if opts.get('dir') and not util.safehasattr(repo, 'dirlog'):
1160 1160 raise error.Abort("This version doesn't support --dir option",
1161 1161 hint="use 3.5 or later")
1162 1162 return orig(repo, cmd, file_, opts)
1163 1163 extensions.wrapfunction(cmdutil, 'openrevlog', openrevlog)
@@ -1,162 +1,163
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 98 perfrevlogrevision
99 99 Benchmark obtaining a revlog revision.
100 100 perfrevrange (no help text available)
101 101 perfrevset benchmark the execution time of a revset
102 102 perfstartup (no help text available)
103 103 perfstatus (no help text available)
104 104 perftags (no help text available)
105 105 perftemplating
106 106 (no help text available)
107 107 perfvolatilesets
108 108 benchmark the computation of various volatile set
109 109 perfwalk (no help text available)
110 110
111 111 (use 'hg help -v perfstatusext' to show built-in aliases and global options)
112 112 $ hg perfaddremove
113 113 $ hg perfancestors
114 114 $ hg perfancestorset 2
115 115 $ hg perfannotate a
116 116 $ hg perfbdiff -c 1
117 $ hg perfbdiff --alldata 1
117 118 $ hg perfbranchmap
118 119 $ hg perfcca
119 120 $ hg perfchangegroupchangelog
120 121 $ hg perfchangeset 2
121 122 $ hg perfctxfiles 2
122 123 $ hg perfdiffwd
123 124 $ hg perfdirfoldmap
124 125 $ hg perfdirs
125 126 $ hg perfdirstate
126 127 $ hg perfdirstatedirs
127 128 $ hg perfdirstatefoldmap
128 129 $ hg perfdirstatewrite
129 130 $ hg perffncacheencode
130 131 $ hg perffncacheload
131 132 $ hg perffncachewrite
132 133 $ hg perfheads
133 134 $ hg perfindex
134 135 $ hg perfloadmarkers
135 136 $ hg perflog
136 137 $ hg perflookup 2
137 138 $ hg perflrucache
138 139 $ hg perfmanifest 2
139 140 $ hg perfmergecalculate -r 3
140 141 $ hg perfmoonwalk
141 142 $ hg perfnodelookup 2
142 143 $ hg perfpathcopies 1 2
143 144 $ hg perfrawfiles 2
144 145 $ hg perfrevlog .hg/store/data/a.i
145 146 $ hg perfrevlogrevision -m 0
146 147 $ hg perfrevrange
147 148 $ hg perfrevset 'all()'
148 149 $ hg perfstartup
149 150 $ hg perfstatus
150 151 $ hg perftags
151 152 $ hg perftemplating
152 153 $ hg perfvolatilesets
153 154 $ hg perfwalk
154 155 $ hg perfparents
155 156
156 157 Check perf.py for historical portability
157 158
158 159 $ cd "$TESTDIR/.."
159 160
160 161 $ (hg files -r 1.2 glob:mercurial/*.c glob:mercurial/*.py;
161 162 > hg files -r tip glob:mercurial/*.c glob:mercurial/*.py) |
162 163 > "$TESTDIR"/check-perf-code.py contrib/perf.py
General Comments 0
You need to be logged in to leave comments. Login now