perf: add a perfnodemap command
authorBoris Feld <boris.feld@octobus.net>
Fri, 25 Jan 2019 18:55:45 -0500
changeset 41469 c9ff93889550
parent 41468 9cb51e74e9ad
child 41470 d1a273074f62
perf: add a perfnodemap command The command focus on timing of the nodemap object itself.
contrib/perf.py
tests/test-contrib-perf.t
--- a/contrib/perf.py	Wed Jan 30 13:07:20 2019 -0800
+++ b/contrib/perf.py	Fri Jan 25 18:55:45 2019 -0500
@@ -1036,7 +1036,8 @@
     * -10000:
     * -10000: + 0
 
-    It is not currently possible to check for lookup of a missing node."""
+    It is not currently possible to check for lookup of a missing node. For
+    deeper lookup benchmarking, checkout the `perfnodemap` command."""
     import mercurial.revlog
     opts = _byteskwargs(opts)
     timer, fm = gettimer(ui, opts)
@@ -1066,6 +1067,58 @@
     timer(d, setup=setup)
     fm.end()
 
+@command(b'perfnodemap', [
+            (b'', b'rev', [], b'revision to be looked up (default tip)'),
+    ] + formatteropts)
+def perfnodemap(ui, repo, **opts):
+    """benchmark the time necessary to look up revision from a cold nodemap
+
+    Depending on the implementation, the amount and order of revision we look
+    up can varies. Example of useful set to test:
+    * tip
+    * 0
+    * -10:
+    * :10
+    * -10: + :10
+    * :10: + -10:
+    * -10000:
+    * -10000: + 0
+
+    The command currently focus on valid binary lookup. Benchmarking for
+    hexlookup, prefix lookup and missing lookup would also be valuable.
+    """
+    import mercurial.revlog
+    opts = _byteskwargs(opts)
+    timer, fm = gettimer(ui, opts)
+    mercurial.revlog._prereadsize = 2**24 # disable lazy parser in old hg
+
+    unfi = repo.unfiltered()
+    # find the filecache func directly
+    # This avoid polluting the benchmark with the filecache logic
+    makecl = unfi.__class__.changelog.func
+    if not opts[b'rev']:
+        raise error.Abort('use --rev to specify revisions to look up')
+    revs = scmutil.revrange(repo, opts[b'rev'])
+    cl = repo.changelog
+    nodes = [cl.node(r) for r in revs]
+
+    # use a list to pass reference to a nodemap from one closure to the next
+    nodeget = [None]
+    def setnodeget():
+        # probably not necessary, but for good measure
+        clearchangelog(unfi)
+        nodeget[0] = makecl(unfi).nodemap.get
+
+    def setup():
+        setnodeget()
+    def d():
+        get = nodeget[0]
+        for n in nodes:
+            get(n)
+
+    timer(d, setup=setup)
+    fm.end()
+
 @command(b'perfstartup', formatteropts)
 def perfstartup(ui, repo, **opts):
     opts = _byteskwargs(opts)
--- a/tests/test-contrib-perf.t	Wed Jan 30 13:07:20 2019 -0800
+++ b/tests/test-contrib-perf.t	Fri Jan 25 18:55:45 2019 -0500
@@ -109,6 +109,8 @@
    perfmoonwalk  benchmark walking the changelog backwards
    perfnodelookup
                  (no help text available)
+   perfnodemap   benchmark the time necessary to look up revision from a cold
+                 nodemap
    perfparents   (no help text available)
    perfpathcopies
                  benchmark the copy tracing logic