changeset 19292:e0aa6fff8f02

annotate: simplify annotate parent function The annotate algorithm used a custom parents() function to try to reuse filectx and filelogs. I simplified it a bit to rely more heavily on the self.parents() which makes it work well with alternative filectx implementations. I tested performance on a file with 5000+ revisions but no renames, and on a file with 500 revisions repeating a series of 4 edits+renames and saw zero performance hit. In fact, it was reliably a couple milliseconds faster now. Added the perfannotate command to contrib/perf.py for future use.
author Durham Goode <durham@fb.com>
date Thu, 30 May 2013 19:29:03 -0700
parents 93635f69c93b
children 446ab88d3f1c
files contrib/perf.py mercurial/context.py
diffstat 2 files changed, 16 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/contrib/perf.py	Thu May 30 19:26:56 2013 -0700
+++ b/contrib/perf.py	Thu May 30 19:29:03 2013 -0700
@@ -45,6 +45,11 @@
         except Exception:
             timer(lambda: len(list(cmdutil.walk(repo, pats, {}))))
 
+@command('perfannotate')
+def perfannotate(ui, repo, f):
+    fc = repo['.'][f]
+    timer(lambda: len(fc.annotate(True)))
+
 @command('perfstatus',
          [('u', 'unknown', False,
            'ask status to look for unknown files')])
--- a/mercurial/context.py	Thu May 30 19:26:56 2013 -0700
+++ b/mercurial/context.py	Thu May 30 19:29:03 2013 -0700
@@ -649,25 +649,21 @@
             return child
 
         getlog = util.lrucachefunc(lambda x: self._repo.file(x))
-        def getctx(path, fileid):
-            log = path == self._path and self._filelog or getlog(path)
-            return filectx(self._repo, path, fileid=fileid, filelog=log)
-        getctx = util.lrucachefunc(getctx)
 
         def parents(f):
-            # we want to reuse filectx objects as much as possible
-            p = f._path
-            if f._filerev is None: # working dir
-                pl = [(n.path(), n.filerev()) for n in f.parents()]
-            else:
-                pl = [(p, n) for n in f._filelog.parentrevs(f._filerev)]
+            pl = f.parents()
+
+            # Don't return renamed parents if we aren't following.
+            if not follow:
+                pl = [p for p in pl if p.path() == f.path()]
 
-            if follow:
-                r = f.renamed()
-                if r:
-                    pl[0] = (r[0], getlog(r[0]).rev(r[1]))
+            # renamed filectx won't have a filelog yet, so set it
+            # from the cache to save time
+            for p in pl:
+                if not '_filelog' in p.__dict__:
+                    p._filelog = getlog(p.path())
 
-            return [getctx(p, n) for p, n in pl if n != nullrev]
+            return pl
 
         # use linkrev to find the first changeset where self appeared
         if self.rev() != self.linkrev():