Patchwork [3,of,4] cmdutil: stop pretending we can calculate revs for graphlog lazily

login
register
mail settings
Submitter Siddharth Agarwal
Date Dec. 29, 2012, 12:56 a.m.
Message ID <25e3eb40555803397989.1356742599@sid0x220>
Download mbox | patch
Permalink /patch/325/
State Accepted
Commit 9d350f2d9458015ccc2f136e95cd666d9007943a
Headers show

Comments

Siddharth Agarwal - Dec. 29, 2012, 12:56 a.m.
# HG changeset patch
# User Siddharth Agarwal <sid0 at fb.com>
# Date 1356740700 28800
# Node ID 25e3eb405558033979899284c156231783935ae9
# Parent  d518e5bb7e24789992eacb6a07c6eb74308413da
cmdutil: stop pretending we can calculate revs for graphlog lazily

cmdutil.getgraphlogrevs does a ton of work trying to build a graphlog lazily,
and then cmdutil.graphlog comes along and destroys all of that.
graphmod.dagwalker requires that it be given the full list of revs upfront so
that it can perform filtering and tests against known revs.

For a repository with over 400,000 changesets, this speeds up graphlog by
around 0.02 seconds (~20% with a small limit).

Patch

diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py
--- a/mercurial/cmdutil.py
+++ b/mercurial/cmdutil.py
@@ -1399,34 +1399,8 @@  def getgraphlogrevs(repo, pats, opts):
     callable taking a revision number and returning a match objects
     filtering the files to be detailed when displaying the revision.
     """
-    def increasingrevs(repo, revs, matcher):
-        # The sorted input rev sequence is chopped in sub-sequences
-        # which are sorted in ascending order and passed to the
-        # matcher. The filtered revs are sorted again as they were in
-        # the original sub-sequence. This achieve several things:
-        #
-        # - getlogrevs() now returns a generator which behaviour is
-        #   adapted to log need. First results come fast, last ones
-        #   are batched for performances.
-        #
-        # - revset matchers often operate faster on revision in
-        #   changelog order, because most filters deal with the
-        #   changelog.
-        #
-        # - revset matchers can reorder revisions. "A or B" typically
-        #   returns returns the revision matching A then the revision
-        #   matching B. We want to hide this internal implementation
-        #   detail from the caller, and sorting the filtered revision
-        #   again achieves this.
-        for i, window in increasingwindows(0, len(revs), windowsize=1):
-            orevs = revs[i:i + window]
-            nrevs = set(matcher(repo, sorted(orevs)))
-            for rev in orevs:
-                if rev in nrevs:
-                    yield rev
-
     if not len(repo):
-        return iter([]), None, None
+        return [], None, None
     # Default --rev value depends on --follow but --follow behaviour
     # depends on revisions resolved from --rev...
     follow = opts.get('follow') or opts.get('follow_first')
@@ -1443,20 +1417,25 @@  def getgraphlogrevs(repo, pats, opts):
             revs = list(repo.changelog)
             revs.reverse()
     if not revs:
-        return iter([]), None, None
+        return [], None, None
     expr, filematcher = _makegraphlogrevset(repo, pats, opts, revs)
     if possiblyunsorted:
         revs.sort(reverse=True)
     if expr:
+        # Revset matchers often operate faster on revisions in changelog
+        # order, because most filters deal with the changelog.
+        revs.reverse()
         matcher = revset.match(repo.ui, expr)
-        revs = increasingrevs(repo, revs, matcher)
+        # Revset matches can reorder revisions. "A or B" typically returns
+        # returns the revision matching A then the revision matching B. Sort
+        # again to fix that.
+        revs = matcher(repo, revs)
+        revs.sort(reverse=True)
     if not opts.get('hidden'):
         # --hidden is still experimental and not worth a dedicated revset
         # yet. Fortunately, filtering revision number is fast.
         hiddenrevs = repo.hiddenrevs
-        revs = (r for r in revs if r not in hiddenrevs)
-    else:
-        revs = iter(revs)
+        revs = [r for r in revs if r not in hiddenrevs]
     return revs, expr, filematcher
 
 def displaygraph(ui, dag, displayer, showparents, edgefn, getrenamed=None,
@@ -1491,7 +1470,6 @@  def displaygraph(ui, dag, displayer, sho
 def graphlog(ui, repo, *pats, **opts):
     # Parameters are identical to log command ones
     revs, expr, filematcher = getgraphlogrevs(repo, pats, opts)
-    revs = sorted(revs, reverse=1)
     limit = loglimit(opts)
     if limit is not None:
         revs = revs[:limit]