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