##// END OF EJS Templates
revsetbenchmarks: factor out result output into a function...
Pierre-Yves David -
r25531:371d8afc default
parent child Browse files
Show More
@@ -1,184 +1,187
1 1 #!/usr/bin/env python
2 2
3 3 # Measure the performance of a list of revsets against multiple revisions
4 4 # defined by parameter. Checkout one by one and run perfrevset with every
5 5 # revset in the list to benchmark its performance.
6 6 #
7 7 # - First argument is a revset of mercurial own repo to runs against.
8 8 # - Second argument is the file from which the revset array will be taken
9 9 # If second argument is omitted read it from standard input
10 10 #
11 11 # You should run this from the root of your mercurial repository.
12 12 #
13 13 # This script also does one run of the current version of mercurial installed
14 14 # to compare performance.
15 15
16 16 import sys
17 17 import os
18 18 import re
19 19 from subprocess import check_call, Popen, CalledProcessError, STDOUT, PIPE
20 20 # cannot use argparse, python 2.7 only
21 21 from optparse import OptionParser
22 22
23 23 def check_output(*args, **kwargs):
24 24 kwargs.setdefault('stderr', PIPE)
25 25 kwargs.setdefault('stdout', PIPE)
26 26 proc = Popen(*args, **kwargs)
27 27 output, error = proc.communicate()
28 28 if proc.returncode != 0:
29 29 raise CalledProcessError(proc.returncode, ' '.join(args[0]))
30 30 return output
31 31
32 32 def update(rev):
33 33 """update the repo to a revision"""
34 34 try:
35 35 check_call(['hg', 'update', '--quiet', '--check', str(rev)])
36 36 except CalledProcessError, exc:
37 37 print >> sys.stderr, 'update to revision %s failed, aborting' % rev
38 38 sys.exit(exc.returncode)
39 39
40 40
41 41 def hg(cmd, repo=None):
42 42 """run a mercurial command
43 43
44 44 <cmd> is the list of command + argument,
45 45 <repo> is an optional repository path to run this command in."""
46 46 fullcmd = ['./hg']
47 47 if repo is not None:
48 48 fullcmd += ['-R', repo]
49 49 fullcmd += ['--config',
50 50 'extensions.perf=' + os.path.join(contribdir, 'perf.py')]
51 51 fullcmd += cmd
52 52 return check_output(fullcmd, stderr=STDOUT)
53 53
54 54 def perf(revset, target=None):
55 55 """run benchmark for this very revset"""
56 56 try:
57 57 output = hg(['perfrevset', revset], repo=target)
58 58 return parseoutput(output)
59 59 except CalledProcessError, exc:
60 60 print >> sys.stderr, 'abort: cannot run revset benchmark: %s' % exc.cmd
61 61 if exc.output is None:
62 62 print >> sys.stderr, '(no ouput)'
63 63 else:
64 64 print >> sys.stderr, exc.output
65 65 sys.exit(exc.returncode)
66 66
67 67 outputre = re.compile(r'! wall (\d+.\d+) comb (\d+.\d+) user (\d+.\d+) '
68 68 'sys (\d+.\d+) \(best of (\d+)\)')
69 69
70 70 def parseoutput(output):
71 71 """parse a textual output into a dict
72 72
73 73 We cannot just use json because we want to compare with old
74 74 versions of Mercurial that may not support json output.
75 75 """
76 76 match = outputre.search(output)
77 77 if not match:
78 78 print >> sys.stderr, 'abort: invalid output:'
79 79 print >> sys.stderr, output
80 80 sys.exit(1)
81 81 return {'comb': float(match.group(2)),
82 82 'count': int(match.group(5)),
83 83 'sys': float(match.group(3)),
84 84 'user': float(match.group(4)),
85 85 'wall': float(match.group(1)),
86 86 }
87 87
88 88 def printrevision(rev):
89 89 """print data about a revision"""
90 90 sys.stdout.write("Revision: ")
91 91 sys.stdout.flush()
92 92 check_call(['hg', 'log', '--rev', str(rev), '--template',
93 93 '{desc|firstline}\n'])
94 94
95 def formatresult(data):
96 """format the data dict into a line of text for humans"""
97 return ("wall %f comb %f user %f sys %f (best of %d)"
98 % (data['wall'], data['comb'], data['user'],
99 data['sys'], data['count']))
95 def printresult(idx, data, maxidx):
96 """print a line of result to stdout"""
97 mask = '%i) %s'
100 98
99 out = ("wall %f comb %f user %f sys %f (best of %d)"
100 % (data['wall'], data['comb'], data['user'],
101 data['sys'], data['count']))
102
103 print mask % (idx, out)
101 104
102 105 def getrevs(spec):
103 106 """get the list of rev matched by a revset"""
104 107 try:
105 108 out = check_output(['hg', 'log', '--template={rev}\n', '--rev', spec])
106 109 except CalledProcessError, exc:
107 110 print >> sys.stderr, "abort, can't get revision from %s" % spec
108 111 sys.exit(exc.returncode)
109 112 return [r for r in out.split() if r]
110 113
111 114
112 115 parser = OptionParser(usage="usage: %prog [options] <revs>")
113 116 parser.add_option("-f", "--file",
114 117 help="read revset from FILE (stdin if omitted)",
115 118 metavar="FILE")
116 119 parser.add_option("-R", "--repo",
117 120 help="run benchmark on REPO", metavar="REPO")
118 121
119 122 (options, args) = parser.parse_args()
120 123
121 124 if len(sys.argv) < 2:
122 125 parser.print_help()
123 126 sys.exit(255)
124 127
125 128 # the directory where both this script and the perf.py extension live.
126 129 contribdir = os.path.dirname(__file__)
127 130
128 131 target_rev = args[0]
129 132
130 133 revsetsfile = sys.stdin
131 134 if options.file:
132 135 revsetsfile = open(options.file)
133 136
134 137 revsets = [l.strip() for l in revsetsfile if not l.startswith('#')]
135 138
136 139 print "Revsets to benchmark"
137 140 print "----------------------------"
138 141
139 142 for idx, rset in enumerate(revsets):
140 143 print "%i) %s" % (idx, rset)
141 144
142 145 print "----------------------------"
143 146 print
144 147
145 148
146 149 revs = getrevs(target_rev)
147 150
148 151 results = []
149 152 for r in revs:
150 153 print "----------------------------"
151 154 printrevision(r)
152 155 print "----------------------------"
153 156 update(r)
154 157 res = []
155 158 results.append(res)
156 159 for idx, rset in enumerate(revsets):
157 160 data = perf(rset, target=options.repo)
158 161 res.append(data)
159 print "%i)" % idx, formatresult(data)
162 printresult(idx, data, len(revsets))
160 163 sys.stdout.flush()
161 164 print "----------------------------"
162 165
163 166
164 167 print """
165 168
166 169 Result by revset
167 170 ================
168 171 """
169 172
170 173 print 'Revision:', revs
171 174 for idx, rev in enumerate(revs):
172 175 sys.stdout.write('%i) ' % idx)
173 176 sys.stdout.flush()
174 177 printrevision(rev)
175 178
176 179 print
177 180 print
178 181
179 182 for ridx, rset in enumerate(revsets):
180 183
181 184 print "revset #%i: %s" % (ridx, rset)
182 185 for idx, data in enumerate(results):
183 print '%i) %s' % (idx, formatresult(data[ridx]))
186 printresult(idx, data[ridx], len(results))
184 187 print
General Comments 0
You need to be logged in to leave comments. Login now