OLD | NEW |
---|---|
(Empty) | |
1 #!/usr/bin/env python | |
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
3 # Use of this source code is governed by a BSD-style license that can be | |
4 # found in the LICENSE file. | |
5 | |
6 """Snapshot Build Linear Benchmark Tool | |
7 | |
8 This script executes and gathers stats from a series of snapshot archives. It | |
9 starts at a start revision (it will try to guess HEAD) and asks for an end | |
10 revision. It will then linearly run across this revision range by downloading, | |
11 unzipping, and gathers stats for each revision. | |
12 """ | |
13 | |
14 import optparse | |
15 import os | |
16 import sys | |
17 from distutils.version import LooseVersion | |
18 import inspect | |
19 | |
20 cmd_folder = os.path.realpath(os.path.abspath(os.path.split(inspect.getfile( | |
21 inspect.currentframe() ))[0])) | |
22 | |
23 bisect_builds_dir = os.path.join(cmd_folder, "..") | |
24 | |
25 if bisect_builds_dir not in sys.path: | |
26 sys.path.insert(0, bisect_builds_dir) | |
27 | |
28 bisect_builds = __import__('bisect-builds') | |
29 | |
30 def gather_stats(platform, | |
Robert Sesek
2012/09/24 17:52:30
Chromium style should be GatherStats.
hartmanng
2012/09/24 20:13:20
Done.
| |
31 official_builds, | |
32 execute, | |
33 start_rev=0, | |
34 end_rev=0, | |
35 num_runs=1, | |
36 stdoutdir=None): | |
37 """Given start and known end revisions, run sequentially | |
38 on archived revisions, gathering performance stats at each one. | |
39 | |
40 @param platform Which build to download/run ('mac', 'win', 'linux64', etc.). | |
41 @param official_builds Specify build type (Chromium or Official build). | |
42 @param execute String specifying what command to run at each revision. | |
43 @param start_rev Number/tag of the revision to start on. | |
44 @param end_rev Number/tag of the revision to end on. | |
45 @param num_runs Number of times to run each build. | |
46 @param stdoutdir The (optional) path to an output directory.""" | |
47 | |
48 context = bisect_builds.PathContext(platform, start_rev, end_rev, | |
49 official_builds) | |
50 cwd = os.getcwd() | |
51 | |
52 | |
53 print "Downloading list of known revisions..." | |
54 _GetDownloadPath = lambda rev: os.path.join(cwd, | |
55 '%s-%s' % (str(rev), context.archive_name)) | |
56 if official_builds: | |
57 revlist = context.GetOfficialBuildsList() | |
58 else: | |
59 revlist = context.GetRevList() | |
60 | |
61 print 'Running on range [%s, %s].' % (revlist[0], revlist[-1]) | |
62 | |
63 # Initialize our revision index and fetch the first revision. | |
64 rev = revlist[0] | |
65 next_rev = 0 | |
66 zipfile = _GetDownloadPath(rev) | |
67 initial_fetch = bisect_builds.DownloadJob(context, 'initial_fetch', rev, | |
68 zipfile) | |
69 initial_fetch.Start() | |
70 initial_fetch.WaitFor() | |
71 index = 1 | |
72 | |
73 while zipfile and index <= len(revlist): | |
74 cur_fetch = None | |
75 if index < len(revlist): | |
76 # Pre-fetch next revision | |
77 next_rev = revlist[index] | |
78 cur_fetch = bisect_builds.DownloadJob(context, 'cur_fetch', next_rev, | |
79 _GetDownloadPath(next_rev)) | |
80 cur_fetch.Start() | |
81 | |
82 # Run test on the index revision. | |
83 def execute_args(chrome_path): | |
84 return (execute % chrome_path).split(' ') | |
85 | |
86 # Run test on the index revision. | |
87 (status, stdout, stderr) = bisect_builds.RunRevision(context, | |
88 rev, | |
89 zipfile, | |
90 num_runs, | |
91 execute_args, | |
92 stdoutdir) | |
93 | |
94 rev = next_rev | |
95 | |
96 os.unlink(zipfile) | |
97 zipfile = None | |
98 | |
99 # Wait for fetch to complete. | |
100 try: | |
101 if cur_fetch: | |
102 cur_fetch.WaitFor() | |
103 index = index + 1 | |
104 zipfile = cur_fetch.zipfile | |
105 except SystemExit: | |
106 print "Cleaning up..." | |
107 for f in [_GetDownloadPath(revlist[index])]: | |
108 try: | |
109 os.unlink(f) | |
110 except OSError: | |
111 pass | |
112 sys.exit(0) | |
113 | |
114 return 0 | |
115 | |
116 def main(): | |
117 usage = ('%prog [options]\n' | |
118 'Collects benchmark statistics on snapshot builds.\n') | |
119 parser = optparse.OptionParser(usage=usage) | |
120 # Strangely, the default help output doesn't include the choice list. | |
121 choices = ['mac', 'win', 'linux', 'linux64'] | |
122 # linux-chromiumos lacks a continuous archive http://crbug.com/78158 | |
123 parser.add_option('-a', '--archive', | |
124 choices = choices, | |
125 help = 'The buildbot archive to run [%s].' % | |
126 '|'.join(choices)) | |
127 parser.add_option('-o', action="store_true", dest='official_builds', | |
128 help = 'Run across official ' + | |
129 'Chrome builds (internal only) instead of ' + | |
130 'Chromium archives.') | |
131 parser.add_option('-e', '--end', type = 'str', | |
132 help = 'The revision to end on. Default is HEAD.') | |
133 parser.add_option('-s', '--start', type = 'str', | |
134 help = 'The revision to start from. Default is 0.') | |
135 parser.add_option('-t', '--times', type = 'int', | |
136 help = 'Number of times to run each build. Temporary' + | |
137 ' profiles are reused. Default is 1.', | |
138 default = 1) | |
139 parser.add_option('-x', '--execute', type='str', | |
140 help = 'Command to execute for each revision. Include a ' + | |
141 'single %s to specify the location of the downloaded ' + | |
142 'chrome executable. Default is \'python ' + | |
143 'run_scrolling_benchmark page_sets/Q32012.json ' + | |
144 '--browser-executable=%s\'.', | |
145 default = 'python ./run_scrolling_benchmark ' + | |
146 'page_sets/Q32012.json --browser-executable=%s') | |
147 parser.add_option('-d', '--output-directory', '--stdoutdir', type='str', | |
148 help = 'Save stdout to files for each revision.', | |
149 default = None) | |
150 parser.add_option('-r', '--revisions', type = 'int', | |
151 help = 'Number of revisions to run if a start revision ' + | |
152 'isn\'t specified. Default is 500.', | |
153 default = 500) | |
154 (opts, args) = parser.parse_args() | |
155 | |
156 if opts.archive is None: | |
157 print 'Error: missing required parameter: --archive' | |
158 print | |
159 parser.print_help() | |
160 return 1 | |
161 | |
162 # Create the context. Initialize 0 for the revisions as they are set below. | |
163 context = bisect_builds.PathContext(opts.archive, 0, 0, opts.official_builds) | |
164 # Pick a starting point, try to get HEAD for this. | |
165 if opts.end: | |
166 end_rev = opts.end | |
167 else: | |
168 end_rev = '999.0.0.0' | |
169 if not opts.official_builds: | |
170 end_rev = GetChromiumRevision(context.GetLastChangeURL()) | |
171 | |
172 # Find out where to start. | |
173 if opts.start: | |
174 start_rev = opts.start | |
175 else: | |
176 if opts.official_builds: | |
177 r = int(end_rev[:end_rev.find('.')]) - opts.revisions + 1 | |
178 start_rev = str(r) + '.0.0.0' | |
179 else: | |
180 start_rev = int(end_rev) - opts.revisions + 1 | |
181 | |
182 if opts.official_builds: | |
183 start_rev = LooseVersion(start_rev) | |
184 end_rev = LooseVersion(end_rev) | |
185 else: | |
186 start_rev = int(start_rev) | |
187 end_rev = int(end_rev) | |
188 | |
189 if opts.official_builds and start_rev < LooseVersion('0.0.0.0') or \ | |
190 not opts.official_builds and start_rev < 0: | |
191 print ('The start revision (%s) must be greater than 0.\n' % start_rev) | |
192 parser.print_help() | |
193 return 1 | |
194 | |
195 if start_rev > end_rev: | |
196 print ('The start revision (%s) must precede the end revision (%s).\n' % | |
197 (start_rev, end_rev)) | |
198 parser.print_help() | |
199 return 1 | |
200 | |
201 if opts.times < 1: | |
202 print('Number of times to run (%d) must be greater than or equal to 1.' % | |
203 opts.times) | |
204 parser.print_help() | |
205 return 1 | |
206 | |
207 return gather_stats(opts.archive, opts.official_builds, opts.execute, | |
208 start_rev, end_rev, opts.times, opts.output_directory) | |
209 | |
210 if __name__ == '__main__': | |
211 sys.exit(main()) | |
OLD | NEW |