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