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.
--- 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():