Index: tools/auto_bisect/bisect_perf_regression.py |
diff --git a/tools/auto_bisect/bisect_perf_regression.py b/tools/auto_bisect/bisect_perf_regression.py |
index 333bcc07a8506a32954e1cfe84b58c8a19ba7f5c..187e80f99eca1ce3bd142ad62442b933b3935d88 100755 |
--- a/tools/auto_bisect/bisect_perf_regression.py |
+++ b/tools/auto_bisect/bisect_perf_regression.py |
@@ -86,6 +86,10 @@ MAX_LINUX_BUILD_TIME = 14400 |
# The confidence percentage we require to consider the initial range a |
# regression based on the test results of the inital good and bad revisions. |
REGRESSION_CONFIDENCE = 80 |
+# How many times to repeat the test on the last known good and first known bad |
+# revisions in order to assess a more accurate confidence score in the |
+# regression culprit. |
+BORDER_REVISIONS_EXTRA_RUNS = 2 |
# Patch template to add a new file, DEPS.sha under src folder. |
# This file contains SHA1 value of the DEPS changes made while bisecting |
@@ -1272,7 +1276,7 @@ class BisectPerformanceMetrics(object): |
def RunPerformanceTestAndParseResults( |
self, command_to_run, metric, reset_on_first_run=False, |
- upload_on_last_run=False, results_label=None): |
+ upload_on_last_run=False, results_label=None, test_run_multiplier=1): |
"""Runs a performance test on the current revision and parses the results. |
Args: |
@@ -1285,6 +1289,8 @@ class BisectPerformanceMetrics(object): |
results_label: A value for the option flag --results-label. |
The arguments reset_on_first_run, upload_on_last_run and results_label |
are all ignored if the test is not a Telemetry test. |
+ test_run_multiplier: Factor by which to multiply the number of test runs |
+ and the timeout period specified in self.opts. |
Returns: |
(values dict, 0) if --debug_ignore_perf_test was passed. |
@@ -1326,7 +1332,8 @@ class BisectPerformanceMetrics(object): |
metric_values = [] |
output_of_all_runs = '' |
- for i in xrange(self.opts.repeat_test_count): |
+ repeat_count = self.opts.repeat_test_count * test_run_multiplier |
+ for i in xrange(repeat_count): |
# Can ignore the return code since if the tests fail, it won't return 0. |
current_args = copy.copy(args) |
if is_telemetry: |
@@ -1368,7 +1375,8 @@ class BisectPerformanceMetrics(object): |
metric_values.append(return_code) |
elapsed_minutes = (time.time() - start_time) / 60.0 |
- if elapsed_minutes >= self.opts.max_time_minutes: |
+ time_limit = self.opts.max_time_minutes * test_run_multiplier |
+ if elapsed_minutes >= time_limit: |
break |
if metric and len(metric_values) == 0: |
@@ -1473,7 +1481,8 @@ class BisectPerformanceMetrics(object): |
return False |
def RunTest(self, revision, depot, command, metric, skippable=False, |
- skip_sync=False, create_patch=False, force_build=False): |
+ skip_sync=False, create_patch=False, force_build=False, |
+ test_run_multiplier=1): |
"""Performs a full sync/build/run of the specified revision. |
Args: |
@@ -1484,6 +1493,8 @@ class BisectPerformanceMetrics(object): |
skip_sync: Skip the sync step. |
create_patch: Create a patch with any locally modified files. |
force_build: Force a local build. |
+ test_run_multiplier: Factor by which to multiply the given number of runs |
+ and the set timeout period. |
Returns: |
On success, a tuple containing the results of the performance test. |
@@ -1525,7 +1536,8 @@ class BisectPerformanceMetrics(object): |
command = self.GetCompatibleCommand(command, revision, depot) |
# Run the command and get the results. |
- results = self.RunPerformanceTestAndParseResults(command, metric) |
+ results = self.RunPerformanceTestAndParseResults( |
+ command, metric, test_run_multiplier=test_run_multiplier) |
# Restore build output directory once the tests are done, to avoid |
# any discrepancies. |
@@ -2439,6 +2451,9 @@ class BisectPerformanceMetrics(object): |
self.printer.PrintPartialResults(bisect_state) |
bisect_utils.OutputAnnotationStepClosed() |
+ |
+ self._ConfidenceExtraTestRuns(min_revision_state, max_revision_state, |
+ command_to_run, metric) |
results = BisectResults(bisect_state, self.depot_registry, self.opts, |
self.warnings) |
@@ -2452,6 +2467,21 @@ class BisectPerformanceMetrics(object): |
'[%s..%s]' % (good_revision, bad_revision)) |
return BisectResults(error=error) |
+ def _ConfidenceExtraTestRuns(self, good_state, bad_state, command_to_run, |
+ metric): |
+ if (bool(good_state.passed) != bool(bad_state.passed) |
+ and good_state.passed not in ('Skipped', 'Build Failed') |
+ and bad_state.passed not in ('Skipped', 'Build Failed')): |
+ for state in (good_state, bad_state): |
+ run_results = self.RunTest( |
+ state.revision, |
+ state.depot, |
+ command_to_run, |
+ metric, |
+ test_run_multiplier=BORDER_REVISIONS_EXTRA_RUNS) |
+ # Is extend the right thing to do here? |
+ state.value['values'].extend(run_results[0]['values']) |
+ |
def _IsPlatformSupported(): |
"""Checks that this platform and build system are supported. |