revsetbenchmarks.py
152 lines
| 4.3 KiB
| text/x-python
|
PythonLexer
/ contrib / revsetbenchmarks.py
Pierre-Yves David
|
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. | ||||
# | ||||
# - First argument is a revset of mercurial own repo to runs against. | ||||
# - Second argument is the file from which the revset array will be taken | ||||
# If second argument is omitted read it from standard input | ||||
# | ||||
# You should run this from the root of your mercurial repository. | ||||
# | ||||
# This script also does one run of the current version of mercurial installed | ||||
# to compare performance. | ||||
import sys | ||||
Pierre-Yves David
|
r21548 | import os | ||
Durham Goode
|
r20893 | from subprocess import check_call, Popen, CalledProcessError, STDOUT, PIPE | ||
Pierre-Yves David
|
r21287 | # cannot use argparse, python 2.7 only | ||
from optparse import OptionParser | ||||
Durham Goode
|
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
|
r21202 | raise CalledProcessError(proc.returncode, ' '.join(args[0])) | ||
Durham Goode
|
r20893 | return output | ||
Pierre-Yves David
|
r20848 | |||
Pierre-Yves David
|
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
|
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
|
r21549 | def perf(revset, target=None): | ||
Pierre-Yves David
|
r20851 | """run benchmark for this very revset""" | ||
try: | ||||
Pierre-Yves David
|
r25528 | output = hg(['perfrevset', revset], repo=target) | ||
Pierre-Yves David
|
r20854 | output = output.lstrip('!') # remove useless ! in this context | ||
return output.strip() | ||||
Pierre-Yves David
|
r20851 | except CalledProcessError, exc: | ||
print >> sys.stderr, 'abort: cannot run revset benchmark' | ||||
sys.exit(exc.returncode) | ||||
Pierre-Yves David
|
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
|
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
|
r21287 | parser = OptionParser(usage="usage: %prog [options] <revs>") | ||
parser.add_option("-f", "--file", | ||||
Mads Kiilerich
|
r23139 | help="read revset from FILE (stdin if omitted)", | ||
Pierre-Yves David
|
r22555 | metavar="FILE") | ||
Pierre-Yves David
|
r21549 | parser.add_option("-R", "--repo", | ||
help="run benchmark on REPO", metavar="REPO") | ||||
Pierre-Yves David
|
r21287 | |||
(options, args) = parser.parse_args() | ||||
Pierre-Yves David
|
r20848 | |||
Pierre-Yves David
|
r21286 | if len(sys.argv) < 2: | ||
Pierre-Yves David
|
r21287 | parser.print_help() | ||
Pierre-Yves David
|
r21286 | sys.exit(255) | ||
Pierre-Yves David
|
r21548 | # the directory where both this script and the perf.py extension live. | ||
contribdir = os.path.dirname(__file__) | ||||
Pierre-Yves David
|
r21287 | |||
target_rev = args[0] | ||||
Pierre-Yves David
|
r20848 | |||
revsetsfile = sys.stdin | ||||
Pierre-Yves David
|
r21287 | if options.file: | ||
revsetsfile = open(options.file) | ||||
Pierre-Yves David
|
r20848 | |||
Pierre-Yves David
|
r22556 | revsets = [l.strip() for l in revsetsfile if not l.startswith('#')] | ||
Pierre-Yves David
|
r20848 | |||
print "Revsets to benchmark" | ||||
print "----------------------------" | ||||
for idx, rset in enumerate(revsets): | ||||
print "%i) %s" % (idx, rset) | ||||
print "----------------------------" | ||||
Pierre-Yves David
|
r20853 | revs = getrevs(target_rev) | ||
Pierre-Yves David
|
r20848 | |||
Pierre-Yves David
|
r20855 | results = [] | ||
Pierre-Yves David
|
r20848 | for r in revs: | ||
print "----------------------------" | ||||
Pierre-Yves David
|
r20852 | printrevision(r) | ||
Pierre-Yves David
|
r20848 | print "----------------------------" | ||
Pierre-Yves David
|
r20850 | update(r) | ||
Pierre-Yves David
|
r20855 | res = [] | ||
results.append(res) | ||||
Pierre-Yves David
|
r20848 | for idx, rset in enumerate(revsets): | ||
Pierre-Yves David
|
r21549 | data = perf(rset, target=options.repo) | ||
Pierre-Yves David
|
r20855 | res.append(data) | ||
print "%i)" % idx, data | ||||
sys.stdout.flush() | ||||
Pierre-Yves David
|
r20848 | print "----------------------------" | ||
Pierre-Yves David
|
r20855 | |||
print """ | ||||
Result by revset | ||||
================ | ||||
""" | ||||
print 'Revision:', revs | ||||
for idx, rev in enumerate(revs): | ||||
sys.stdout.write('%i) ' % idx) | ||||
sys.stdout.flush() | ||||
printrevision(rev) | ||||
for ridx, rset in enumerate(revsets): | ||||
print "revset #%i: %s" % (ridx, rset) | ||||
for idx, data in enumerate(results): | ||||
print '%i) %s' % (idx, data[ridx]) | ||||