Chromium Code Reviews| 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 opening Chromium for you. After testing the specific revision, | |
| 12 it will continuing the process. | |
|
Ian Vollick
2012/09/18 17:46:32
Does this script do all the guessing and asking th
hartmanng
2012/09/19 02:17:55
Done.
| |
| 13 """ | |
| 14 | |
| 15 import optparse | |
| 16 import os | |
| 17 import sys | |
| 18 import tempfile | |
| 19 from distutils.version import LooseVersion | |
| 20 | |
| 21 sys.path.insert(0, "..") | |
|
Ian Vollick
2012/09/18 17:46:32
Does this make an assumption about where the scrip
hartmanng
2012/09/19 02:17:55
Done.
| |
| 22 bisect_builds = __import__('bisect-builds') | |
| 23 | |
| 24 def gather_stats(platform, | |
| 25 official_builds, | |
| 26 execute, | |
| 27 start_rev=0, | |
| 28 end_rev=0, | |
| 29 num_runs=1, | |
| 30 stdoutdir=None): | |
| 31 """Given start and known end revisions, run sequentially | |
| 32 on archived revisions, gathering performance stats at each one. | |
| 33 | |
| 34 @param platform Which build to download/run ('mac', 'win', 'linux64', etc.). | |
| 35 @param official_builds Specify build type (Chromium or Official build). | |
| 36 @param execute String specifying what command to run at each revision. | |
| 37 @param start_rev Number/tag of the revision to start on. | |
| 38 @param end_rev Number/tag of the revision to end on. | |
| 39 @param num_runs Number of times to run each build. | |
| 40 @param stdoutdir The (optional) path to an output directory.""" | |
| 41 | |
| 42 context = bisect_builds.PathContext(platform, start_rev, end_rev, | |
| 43 official_builds) | |
| 44 cwd = os.getcwd() | |
| 45 | |
| 46 | |
| 47 print "Downloading list of known revisions..." | |
| 48 _GetDownloadPath = lambda rev: os.path.join(cwd, | |
| 49 '%s-%s' % (str(rev), context.archive_name)) | |
| 50 if official_builds: | |
| 51 revlist = context.GetOfficialBuildsList() | |
| 52 else: | |
| 53 revlist = context.GetRevList() | |
| 54 | |
| 55 print 'Running on range [%s, %s].' % (revlist[0], revlist[-1]) | |
| 56 | |
| 57 # Figure out our bookends and first pivot point; fetch the pivot revision. | |
|
Ian Vollick
2012/09/18 17:46:32
Should avoid bisect-specific language now. Pivot i
hartmanng
2012/09/19 02:17:55
Done.
| |
| 58 rev = revlist[0] | |
| 59 next_rev = 0 | |
| 60 zipfile = _GetDownloadPath(rev) | |
| 61 initial_fetch = bisect_builds.DownloadJob(context, 'initial_fetch', rev, | |
| 62 zipfile) | |
| 63 initial_fetch.Start() | |
| 64 initial_fetch.WaitFor() | |
| 65 pivot = 1 | |
| 66 | |
| 67 while zipfile and pivot < len(revlist): | |
|
Ian Vollick
2012/09/18 17:46:32
Why not 'for rev in revlist:'?
Also, isn't pivot
hartmanng
2012/09/19 02:17:55
Yes you're right, it didn't test the last revision
| |
| 68 # Pre-fetch next pivot | |
| 69 cur_fetch = None | |
| 70 next_rev = revlist[pivot] | |
| 71 cur_fetch = bisect_builds.DownloadJob(context, 'cur_fetch', next_rev, | |
| 72 _GetDownloadPath(next_rev)) | |
| 73 cur_fetch.Start() | |
| 74 | |
| 75 # Run test on the pivot revision. | |
| 76 tempdir = tempfile.mkdtemp(prefix='gather_stats_tmp') | |
| 77 args = (execute % os.path.join(tempdir, | |
| 78 context.GetLaunchPath())).split(' ') | |
| 79 print args | |
| 80 (status, stdout, stderr) = bisect_builds.RunRevision(context, | |
| 81 rev, | |
| 82 zipfile, | |
| 83 num_runs, | |
| 84 args, | |
| 85 tempdir, | |
| 86 stdoutdir) | |
| 87 try: | |
| 88 shutil.rmtree(tempdir, True) | |
| 89 except Exception, e: | |
| 90 pass | |
| 91 | |
| 92 rev = next_rev | |
| 93 | |
| 94 os.unlink(zipfile) | |
| 95 zipfile = None | |
| 96 | |
| 97 # Wait for fetch to complete. | |
| 98 try: | |
| 99 if cur_fetch: | |
| 100 cur_fetch.WaitFor() | |
| 101 pivot = pivot + 1 | |
| 102 zipfile = cur_fetch.zipfile | |
| 103 except SystemExit: | |
| 104 print "Cleaning up..." | |
| 105 for f in [_GetDownloadPath(revlist[pivot])]: | |
| 106 try: | |
| 107 os.unlink(f) | |
| 108 except OSError: | |
| 109 pass | |
| 110 sys.exit(0) | |
| 111 | |
| 112 return 0 | |
| 113 | |
| 114 def main(): | |
| 115 usage = ('%prog [options]\n' | |
| 116 'Perform binary search on the snapshot builds.\n' | |
|
Ian Vollick
2012/09/18 17:46:32
This text needs to be updated.
hartmanng
2012/09/19 02:17:55
Done.
| |
| 117 '\n' | |
| 118 'Tip: add "-- --no-first-run" to bypass the first run prompts.') | |
| 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.') | |
|
Ian Vollick
2012/09/18 17:46:32
0's a rough starting revision! It would be nice if
hartmanng
2012/09/19 02:17:55
I agree, but do you know a good way to get dates o
| |
| 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 (opts, args) = parser.parse_args() | |
| 151 | |
| 152 if opts.archive is None: | |
| 153 print 'Error: missing required parameter: --archive' | |
| 154 print | |
| 155 parser.print_help() | |
| 156 return 1 | |
| 157 | |
| 158 # Create the context. Initialize 0 for the revisions as they are set below. | |
| 159 context = bisect_builds.PathContext(opts.archive, 0, 0, opts.official_builds) | |
| 160 # Pick a starting point, try to get HEAD for this. | |
| 161 if opts.end: | |
| 162 end_rev = opts.end | |
| 163 else: | |
| 164 end_rev = '999.0.0.0' | |
| 165 if not opts.official_builds: | |
| 166 end_rev = GetChromiumRevision(context.GetLastChangeURL()) | |
| 167 | |
| 168 # Find out when we were good. | |
| 169 if opts.start: | |
| 170 start_rev = opts.start | |
| 171 else: | |
| 172 start_rev = '0.0.0.0' if opts.official_builds else 0 | |
| 173 | |
| 174 if opts.official_builds: | |
| 175 start_rev = LooseVersion(start_rev) | |
| 176 end_rev = LooseVersion(end_rev) | |
| 177 else: | |
| 178 start_rev = int(start_rev) | |
| 179 end_rev = int(end_rev) | |
| 180 | |
| 181 if start_rev > end_rev: | |
| 182 print ('The start revision (%s) must precede the end revision (%s).\n' % | |
| 183 (start_rev, end_rev)) | |
| 184 parser.print_help() | |
| 185 return 1 | |
| 186 | |
| 187 if opts.times < 1: | |
| 188 print('Number of times to run (%d) must be greater than or equal to 1.' % | |
| 189 opts.times) | |
| 190 parser.print_help() | |
| 191 return 1 | |
| 192 | |
| 193 return gather_stats(opts.archive, opts.official_builds, opts.execute, | |
| 194 start_rev, end_rev, opts.times, opts.output_directory) | |
| 195 | |
| 196 if __name__ == '__main__': | |
| 197 sys.exit(main()) | |
| OLD | NEW |