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