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