Patchwork D1971: perf: add a perfunidiff command for benchmarking unified diff speed

login
register
mail settings
Submitter phabricator
Date Feb. 1, 2018, 9:58 p.m.
Message ID <differential-rev-PHID-DREV-iietjdr6t6x5p5wgxqbc-req@phab.mercurial-scm.org>
Download mbox | patch
Permalink /patch/27154/
State Superseded
Headers show

Comments

phabricator - Feb. 1, 2018, 9:58 p.m.
durin42 created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REPOSITORY
  rHG Mercurial

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

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

CHANGE DETAILS




To: durin42, #hg-reviewers
Cc: mercurial-devel
phabricator - Feb. 1, 2018, 10:46 p.m.
indygreg accepted this revision.
indygreg added a comment.
This revision is now accepted and ready to land.


  Nice.

REPOSITORY
  rHG Mercurial

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

To: durin42, #hg-reviewers, indygreg
Cc: indygreg, 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
@@ -114,6 +114,7 @@ 
    perftags      (no help text available)
    perftemplating
                  (no help text available)
+   perfunidiff   benchmark a unified diff between revisions
    perfvolatilesets
                  benchmark the computation of various volatile set
    perfwalk      (no help text available)
@@ -126,6 +127,8 @@ 
   $ hg perfannotate a
   $ hg perfbdiff -c 1
   $ hg perfbdiff --alldata 1
+  $ hg perfunidiff -c 1
+  $ hg perfunidiff --alldata 1
   $ hg perfbookmarks
   $ hg perfbranchmap
   $ hg perfcca
diff --git a/contrib/perf.py b/contrib/perf.py
--- a/contrib/perf.py
+++ b/contrib/perf.py
@@ -1031,6 +1031,71 @@ 
         with ready:
             ready.notify_all()
 
+@command('perfunidiff', revlogopts + formatteropts + [
+    ('', 'count', 1, 'number of revisions to test (when using --startrev)'),
+    ('', 'alldata', False, 'test unidiffs for all associated revisions'),
+    ], '-c|-m|FILE REV')
+def perfunidiff(ui, repo, file_, rev=None, count=None, **opts):
+    """benchmark a unified diff between revisions
+
+    This doesn't include any copy tracing - it's just a unified diff
+    of the texts.
+
+    By default, benchmark a diff between its delta parent and itself.
+
+    With ``--count``, benchmark diffs between delta parents and self for N
+    revisions starting at the specified revision.
+
+    With ``--alldata``, assume the requested revision is a changeset and
+    measure diffs for all changes related to that changeset (manifest
+    and filelogs).
+    """
+    if opts['alldata']:
+        opts['changelog'] = True
+
+    if opts.get('changelog') or opts.get('manifest'):
+        file_, rev = None, file_
+    elif rev is None:
+        raise error.CommandError('perfunidiff', 'invalid arguments')
+
+    textpairs = []
+
+    r = cmdutil.openrevlog(repo, 'perfunidiff', file_, opts)
+
+    startrev = r.rev(r.lookup(rev))
+    for rev in range(startrev, min(startrev + count, len(r) - 1)):
+        if opts['alldata']:
+            # Load revisions associated with changeset.
+            ctx = repo[rev]
+            mtext = repo.manifestlog._revlog.revision(ctx.manifestnode())
+            for pctx in ctx.parents():
+                pman = repo.manifestlog._revlog.revision(pctx.manifestnode())
+                textpairs.append((pman, mtext))
+
+            # Load filelog revisions by iterating manifest delta.
+            man = ctx.manifest()
+            pman = ctx.p1().manifest()
+            for filename, change in pman.diff(man).items():
+                fctx = repo.file(filename)
+                f1 = fctx.revision(change[0][0] or -1)
+                f2 = fctx.revision(change[1][0] or -1)
+                textpairs.append((f1, f2))
+        else:
+            dp = r.deltaparent(rev)
+            textpairs.append((r.revision(dp), r.revision(rev)))
+
+    def d():
+        for left, right in textpairs:
+            # The date strings don't matter, so we pass empty strings.
+            headerlines, hunks = mdiff.unidiff(
+                left, '', right, '', 'left', 'right')
+            # consume iterators in roughly the way patch.py does
+            b'\n'.join(headerlines)
+            b''.join(sum((list(hlines) for hrange, hlines in hunks), []))
+    timer, fm = gettimer(ui, opts)
+    timer(d)
+    fm.end()
+
 @command('perfdiffwd', formatteropts)
 def perfdiffwd(ui, repo, **opts):
     """Profile diff of working directory changes"""