| OLD | NEW |
| 1 # Copyright 2012 the V8 project authors. All rights reserved. | 1 # Copyright 2012 the V8 project authors. All rights reserved. |
| 2 # Redistribution and use in source and binary forms, with or without | 2 # Redistribution and use in source and binary forms, with or without |
| 3 # modification, are permitted provided that the following conditions are | 3 # modification, are permitted provided that the following conditions are |
| 4 # met: | 4 # met: |
| 5 # | 5 # |
| 6 # * Redistributions of source code must retain the above copyright | 6 # * Redistributions of source code must retain the above copyright |
| 7 # notice, this list of conditions and the following disclaimer. | 7 # notice, this list of conditions and the following disclaimer. |
| 8 # * Redistributions in binary form must reproduce the above | 8 # * Redistributions in binary form must reproduce the above |
| 9 # copyright notice, this list of conditions and the following | 9 # copyright notice, this list of conditions and the following |
| 10 # disclaimer in the documentation and/or other materials provided | 10 # disclaimer in the documentation and/or other materials provided |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 58 output = commands.Execute(job.command, job.verbose, job.timeout) | 58 output = commands.Execute(job.command, job.verbose, job.timeout) |
| 59 return (job.id, output, time.time() - start_time) | 59 return (job.id, output, time.time() - start_time) |
| 60 | 60 |
| 61 class Runner(object): | 61 class Runner(object): |
| 62 | 62 |
| 63 def __init__(self, suites, progress_indicator, context): | 63 def __init__(self, suites, progress_indicator, context): |
| 64 self.datapath = os.path.join("out", "testrunner_data") | 64 self.datapath = os.path.join("out", "testrunner_data") |
| 65 self.perf_data_manager = perfdata.PerfDataManager(self.datapath) | 65 self.perf_data_manager = perfdata.PerfDataManager(self.datapath) |
| 66 self.perfdata = self.perf_data_manager.GetStore(context.arch, context.mode) | 66 self.perfdata = self.perf_data_manager.GetStore(context.arch, context.mode) |
| 67 self.perf_failures = False | 67 self.perf_failures = False |
| 68 self.printed_allocations = False |
| 68 self.tests = [ t for s in suites for t in s.tests ] | 69 self.tests = [ t for s in suites for t in s.tests ] |
| 69 if not context.no_sorting: | 70 if not context.no_sorting: |
| 70 for t in self.tests: | 71 for t in self.tests: |
| 71 t.duration = self.perfdata.FetchPerfData(t) or 1.0 | 72 t.duration = self.perfdata.FetchPerfData(t) or 1.0 |
| 72 self.tests.sort(key=lambda t: t.duration, reverse=True) | 73 self.tests.sort(key=lambda t: t.duration, reverse=True) |
| 73 self._CommonInit(len(self.tests), progress_indicator, context) | 74 self._CommonInit(len(self.tests), progress_indicator, context) |
| 74 | 75 |
| 75 def _CommonInit(self, num_tests, progress_indicator, context): | 76 def _CommonInit(self, num_tests, progress_indicator, context): |
| 76 self.indicator = progress_indicator | 77 self.indicator = progress_indicator |
| 77 progress_indicator.runner = self | 78 progress_indicator.runner = self |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 142 # as unexpected even if it flakily passes in order to include it in the | 143 # as unexpected even if it flakily passes in order to include it in the |
| 143 # output. | 144 # output. |
| 144 self.indicator.HasRun(test, has_unexpected_output or test.run > 1) | 145 self.indicator.HasRun(test, has_unexpected_output or test.run > 1) |
| 145 if has_unexpected_output: | 146 if has_unexpected_output: |
| 146 # Rerun test failures after the indicator has processed the results. | 147 # Rerun test failures after the indicator has processed the results. |
| 147 self._MaybeRerun(pool, test) | 148 self._MaybeRerun(pool, test) |
| 148 # Update the perf database if the test succeeded. | 149 # Update the perf database if the test succeeded. |
| 149 return not has_unexpected_output | 150 return not has_unexpected_output |
| 150 | 151 |
| 151 def _ProcessTestPredictable(self, test, result, pool): | 152 def _ProcessTestPredictable(self, test, result, pool): |
| 153 def HasDifferentAllocations(output1, output2): |
| 154 def AllocationStr(stdout): |
| 155 for line in reversed((stdout or "").splitlines()): |
| 156 if line.startswith("### Allocations = "): |
| 157 self.printed_allocations = True |
| 158 return line |
| 159 return "" |
| 160 return (AllocationStr(output1.stdout) != AllocationStr(output2.stdout)) |
| 161 |
| 152 # Always pass the test duration for the database update. | 162 # Always pass the test duration for the database update. |
| 153 test.duration = result[2] | 163 test.duration = result[2] |
| 154 if test.run == 1 and result[1].HasTimedOut(): | 164 if test.run == 1 and result[1].HasTimedOut(): |
| 155 # If we get a timeout in the first run, we are already in an | 165 # If we get a timeout in the first run, we are already in an |
| 156 # unpredictable state. Just report it as a failure and don't rerun. | 166 # unpredictable state. Just report it as a failure and don't rerun. |
| 157 self.indicator.AboutToRun(test) | 167 self.indicator.AboutToRun(test) |
| 158 test.output = result[1] | 168 test.output = result[1] |
| 159 self.remaining -= 1 | 169 self.remaining -= 1 |
| 160 self.failed.append(test) | 170 self.failed.append(test) |
| 161 self.indicator.HasRun(test, True) | 171 self.indicator.HasRun(test, True) |
| 162 if test.run > 1 and test.output != result[1]: | 172 if test.run > 1 and HasDifferentAllocations(test.output, result[1]): |
| 163 # From the second run on, check for differences. If a difference is | 173 # From the second run on, check for different allocations. If a |
| 164 # found, call the indicator twice to report both tests. All runs of each | 174 # difference is found, call the indicator twice to report both tests. |
| 165 # test are counted as one for the statistic. | 175 # All runs of each test are counted as one for the statistic. |
| 166 self.indicator.AboutToRun(test) | 176 self.indicator.AboutToRun(test) |
| 167 self.remaining -= 1 | 177 self.remaining -= 1 |
| 168 self.failed.append(test) | 178 self.failed.append(test) |
| 169 self.indicator.HasRun(test, True) | 179 self.indicator.HasRun(test, True) |
| 170 self.indicator.AboutToRun(test) | 180 self.indicator.AboutToRun(test) |
| 171 test.output = result[1] | 181 test.output = result[1] |
| 172 self.indicator.HasRun(test, True) | 182 self.indicator.HasRun(test, True) |
| 173 elif test.run >= 3: | 183 elif test.run >= 3: |
| 174 # No difference on the third run -> report a success. | 184 # No difference on the third run -> report a success. |
| 175 self.indicator.AboutToRun(test) | 185 self.indicator.AboutToRun(test) |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 226 pool.terminate() | 236 pool.terminate() |
| 227 self._RunPerfSafe(lambda: self.perf_data_manager.close()) | 237 self._RunPerfSafe(lambda: self.perf_data_manager.close()) |
| 228 if self.perf_failures: | 238 if self.perf_failures: |
| 229 # Nuke perf data in case of failures. This might not work on windows as | 239 # Nuke perf data in case of failures. This might not work on windows as |
| 230 # some files might still be open. | 240 # some files might still be open. |
| 231 print "Deleting perf test data due to db corruption." | 241 print "Deleting perf test data due to db corruption." |
| 232 shutil.rmtree(self.datapath) | 242 shutil.rmtree(self.datapath) |
| 233 if queued_exception: | 243 if queued_exception: |
| 234 raise queued_exception | 244 raise queued_exception |
| 235 | 245 |
| 246 # Make sure that any allocations were printed in predictable mode. |
| 247 assert not self.context.predictable or self.printed_allocations |
| 236 | 248 |
| 237 def GetCommand(self, test): | 249 def GetCommand(self, test): |
| 238 d8testflag = [] | 250 d8testflag = [] |
| 239 shell = test.suite.shell() | 251 shell = test.suite.shell() |
| 240 if shell == "d8": | 252 if shell == "d8": |
| 241 d8testflag = ["--test"] | 253 d8testflag = ["--test"] |
| 242 if utils.IsWindows(): | 254 if utils.IsWindows(): |
| 243 shell += ".exe" | 255 shell += ".exe" |
| 244 cmd = (self.context.command_prefix + | 256 cmd = (self.context.command_prefix + |
| 245 [os.path.abspath(os.path.join(self.context.shell_dir, shell))] + | 257 [os.path.abspath(os.path.join(self.context.shell_dir, shell))] + |
| 246 d8testflag + | 258 d8testflag + |
| 247 ["--random-seed=%s" % self.context.random_seed] + | 259 ["--random-seed=%s" % self.context.random_seed] + |
| 248 test.suite.GetFlagsForTestCase(test, self.context) + | 260 test.suite.GetFlagsForTestCase(test, self.context) + |
| 249 self.context.extra_flags) | 261 self.context.extra_flags) |
| 250 return cmd | 262 return cmd |
| 251 | 263 |
| 252 | 264 |
| 253 class BreakNowException(Exception): | 265 class BreakNowException(Exception): |
| 254 def __init__(self, value): | 266 def __init__(self, value): |
| 255 self.value = value | 267 self.value = value |
| 256 def __str__(self): | 268 def __str__(self): |
| 257 return repr(self.value) | 269 return repr(self.value) |
| OLD | NEW |