contrib/revsetbenchmarks.py
changeset 28564 6d7da0901a28
parent 28073 c4bec3c45ec9
child 29210 984c4d23d39c
equal deleted inserted replaced
28563:62250a48dc7f 28564:6d7da0901a28
     6 #
     6 #
     7 # You should run this from the root of your mercurial repository.
     7 # You should run this from the root of your mercurial repository.
     8 #
     8 #
     9 # call with --help for details
     9 # call with --help for details
    10 
    10 
    11 import sys
    11 from __future__ import absolute_import, print_function
       
    12 import math
    12 import os
    13 import os
    13 import re
    14 import re
    14 import math
    15 import sys
    15 from subprocess import check_call, Popen, CalledProcessError, STDOUT, PIPE
    16 from subprocess import (
       
    17     CalledProcessError,
       
    18     check_call,
       
    19     PIPE,
       
    20     Popen,
       
    21     STDOUT,
       
    22 )
    16 # cannot use argparse, python 2.7 only
    23 # cannot use argparse, python 2.7 only
    17 from optparse import OptionParser
    24 from optparse import (
       
    25     OptionParser,
       
    26 )
    18 
    27 
    19 DEFAULTVARIANTS = ['plain', 'min', 'max', 'first', 'last',
    28 DEFAULTVARIANTS = ['plain', 'min', 'max', 'first', 'last',
    20                    'reverse', 'reverse+first', 'reverse+last',
    29                    'reverse', 'reverse+first', 'reverse+last',
    21                    'sort', 'sort+first', 'sort+last']
    30                    'sort', 'sort+first', 'sort+last']
    22 
    31 
    34     try:
    43     try:
    35         check_call(['hg', 'update', '--quiet', '--check', str(rev)])
    44         check_call(['hg', 'update', '--quiet', '--check', str(rev)])
    36         check_output(['make', 'local'],
    45         check_output(['make', 'local'],
    37                      stderr=None)  # suppress output except for error/warning
    46                      stderr=None)  # suppress output except for error/warning
    38     except CalledProcessError as exc:
    47     except CalledProcessError as exc:
    39         print >> sys.stderr, 'update to revision %s failed, aborting' % rev
    48         print('update to revision %s failed, aborting'%rev, file=sys.stderr)
    40         sys.exit(exc.returncode)
    49         sys.exit(exc.returncode)
    41 
    50 
    42 
    51 
    43 def hg(cmd, repo=None):
    52 def hg(cmd, repo=None):
    44     """run a mercurial command
    53     """run a mercurial command
    60         if contexts:
    69         if contexts:
    61             args.append('--contexts')
    70             args.append('--contexts')
    62         output = hg(args, repo=target)
    71         output = hg(args, repo=target)
    63         return parseoutput(output)
    72         return parseoutput(output)
    64     except CalledProcessError as exc:
    73     except CalledProcessError as exc:
    65         print >> sys.stderr, 'abort: cannot run revset benchmark: %s' % exc.cmd
    74         print('abort: cannot run revset benchmark: %s'%exc.cmd, file=sys.stderr)
    66         if getattr(exc, 'output', None) is None: # no output before 2.7
    75         if getattr(exc, 'output', None) is None: # no output before 2.7
    67             print >> sys.stderr, '(no output)'
    76             print('(no output)', file=sys.stderr)
    68         else:
    77         else:
    69             print >> sys.stderr, exc.output
    78             print(exc.output, file=sys.stderr)
    70         return None
    79         return None
    71 
    80 
    72 outputre = re.compile(r'! wall (\d+.\d+) comb (\d+.\d+) user (\d+.\d+) '
    81 outputre = re.compile(r'! wall (\d+.\d+) comb (\d+.\d+) user (\d+.\d+) '
    73                       'sys (\d+.\d+) \(best of (\d+)\)')
    82                       'sys (\d+.\d+) \(best of (\d+)\)')
    74 
    83 
    78     We cannot just use json because we want to compare with old
    87     We cannot just use json because we want to compare with old
    79     versions of Mercurial that may not support json output.
    88     versions of Mercurial that may not support json output.
    80     """
    89     """
    81     match = outputre.search(output)
    90     match = outputre.search(output)
    82     if not match:
    91     if not match:
    83         print >> sys.stderr, 'abort: invalid output:'
    92         print('abort: invalid output:', file=sys.stderr)
    84         print >> sys.stderr, output
    93         print(output, file=sys.stderr)
    85         sys.exit(1)
    94         sys.exit(1)
    86     return {'comb': float(match.group(2)),
    95     return {'comb': float(match.group(2)),
    87             'count': int(match.group(5)),
    96             'count': int(match.group(5)),
    88             'sys': float(match.group(3)),
    97             'sys': float(match.group(3)),
    89             'user': float(match.group(4)),
    98             'user': float(match.group(4)),
   181         if verbose:
   190         if verbose:
   182             out.append(formattiming(data[var]['comb']))
   191             out.append(formattiming(data[var]['comb']))
   183             out.append(formattiming(data[var]['user']))
   192             out.append(formattiming(data[var]['user']))
   184             out.append(formattiming(data[var]['sys']))
   193             out.append(formattiming(data[var]['sys']))
   185             out.append('%6d'    % data[var]['count'])
   194             out.append('%6d'    % data[var]['count'])
   186     print mask % (idx, ' '.join(out))
   195     print(mask % (idx, ' '.join(out)))
   187 
   196 
   188 def printheader(variants, maxidx, verbose=False, relative=False):
   197 def printheader(variants, maxidx, verbose=False, relative=False):
   189     header = [' ' * (idxwidth(maxidx) + 1)]
   198     header = [' ' * (idxwidth(maxidx) + 1)]
   190     for var in variants:
   199     for var in variants:
   191         if not var:
   200         if not var:
   198         if verbose:
   207         if verbose:
   199             header.append('%-8s' % 'comb')
   208             header.append('%-8s' % 'comb')
   200             header.append('%-8s' % 'user')
   209             header.append('%-8s' % 'user')
   201             header.append('%-8s' % 'sys')
   210             header.append('%-8s' % 'sys')
   202             header.append('%6s' % 'count')
   211             header.append('%6s' % 'count')
   203     print ' '.join(header)
   212     print(' '.join(header))
   204 
   213 
   205 def getrevs(spec):
   214 def getrevs(spec):
   206     """get the list of rev matched by a revset"""
   215     """get the list of rev matched by a revset"""
   207     try:
   216     try:
   208         out = check_output(['hg', 'log', '--template={rev}\n', '--rev', spec])
   217         out = check_output(['hg', 'log', '--template={rev}\n', '--rev', spec])
   209     except CalledProcessError as exc:
   218     except CalledProcessError as exc:
   210         print >> sys.stderr, "abort, can't get revision from %s" % spec
   219         print("abort, can't get revision from %s"%spec, file=sys.stderr)
   211         sys.exit(exc.returncode)
   220         sys.exit(exc.returncode)
   212     return [r for r in out.split() if r]
   221     return [r for r in out.split() if r]
   213 
   222 
   214 
   223 
   215 def applyvariants(revset, variant):
   224 def applyvariants(revset, variant):
   259     revsetsfile = open(options.file)
   268     revsetsfile = open(options.file)
   260 
   269 
   261 revsets = [l.strip() for l in revsetsfile if not l.startswith('#')]
   270 revsets = [l.strip() for l in revsetsfile if not l.startswith('#')]
   262 revsets = [l for l in revsets if l]
   271 revsets = [l for l in revsets if l]
   263 
   272 
   264 print "Revsets to benchmark"
   273 print("Revsets to benchmark")
   265 print "----------------------------"
   274 print("----------------------------")
   266 
   275 
   267 for idx, rset in enumerate(revsets):
   276 for idx, rset in enumerate(revsets):
   268     print "%i) %s" % (idx, rset)
   277     print("%i) %s" % (idx, rset))
   269 
   278 
   270 print "----------------------------"
   279 print("----------------------------")
   271 print
   280 print()
   272 
   281 
   273 revs = []
   282 revs = []
   274 for a in args:
   283 for a in args:
   275     revs.extend(getrevs(a))
   284     revs.extend(getrevs(a))
   276 
   285 
   277 variants = options.variants.split(',')
   286 variants = options.variants.split(',')
   278 
   287 
   279 results = []
   288 results = []
   280 for r in revs:
   289 for r in revs:
   281     print "----------------------------"
   290     print("----------------------------")
   282     printrevision(r)
   291     printrevision(r)
   283     print "----------------------------"
   292     print("----------------------------")
   284     update(r)
   293     update(r)
   285     res = []
   294     res = []
   286     results.append(res)
   295     results.append(res)
   287     printheader(variants, len(revsets), verbose=options.verbose)
   296     printheader(variants, len(revsets), verbose=options.verbose)
   288     for idx, rset in enumerate(revsets):
   297     for idx, rset in enumerate(revsets):
   293             varres[var] = data
   302             varres[var] = data
   294         res.append(varres)
   303         res.append(varres)
   295         printresult(variants, idx, varres, len(revsets),
   304         printresult(variants, idx, varres, len(revsets),
   296                     verbose=options.verbose)
   305                     verbose=options.verbose)
   297         sys.stdout.flush()
   306         sys.stdout.flush()
   298     print "----------------------------"
   307     print("----------------------------")
   299 
   308 
   300 
   309 
   301 print """
   310 print("""
   302 
   311 
   303 Result by revset
   312 Result by revset
   304 ================
   313 ================
   305 """
   314 """)
   306 
   315 
   307 print 'Revision:'
   316 print('Revision:')
   308 for idx, rev in enumerate(revs):
   317 for idx, rev in enumerate(revs):
   309     sys.stdout.write('%i) ' % idx)
   318     sys.stdout.write('%i) ' % idx)
   310     sys.stdout.flush()
   319     sys.stdout.flush()
   311     printrevision(rev)
   320     printrevision(rev)
   312 
   321 
   313 print
   322 print()
   314 print
   323 print()
   315 
   324 
   316 for ridx, rset in enumerate(revsets):
   325 for ridx, rset in enumerate(revsets):
   317 
   326 
   318     print "revset #%i: %s" % (ridx, rset)
   327     print("revset #%i: %s" % (ridx, rset))
   319     printheader(variants, len(results), verbose=options.verbose, relative=True)
   328     printheader(variants, len(results), verbose=options.verbose, relative=True)
   320     ref = None
   329     ref = None
   321     for idx, data in enumerate(results):
   330     for idx, data in enumerate(results):
   322         printresult(variants, idx, data[ridx], len(results),
   331         printresult(variants, idx, data[ridx], len(results),
   323                     verbose=options.verbose, reference=ref)
   332                     verbose=options.verbose, reference=ref)
   324         ref = data[ridx]
   333         ref = data[ridx]
   325     print
   334     print()