From patchwork Sat Nov 5 16:41:14 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [STABLE, V2] hgweb: cache fctx.parents() in annotate command (issue5414) From: Gregory Szorc X-Patchwork-Id: 17350 Message-Id: <1258a74819e5c2b4904d.1478364074@ubuntu-vm-main> To: mercurial-devel@mercurial-scm.org Date: Sat, 05 Nov 2016 09:41:14 -0700 # HG changeset patch # User Gregory Szorc # Date 1478363887 25200 # Sat Nov 05 09:38:07 2016 -0700 # Branch stable # Node ID 1258a74819e5c2b4904d11c71231e3b3f33a0aa1 # Parent e5cc44ea12de681d971fcbebb65a7fb71fd1c3c7 hgweb: cache fctx.parents() in annotate command (issue5414) 9c37df347485 introduced a call to fctx.parents() for each line in annotate output. This function call isn't cheap, as it requires linkrev adjustment. Since multiple lines in annotate output tend to belong to the same file revision, a cache of fctx.parents() lookups for each input should be effective in the common case. So we implement one. Since the cache has to precompute parents so an aborted generator doesn't leave an incomplete cache, we could just return a list. However, we preserve the generator for backwards compatibility. The effect of this change when requesting /annotate/96ca0ecdcfa/ browser/locales/en-US/chrome/browser/downloads/downloads.dtd on the mozilla-aurora repo is significant: p1(9c37df347485) 5.5s 9c37df347485: 66.3s this patch: 10.8s We're still slower than before. But only by ~2x instead of ~12x. On the tip revisions of layout/base/nsCSSFrameConstructor.cpp file in the mozilla-unified repo, time went from 12.5s to 14.5s and back to 12.5s. I'm not sure why the mozilla-aurora repo is so slow. Looking at the code of basefilectx.parents(), there is room for further improvements. Notably, we still perform redundant calls to filelog.renamed() and basefilectx._parentfilectx(). And basefilectx.annotate() also makes similar calls, so there is potential for object reuse. However, introducing caches here are not appropriate for the stable branch. diff --git a/mercurial/hgweb/webcommands.py b/mercurial/hgweb/webcommands.py --- a/mercurial/hgweb/webcommands.py +++ b/mercurial/hgweb/webcommands.py @@ -861,12 +861,24 @@ def annotate(web, req, tmpl): f = fctx.path() parity = paritygen(web.stripecount) + # parents() is called once per line and several lines likely belong to + # same revision. So it is worth caching. + # TODO there are still redundant operations within basefilectx.parents() + # and from the fctx.annotate() call itself that could be cached. + parentscache = {} def parents(f): - for p in f.parents(): - yield { - "node": p.hex(), - "rev": p.rev(), - } + rev = f.rev() + if rev not in parentscache: + parentscache[rev] = [] + for p in f.parents(): + entry = { + 'node': p.hex(), + 'rev': p.rev(), + } + parentscache[rev].append(entry) + + for p in parentscache[rev]: + yield p def annotate(**map): if util.binary(fctx.data()):