changeset 51977:42a116f1cdc1

branchmap-v3: introduce a "stop_rev" argument to `headsrevs` The `headsrevs` method of the revlog already have a `revs` argument to compute the headrevs of a limited set of heads. However, it disable the use of the native compiled code to compute the heads, which slows down the branchmap v3 code a lot. The branchmap v3 usage is actually quite constrained as we will always only ignores a part at the top of the graph. So we could be significantly faster. We start by making small change to the python side to improve the situation and introduce the new API. More collaboration with the native code are coming later. This massively speedup operation and close most of the remaining gaps between branchmap-v3 and branchmap-v2. especially on repository with many revs like mozilla-try. A small overhead remains mostly because the `headrevs` logic currently has some inefficiently. We will look into them from there. ### benchmark.name = hg.command.unbundle # bin-env-vars.hg.py-re2-module = default # benchmark.variants.issue6528 = disabled # benchmark.variants.resource-usage = default # benchmark.variants.reuse-external-delta-parent = yes # benchmark.variants.revs = any-1-extra-rev # benchmark.variants.source = unbundle # benchmark.variants.validate = default # benchmark.variants.verbosity = quiet ## data-env-vars.name = netbeans-2018-08-01-zstd-sparse-revlog # bin-env-vars.hg.flavor = default branch-v2: 0.233711 ~~~~~ branch-v3 before: 0.368769 (+57.79%, +0.14) branch-v3 after: 0.239857 (+2.63%, +0.01) # bin-env-vars.hg.flavor = rust branch-v2: 0.235230 ~~~~~ branch-v3 before: 0.372460 (+58.34%, +0.14) branch-v3 after: 0.240972 (+2.44%, +0.01) ## data-env-vars.name = netbeans-2018-08-01-ds2-pnm # bin-env-vars.hg.flavor = rust branch-v2: 0.255586 ~~~~~ branch-v3 before: 0.318907 (+24.78%, +0.06) branch-v3 after: 0.268560 (+5.08%, +0.01) ## data-env-vars.name = mozilla-central-2024-03-22-zstd-sparse-revlog # bin-env-vars.hg.flavor = default branch-v2: 0.339010 ~~~~~ branch-v3 before: 0.349752 (+3.17%, +0.01) branch-v3 after: 0.349389 (+3.06%, +0.01) # bin-env-vars.hg.flavor = rust branch-v2: 0.346525 ~~~~~ branch-v3 before: 0.354300 (+2.24%, +0.01) branch-v3 after: 0.355661 (+2.64%, +0.01) ## data-env-vars.name = mozilla-central-2024-03-22-ds2-pnm # bin-env-vars.hg.flavor = rust branch-v2: 0.380202 ~~~~~ branch-v3 before: 0.396293 (+4.23%, +0.02) branch-v3 after: 0.408851 (+7.54%, +0.03) ## data-env-vars.name = mozilla-unified-2024-03-22-zstd-sparse-revlog # bin-env-vars.hg.flavor = default branch-v2: 0.412165 ~~~~~ branch-v3 before: 0.424769 (+3.06%, +0.01) branch-v3 after: 0.427782 (+3.79%, +0.02) # bin-env-vars.hg.flavor = rust branch-v2: 0.412397 ~~~~~ branch-v3 before: 0.421796 (+2.28%, +0.01) branch-v3 after: 0.422354 (+2.41%, +0.01) ## data-env-vars.name = mozilla-unified-2024-03-22-ds2-pnm # bin-env-vars.hg.flavor = rust branch-v2: 0.429501 ~~~~~ branch-v3 before: 0.443849 (+3.34%, +0.01) branch-v3 after: 0.443197 (+3.19%, +0.01) ## data-env-vars.name = mozilla-try-2024-03-26-zstd-sparse-revlog # bin-env-vars.hg.flavor = default branch-v2: 3.403171 ~~~~~ branch-v3 before: 6.234055 (+83.18%, +2.83) branch-v3 after: 3.819477 (+12.23%, +0.42) # bin-env-vars.hg.flavor = rust branch-v2: 3.454876 ~~~~~ branch-v3 before: 6.307813 (+82.58%, +2.85) branch-v3 after: 3.590284 (+3.92%, +0.14) ## data-env-vars.name = mozilla-try-2024-03-26-ds2-pnm # bin-env-vars.hg.flavor = rust branch-v2: 3.465435 ~~~~~ branch-v3 before: 5.176076 (+49.36%, +1.71) branch-v3 after: 3.633278 (+4.84%, +0.17)
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Tue, 03 Sep 2024 11:11:17 +0200
parents 41b8892a2054
children 5d1e6f447d2d
files mercurial/branchmap.py mercurial/repoview.py mercurial/revlog.py
diffstat 3 files changed, 16 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/branchmap.py	Tue Sep 03 02:13:03 2024 +0200
+++ b/mercurial/branchmap.py	Tue Sep 03 11:11:17 2024 +0200
@@ -884,8 +884,7 @@
         elif self.tiprev == cl.tiprev():
             return cl.headrevs()
         else:
-            # XXX passing tiprev as ceiling of cl.headrevs could be faster
-            heads = cl.headrevs(cl.revs(stop=self.tiprev))
+            heads = cl.headrevs(stop_rev=self.tiprev + 1)
             return heads
 
     def _write_header(self, fp) -> None:
--- a/mercurial/repoview.py	Tue Sep 03 02:13:03 2024 +0200
+++ b/mercurial/repoview.py	Tue Sep 03 11:11:17 2024 +0200
@@ -310,9 +310,14 @@
         # no Rust fast path implemented yet, so just loop in Python
         return [self.node(r) for r in self.headrevs()]
 
-    def headrevs(self, revs=None):
+    def headrevs(self, revs=None, stop_rev=None):
         if revs is None:
-            return self.index.headrevs(self.filteredrevs)
+            filtered = self.filteredrevs
+            if stop_rev is not None and stop_rev < len(self.index):
+                filtered = set(self.filteredrevs)
+                filtered.update(range(stop_rev, len(self.index)))
+            return self.index.headrevs(filtered)
+        assert stop_rev is None
 
         revs = self._checknofilteredinrevs(revs)
         return super(filteredchangelogmixin, self).headrevs(revs)
--- a/mercurial/revlog.py	Tue Sep 03 02:13:03 2024 +0200
+++ b/mercurial/revlog.py	Tue Sep 03 11:11:17 2024 +0200
@@ -2380,9 +2380,15 @@
         assert heads
         return (orderedout, roots, heads)
 
-    def headrevs(self, revs=None):
+    def headrevs(self, revs=None, stop_rev=None):
         if revs is None:
-            return self.index.headrevs()
+            excluded = None
+            if stop_rev is not None and stop_rev < len(self.index):
+                # We should let the native code handle it, but that a
+                # simple enough first step.
+                excluded = range(stop_rev, len(self.index))
+            return self.index.headrevs(excluded)
+        assert stop_rev is None
         if rustdagop is not None and self.index.rust_ext_compat:
             return rustdagop.headrevs(self.index, revs)
         return dagop.headrevs(revs, self._uncheckedparentrevs)