Mercurial > hg
changeset 35861:ed939545edd0
perf: add a perfunidiff command for benchmarking unified diff speed
Differential Revision: https://phab.mercurial-scm.org/D1971
author | Augie Fackler <augie@google.com> |
---|---|
date | Thu, 25 Jan 2018 14:46:19 -0500 |
parents | d9e71cce3b2f |
children | 1ab7b16c9437 |
files | contrib/perf.py tests/test-contrib-perf.t |
diffstat | 2 files changed, 68 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/contrib/perf.py Wed Jan 31 11:28:18 2018 -0800 +++ b/contrib/perf.py Thu Jan 25 14:46:19 2018 -0500 @@ -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"""
--- a/tests/test-contrib-perf.t Wed Jan 31 11:28:18 2018 -0800 +++ b/tests/test-contrib-perf.t Thu Jan 25 14:46:19 2018 -0500 @@ -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