##// END OF EJS Templates
revsetbenchmarks: fix argument parsing...
revsetbenchmarks: fix argument parsing The file doc was saying something, the code was doing something else, the argument validation was doing a third thing. Doc and behavior now comply with the argument defined in the code.

File last commit:

r25535:6d1e4566 default
r25535:6d1e4566 default
Show More
revsetbenchmarks.py
213 lines | 6.0 KiB | text/x-python | PythonLexer
/ contrib / revsetbenchmarks.py
Pierre-Yves David
revsetbenchmark: simplify and convert the script to python...
r20848 #!/usr/bin/env python
# Measure the performance of a list of revsets against multiple revisions
# defined by parameter. Checkout one by one and run perfrevset with every
# revset in the list to benchmark its performance.
#
Pierre-Yves David
revsetbenchmarks: fix argument parsing...
r25535 # You should run this from the root of your mercurial repository.
Pierre-Yves David
revsetbenchmark: simplify and convert the script to python...
r20848 #
Pierre-Yves David
revsetbenchmarks: fix argument parsing...
r25535 # call with --help for details
Pierre-Yves David
revsetbenchmark: simplify and convert the script to python...
r20848 #
# This script also does one run of the current version of mercurial installed
# to compare performance.
import sys
Pierre-Yves David
revsetbenchmark: automatically finds the perf extension...
r21548 import os
Pierre-Yves David
revsetbenchmarks: parse perfrevset output into actual number...
r25530 import re
Durham Goode
revsetbenchmark: remove python 2.7 dependency...
r20893 from subprocess import check_call, Popen, CalledProcessError, STDOUT, PIPE
Pierre-Yves David
revsetbenchmark: use optparse to retrieve argument...
r21287 # cannot use argparse, python 2.7 only
from optparse import OptionParser
Durham Goode
revsetbenchmark: remove python 2.7 dependency...
r20893 def check_output(*args, **kwargs):
kwargs.setdefault('stderr', PIPE)
kwargs.setdefault('stdout', PIPE)
proc = Popen(*args, **kwargs)
output, error = proc.communicate()
if proc.returncode != 0:
Pierre-Yves David
revsetbenchmark: fix error raising...
r21202 raise CalledProcessError(proc.returncode, ' '.join(args[0]))
Durham Goode
revsetbenchmark: remove python 2.7 dependency...
r20893 return output
Pierre-Yves David
revsetbenchmark: simplify and convert the script to python...
r20848
Pierre-Yves David
revsetbenchmark: convert update to proper subprocess call
r20850 def update(rev):
"""update the repo to a revision"""
try:
check_call(['hg', 'update', '--quiet', '--check', str(rev)])
except CalledProcessError, exc:
print >> sys.stderr, 'update to revision %s failed, aborting' % rev
sys.exit(exc.returncode)
Pierre-Yves David
revsetbenchmarks: extract call to mercurial into a function...
r25528
def hg(cmd, repo=None):
"""run a mercurial command
<cmd> is the list of command + argument,
<repo> is an optional repository path to run this command in."""
fullcmd = ['./hg']
if repo is not None:
fullcmd += ['-R', repo]
fullcmd += ['--config',
'extensions.perf=' + os.path.join(contribdir, 'perf.py')]
fullcmd += cmd
return check_output(fullcmd, stderr=STDOUT)
Pierre-Yves David
revsetbenchmark: support for running on other repo...
r21549 def perf(revset, target=None):
Pierre-Yves David
revsetbenchmark: convert performance call to proper subprocess call
r20851 """run benchmark for this very revset"""
try:
Pierre-Yves David
revsetbenchmarks: extract call to mercurial into a function...
r25528 output = hg(['perfrevset', revset], repo=target)
Pierre-Yves David
revsetbenchmarks: parse perfrevset output into actual number...
r25530 return parseoutput(output)
Pierre-Yves David
revsetbenchmark: convert performance call to proper subprocess call
r20851 except CalledProcessError, exc:
Pierre-Yves David
revsetbenchmarks: improve error output in case of failure...
r25529 print >> sys.stderr, 'abort: cannot run revset benchmark: %s' % exc.cmd
if exc.output is None:
print >> sys.stderr, '(no ouput)'
else:
print >> sys.stderr, exc.output
Pierre-Yves David
revsetbenchmark: convert performance call to proper subprocess call
r20851 sys.exit(exc.returncode)
Pierre-Yves David
revsetbenchmarks: parse perfrevset output into actual number...
r25530 outputre = re.compile(r'! wall (\d+.\d+) comb (\d+.\d+) user (\d+.\d+) '
'sys (\d+.\d+) \(best of (\d+)\)')
def parseoutput(output):
"""parse a textual output into a dict
We cannot just use json because we want to compare with old
versions of Mercurial that may not support json output.
"""
match = outputre.search(output)
if not match:
print >> sys.stderr, 'abort: invalid output:'
print >> sys.stderr, output
sys.exit(1)
return {'comb': float(match.group(2)),
'count': int(match.group(5)),
'sys': float(match.group(3)),
'user': float(match.group(4)),
'wall': float(match.group(1)),
}
Pierre-Yves David
revsetbenchmark: convert revision display to proper subprocesscall
r20852 def printrevision(rev):
"""print data about a revision"""
sys.stdout.write("Revision: ")
sys.stdout.flush()
check_call(['hg', 'log', '--rev', str(rev), '--template',
'{desc|firstline}\n'])
Pierre-Yves David
revsetbenchmarks: ensure all indexes have the same width...
r25532 def idxwidth(nbidx):
"""return the max width of number used for index
Augie Fackler
revsetbenchmarks: clarify comment based on irc discussion
r25533 This is similar to log10(nbidx), but we use custom code here
because we start with zero and we'd rather not deal with all the
extra rounding business that log10 would imply.
"""
Pierre-Yves David
revsetbenchmarks: ensure all indexes have the same width...
r25532 nbidx -= 1 # starts at 0
idxwidth = 0
while nbidx:
idxwidth += 1
nbidx //= 10
if not idxwidth:
idxwidth = 1
return idxwidth
Pierre-Yves David
revsetbenchmarks: factor out result output into a function...
r25531 def printresult(idx, data, maxidx):
"""print a line of result to stdout"""
Pierre-Yves David
revsetbenchmarks: ensure all indexes have the same width...
r25532 mask = '%%0%ii) %%s' % idxwidth(maxidx)
Pierre-Yves David
revsetbenchmarks: use a more compact output format with a header...
r25534 out = ['%10.6f' % data['wall'],
'%10.6f' % data['comb'],
'%10.6f' % data['user'],
'%10.6f' % data['sys'],
'%6d' % data['count'],
]
print mask % (idx, ' '.join(out))
Pierre-Yves David
revsetbenchmarks: parse perfrevset output into actual number...
r25530
Pierre-Yves David
revsetbenchmarks: use a more compact output format with a header...
r25534 def printheader(maxidx):
header = [' ' * (idxwidth(maxidx) + 1),
' %-8s' % 'wall',
' %-8s' % 'comb',
' %-8s' % 'user',
' %-8s' % 'sys',
'%6s' % 'count',
]
print ' '.join(header)
Pierre-Yves David
revsetbenchmarks: parse perfrevset output into actual number...
r25530
Pierre-Yves David
revsetbenchmark: get revision to benchmark in a function...
r20853 def getrevs(spec):
"""get the list of rev matched by a revset"""
try:
out = check_output(['hg', 'log', '--template={rev}\n', '--rev', spec])
except CalledProcessError, exc:
print >> sys.stderr, "abort, can't get revision from %s" % spec
sys.exit(exc.returncode)
return [r for r in out.split() if r]
Pierre-Yves David
revsetbenchmark: use optparse to retrieve argument...
r21287 parser = OptionParser(usage="usage: %prog [options] <revs>")
parser.add_option("-f", "--file",
Mads Kiilerich
spelling: fixes from proofreading of spell checker issues
r23139 help="read revset from FILE (stdin if omitted)",
Pierre-Yves David
revsetbenchmark: make it clear that revsets may be read from stdin
r22555 metavar="FILE")
Pierre-Yves David
revsetbenchmark: support for running on other repo...
r21549 parser.add_option("-R", "--repo",
help="run benchmark on REPO", metavar="REPO")
Pierre-Yves David
revsetbenchmark: use optparse to retrieve argument...
r21287
(options, args) = parser.parse_args()
Pierre-Yves David
revsetbenchmark: simplify and convert the script to python...
r20848
Pierre-Yves David
revsetbenchmarks: fix argument parsing...
r25535 if not args:
Pierre-Yves David
revsetbenchmark: use optparse to retrieve argument...
r21287 parser.print_help()
Pierre-Yves David
revsetbenchmark: add a usage message when no arguments are passed...
r21286 sys.exit(255)
Pierre-Yves David
revsetbenchmark: automatically finds the perf extension...
r21548 # the directory where both this script and the perf.py extension live.
contribdir = os.path.dirname(__file__)
Pierre-Yves David
revsetbenchmark: use optparse to retrieve argument...
r21287
Pierre-Yves David
revsetbenchmark: simplify and convert the script to python...
r20848 revsetsfile = sys.stdin
Pierre-Yves David
revsetbenchmark: use optparse to retrieve argument...
r21287 if options.file:
revsetsfile = open(options.file)
Pierre-Yves David
revsetbenchmark: simplify and convert the script to python...
r20848
Pierre-Yves David
revsetbenchmark: allow comments ('#' prefix) in the revset input
r22556 revsets = [l.strip() for l in revsetsfile if not l.startswith('#')]
Pierre-Yves David
revsetbenchmark: simplify and convert the script to python...
r20848
print "Revsets to benchmark"
print "----------------------------"
for idx, rset in enumerate(revsets):
print "%i) %s" % (idx, rset)
print "----------------------------"
print
Pierre-Yves David
revsetbenchmarks: fix argument parsing...
r25535 revs = []
for a in args:
revs.extend(getrevs(a))
Pierre-Yves David
revsetbenchmark: simplify and convert the script to python...
r20848
Pierre-Yves David
revsetbenchmark: add a summary at the end of execution...
r20855 results = []
Pierre-Yves David
revsetbenchmark: simplify and convert the script to python...
r20848 for r in revs:
print "----------------------------"
Pierre-Yves David
revsetbenchmark: convert revision display to proper subprocesscall
r20852 printrevision(r)
Pierre-Yves David
revsetbenchmark: simplify and convert the script to python...
r20848 print "----------------------------"
Pierre-Yves David
revsetbenchmark: convert update to proper subprocess call
r20850 update(r)
Pierre-Yves David
revsetbenchmark: add a summary at the end of execution...
r20855 res = []
results.append(res)
Pierre-Yves David
revsetbenchmarks: use a more compact output format with a header...
r25534 printheader(len(revsets))
Pierre-Yves David
revsetbenchmark: simplify and convert the script to python...
r20848 for idx, rset in enumerate(revsets):
Pierre-Yves David
revsetbenchmark: support for running on other repo...
r21549 data = perf(rset, target=options.repo)
Pierre-Yves David
revsetbenchmark: add a summary at the end of execution...
r20855 res.append(data)
Pierre-Yves David
revsetbenchmarks: factor out result output into a function...
r25531 printresult(idx, data, len(revsets))
Pierre-Yves David
revsetbenchmark: add a summary at the end of execution...
r20855 sys.stdout.flush()
Pierre-Yves David
revsetbenchmark: simplify and convert the script to python...
r20848 print "----------------------------"
Pierre-Yves David
revsetbenchmark: add a summary at the end of execution...
r20855
print """
Result by revset
================
"""
print 'Revision:', revs
for idx, rev in enumerate(revs):
sys.stdout.write('%i) ' % idx)
sys.stdout.flush()
printrevision(rev)
print
print
for ridx, rset in enumerate(revsets):
print "revset #%i: %s" % (ridx, rset)
Pierre-Yves David
revsetbenchmarks: use a more compact output format with a header...
r25534 printheader(len(results))
Pierre-Yves David
revsetbenchmark: add a summary at the end of execution...
r20855 for idx, data in enumerate(results):
Pierre-Yves David
revsetbenchmarks: factor out result output into a function...
r25531 printresult(idx, data[ridx], len(results))
Pierre-Yves David
revsetbenchmark: add a summary at the end of execution...
r20855 print