Patchwork D1385: perf: add command to benchmark bundle reading

login
register
mail settings
Submitter phabricator
Date Nov. 20, 2017, 11:49 p.m.
Message ID <951cb8624c6888605a27659c74e8a5f5@localhost.localdomain>
Download mbox | patch
Permalink /patch/25687/
State Not Applicable
Headers show

Comments

phabricator - Nov. 20, 2017, 11:49 p.m.
This revision was automatically updated to reflect the committed changes.
Closed by commit rHGe96613048bdd: perf: add command to benchmark bundle reading (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D1385?vs=3463&id=3689

REVISION DETAIL
  https://phab.mercurial-scm.org/D1385

AFFECTED FILES
  contrib/perf.py
  tests/test-contrib-perf.t

CHANGE DETAILS




To: indygreg, #hg-reviewers, durin42
Cc: mercurial-devel

Patch

diff --git a/tests/test-contrib-perf.t b/tests/test-contrib-perf.t
--- a/tests/test-contrib-perf.t
+++ b/tests/test-contrib-perf.t
@@ -55,6 +55,8 @@ 
                  benchmark parsing bookmarks from disk to memory
    perfbranchmap
                  benchmark the update of a branchmap
+   perfbundleread
+                 Benchmark reading of bundle files.
    perfcca       (no help text available)
    perfchangegroupchangelog
                  Benchmark producing a changelog group for a changegroup.
@@ -173,3 +175,7 @@ 
   $ (testrepohg files -r 1.2 glob:mercurial/*.c glob:mercurial/*.py;
   >  testrepohg files -r tip glob:mercurial/*.c glob:mercurial/*.py) |
   > "$TESTDIR"/check-perf-code.py contrib/perf.py
+  contrib/perf.py:498:
+   >     from mercurial import (
+   import newer module separately in try clause for early Mercurial
+  [1]
diff --git a/contrib/perf.py b/contrib/perf.py
--- a/contrib/perf.py
+++ b/contrib/perf.py
@@ -488,6 +488,117 @@ 
     timer(d)
     fm.end()
 
+@command('perfbundleread', formatteropts, 'BUNDLE')
+def perfbundleread(ui, repo, bundlepath, **opts):
+    """Benchmark reading of bundle files.
+
+    This command is meant to isolate the I/O part of bundle reading as
+    much as possible.
+    """
+    from mercurial import (
+        bundle2,
+        exchange,
+        streamclone,
+    )
+
+    def makebench(fn):
+        def run():
+            with open(bundlepath, 'rb') as fh:
+                bundle = exchange.readbundle(ui, fh, bundlepath)
+                fn(bundle)
+
+        return run
+
+    def makereadnbytes(size):
+        def run():
+            with open(bundlepath, 'rb') as fh:
+                bundle = exchange.readbundle(ui, fh, bundlepath)
+                while bundle.read(size):
+                    pass
+
+        return run
+
+    def makestdioread(size):
+        def run():
+            with open(bundlepath, 'rb') as fh:
+                while fh.read(size):
+                    pass
+
+        return run
+
+    # bundle1
+
+    def deltaiter(bundle):
+        for delta in bundle.deltaiter():
+            pass
+
+    def iterchunks(bundle):
+        for chunk in bundle.getchunks():
+            pass
+
+    # bundle2
+
+    def forwardchunks(bundle):
+        for chunk in bundle._forwardchunks():
+            pass
+
+    def iterparts(bundle):
+        for part in bundle.iterparts():
+            pass
+
+    def seek(bundle):
+        for part in bundle.iterparts():
+            part.seek(0, os.SEEK_END)
+
+    def makepartreadnbytes(size):
+        def run():
+            with open(bundlepath, 'rb') as fh:
+                bundle = exchange.readbundle(ui, fh, bundlepath)
+                for part in bundle.iterparts():
+                    while part.read(size):
+                        pass
+
+        return run
+
+    benches = [
+        (makestdioread(8192), 'read(8k)'),
+        (makestdioread(16384), 'read(16k)'),
+        (makestdioread(32768), 'read(32k)'),
+        (makestdioread(131072), 'read(128k)'),
+    ]
+
+    with open(bundlepath, 'rb') as fh:
+        bundle = exchange.readbundle(ui, fh, bundlepath)
+
+        if isinstance(bundle, changegroup.cg1unpacker):
+            benches.extend([
+                (makebench(deltaiter), 'cg1 deltaiter()'),
+                (makebench(iterchunks), 'cg1 getchunks()'),
+                (makereadnbytes(8192), 'cg1 read(8k)'),
+                (makereadnbytes(16384), 'cg1 read(16k)'),
+                (makereadnbytes(32768), 'cg1 read(32k)'),
+                (makereadnbytes(131072), 'cg1 read(128k)'),
+            ])
+        elif isinstance(bundle, bundle2.unbundle20):
+            benches.extend([
+                (makebench(forwardchunks), 'bundle2 forwardchunks()'),
+                (makebench(iterparts), 'bundle2 iterparts()'),
+                (makebench(seek), 'bundle2 part seek()'),
+                (makepartreadnbytes(8192), 'bundle2 part read(8k)'),
+                (makepartreadnbytes(16384), 'bundle2 part read(16k)'),
+                (makepartreadnbytes(32768), 'bundle2 part read(32k)'),
+                (makepartreadnbytes(131072), 'bundle2 part read(128k)'),
+            ])
+        elif isinstance(bundle, streamclone.streamcloneapplier):
+            raise error.Abort('stream clone bundles not supported')
+        else:
+            raise error.Abort('unhandled bundle type: %s' % type(bundle))
+
+    for fn, title in benches:
+        timer, fm = gettimer(ui, opts)
+        timer(fn, title=title)
+        fm.end()
+
 @command('perfchangegroupchangelog', formatteropts +
          [('', 'version', '02', 'changegroup version'),
           ('r', 'rev', '', 'revisions to add to changegroup')])