Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # | 2 # |
| 3 # Copyright 2012 the V8 project authors. All rights reserved. | 3 # Copyright 2012 the V8 project authors. All rights reserved. |
| 4 # Redistribution and use in source and binary forms, with or without | 4 # Redistribution and use in source and binary forms, with or without |
| 5 # modification, are permitted provided that the following conditions are | 5 # modification, are permitted provided that the following conditions are |
| 6 # met: | 6 # met: |
| 7 # | 7 # |
| 8 # * Redistributions of source code must retain the above copyright | 8 # * Redistributions of source code must retain the above copyright |
| 9 # notice, this list of conditions and the following disclaimer. | 9 # notice, this list of conditions and the following disclaimer. |
| 10 # * Redistributions in binary form must reproduce the above | 10 # * Redistributions in binary form must reproduce the above |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 21 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 21 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 22 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 22 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 23 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 23 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 29 | 29 |
| 30 | 30 |
| 31 import json | |
| 32 import math | |
| 31 import multiprocessing | 33 import multiprocessing |
| 32 import optparse | 34 import optparse |
| 33 import os | 35 import os |
| 34 from os.path import join | 36 from os.path import join |
| 37 import random | |
| 35 import shlex | 38 import shlex |
| 36 import subprocess | 39 import subprocess |
| 37 import sys | 40 import sys |
| 38 import time | 41 import time |
| 39 | 42 |
| 40 from testrunner.local import execution | 43 from testrunner.local import execution |
| 41 from testrunner.local import progress | 44 from testrunner.local import progress |
| 42 from testrunner.local import testsuite | 45 from testrunner.local import testsuite |
| 43 from testrunner.local import utils | 46 from testrunner.local import utils |
| 44 from testrunner.local import verbose | 47 from testrunner.local import verbose |
| 45 from testrunner.network import network_execution | |
| 46 from testrunner.objects import context | 48 from testrunner.objects import context |
| 47 | 49 |
| 48 | 50 |
| 49 ARCH_GUESS = utils.DefaultArch() | 51 ARCH_GUESS = utils.DefaultArch() |
| 50 DEFAULT_TESTS = ["mjsunit", "cctest", "message", "preparser"] | 52 DEFAULT_TESTS = ["mjsunit"] |
| 51 TIMEOUT_DEFAULT = 60 | 53 TIMEOUT_DEFAULT = 60 |
| 52 TIMEOUT_SCALEFACTOR = {"debug" : 4, | 54 TIMEOUT_SCALEFACTOR = {"debug" : 4, |
| 53 "release" : 1 } | 55 "release" : 1 } |
| 54 | 56 |
| 55 # Use this to run several variants of the tests. | |
| 56 VARIANT_FLAGS = [[], | |
| 57 ["--stress-opt", "--always-opt"], | |
| 58 ["--nocrankshaft"]] | |
| 59 MODE_FLAGS = { | 57 MODE_FLAGS = { |
| 60 "debug" : ["--nobreak-on-abort", "--nodead-code-elimination", | 58 "debug" : ["--nobreak-on-abort", "--nodead-code-elimination", |
| 61 "--nofold-constants", "--enable-slow-asserts", | 59 "--nofold-constants", "--enable-slow-asserts", |
| 62 "--debug-code", "--verify-heap"], | 60 "--debug-code", "--verify-heap", |
| 61 "--noparallel-recompilation"], | |
| 63 "release" : ["--nobreak-on-abort", "--nodead-code-elimination", | 62 "release" : ["--nobreak-on-abort", "--nodead-code-elimination", |
| 64 "--nofold-constants"]} | 63 "--nofold-constants", "--noparallel-recompilation"]} |
| 65 | 64 |
| 66 SUPPORTED_ARCHS = ["android_arm", | 65 SUPPORTED_ARCHS = ["android_arm", |
| 67 "android_ia32", | 66 "android_ia32", |
| 68 "arm", | 67 "arm", |
| 69 "ia32", | 68 "ia32", |
| 70 "mipsel", | 69 "mipsel", |
| 71 "nacl_ia32", | 70 "nacl_ia32", |
| 72 "nacl_x64", | 71 "nacl_x64", |
| 73 "x64"] | 72 "x64"] |
| 74 # Double the timeout for these: | 73 # Double the timeout for these: |
| 75 SLOW_ARCHS = ["android_arm", | 74 SLOW_ARCHS = ["android_arm", |
| 76 "android_ia32", | 75 "android_ia32", |
| 77 "arm", | 76 "arm", |
| 78 "mipsel", | 77 "mipsel", |
| 79 "nacl_ia32", | 78 "nacl_ia32", |
| 80 "nacl_x64"] | 79 "nacl_x64"] |
| 80 MAX_DEOPT = 1000000000 | |
| 81 DISTRIBUTION_MODES = ["smooth", "random"] | |
| 82 | |
| 83 | |
| 84 class RandomDistribution: | |
| 85 def __init__(self, seed=None): | |
| 86 seed = seed or random.randint(1, sys.maxint) | |
| 87 print "Using random distribution with seed %d" % seed | |
| 88 self._random = random.Random(seed) | |
| 89 | |
| 90 def Distribute(self, n, m): | |
| 91 if n > m: | |
| 92 n = m | |
| 93 return self._random.sample(xrange(1, m + 1), n) | |
| 94 | |
| 95 | |
| 96 class SmoothDistribution: | |
| 97 """Distribute n numbers into the interval [1:m]. | |
| 98 F1: Factor of the first derivation of the distribution function. | |
| 99 F2: Factor of the second derivation of the distribution function. | |
| 100 With F1 and F2 set to 0, the distribution will be equal. | |
| 101 """ | |
| 102 def __init__(self, factor1=2.0, factor2=0.2): | |
| 103 self._factor1 = factor1 | |
| 104 self._factor2 = factor2 | |
| 105 | |
| 106 def Distribute(self, n, m): | |
| 107 if n > m: | |
| 108 n = m | |
| 109 if n <= 1: | |
| 110 return [ 1 ] | |
| 111 | |
| 112 result = [] | |
| 113 x = 0.0 | |
| 114 dx = 1.0 | |
| 115 ddx = self._factor1 | |
| 116 dddx = self._factor2 | |
| 117 for i in range(0, n): | |
| 118 result += [ x ] | |
| 119 x += dx | |
| 120 dx += ddx | |
| 121 ddx += dddx | |
| 122 | |
| 123 # Project the distribution into the interval [0:M]. | |
| 124 result = [ x * m / result[-1] for x in result ] | |
| 125 | |
| 126 # Equalize by n. The closer n is to m, the more equal will be the | |
| 127 # distribution. | |
| 128 for (i, x) in enumerate(result): | |
| 129 # The value of x if it was equally distributed. | |
| 130 equal_x = i / float(n - 1) * float(m - 1) + 1 | |
| 131 | |
| 132 # Difference factor between actual and equal distribution. | |
| 133 diff = 1 - (x / equal_x) | |
| 134 | |
| 135 # Equalize x dependent on the number of values to distribute. | |
| 136 result[i] = int(x + (i + 1) * diff) | |
| 137 return result | |
| 138 | |
| 139 | |
| 140 def Distribution(options): | |
| 141 if options.distribution_mode == "random": | |
| 142 return RandomDistribution(options.seed) | |
| 143 if options.distribution_mode == "smooth": | |
| 144 return SmoothDistribution(options.distribution_factor1, | |
| 145 options.distribution_factor2) | |
| 81 | 146 |
| 82 | 147 |
| 83 def BuildOptions(): | 148 def BuildOptions(): |
| 84 result = optparse.OptionParser() | 149 result = optparse.OptionParser() |
| 85 result.add_option("--arch", | 150 result.add_option("--arch", |
| 86 help=("The architecture to run tests for, " | 151 help=("The architecture to run tests for, " |
| 87 "'auto' or 'native' for auto-detect"), | 152 "'auto' or 'native' for auto-detect"), |
| 88 default="ia32,x64,arm") | 153 default="ia32,x64,arm") |
| 89 result.add_option("--arch-and-mode", | 154 result.add_option("--arch-and-mode", |
| 90 help="Architecture and mode in the format 'arch.mode'", | 155 help="Architecture and mode in the format 'arch.mode'", |
| 91 default=None) | 156 default=None) |
| 92 result.add_option("--buildbot", | 157 result.add_option("--buildbot", |
| 93 help="Adapt to path structure used on buildbots", | 158 help="Adapt to path structure used on buildbots", |
| 94 default=False, action="store_true") | 159 default=False, action="store_true") |
| 95 result.add_option("--cat", help="Print the source of the tests", | |
| 96 default=False, action="store_true") | |
| 97 result.add_option("--command-prefix", | 160 result.add_option("--command-prefix", |
| 98 help="Prepended to each shell command used to run a test", | 161 help="Prepended to each shell command used to run a test", |
| 99 default="") | 162 default="") |
| 163 result.add_option("--coverage", help=("Exponential test coverage " | |
| 164 "(range 0.0, 1.0) -- 0.0: one test, 1.0 all tests (slow)"), | |
| 165 default=0.4, type="float") | |
| 166 result.add_option("--coverage-lift", help=("Lifts test coverage for tests " | |
| 167 "with a small number of deopt points (range 0, inf)"), | |
| 168 default=20, type="int") | |
| 100 result.add_option("--download-data", help="Download missing test suite data", | 169 result.add_option("--download-data", help="Download missing test suite data", |
| 101 default=False, action="store_true") | 170 default=False, action="store_true") |
| 171 result.add_option("--distribution-factor1", help=("Factor of the first " | |
| 172 "derivation of the distribution function"), default=2.0, | |
| 173 type="float") | |
| 174 result.add_option("--distribution-factor2", help=("Factor of the second " | |
| 175 "derivation of the distribution function"), default=0.7, | |
| 176 type="float") | |
| 177 result.add_option("--distribution-mode", help=("How to select deopt points " | |
| 178 "for a given test (smooth|random)"), | |
| 179 default="smooth") | |
| 180 result.add_option("--dump-results-file", help=("Dump maximum number of " | |
| 181 "deopt points per test to a file")) | |
| 102 result.add_option("--extra-flags", | 182 result.add_option("--extra-flags", |
| 103 help="Additional flags to pass to each test command", | 183 help="Additional flags to pass to each test command", |
| 104 default="") | 184 default="") |
| 105 result.add_option("--isolates", help="Whether to test isolates", | 185 result.add_option("--isolates", help="Whether to test isolates", |
| 106 default=False, action="store_true") | 186 default=False, action="store_true") |
| 107 result.add_option("-j", help="The number of parallel tasks to run", | 187 result.add_option("-j", help="The number of parallel tasks to run", |
| 108 default=0, type="int") | 188 default=0, type="int") |
| 109 result.add_option("-m", "--mode", | 189 result.add_option("-m", "--mode", |
| 110 help="The test modes in which to run (comma-separated)", | 190 help="The test modes in which to run (comma-separated)", |
| 111 default="release,debug") | 191 default="release,debug") |
| 112 result.add_option("--no-network", "--nonetwork", | |
| 113 help="Don't distribute tests on the network", | |
| 114 default=(utils.GuessOS() != "linux"), | |
| 115 dest="no_network", action="store_true") | |
| 116 result.add_option("--no-presubmit", "--nopresubmit", | |
| 117 help='Skip presubmit checks', | |
| 118 default=False, dest="no_presubmit", action="store_true") | |
| 119 result.add_option("--no-stress", "--nostress", | |
| 120 help="Don't run crankshaft --always-opt --stress-op test", | |
| 121 default=False, dest="no_stress", action="store_true") | |
| 122 result.add_option("--outdir", help="Base directory with compile output", | 192 result.add_option("--outdir", help="Base directory with compile output", |
| 123 default="out") | 193 default="out") |
| 124 result.add_option("-p", "--progress", | 194 result.add_option("-p", "--progress", |
| 125 help=("The style of progress indicator" | 195 help=("The style of progress indicator" |
| 126 " (verbose, dots, color, mono)"), | 196 " (verbose, dots, color, mono)"), |
| 127 choices=progress.PROGRESS_INDICATORS.keys(), default="mono") | 197 choices=progress.PROGRESS_INDICATORS.keys(), |
| 128 result.add_option("--report", help="Print a summary of the tests to be run", | 198 default="mono") |
| 129 default=False, action="store_true") | |
| 130 result.add_option("--shard-count", | 199 result.add_option("--shard-count", |
| 131 help="Split testsuites into this number of shards", | 200 help="Split testsuites into this number of shards", |
| 132 default=1, type="int") | 201 default=1, type="int") |
| 133 result.add_option("--shard-run", | 202 result.add_option("--shard-run", |
| 134 help="Run this shard from the split up tests.", | 203 help="Run this shard from the split up tests.", |
| 135 default=1, type="int") | 204 default=1, type="int") |
| 136 result.add_option("--shell", help="DEPRECATED! use --shell-dir", default="") | |
| 137 result.add_option("--shell-dir", help="Directory containing executables", | 205 result.add_option("--shell-dir", help="Directory containing executables", |
| 138 default="") | 206 default="") |
| 139 result.add_option("--stress-only", | 207 result.add_option("--seed", help="The seed for the random distribution", |
| 140 help="Only run tests with --always-opt --stress-opt", | 208 type="int") |
| 141 default=False, action="store_true") | |
| 142 result.add_option("--time", help="Print timing information after running", | |
| 143 default=False, action="store_true") | |
| 144 result.add_option("-t", "--timeout", help="Timeout in seconds", | 209 result.add_option("-t", "--timeout", help="Timeout in seconds", |
| 145 default= -1, type="int") | 210 default= -1, type="int") |
| 146 result.add_option("-v", "--verbose", help="Verbose output", | 211 result.add_option("-v", "--verbose", help="Verbose output", |
| 147 default=False, action="store_true") | 212 default=False, action="store_true") |
| 148 result.add_option("--valgrind", help="Run tests through valgrind", | |
| 149 default=False, action="store_true") | |
| 150 result.add_option("--warn-unused", help="Report unused rules", | |
| 151 default=False, action="store_true") | |
| 152 result.add_option("--junitout", help="File name of the JUnit output") | |
| 153 result.add_option("--junittestsuite", | |
| 154 help="The testsuite name in the JUnit output file", | |
| 155 default="v8tests") | |
| 156 return result | 213 return result |
| 157 | 214 |
| 158 | 215 |
| 159 def ProcessOptions(options): | 216 def ProcessOptions(options): |
| 160 global VARIANT_FLAGS | 217 global VARIANT_FLAGS |
| 161 | 218 |
| 162 # Architecture and mode related stuff. | 219 # Architecture and mode related stuff. |
| 163 if options.arch_and_mode: | 220 if options.arch_and_mode: |
| 164 tokens = options.arch_and_mode.split(".") | 221 tokens = options.arch_and_mode.split(".") |
| 165 options.arch = tokens[0] | 222 options.arch = tokens[0] |
| 166 options.mode = tokens[1] | 223 options.mode = tokens[1] |
| 167 options.mode = options.mode.split(",") | 224 options.mode = options.mode.split(",") |
| 168 for mode in options.mode: | 225 for mode in options.mode: |
| 169 if not mode.lower() in ["debug", "release"]: | 226 if not mode.lower() in ["debug", "release"]: |
| 170 print "Unknown mode %s" % mode | 227 print "Unknown mode %s" % mode |
| 171 return False | 228 return False |
| 172 if options.arch in ["auto", "native"]: | 229 if options.arch in ["auto", "native"]: |
| 173 options.arch = ARCH_GUESS | 230 options.arch = ARCH_GUESS |
| 174 options.arch = options.arch.split(",") | 231 options.arch = options.arch.split(",") |
| 175 for arch in options.arch: | 232 for arch in options.arch: |
| 176 if not arch in SUPPORTED_ARCHS: | 233 if not arch in SUPPORTED_ARCHS: |
| 177 print "Unknown architecture %s" % arch | 234 print "Unknown architecture %s" % arch |
| 178 return False | 235 return False |
| 179 | 236 |
| 180 # Special processing of other options, sorted alphabetically. | 237 # Special processing of other options, sorted alphabetically. |
| 181 | |
| 182 if options.buildbot: | |
| 183 # Buildbots run presubmit tests as a separate step. | |
| 184 options.no_presubmit = True | |
| 185 options.no_network = True | |
| 186 if options.command_prefix: | |
| 187 print("Specifying --command-prefix disables network distribution, " | |
| 188 "running tests locally.") | |
| 189 options.no_network = True | |
| 190 options.command_prefix = shlex.split(options.command_prefix) | 238 options.command_prefix = shlex.split(options.command_prefix) |
| 191 options.extra_flags = shlex.split(options.extra_flags) | 239 options.extra_flags = shlex.split(options.extra_flags) |
| 192 if options.j == 0: | 240 if options.j == 0: |
| 193 options.j = multiprocessing.cpu_count() | 241 options.j = multiprocessing.cpu_count() |
| 194 if options.no_stress: | 242 if not options.distribution_mode in DISTRIBUTION_MODES: |
| 195 VARIANT_FLAGS = [[], ["--nocrankshaft"]] | 243 print "Unknown distribution mode %s" % options.distribution_mode |
| 196 if not options.shell_dir: | 244 return False |
| 197 if options.shell: | 245 if options.distribution_factor1 < 0.0: |
| 198 print "Warning: --shell is deprecated, use --shell-dir instead." | 246 options.distribution_factor1 = 0.0 |
|
Jakob Kummerow
2013/07/23 15:13:43
might want to print a warning here too: "Invalid -
| |
| 199 options.shell_dir = os.path.dirname(options.shell) | 247 if options.distribution_factor2 < 0.0: |
| 200 if options.stress_only: | 248 options.distribution_factor2 = 0.0 |
| 201 VARIANT_FLAGS = [["--stress-opt", "--always-opt"]] | 249 if options.coverage < 0.0 or options.coverage > 1.0: |
| 202 if options.valgrind: | 250 options.coverage = 0.4 |
| 203 run_valgrind = os.path.join("tools", "run-valgrind.py") | 251 if options.coverage_lift < 0: |
| 204 # This is OK for distributed running, so we don't need to set no_network. | 252 options.coverage_lift = 0 |
| 205 options.command_prefix = (["python", "-u", run_valgrind] + | |
| 206 options.command_prefix) | |
| 207 return True | 253 return True |
| 208 | 254 |
| 209 | 255 |
| 210 def ShardTests(tests, shard_count, shard_run): | 256 def ShardTests(tests, shard_count, shard_run): |
| 211 if shard_count < 2: | 257 if shard_count < 2: |
| 212 return tests | 258 return tests |
| 213 if shard_run < 1 or shard_run > shard_count: | 259 if shard_run < 1 or shard_run > shard_count: |
| 214 print "shard-run not a valid number, should be in [1:shard-count]" | 260 print "shard-run not a valid number, should be in [1:shard-count]" |
| 215 print "defaulting back to running all tests" | 261 print "defaulting back to running all tests" |
| 216 return tests | 262 return tests |
| 217 count = 0 | 263 count = 0 |
| 218 shard = [] | 264 shard = [] |
| 219 for test in tests: | 265 for test in tests: |
| 220 if count % shard_count == shard_run - 1: | 266 if count % shard_count == shard_run - 1: |
| 221 shard.append(test) | 267 shard.append(test) |
| 222 count += 1 | 268 count += 1 |
| 223 return shard | 269 return shard |
| 224 | 270 |
| 225 | 271 |
| 226 def Main(): | 272 def Main(): |
| 227 parser = BuildOptions() | 273 parser = BuildOptions() |
| 228 (options, args) = parser.parse_args() | 274 (options, args) = parser.parse_args() |
| 229 if not ProcessOptions(options): | 275 if not ProcessOptions(options): |
| 230 parser.print_help() | 276 parser.print_help() |
| 231 return 1 | 277 return 1 |
| 232 | 278 |
| 233 exit_code = 0 | 279 exit_code = 0 |
| 234 workspace = os.path.abspath(join(os.path.dirname(sys.argv[0]), "..")) | 280 workspace = os.path.abspath(join(os.path.dirname(sys.argv[0]), "..")) |
| 235 if not options.no_presubmit: | |
| 236 print ">>> running presubmit tests" | |
| 237 code = subprocess.call( | |
| 238 [sys.executable, join(workspace, "tools", "presubmit.py")]) | |
| 239 exit_code = code | |
| 240 | 281 |
| 241 suite_paths = utils.GetSuitePaths(join(workspace, "test")) | 282 suite_paths = utils.GetSuitePaths(join(workspace, "test")) |
| 242 | 283 |
| 243 if len(args) == 0: | 284 if len(args) == 0: |
| 244 suite_paths = [ s for s in suite_paths if s in DEFAULT_TESTS ] | 285 suite_paths = [ s for s in suite_paths if s in DEFAULT_TESTS ] |
| 245 else: | 286 else: |
| 246 args_suites = set() | 287 args_suites = set() |
| 247 for arg in args: | 288 for arg in args: |
| 248 suite = arg.split(os.path.sep)[0] | 289 suite = arg.split(os.path.sep)[0] |
| 249 if not suite in args_suites: | 290 if not suite in args_suites: |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 261 for s in suites: | 302 for s in suites: |
| 262 s.DownloadData() | 303 s.DownloadData() |
| 263 | 304 |
| 264 for mode in options.mode: | 305 for mode in options.mode: |
| 265 for arch in options.arch: | 306 for arch in options.arch: |
| 266 code = Execute(arch, mode, args, options, suites, workspace) | 307 code = Execute(arch, mode, args, options, suites, workspace) |
| 267 exit_code = exit_code or code | 308 exit_code = exit_code or code |
| 268 return exit_code | 309 return exit_code |
| 269 | 310 |
| 270 | 311 |
| 312 def CalculateNTests(m, options): | |
| 313 """Calculates the number of tests from m deopt points with exponential | |
| 314 coverage. | |
| 315 The coverage is expected to be between 0.0 and 1.0. | |
| 316 The 'coverage lift' lifts the coverage for tests with smaller m values. | |
| 317 """ | |
| 318 c = float(options.coverage) | |
| 319 l = float(options.coverage_lift) | |
| 320 return int(math.pow(float(m), (float(m) * c + l) / (float(m) + l))) | |
|
Jakob Kummerow
2013/07/23 15:13:43
I think you can s/float(m)/m/ three times here.
| |
| 321 | |
| 322 | |
| 271 def Execute(arch, mode, args, options, suites, workspace): | 323 def Execute(arch, mode, args, options, suites, workspace): |
| 272 print(">>> Running tests for %s.%s" % (arch, mode)) | 324 print(">>> Running tests for %s.%s" % (arch, mode)) |
| 273 | 325 |
| 326 dist = Distribution(options) | |
| 327 | |
| 274 shell_dir = options.shell_dir | 328 shell_dir = options.shell_dir |
| 275 if not shell_dir: | 329 if not shell_dir: |
| 276 if options.buildbot: | 330 if options.buildbot: |
| 277 shell_dir = os.path.join(workspace, options.outdir, mode) | 331 shell_dir = os.path.join(workspace, options.outdir, mode) |
| 278 mode = mode.lower() | 332 mode = mode.lower() |
| 279 else: | 333 else: |
| 280 shell_dir = os.path.join(workspace, options.outdir, | 334 shell_dir = os.path.join(workspace, options.outdir, |
| 281 "%s.%s" % (arch, mode)) | 335 "%s.%s" % (arch, mode)) |
| 282 shell_dir = os.path.relpath(shell_dir) | 336 shell_dir = os.path.relpath(shell_dir) |
| 283 | 337 |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 296 mode_flags, options.verbose, | 350 mode_flags, options.verbose, |
| 297 timeout, options.isolates, | 351 timeout, options.isolates, |
| 298 options.command_prefix, | 352 options.command_prefix, |
| 299 options.extra_flags) | 353 options.extra_flags) |
| 300 | 354 |
| 301 # Find available test suites and read test cases from them. | 355 # Find available test suites and read test cases from them. |
| 302 variables = { | 356 variables = { |
| 303 "mode": mode, | 357 "mode": mode, |
| 304 "arch": arch, | 358 "arch": arch, |
| 305 "system": utils.GuessOS(), | 359 "system": utils.GuessOS(), |
| 306 "isolates": options.isolates | 360 "isolates": options.isolates, |
| 361 "deopt_fuzzer": True, | |
| 307 } | 362 } |
| 308 all_tests = [] | 363 all_tests = [] |
| 309 num_tests = 0 | 364 num_tests = 0 |
| 310 test_id = 0 | 365 test_id = 0 |
| 366 | |
| 367 # Remember test case prototypes for the fuzzing phase. | |
| 368 test_backup = dict((s, []) for s in suites) | |
| 369 | |
| 311 for s in suites: | 370 for s in suites: |
| 312 s.ReadStatusFile(variables) | 371 s.ReadStatusFile(variables) |
| 313 s.ReadTestCases(ctx) | 372 s.ReadTestCases(ctx) |
| 314 if len(args) > 0: | 373 if len(args) > 0: |
| 315 s.FilterTestCasesByArgs(args) | 374 s.FilterTestCasesByArgs(args) |
| 316 all_tests += s.tests | 375 all_tests += s.tests |
| 317 s.FilterTestCasesByStatus(options.warn_unused) | 376 s.FilterTestCasesByStatus(False) |
| 318 if options.cat: | 377 test_backup[s] = s.tests |
| 319 verbose.PrintTestSource(s.tests) | 378 analysis_flags = [ |
|
Jakob Kummerow
2013/07/23 15:13:43
couple nits here:
(1) use proper string formatting
| |
| 320 continue | 379 '--deopt-every-n-times', |
| 321 variant_flags = s.VariantFlags() or VARIANT_FLAGS | 380 str(MAX_DEOPT), |
| 322 s.tests = [ t.CopyAddingFlags(v) for t in s.tests for v in variant_flags ] | 381 '--print-deopt-stress', |
| 323 s.tests = ShardTests(s.tests, options.shard_count, options.shard_run) | 382 ] |
| 383 s.tests = [ t.CopyAddingFlags(analysis_flags) for t in s.tests ] | |
| 324 num_tests += len(s.tests) | 384 num_tests += len(s.tests) |
| 325 for t in s.tests: | 385 for t in s.tests: |
| 326 t.id = test_id | 386 t.id = test_id |
| 327 test_id += 1 | 387 test_id += 1 |
| 328 | 388 |
| 329 if options.cat: | 389 if num_tests == 0: |
| 330 return 0 # We're done here. | 390 print "No tests to run." |
| 391 return 0 | |
| 331 | 392 |
| 332 if options.report: | 393 try: |
| 333 verbose.PrintReport(all_tests) | 394 print(">>> Collection phase") |
| 395 progress_indicator = progress.PROGRESS_INDICATORS[options.progress]() | |
| 396 runner = execution.Runner(suites, progress_indicator, ctx) | |
| 397 | |
| 398 exit_code = runner.Run(options.j) | |
| 399 if runner.terminate: | |
| 400 return exit_code | |
| 401 | |
| 402 except KeyboardInterrupt: | |
| 403 return 1 | |
| 404 | |
| 405 print(">>> Analysis phase") | |
| 406 num_tests = 0 | |
| 407 test_id = 0 | |
| 408 for s in suites: | |
| 409 test_results = {} | |
| 410 for t in s.tests: | |
| 411 for line in t.output.stdout.splitlines(): | |
| 412 if line.startswith('=== Stress deopt counter: '): | |
|
Jakob Kummerow
2013/07/23 15:13:43
nit: ""
| |
| 413 test_results[t.path] = MAX_DEOPT - int(line.split(' ')[-1]) | |
| 414 for t in s.tests: | |
| 415 if t.path not in test_results: | |
| 416 print "Missing results for " + t.path | |
|
Jakob Kummerow
2013/07/23 15:13:43
print "... %s" % t.path
| |
| 417 if options.dump_results_file: | |
| 418 results_dict = dict((t.path, n) for (t, n) in test_results.iteritems()) | |
| 419 with file(dump_results_file + "." + str(time.time()), 'w') as f: | |
|
Jakob Kummerow
2013/07/23 15:13:43
file("%s.%d.txt" % (dump_results_file, time.time()
| |
| 420 f.write(json.dumps(results_dict)) | |
| 421 | |
| 422 # Reset tests and redistribute the prototypes from the collection phase. | |
| 423 s.tests = [] | |
| 424 if options.verbose: | |
| 425 print "Test distributions:" | |
| 426 for t in test_backup[s]: | |
| 427 max_deopt = test_results.get(t.path, 0) | |
| 428 if max_deopt == 0: | |
| 429 continue | |
| 430 n_deopt = CalculateNTests(max_deopt, options) | |
| 431 distribution = dist.Distribute(n_deopt, max_deopt) | |
| 432 if options.verbose: | |
| 433 print t.path + " " + str(distribution) | |
|
Jakob Kummerow
2013/07/23 15:13:43
print "%s %s" % (t.path, distribution)
| |
| 434 for i in distribution: | |
| 435 fuzzing_flags = ['--deopt-every-n-times', str(i)] | |
|
Jakob Kummerow
2013/07/23 15:13:43
nit: "" (and ideally: "%d" % i)
| |
| 436 s.tests.append(t.CopyAddingFlags(fuzzing_flags)) | |
| 437 num_tests += len(s.tests) | |
| 438 for t in s.tests: | |
| 439 t.id = test_id | |
| 440 test_id += 1 | |
| 334 | 441 |
| 335 if num_tests == 0: | 442 if num_tests == 0: |
| 336 print "No tests to run." | 443 print "No tests to run." |
| 337 return 0 | 444 return 0 |
| 338 | 445 |
| 339 # Run the tests, either locally or distributed on the network. | |
| 340 try: | 446 try: |
| 341 start_time = time.time() | 447 print(">>> Deopt fuzzing phase (%d test cases)" % num_tests) |
| 342 progress_indicator = progress.PROGRESS_INDICATORS[options.progress]() | 448 progress_indicator = progress.PROGRESS_INDICATORS[options.progress]() |
| 343 if options.junitout: | 449 runner = execution.Runner(suites, progress_indicator, ctx) |
| 344 progress_indicator = progress.JUnitTestProgressIndicator( | |
| 345 progress_indicator, options.junitout, options.junittestsuite) | |
| 346 | |
| 347 run_networked = not options.no_network | |
| 348 if not run_networked: | |
| 349 print("Network distribution disabled, running tests locally.") | |
| 350 elif utils.GuessOS() != "linux": | |
| 351 print("Network distribution is only supported on Linux, sorry!") | |
| 352 run_networked = False | |
| 353 peers = [] | |
| 354 if run_networked: | |
| 355 peers = network_execution.GetPeers() | |
| 356 if not peers: | |
| 357 print("No connection to distribution server; running tests locally.") | |
| 358 run_networked = False | |
| 359 elif len(peers) == 1: | |
| 360 print("No other peers on the network; running tests locally.") | |
| 361 run_networked = False | |
| 362 elif num_tests <= 100: | |
| 363 print("Less than 100 tests, running them locally.") | |
| 364 run_networked = False | |
| 365 | |
| 366 if run_networked: | |
| 367 runner = network_execution.NetworkedRunner(suites, progress_indicator, | |
| 368 ctx, peers, workspace) | |
| 369 else: | |
| 370 runner = execution.Runner(suites, progress_indicator, ctx) | |
| 371 | 450 |
| 372 exit_code = runner.Run(options.j) | 451 exit_code = runner.Run(options.j) |
| 373 if runner.terminate: | 452 if runner.terminate: |
| 374 return exit_code | 453 return exit_code |
| 375 overall_duration = time.time() - start_time | 454 |
| 376 except KeyboardInterrupt: | 455 except KeyboardInterrupt: |
| 377 return 1 | 456 return 1 |
| 378 | 457 |
| 379 if options.time: | |
| 380 verbose.PrintTestDurations(suites, overall_duration) | |
| 381 return exit_code | 458 return exit_code |
| 382 | 459 |
| 383 | 460 |
| 384 if __name__ == "__main__": | 461 if __name__ == "__main__": |
| 385 sys.exit(Main()) | 462 sys.exit(Main()) |
| OLD | NEW |