Mercurial > public > mercurial-scm > hg
comparison mercurial/dispatch.py @ 34306:bd50aa1aa035
alias: make alias command lazily resolved
With many aliases, resolving them could have some visible overhead. Below is
part of traceprof [1] output of `hg bookmark --hidden`:
(time unit: ms)
37 \ addaliases dispatch.py:526
37 | __init__ (60 times) dispatch.py:402
33 | findcmd (108 times) cmdutil.py:721
16 | findpossible (49 times) cmdutil.py:683
It may get better by optimizing `findcmd` to do a bisect, but we don't
really need to resolve an alias if it's not used, so let's make those
command entries lazy.
After this patch, `addalias` takes less than 1ms.
.. perf:: improved performance when many aliases are defined
[1]: https://bitbucket.org/facebook/hg-experimental/src/9aca0dbdbdfc48457e5d2581ca2d6e662fced2e6/hgext3rd/traceprof.pyx
Differential Revision: https://phab.mercurial-scm.org/D805
author | Jun Wu <quark@fb.com> |
---|---|
date | Sat, 23 Sep 2017 13:46:12 -0700 |
parents | 0e48813cc106 |
children | a57c938e7ac8 |
comparison
equal
deleted
inserted
replaced
34305:0e48813cc106 | 34306:bd50aa1aa035 |
---|---|
521 except error.SignatureError: | 521 except error.SignatureError: |
522 args = ' '.join([self.cmdname] + self.args) | 522 args = ' '.join([self.cmdname] + self.args) |
523 ui.debug("alias '%s' expands to '%s'\n" % (self.name, args)) | 523 ui.debug("alias '%s' expands to '%s'\n" % (self.name, args)) |
524 raise | 524 raise |
525 | 525 |
526 class lazyaliasentry(object): | |
527 """like a typical command entry (func, opts, help), but is lazy""" | |
528 | |
529 def __init__(self, name, definition, cmdtable, source): | |
530 self.name = name | |
531 self.definition = definition | |
532 self.cmdtable = cmdtable.copy() | |
533 self.source = source | |
534 | |
535 @util.propertycache | |
536 def _aliasdef(self): | |
537 return cmdalias(self.name, self.definition, self.cmdtable, self.source) | |
538 | |
539 def __getitem__(self, n): | |
540 aliasdef = self._aliasdef | |
541 if n == 0: | |
542 return aliasdef | |
543 elif n == 1: | |
544 return aliasdef.opts | |
545 elif n == 2: | |
546 return aliasdef.help | |
547 else: | |
548 raise IndexError | |
549 | |
550 def __iter__(self): | |
551 for i in range(3): | |
552 yield self[i] | |
553 | |
554 def __len__(self): | |
555 return 3 | |
556 | |
526 def addaliases(ui, cmdtable): | 557 def addaliases(ui, cmdtable): |
527 # aliases are processed after extensions have been loaded, so they | 558 # aliases are processed after extensions have been loaded, so they |
528 # may use extension commands. Aliases can also use other alias definitions, | 559 # may use extension commands. Aliases can also use other alias definitions, |
529 # but only if they have been defined prior to the current definition. | 560 # but only if they have been defined prior to the current definition. |
530 for alias, definition in ui.configitems('alias'): | 561 for alias, definition in ui.configitems('alias'): |
531 try: | 562 try: |
532 if cmdtable[alias][0].definition == definition: | 563 if cmdtable[alias].definition == definition: |
533 continue | 564 continue |
534 except (KeyError, AttributeError): | 565 except (KeyError, AttributeError): |
535 # definition might not exist or it might not be a cmdalias | 566 # definition might not exist or it might not be a cmdalias |
536 pass | 567 pass |
537 | 568 |
538 source = ui.configsource('alias', alias) | 569 source = ui.configsource('alias', alias) |
539 aliasdef = cmdalias(alias, definition, cmdtable, source) | 570 entry = lazyaliasentry(alias, definition, cmdtable, source) |
540 cmdtable[aliasdef.name] = (aliasdef, aliasdef.opts, aliasdef.help) | 571 cmdtable[alias] = entry |
541 | 572 |
542 def _parse(ui, args): | 573 def _parse(ui, args): |
543 options = {} | 574 options = {} |
544 cmdoptions = {} | 575 cmdoptions = {} |
545 | 576 |