Mercurial > hg
changeset 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 | afcbc6f64d27 |
files | mercurial/dispatch.py |
diffstat | 1 files changed, 34 insertions(+), 3 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial/dispatch.py Sat Sep 23 13:31:09 2017 -0700 +++ b/mercurial/dispatch.py Sat Sep 23 13:46:12 2017 -0700 @@ -523,21 +523,52 @@ ui.debug("alias '%s' expands to '%s'\n" % (self.name, args)) raise +class lazyaliasentry(object): + """like a typical command entry (func, opts, help), but is lazy""" + + def __init__(self, name, definition, cmdtable, source): + self.name = name + self.definition = definition + self.cmdtable = cmdtable.copy() + self.source = source + + @util.propertycache + def _aliasdef(self): + return cmdalias(self.name, self.definition, self.cmdtable, self.source) + + def __getitem__(self, n): + aliasdef = self._aliasdef + if n == 0: + return aliasdef + elif n == 1: + return aliasdef.opts + elif n == 2: + return aliasdef.help + else: + raise IndexError + + def __iter__(self): + for i in range(3): + yield self[i] + + def __len__(self): + return 3 + def addaliases(ui, cmdtable): # aliases are processed after extensions have been loaded, so they # may use extension commands. Aliases can also use other alias definitions, # but only if they have been defined prior to the current definition. for alias, definition in ui.configitems('alias'): try: - if cmdtable[alias][0].definition == definition: + if cmdtable[alias].definition == definition: continue except (KeyError, AttributeError): # definition might not exist or it might not be a cmdalias pass source = ui.configsource('alias', alias) - aliasdef = cmdalias(alias, definition, cmdtable, source) - cmdtable[aliasdef.name] = (aliasdef, aliasdef.opts, aliasdef.help) + entry = lazyaliasentry(alias, definition, cmdtable, source) + cmdtable[alias] = entry def _parse(ui, args): options = {}