##// END OF EJS Templates
revsetbenchmarks: clarify comment based on irc discussion
Augie Fackler -
r25533:4bdf6f58 default
parent child Browse files
Show More
@@ -1,200 +1,203
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 95 def idxwidth(nbidx):
96 96 """return the max width of number used for index
97 97
98 Yes, this is basically a log10."""
98 This is similar to log10(nbidx), but we use custom code here
99 because we start with zero and we'd rather not deal with all the
100 extra rounding business that log10 would imply.
101 """
99 102 nbidx -= 1 # starts at 0
100 103 idxwidth = 0
101 104 while nbidx:
102 105 idxwidth += 1
103 106 nbidx //= 10
104 107 if not idxwidth:
105 108 idxwidth = 1
106 109 return idxwidth
107 110
108 111 def printresult(idx, data, maxidx):
109 112 """print a line of result to stdout"""
110 113 mask = '%%0%ii) %%s' % idxwidth(maxidx)
111 114
112 115 out = ("wall %f comb %f user %f sys %f (best of %d)"
113 116 % (data['wall'], data['comb'], data['user'],
114 117 data['sys'], data['count']))
115 118
116 119 print mask % (idx, out)
117 120
118 121 def getrevs(spec):
119 122 """get the list of rev matched by a revset"""
120 123 try:
121 124 out = check_output(['hg', 'log', '--template={rev}\n', '--rev', spec])
122 125 except CalledProcessError, exc:
123 126 print >> sys.stderr, "abort, can't get revision from %s" % spec
124 127 sys.exit(exc.returncode)
125 128 return [r for r in out.split() if r]
126 129
127 130
128 131 parser = OptionParser(usage="usage: %prog [options] <revs>")
129 132 parser.add_option("-f", "--file",
130 133 help="read revset from FILE (stdin if omitted)",
131 134 metavar="FILE")
132 135 parser.add_option("-R", "--repo",
133 136 help="run benchmark on REPO", metavar="REPO")
134 137
135 138 (options, args) = parser.parse_args()
136 139
137 140 if len(sys.argv) < 2:
138 141 parser.print_help()
139 142 sys.exit(255)
140 143
141 144 # the directory where both this script and the perf.py extension live.
142 145 contribdir = os.path.dirname(__file__)
143 146
144 147 target_rev = args[0]
145 148
146 149 revsetsfile = sys.stdin
147 150 if options.file:
148 151 revsetsfile = open(options.file)
149 152
150 153 revsets = [l.strip() for l in revsetsfile if not l.startswith('#')]
151 154
152 155 print "Revsets to benchmark"
153 156 print "----------------------------"
154 157
155 158 for idx, rset in enumerate(revsets):
156 159 print "%i) %s" % (idx, rset)
157 160
158 161 print "----------------------------"
159 162 print
160 163
161 164
162 165 revs = getrevs(target_rev)
163 166
164 167 results = []
165 168 for r in revs:
166 169 print "----------------------------"
167 170 printrevision(r)
168 171 print "----------------------------"
169 172 update(r)
170 173 res = []
171 174 results.append(res)
172 175 for idx, rset in enumerate(revsets):
173 176 data = perf(rset, target=options.repo)
174 177 res.append(data)
175 178 printresult(idx, data, len(revsets))
176 179 sys.stdout.flush()
177 180 print "----------------------------"
178 181
179 182
180 183 print """
181 184
182 185 Result by revset
183 186 ================
184 187 """
185 188
186 189 print 'Revision:', revs
187 190 for idx, rev in enumerate(revs):
188 191 sys.stdout.write('%i) ' % idx)
189 192 sys.stdout.flush()
190 193 printrevision(rev)
191 194
192 195 print
193 196 print
194 197
195 198 for ridx, rset in enumerate(revsets):
196 199
197 200 print "revset #%i: %s" % (ridx, rset)
198 201 for idx, data in enumerate(results):
199 202 printresult(idx, data[ridx], len(results))
200 203 print
General Comments 0
You need to be logged in to leave comments. Login now