D805: alias: make alias command lazily resolved

quark (Jun Wu) phabricator at mercurial-scm.org
Sat Sep 23 20:57:54 UTC 2017


quark created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  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.
  
  [1]: https://bitbucket.org/facebook/hg-experimental/src/9aca0dbdbdfc48457e5d2581ca2d6e662fced2e6/hgext3rd/traceprof.pyx

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D805

AFFECTED FILES
  mercurial/dispatch.py

CHANGE DETAILS

diff --git a/mercurial/dispatch.py b/mercurial/dispatch.py
--- a/mercurial/dispatch.py
+++ b/mercurial/dispatch.py
@@ -523,6 +523,37 @@
                 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,
@@ -537,8 +568,8 @@
             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 = {}



To: quark, #hg-reviewers
Cc: mercurial-devel


More information about the Mercurial-devel mailing list