Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(6)

Unified Diff: tools/auto_bisect/bisect_perf_regression.py

Issue 664753002: Refactored auto_bisect bot (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git/+/master
Patch Set: Rebase Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | tools/auto_bisect/bisect_perf_regression_test.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 db63bba122194624b1536c4ba8d1bfef619fb539..f90074f4d7533adda3937ef5e8740afa4898efef 100755
--- a/tools/auto_bisect/bisect_perf_regression.py
+++ b/tools/auto_bisect/bisect_perf_regression.py
@@ -33,7 +33,6 @@ Example usage using git hashes:
"""
import copy
-import datetime
import errno
import hashlib
import optparse
@@ -49,7 +48,9 @@ import zipfile
sys.path.append(os.path.join(
os.path.dirname(__file__), os.path.pardir, 'telemetry'))
+from bisect_printer import BisectPrinter
from bisect_results import BisectResults
+from bisect_state import BisectState
import bisect_utils
import builder
import math_utils
@@ -57,99 +58,6 @@ import request_build
import source_control
from telemetry.util import cloud_storage
-# Below is the map of "depot" names to information about each depot. Each depot
-# is a repository, and in the process of bisecting, revision ranges in these
-# repositories may also be bisected.
-#
-# Each depot information dictionary may contain:
-# src: Path to the working directory.
-# recurse: True if this repository will get bisected.
-# depends: A list of other repositories that are actually part of the same
-# repository in svn. If the repository has any dependent repositories
-# (e.g. skia/src needs skia/include and skia/gyp to be updated), then
-# they are specified here.
-# svn: URL of SVN repository. Needed for git workflow to resolve hashes to
-# SVN revisions.
-# from: Parent depot that must be bisected before this is bisected.
-# deps_var: Key name in vars variable in DEPS file that has revision
-# information.
-DEPOT_DEPS_NAME = {
- 'chromium': {
- 'src': 'src',
- 'recurse': True,
- 'depends': None,
- 'from': ['cros', 'android-chrome'],
- 'viewvc':
- 'http://src.chromium.org/viewvc/chrome?view=revision&revision=',
- 'deps_var': 'chromium_rev'
- },
- 'webkit': {
- 'src': 'src/third_party/WebKit',
- 'recurse': True,
- 'depends': None,
- 'from': ['chromium'],
- 'viewvc':
- 'http://src.chromium.org/viewvc/blink?view=revision&revision=',
- 'deps_var': 'webkit_revision'
- },
- 'angle': {
- 'src': 'src/third_party/angle',
- 'src_old': 'src/third_party/angle_dx11',
- 'recurse': True,
- 'depends': None,
- 'from': ['chromium'],
- 'platform': 'nt',
- 'deps_var': 'angle_revision'
- },
- 'v8': {
- 'src': 'src/v8',
- 'recurse': True,
- 'depends': None,
- 'from': ['chromium'],
- 'custom_deps': bisect_utils.GCLIENT_CUSTOM_DEPS_V8,
- 'viewvc': 'https://code.google.com/p/v8/source/detail?r=',
- 'deps_var': 'v8_revision'
- },
- 'v8_bleeding_edge': {
- 'src': 'src/v8_bleeding_edge',
- 'recurse': True,
- 'depends': None,
- 'svn': 'https://v8.googlecode.com/svn/branches/bleeding_edge',
- 'from': ['v8'],
- 'viewvc': 'https://code.google.com/p/v8/source/detail?r=',
- 'deps_var': 'v8_revision'
- },
- 'skia/src': {
- 'src': 'src/third_party/skia/src',
- 'recurse': True,
- 'svn': 'http://skia.googlecode.com/svn/trunk/src',
- 'depends': ['skia/include', 'skia/gyp'],
- 'from': ['chromium'],
- 'viewvc': 'https://code.google.com/p/skia/source/detail?r=',
- 'deps_var': 'skia_revision'
- },
- 'skia/include': {
- 'src': 'src/third_party/skia/include',
- 'recurse': False,
- 'svn': 'http://skia.googlecode.com/svn/trunk/include',
- 'depends': None,
- 'from': ['chromium'],
- 'viewvc': 'https://code.google.com/p/skia/source/detail?r=',
- 'deps_var': 'None'
- },
- 'skia/gyp': {
- 'src': 'src/third_party/skia/gyp',
- 'recurse': False,
- 'svn': 'http://skia.googlecode.com/svn/trunk/gyp',
- 'depends': None,
- 'from': ['chromium'],
- 'viewvc': 'https://code.google.com/p/skia/source/detail?r=',
- 'deps_var': 'None'
- }
-}
-
-DEPOT_NAMES = DEPOT_DEPS_NAME.keys()
-
# The script is in chromium/src/tools/auto_bisect. Throughout this script,
# we use paths to other things in the chromium/src repository.
@@ -167,9 +75,6 @@ MAX_MAC_BUILD_TIME = 14400
MAX_WIN_BUILD_TIME = 14400
MAX_LINUX_BUILD_TIME = 14400
-# The percentage at which confidence is considered high.
-HIGH_CONFIDENCE = 95
-
# Patch template to add a new file, DEPS.sha under src folder.
# This file contains SHA1 value of the DEPS changes made while bisecting
# dependency repositories. This patch send along with DEPS patch to try server.
@@ -184,72 +89,6 @@ new file mode 100644
+%(deps_sha)s
"""
-# The possible values of the --bisect_mode flag, which determines what to
-# use when classifying a revision as "good" or "bad".
-BISECT_MODE_MEAN = 'mean'
-BISECT_MODE_STD_DEV = 'std_dev'
-BISECT_MODE_RETURN_CODE = 'return_code'
-
-# The perf dashboard looks for a string like "Estimated Confidence: 95%"
-# to decide whether or not to cc the author(s). If you change this, please
-# update the perf dashboard as well.
-RESULTS_BANNER = """
-===== BISECT JOB RESULTS =====
-Status: %(status)s
-
-Test Command: %(command)s
-Test Metric: %(metrics)s
-Relative Change: %(change)s
-Estimated Confidence: %(confidence).02f%%"""
-
-# The perf dashboard specifically looks for the string
-# "Author : " to parse out who to cc on a bug. If you change the
-# formatting here, please update the perf dashboard as well.
-RESULTS_REVISION_INFO = """
-===== SUSPECTED CL(s) =====
-Subject : %(subject)s
-Author : %(author)s%(email_info)s%(commit_info)s
-Commit : %(cl)s
-Date : %(cl_date)s"""
-
-REPRO_STEPS_LOCAL = """
-==== INSTRUCTIONS TO REPRODUCE ====
-To run locally:
- - Use the test command given under 'BISECT JOB RESULTS' above.
- - Consider using a profiler. Pass --profiler=list to list available profilers.
-"""
-
-REPRO_STEPS_TRYJOB = """
-To reproduce on a performance try bot:
- 1. Edit run-perf-test.cfg
- 2. $ git try -b <bot> --svn_repo='svn://svn.chromium.org/chrome-try/try-perf'
-
-Notes:
- a) Follow the in-file instructions in run-perf-test.cfg.
- b) run-perf-test.cfg is under tools/ or under third_party/WebKit/Tools.
- c) Do your edits preferably under a new git branch.
- d) --browser=release and --browser=android-chromium-testshell are supported
- depending on the platform (desktop|android).
- e) Strip any src/ directories from the head of relative path names.
- f) Make sure to use the appropriate bot on step 3.
-
-For more details please visit
-https://sites.google.com/a/chromium.org/dev/developers/performance-try-bots"""
-
-REPRO_STEPS_TRYJOB_TELEMETRY = """
-To reproduce on a performance try bot:
-%(command)s
-(Where <bot-name> comes from tools/perf/run_benchmark --browser=list)
-
-For more details please visit
-https://sites.google.com/a/chromium.org/dev/developers/performance-try-bots
-"""
-
-RESULTS_THANKYOU = """
-| O O | Visit http://www.chromium.org/developers/core-principles for Chrome's
-| X | policy on perf regressions. Contact chrome-perf-dashboard-team with any
-| / \ | questions or suggestions about bisecting. THANK YOU."""
-
# Git branch name used to run bisect try jobs.
BISECT_TRYJOB_BRANCH = 'bisect-tryjob'
# Git master branch name.
@@ -265,14 +104,6 @@ class RunGitError(Exception):
return '%s\nError executing git command.' % self.args[0]
-def _AddAdditionalDepotInfo(depot_info):
- """Adds additional depot info to the global depot variables."""
- global DEPOT_DEPS_NAME
- global DEPOT_NAMES
- DEPOT_DEPS_NAME = dict(DEPOT_DEPS_NAME.items() + depot_info.items())
- DEPOT_NAMES = DEPOT_DEPS_NAME.keys()
-
-
def GetSHA1HexDigest(contents):
"""Returns SHA1 hex digest of the given string."""
return hashlib.sha1(contents).hexdigest()
@@ -570,7 +401,7 @@ def _UpdateDEPSForAngle(revision, depot, deps_file):
in such cases check "deps" dictionary variable that matches
angle.git@[a-fA-F0-9]{40}$ and replace git hash.
"""
- deps_var = DEPOT_DEPS_NAME[depot]['deps_var']
+ deps_var = bisect_utils.DEPOT_DEPS_NAME[depot]['deps_var']
try:
deps_contents = ReadStringFromFile(deps_file)
# Check whether the depot and revision pattern in DEPS file vars variable
@@ -758,85 +589,14 @@ def _GenerateProfileIfNecessary(command_args):
return True
-def _AddRevisionsIntoRevisionData(revisions, depot, sort, revision_data):
- """Adds new revisions to the revision_data dictionary and initializes them.
-
- Args:
- revisions: List of revisions to add.
- depot: Depot that's currently in use (src, webkit, etc...)
- sort: Sorting key for displaying revisions.
- revision_data: A dictionary to add the new revisions into.
- Existing revisions will have their sort keys adjusted.
- """
- num_depot_revisions = len(revisions)
-
- for _, v in revision_data.iteritems():
- if v['sort'] > sort:
- v['sort'] += num_depot_revisions
-
- for i in xrange(num_depot_revisions):
- r = revisions[i]
- revision_data[r] = {
- 'revision' : r,
- 'depot' : depot,
- 'value' : None,
- 'perf_time' : 0,
- 'build_time' : 0,
- 'passed' : '?',
- 'sort' : i + sort + 1,
- }
-
-
-def _PrintThankYou():
- print RESULTS_THANKYOU
-
-
-def _PrintTableRow(column_widths, row_data):
- """Prints out a row in a formatted table that has columns aligned.
-
- Args:
- column_widths: A list of column width numbers.
- row_data: A list of items for each column in this row.
- """
- assert len(column_widths) == len(row_data)
- text = ''
- for i in xrange(len(column_widths)):
- current_row_data = row_data[i].center(column_widths[i], ' ')
- text += ('%%%ds' % column_widths[i]) % current_row_data
- print text
-
-
-def _PrintStepTime(revision_data_sorted):
- """Prints information about how long various steps took.
-
- Args:
- revision_data_sorted: The sorted list of revision data dictionaries."""
- step_perf_time_avg = 0.0
- step_build_time_avg = 0.0
- step_count = 0.0
- for _, current_data in revision_data_sorted:
- if current_data['value']:
- step_perf_time_avg += current_data['perf_time']
- step_build_time_avg += current_data['build_time']
- step_count += 1
- if step_count:
- step_perf_time_avg = step_perf_time_avg / step_count
- step_build_time_avg = step_build_time_avg / step_count
- print
- print 'Average build time : %s' % datetime.timedelta(
- seconds=int(step_build_time_avg))
- print 'Average test time : %s' % datetime.timedelta(
- seconds=int(step_perf_time_avg))
-
-
class DepotDirectoryRegistry(object):
def __init__(self, src_cwd):
self.depot_cwd = {}
- for depot in DEPOT_NAMES:
+ for depot in bisect_utils.DEPOT_NAMES:
# The working directory of each depot is just the path to the depot, but
# since we're already in 'src', we can skip that part.
- path_in_src = DEPOT_DEPS_NAME[depot]['src'][4:]
+ path_in_src = bisect_utils.DEPOT_DEPS_NAME[depot]['src'][4:]
self.AddDepot(depot, os.path.join(src_cwd, path_in_src))
self.AddDepot('chromium', src_cwd)
@@ -1051,8 +811,8 @@ class BisectPerformanceMetrics(object):
'bleeding_edge revision r')[1]
bleeding_edge_revision = int(bleeding_edge_revision.split(')')[0])
git_revision = source_control.ResolveToRevision(
- bleeding_edge_revision, 'v8_bleeding_edge', DEPOT_DEPS_NAME, 1,
- cwd=v8_bleeding_edge_dir)
+ bleeding_edge_revision, 'v8_bleeding_edge',
+ bisect_utils.DEPOT_DEPS_NAME, 1, cwd=v8_bleeding_edge_dir)
return git_revision
except (IndexError, ValueError):
pass
@@ -1060,8 +820,8 @@ class BisectPerformanceMetrics(object):
if not git_revision:
# Wasn't successful, try the old way of looking for "Prepare push to"
git_revision = source_control.ResolveToRevision(
- int(commit_position) - 1, 'v8_bleeding_edge', DEPOT_DEPS_NAME, -1,
- cwd=v8_bleeding_edge_dir)
+ int(commit_position) - 1, 'v8_bleeding_edge',
+ bisect_utils.DEPOT_DEPS_NAME, -1, cwd=v8_bleeding_edge_dir)
if git_revision:
revision_info = source_control.QueryRevisionInfo(git_revision,
@@ -1125,7 +885,7 @@ class BisectPerformanceMetrics(object):
rxp = re.compile(".git@(?P<revision>[a-fA-F0-9]+)")
results = {}
- for depot_name, depot_data in DEPOT_DEPS_NAME.iteritems():
+ for depot_name, depot_data in bisect_utils.DEPOT_DEPS_NAME.iteritems():
if (depot_data.get('platform') and
depot_data.get('platform') != os.name):
continue
@@ -1154,10 +914,10 @@ class BisectPerformanceMetrics(object):
for depot_name, depot_revision in parse_results.iteritems():
depot_revision = depot_revision.strip('@')
print depot_name, depot_revision
- for current_name, current_data in DEPOT_DEPS_NAME.iteritems():
- if (current_data.has_key('deps_var') and
- current_data['deps_var'] == depot_name):
- src_name = current_name
+ for cur_name, cur_data in bisect_utils.DEPOT_DEPS_NAME.iteritems():
+ if (cur_data.has_key('deps_var') and
+ cur_data['deps_var'] == depot_name):
+ src_name = cur_name
results[src_name] = depot_revision
break
return results
@@ -1436,8 +1196,8 @@ class BisectPerformanceMetrics(object):
if (self.opts.target_platform in ['chromium', 'android'] and
self.opts.gs_bucket):
return (depot == 'chromium' or
- 'chromium' in DEPOT_DEPS_NAME[depot]['from'] or
- 'v8' in DEPOT_DEPS_NAME[depot]['from'])
+ 'chromium' in bisect_utils.DEPOT_DEPS_NAME[depot]['from'] or
+ 'v8' in bisect_utils.DEPOT_DEPS_NAME[depot]['from'])
return False
def UpdateDepsContents(self, deps_contents, depot, git_revision, deps_key):
@@ -1500,7 +1260,7 @@ class BisectPerformanceMetrics(object):
if not os.path.exists(deps_file):
return False
- deps_var = DEPOT_DEPS_NAME[depot]['deps_var']
+ deps_var = bisect_utils.DEPOT_DEPS_NAME[depot]['deps_var']
# Don't update DEPS file if deps_var is not set in DEPOT_DEPS_NAME.
if not deps_var:
print 'DEPS update not supported for Depot: %s', depot
@@ -1545,8 +1305,8 @@ class BisectPerformanceMetrics(object):
if not chromium_sha:
raise RuntimeError('Failed to determine Chromium revision for %s' %
revision)
- if ('chromium' in DEPOT_DEPS_NAME[depot]['from'] or
- 'v8' in DEPOT_DEPS_NAME[depot]['from']):
+ if ('chromium' in bisect_utils.DEPOT_DEPS_NAME[depot]['from'] or
+ 'v8' in bisect_utils.DEPOT_DEPS_NAME[depot]['from']):
# Checkout DEPS file for the current chromium revision.
if source_control.CheckoutFileAtRevision(
bisect_utils.FILE_DEPS, chromium_sha, cwd=self.src_cwd):
@@ -1601,13 +1361,14 @@ class BisectPerformanceMetrics(object):
return not bisect_utils.RunGClient(['runhooks'], cwd=self.src_cwd)
def _IsBisectModeUsingMetric(self):
- return self.opts.bisect_mode in [BISECT_MODE_MEAN, BISECT_MODE_STD_DEV]
+ return self.opts.bisect_mode in [bisect_utils.BISECT_MODE_MEAN,
+ bisect_utils.BISECT_MODE_STD_DEV]
def _IsBisectModeReturnCode(self):
- return self.opts.bisect_mode in [BISECT_MODE_RETURN_CODE]
+ return self.opts.bisect_mode in [bisect_utils.BISECT_MODE_RETURN_CODE]
def _IsBisectModeStandardDeviation(self):
- return self.opts.bisect_mode in [BISECT_MODE_STD_DEV]
+ return self.opts.bisect_mode in [bisect_utils.BISECT_MODE_STD_DEV]
def GetCompatibleCommand(self, command_to_run, revision, depot):
"""Return a possibly modified test command depending on the revision.
@@ -1816,20 +1577,20 @@ class BisectPerformanceMetrics(object):
# figure out for each mirror which git revision to grab. There's no
# guarantee that the SVN revision will exist for each of the dependent
# depots, so we have to grep the git logs and grab the next earlier one.
- if not is_base and DEPOT_DEPS_NAME[depot]['depends']:
+ if not is_base and bisect_utils.DEPOT_DEPS_NAME[depot]['depends']:
commit_position = source_control.GetCommitPosition(revision)
- for d in DEPOT_DEPS_NAME[depot]['depends']:
+ for d in bisect_utils.DEPOT_DEPS_NAME[depot]['depends']:
self.depot_registry.ChangeToDepotDir(d)
dependant_rev = source_control.ResolveToRevision(
- commit_position, d, DEPOT_DEPS_NAME, -1000)
+ commit_position, d, bisect_utils.DEPOT_DEPS_NAME, -1000)
if dependant_rev:
revisions_to_sync.append([d, dependant_rev])
num_resolved = len(revisions_to_sync)
- num_needed = len(DEPOT_DEPS_NAME[depot]['depends'])
+ num_needed = len(bisect_utils.DEPOT_DEPS_NAME[depot]['depends'])
self.depot_registry.ChangeToDepotDir(depot)
@@ -1967,7 +1728,7 @@ class BisectPerformanceMetrics(object):
if not self._SyncAllRevisions(revisions_to_sync, sync_client):
return ('Failed to sync: [%s]' % str(revision), BUILD_RESULT_FAIL)
- # Try to do any post-sync steps. This may include "gclient runhooks".
+ # Try to do any post-sync steps. This may include "gclient runhooks".
if not self._RunPostSync(depot):
return ('Failed to run [gclient runhooks].', BUILD_RESULT_FAIL)
@@ -2031,7 +1792,8 @@ class BisectPerformanceMetrics(object):
# want so that all the dependencies sync properly as well.
# i.e. gclient sync src@<SHA1>
if sync_client == 'gclient':
- revision = '%s@%s' % (DEPOT_DEPS_NAME[depot]['src'], revision)
+ revision = '%s@%s' % (bisect_utils.DEPOT_DEPS_NAME[depot]['src'],
+ revision)
sync_success = source_control.SyncToRevision(revision, sync_client)
if not sync_success:
@@ -2052,7 +1814,7 @@ class BisectPerformanceMetrics(object):
True if the current_value is closer to the known_good_value than the
known_bad_value.
"""
- if self.opts.bisect_mode == BISECT_MODE_STD_DEV:
+ if self.opts.bisect_mode == bisect_utils.BISECT_MODE_STD_DEV:
dist_to_good_value = abs(current_value['std_dev'] -
known_good_value['std_dev'])
dist_to_bad_value = abs(current_value['std_dev'] -
@@ -2063,18 +1825,18 @@ class BisectPerformanceMetrics(object):
return dist_to_good_value < dist_to_bad_value
- def _FillInV8BleedingEdgeInfo(self, min_revision_data, max_revision_data):
- r1 = self._GetNearestV8BleedingEdgeFromTrunk(min_revision_data['revision'],
+ def _FillInV8BleedingEdgeInfo(self, min_revision_state, max_revision_state):
+ r1 = self._GetNearestV8BleedingEdgeFromTrunk(min_revision_state.revision,
search_forward=True)
- r2 = self._GetNearestV8BleedingEdgeFromTrunk(max_revision_data['revision'],
+ r2 = self._GetNearestV8BleedingEdgeFromTrunk(max_revision_state.revision,
search_forward=False)
- min_revision_data['external']['v8_bleeding_edge'] = r1
- max_revision_data['external']['v8_bleeding_edge'] = r2
+ min_revision_state.external['v8_bleeding_edge'] = r1
+ max_revision_state.external['v8_bleeding_edge'] = r2
if (not self._GetV8BleedingEdgeFromV8TrunkIfMappable(
- min_revision_data['revision'])
+ min_revision_state.revision)
or not self._GetV8BleedingEdgeFromV8TrunkIfMappable(
- max_revision_data['revision'])):
+ max_revision_state.revision)):
self.warnings.append(
'Trunk revisions in V8 did not map directly to bleeding_edge. '
'Attempted to expand the range to find V8 rolls which did map '
@@ -2082,54 +1844,54 @@ class BisectPerformanceMetrics(object):
'valid.')
def _FindNextDepotToBisect(
- self, current_depot, min_revision_data, max_revision_data):
+ self, current_depot, min_revision_state, max_revision_state):
"""Decides which depot the script should dive into next (if any).
Args:
current_depot: Current depot being bisected.
- min_revision_data: Data about the earliest revision in the bisect range.
- max_revision_data: Data about the latest revision in the bisect range.
+ min_revision_state: State of the earliest revision in the bisect range.
+ max_revision_state: State of the latest revision in the bisect range.
Returns:
Name of the depot to bisect next, or None.
"""
external_depot = None
- for next_depot in DEPOT_NAMES:
- if DEPOT_DEPS_NAME[next_depot].has_key('platform'):
- if DEPOT_DEPS_NAME[next_depot]['platform'] != os.name:
+ for next_depot in bisect_utils.DEPOT_NAMES:
+ if bisect_utils.DEPOT_DEPS_NAME[next_depot].has_key('platform'):
+ if bisect_utils.DEPOT_DEPS_NAME[next_depot]['platform'] != os.name:
continue
- if not (DEPOT_DEPS_NAME[next_depot]['recurse']
- and min_revision_data['depot']
- in DEPOT_DEPS_NAME[next_depot]['from']):
+ if not (bisect_utils.DEPOT_DEPS_NAME[next_depot]['recurse']
+ and min_revision_state.depot
+ in bisect_utils.DEPOT_DEPS_NAME[next_depot]['from']):
continue
if current_depot == 'v8':
# We grab the bleeding_edge info here rather than earlier because we
# finally have the revision range. From that we can search forwards and
# backwards to try to match trunk revisions to bleeding_edge.
- self._FillInV8BleedingEdgeInfo(min_revision_data, max_revision_data)
+ self._FillInV8BleedingEdgeInfo(min_revision_state, max_revision_state)
- if (min_revision_data['external'].get(next_depot) ==
- max_revision_data['external'].get(next_depot)):
+ if (min_revision_state.external.get(next_depot) ==
+ max_revision_state.external.get(next_depot)):
continue
- if (min_revision_data['external'].get(next_depot) and
- max_revision_data['external'].get(next_depot)):
+ if (min_revision_state.external.get(next_depot) and
+ max_revision_state.external.get(next_depot)):
external_depot = next_depot
break
return external_depot
def PrepareToBisectOnDepot(
- self, current_depot, end_revision, start_revision, previous_revision):
+ self, current_depot, start_revision, end_revision, previous_revision):
"""Changes to the appropriate directory and gathers a list of revisions
to bisect between |start_revision| and |end_revision|.
Args:
current_depot: The depot we want to bisect.
- end_revision: End of the revision range.
start_revision: Start of the revision range.
+ end_revision: End of the revision range.
previous_revision: The last revision we synced to on |previous_depot|.
Returns:
@@ -2142,10 +1904,11 @@ class BisectPerformanceMetrics(object):
# V8 (and possibly others) is merged in periodically. Bisecting
# this directory directly won't give much good info.
- if DEPOT_DEPS_NAME[current_depot].has_key('custom_deps'):
+ if bisect_utils.DEPOT_DEPS_NAME[current_depot].has_key('custom_deps'):
config_path = os.path.join(self.src_cwd, '..')
- if bisect_utils.RunGClientAndCreateConfig(self.opts,
- DEPOT_DEPS_NAME[current_depot]['custom_deps'], cwd=config_path):
+ if bisect_utils.RunGClientAndCreateConfig(
+ self.opts, bisect_utils.DEPOT_DEPS_NAME[current_depot]['custom_deps'],
+ cwd=config_path):
return []
if bisect_utils.RunGClient(
['sync', '--revision', previous_revision], cwd=self.src_cwd):
@@ -2199,8 +1962,8 @@ class BisectPerformanceMetrics(object):
def PrintRevisionsToBisectMessage(self, revision_list, depot):
if self.opts.output_buildbot_annotations:
- step_name = 'Bisection Range: [%s - %s]' % (
- revision_list[len(revision_list)-1], revision_list[0])
+ step_name = 'Bisection Range: [%s:%s - %s]' % (depot, revision_list[-1],
+ revision_list[0])
bisect_utils.OutputAnnotationStepStart(step_name)
print
@@ -2340,8 +2103,6 @@ class BisectPerformanceMetrics(object):
Returns:
A BisectResults object.
"""
- results = BisectResults(self.depot_registry)
-
# Choose depot to bisect first
target_depot = 'chromium'
if self.opts.target_platform == 'cros':
@@ -2354,25 +2115,25 @@ class BisectPerformanceMetrics(object):
# If they passed SVN revisions, we can try match them to git SHA1 hashes.
bad_revision = source_control.ResolveToRevision(
- bad_revision_in, target_depot, DEPOT_DEPS_NAME, 100)
+ bad_revision_in, target_depot, bisect_utils.DEPOT_DEPS_NAME, 100)
good_revision = source_control.ResolveToRevision(
- good_revision_in, target_depot, DEPOT_DEPS_NAME, -100)
+ good_revision_in, target_depot, bisect_utils.DEPOT_DEPS_NAME, -100)
os.chdir(cwd)
if bad_revision is None:
- results.error = 'Couldn\'t resolve [%s] to SHA1.' % bad_revision_in
- return results
+ return BisectResults(
+ error='Couldn\'t resolve [%s] to SHA1.' % bad_revision_in)
if good_revision is None:
- results.error = 'Couldn\'t resolve [%s] to SHA1.' % good_revision_in
- return results
+ return BisectResults(
+ error='Couldn\'t resolve [%s] to SHA1.' % good_revision_in)
# Check that they didn't accidentally swap good and bad revisions.
if not self.CheckIfRevisionsInProperOrder(
target_depot, good_revision, bad_revision):
- results.error = ('bad_revision < good_revision, did you swap these '
- 'by mistake?')
- return results
+ return BisectResults(error='bad_revision < good_revision, did you swap '
+ 'these by mistake?')
+
bad_revision, good_revision = self.NudgeRevisionsIfDEPSChange(
bad_revision, good_revision, good_revision_in)
if self.opts.output_buildbot_annotations:
@@ -2380,45 +2141,17 @@ class BisectPerformanceMetrics(object):
cannot_bisect = self.CanPerformBisect(good_revision, bad_revision)
if cannot_bisect:
- results.error = cannot_bisect.get('error')
- return results
+ return BisectResults(error=cannot_bisect.get('error'))
print 'Gathering revision range for bisection.'
# Retrieve a list of revisions to do bisection on.
- src_revision_list = self.GetRevisionList(
- target_depot, bad_revision, good_revision)
+ revision_list = self.GetRevisionList(target_depot, bad_revision,
+ good_revision)
if self.opts.output_buildbot_annotations:
bisect_utils.OutputAnnotationStepClosed()
- if src_revision_list:
- # revision_data will store information about a revision such as the
- # depot it came from, the webkit/V8 revision at that time,
- # performance timing, build state, etc...
- revision_data = results.revision_data
-
- # revision_list is the list we're binary searching through at the moment.
- revision_list = []
-
- sort_key_ids = 0
-
- for current_revision_id in src_revision_list:
- sort_key_ids += 1
-
- revision_data[current_revision_id] = {
- 'value' : None,
- 'passed' : '?',
- 'depot' : target_depot,
- 'external' : None,
- 'perf_time' : 0,
- 'build_time' : 0,
- 'sort' : sort_key_ids,
- }
- revision_list.append(current_revision_id)
-
- min_revision = 0
- max_revision = len(revision_list) - 1
-
+ if revision_list:
self.PrintRevisionsToBisectMessage(revision_list, target_depot)
if self.opts.output_buildbot_annotations:
@@ -2438,18 +2171,18 @@ class BisectPerformanceMetrics(object):
bisect_utils.OutputAnnotationStepClosed()
if bad_results[1]:
- results.error = ('An error occurred while building and running '
- 'the \'bad\' reference value. The bisect cannot continue without '
- 'a working \'bad\' revision to start from.\n\nError: %s' %
- bad_results[0])
- return results
+ error = ('An error occurred while building and running the \'bad\' '
+ 'reference value. The bisect cannot continue without '
+ 'a working \'bad\' revision to start from.\n\nError: %s' %
+ bad_results[0])
+ return BisectResults(error=error)
if good_results[1]:
- results.error = ('An error occurred while building and running '
- 'the \'good\' reference value. The bisect cannot continue without '
- 'a working \'good\' revision to start from.\n\nError: %s' %
- good_results[0])
- return results
+ error = ('An error occurred while building and running the \'good\' '
+ 'reference value. The bisect cannot continue without '
+ 'a working \'good\' revision to start from.\n\nError: %s' %
+ good_results[0])
+ return BisectResults(error=error)
# We need these reference values to determine if later runs should be
# classified as pass or fail.
@@ -2461,7 +2194,7 @@ class BisectPerformanceMetrics(object):
# lower is better).
improvement_dir = self.opts.improvement_direction
if improvement_dir:
- higher_is_better = improvement_dir > 0
+ higher_is_better = improvement_dir > 0
if higher_is_better:
message = "Expecting higher values to be better for this metric, "
else:
@@ -2473,49 +2206,55 @@ class BisectPerformanceMetrics(object):
message += "and the metric appears to have decreased. "
if ((higher_is_better and metric_increased) or
(not higher_is_better and not metric_increased)):
- results.error = (message + 'Then, the test results for the ends of '
- 'the given \'good\' - \'bad\' range of revisions '
- 'represent an improvement (and not a regression).')
- return results
+ error = (message + 'Then, the test results for the ends of the given '
+ '\'good\' - \'bad\' range of revisions represent an '
+ 'improvement (and not a regression).')
+ return BisectResults(error=error)
print message, "Therefore we continue to bisect."
+ bisect_state = BisectState(target_depot, revision_list)
+ revision_states = bisect_state.GetRevisionStates()
+
+ min_revision = 0
+ max_revision = len(revision_states) - 1
+
# Can just mark the good and bad revisions explicitly here since we
# already know the results.
- bad_revision_data = revision_data[revision_list[0]]
- bad_revision_data['external'] = bad_results[2]
- bad_revision_data['perf_time'] = bad_results[3]
- bad_revision_data['build_time'] = bad_results[4]
- bad_revision_data['passed'] = False
- bad_revision_data['value'] = known_bad_value
-
- good_revision_data = revision_data[revision_list[max_revision]]
- good_revision_data['external'] = good_results[2]
- good_revision_data['perf_time'] = good_results[3]
- good_revision_data['build_time'] = good_results[4]
- good_revision_data['passed'] = True
- good_revision_data['value'] = known_good_value
-
- next_revision_depot = target_depot
+ bad_revision_state = revision_states[min_revision]
+ bad_revision_state.external = bad_results[2]
+ bad_revision_state.perf_time = bad_results[3]
+ bad_revision_state.build_time = bad_results[4]
+ bad_revision_state.passed = False
+ bad_revision_state.value = known_bad_value
+
+ good_revision_state = revision_states[max_revision]
+ good_revision_state.external = good_results[2]
+ good_revision_state.perf_time = good_results[3]
+ good_revision_state.build_time = good_results[4]
+ good_revision_state.passed = True
+ good_revision_state.value = known_good_value
+
+ bisect_printer = BisectPrinter(self.opts, self.depot_registry)
while True:
- if not revision_list:
+ if not revision_states:
break
- min_revision_data = revision_data[revision_list[min_revision]]
- max_revision_data = revision_data[revision_list[max_revision]]
-
if max_revision - min_revision <= 1:
- current_depot = min_revision_data['depot']
- if min_revision_data['passed'] == '?':
+ min_revision_state = revision_states[min_revision]
+ max_revision_state = revision_states[max_revision]
+ current_depot = min_revision_state.depot
+ # TODO(sergiyb): Under which conditions can first two branches be hit?
+ if min_revision_state.passed == '?':
next_revision_index = min_revision
- elif max_revision_data['passed'] == '?':
+ elif max_revision_state.passed == '?':
next_revision_index = max_revision
elif current_depot in ['android-chrome', 'cros', 'chromium', 'v8']:
- previous_revision = revision_list[min_revision]
+ previous_revision = revision_states[min_revision].revision
# If there were changes to any of the external libraries we track,
# should bisect the changes there as well.
external_depot = self._FindNextDepotToBisect(
- current_depot, min_revision_data, max_revision_data)
+ current_depot, min_revision_state, max_revision_state)
# If there was no change in any of the external depots, the search
# is over.
if not external_depot:
@@ -2527,33 +2266,30 @@ class BisectPerformanceMetrics(object):
'bleeding_edge.')
break
- earliest_revision = max_revision_data['external'][external_depot]
- latest_revision = min_revision_data['external'][external_depot]
+ earliest_revision = max_revision_state.external[external_depot]
+ latest_revision = min_revision_state.external[external_depot]
new_revision_list = self.PrepareToBisectOnDepot(
- external_depot, latest_revision, earliest_revision,
+ external_depot, earliest_revision, latest_revision,
previous_revision)
if not new_revision_list:
- results.error = ('An error occurred attempting to retrieve '
- 'revision range: [%s..%s]' %
- (earliest_revision, latest_revision))
- return results
-
- _AddRevisionsIntoRevisionData(
- new_revision_list, external_depot, min_revision_data['sort'],
- revision_data)
-
- # Reset the bisection and perform it on the newly inserted
- # changelists.
- revision_list = new_revision_list
+ error = ('An error occurred attempting to retrieve revision '
+ 'range: [%s..%s]' % (earliest_revision, latest_revision))
+ return BisectResults(error=error)
+
+ revision_states = bisect_state.CreateRevisionStatesAfter(
+ external_depot, new_revision_list, current_depot,
+ previous_revision)
+
+ # Reset the bisection and perform it on the newly inserted states.
min_revision = 0
- max_revision = len(revision_list) - 1
- sort_key_ids += len(revision_list)
+ max_revision = len(revision_states) - 1
print ('Regression in metric %s appears to be the result of '
'changes in [%s].' % (metric, external_depot))
+ revision_list = [state.revision for state in revision_states]
self.PrintRevisionsToBisectMessage(revision_list, external_depot)
continue
@@ -2563,36 +2299,34 @@ class BisectPerformanceMetrics(object):
next_revision_index = (int((max_revision - min_revision) / 2) +
min_revision)
- next_revision_id = revision_list[next_revision_index]
- next_revision_data = revision_data[next_revision_id]
- next_revision_depot = next_revision_data['depot']
+ next_revision_state = revision_states[next_revision_index]
+ next_revision = next_revision_state.revision
+ next_depot = next_revision_state.depot
- self.depot_registry.ChangeToDepotDir(next_revision_depot)
+ self.depot_registry.ChangeToDepotDir(next_depot)
+ message = 'Working on [%s:%s]' % (next_depot, next_revision)
+ print message
if self.opts.output_buildbot_annotations:
- step_name = 'Working on [%s]' % next_revision_id
- bisect_utils.OutputAnnotationStepStart(step_name)
+ bisect_utils.OutputAnnotationStepStart(message)
- print 'Working on revision: [%s]' % next_revision_id
-
- run_results = self.RunTest(
- next_revision_id, next_revision_depot, command_to_run, metric,
- skippable=True)
+ run_results = self.RunTest(next_revision, next_depot, command_to_run,
+ metric, skippable=True)
# If the build is successful, check whether or not the metric
# had regressed.
if not run_results[1]:
if len(run_results) > 2:
- next_revision_data['external'] = run_results[2]
- next_revision_data['perf_time'] = run_results[3]
- next_revision_data['build_time'] = run_results[4]
+ next_revision_state.external = run_results[2]
+ next_revision_state.perf_time = run_results[3]
+ next_revision_state.build_time = run_results[4]
passed_regression = self._CheckIfRunPassed(run_results[0],
known_good_value,
known_bad_value)
- next_revision_data['passed'] = passed_regression
- next_revision_data['value'] = run_results[0]
+ next_revision_state.passed = passed_regression
+ next_revision_state.value = run_results[0]
if passed_regression:
max_revision = next_revision_index
@@ -2600,313 +2334,28 @@ class BisectPerformanceMetrics(object):
min_revision = next_revision_index
else:
if run_results[1] == BUILD_RESULT_SKIPPED:
- next_revision_data['passed'] = 'Skipped'
+ next_revision_state.passed = 'Skipped'
elif run_results[1] == BUILD_RESULT_FAIL:
- next_revision_data['passed'] = 'Build Failed'
+ next_revision_state.passed = 'Build Failed'
print run_results[0]
# If the build is broken, remove it and redo search.
- revision_list.pop(next_revision_index)
+ revision_states.pop(next_revision_index)
max_revision -= 1
if self.opts.output_buildbot_annotations:
- self._PrintPartialResults(results)
+ bisect_printer.PrintPartialResults(bisect_state)
bisect_utils.OutputAnnotationStepClosed()
- else:
- # Weren't able to sync and retrieve the revision range.
- results.error = ('An error occurred attempting to retrieve revision '
- 'range: [%s..%s]' % (good_revision, bad_revision))
- return results
-
- def _PrintPartialResults(self, results):
- results_dict = results.GetResultsDict()
- self._PrintTestedCommitsTable(results_dict['revision_data_sorted'],
- results_dict['first_working_revision'],
- results_dict['last_broken_revision'],
- 100, final_step=False)
-
- def _ConfidenceLevelStatus(self, results_dict):
- if not results_dict['confidence']:
- return None
- confidence_status = 'Successful with %(level)s confidence%(warning)s.'
- if results_dict['confidence'] >= HIGH_CONFIDENCE:
- level = 'high'
- else:
- level = 'low'
- warning = ' and warnings'
- if not self.warnings:
- warning = ''
- return confidence_status % {'level': level, 'warning': warning}
-
- def _GetViewVCLinkFromDepotAndHash(self, revision_id, depot):
- """Gets link to the repository browser."""
- info = source_control.QueryRevisionInfo(revision_id,
- self.depot_registry.GetDepotDir(depot))
- if depot and DEPOT_DEPS_NAME[depot].has_key('viewvc'):
- try:
- # Format is "git-svn-id: svn://....@123456 <other data>"
- svn_line = [i for i in info['body'].splitlines() if 'git-svn-id:' in i]
- svn_revision = svn_line[0].split('@')
- svn_revision = svn_revision[1].split(' ')[0]
- return DEPOT_DEPS_NAME[depot]['viewvc'] + svn_revision
- except IndexError:
- return ''
- return ''
-
- def _PrintRevisionInfo(self, cl, info, depot=None):
- email_info = ''
- if not info['email'].startswith(info['author']):
- email_info = '\nEmail : %s' % info['email']
- commit_link = self._GetViewVCLinkFromDepotAndHash(cl, depot)
- if commit_link:
- commit_info = '\nLink : %s' % commit_link
- else:
- commit_info = ('\nFailed to parse SVN revision from body:\n%s' %
- info['body'])
- print RESULTS_REVISION_INFO % {
- 'subject': info['subject'],
- 'author': info['author'],
- 'email_info': email_info,
- 'commit_info': commit_info,
- 'cl': cl,
- 'cl_date': info['date']
- }
-
- def _PrintTestedCommitsHeader(self):
- if self.opts.bisect_mode == BISECT_MODE_MEAN:
- _PrintTableRow(
- [20, 12, 70, 14, 12, 13],
- ['Depot', 'Position', 'SHA', 'Mean', 'Std. Error', 'State'])
- elif self.opts.bisect_mode == BISECT_MODE_STD_DEV:
- _PrintTableRow(
- [20, 12, 70, 14, 12, 13],
- ['Depot', 'Position', 'SHA', 'Std. Error', 'Mean', 'State'])
- elif self.opts.bisect_mode == BISECT_MODE_RETURN_CODE:
- _PrintTableRow(
- [20, 12, 70, 14, 13],
- ['Depot', 'Position', 'SHA', 'Return Code', 'State'])
- else:
- assert False, 'Invalid bisect_mode specified.'
-
- def _PrintTestedCommitsEntry(self, current_data, commit_position, cl_link,
- state_str):
- if self.opts.bisect_mode == BISECT_MODE_MEAN:
- std_error = '+-%.02f' % current_data['value']['std_err']
- mean = '%.02f' % current_data['value']['mean']
- _PrintTableRow(
- [20, 12, 70, 12, 14, 13],
- [current_data['depot'], commit_position, cl_link, mean, std_error,
- state_str])
- elif self.opts.bisect_mode == BISECT_MODE_STD_DEV:
- std_error = '+-%.02f' % current_data['value']['std_err']
- mean = '%.02f' % current_data['value']['mean']
- _PrintTableRow(
- [20, 12, 70, 12, 14, 13],
- [current_data['depot'], commit_position, cl_link, std_error, mean,
- state_str])
- elif self.opts.bisect_mode == BISECT_MODE_RETURN_CODE:
- mean = '%d' % current_data['value']['mean']
- _PrintTableRow(
- [20, 12, 70, 14, 13],
- [current_data['depot'], commit_position, cl_link, mean,
- state_str])
-
- def _PrintTestedCommitsTable(
- self, revision_data_sorted, first_working_revision, last_broken_revision,
- confidence, final_step=True):
- print
- if final_step:
- print '===== TESTED COMMITS ====='
- else:
- print '===== PARTIAL RESULTS ====='
- self._PrintTestedCommitsHeader()
- state = 0
- for current_id, current_data in revision_data_sorted:
- if current_data['value']:
- if (current_id == last_broken_revision or
- current_id == first_working_revision):
- # If confidence is too low, don't add this empty line since it's
- # used to put focus on a suspected CL.
- if confidence and final_step:
- print
- state += 1
- if state == 2 and not final_step:
- # Just want a separation between "bad" and "good" cl's.
- print
-
- state_str = 'Bad'
- if state == 1 and final_step:
- state_str = 'Suspected CL'
- elif state == 2:
- state_str = 'Good'
-
- # If confidence is too low, don't bother outputting good/bad.
- if not confidence:
- state_str = ''
- state_str = state_str.center(13, ' ')
-
- cl_link = self._GetViewVCLinkFromDepotAndHash(current_id,
- current_data['depot'])
- if not cl_link:
- cl_link = current_id
- commit_position = source_control.GetCommitPosition(
- current_id, self.depot_registry.GetDepotDir(current_data['depot']))
- commit_position = str(commit_position)
- if not commit_position:
- commit_position = ''
- self._PrintTestedCommitsEntry(current_data, commit_position, cl_link,
- state_str)
-
- def _PrintReproSteps(self):
- """Prints out a section of the results explaining how to run the test.
-
- This message includes the command used to run the test.
- """
- command = '$ ' + self.opts.command
- if bisect_utils.IsTelemetryCommand(self.opts.command):
- command += ('\nAlso consider passing --profiler=list to see available '
- 'profilers.')
- print REPRO_STEPS_LOCAL
- if bisect_utils.IsTelemetryCommand(self.opts.command):
- telemetry_command = re.sub(r'--browser=[^\s]+',
- '--browser=<bot-name>',
- command)
- print REPRO_STEPS_TRYJOB_TELEMETRY % {'command': telemetry_command}
+ return BisectResults(bisect_state, self.depot_registry, self.opts,
+ self.warnings)
else:
- print REPRO_STEPS_TRYJOB
-
- def _PrintOtherRegressions(self, other_regressions, revision_data):
- """Prints a section of the results about other potential regressions."""
- print
- print 'Other regressions may have occurred:'
- print ' %8s %70s %10s' % ('Depot'.center(8, ' '),
- 'Range'.center(70, ' '), 'Confidence'.center(10, ' '))
- for regression in other_regressions:
- current_id, previous_id, confidence = regression
- current_data = revision_data[current_id]
- previous_data = revision_data[previous_id]
-
- current_link = self._GetViewVCLinkFromDepotAndHash(current_id,
- current_data['depot'])
- previous_link = self._GetViewVCLinkFromDepotAndHash(previous_id,
- previous_data['depot'])
-
- # If we can't map it to a viewable URL, at least show the original hash.
- if not current_link:
- current_link = current_id
- if not previous_link:
- previous_link = previous_id
-
- print ' %8s %70s %s' % (
- current_data['depot'], current_link,
- ('%d%%' % confidence).center(10, ' '))
- print ' %8s %70s' % (
- previous_data['depot'], previous_link)
- print
-
- def _CheckForWarnings(self, results_dict):
- if len(results_dict['culprit_revisions']) > 1:
- self.warnings.append('Due to build errors, regression range could '
- 'not be narrowed down to a single commit.')
- if self.opts.repeat_test_count == 1:
- self.warnings.append('Tests were only set to run once. This may '
- 'be insufficient to get meaningful results.')
- if 0 < results_dict['confidence'] < HIGH_CONFIDENCE:
- self.warnings.append('Confidence is not high. Try bisecting again '
- 'with increased repeat_count, larger range, or '
- 'on another metric.')
- if not results_dict['confidence']:
- self.warnings.append('Confidence score is 0%. Try bisecting again on '
- 'another platform or another metric.')
-
- def FormatAndPrintResults(self, bisect_results):
- """Prints the results from a bisection run in a readable format.
-
- Args:
- bisect_results: The results from a bisection test run.
- """
- results_dict = bisect_results.GetResultsDict()
-
- self._CheckForWarnings(results_dict)
-
- if self.opts.output_buildbot_annotations:
- bisect_utils.OutputAnnotationStepStart('Build Status Per Revision')
-
- print
- print 'Full results of bisection:'
- for current_id, current_data in results_dict['revision_data_sorted']:
- build_status = current_data['passed']
-
- if type(build_status) is bool:
- if build_status:
- build_status = 'Good'
- else:
- build_status = 'Bad'
-
- print ' %20s %40s %s' % (current_data['depot'],
- current_id, build_status)
- print
-
- if self.opts.output_buildbot_annotations:
- bisect_utils.OutputAnnotationStepClosed()
- # The perf dashboard scrapes the "results" step in order to comment on
- # bugs. If you change this, please update the perf dashboard as well.
- bisect_utils.OutputAnnotationStepStart('Results')
-
- self._PrintBanner(results_dict)
- self._PrintWarnings()
-
- if results_dict['culprit_revisions'] and results_dict['confidence']:
- for culprit in results_dict['culprit_revisions']:
- cl, info, depot = culprit
- self._PrintRevisionInfo(cl, info, depot)
- if results_dict['other_regressions']:
- self._PrintOtherRegressions(results_dict['other_regressions'],
- results_dict['revision_data'])
- self._PrintTestedCommitsTable(results_dict['revision_data_sorted'],
- results_dict['first_working_revision'],
- results_dict['last_broken_revision'],
- results_dict['confidence'])
- _PrintStepTime(results_dict['revision_data_sorted'])
- self._PrintReproSteps()
- _PrintThankYou()
- if self.opts.output_buildbot_annotations:
- bisect_utils.OutputAnnotationStepClosed()
-
- def _PrintBanner(self, results_dict):
- if self._IsBisectModeReturnCode():
- metrics = 'N/A'
- change = 'Yes'
- else:
- metrics = '/'.join(self.opts.metric)
- change = '%.02f%% (+/-%.02f%%)' % (
- results_dict['regression_size'], results_dict['regression_std_err'])
-
- if results_dict['culprit_revisions'] and results_dict['confidence']:
- status = self._ConfidenceLevelStatus(results_dict)
- else:
- status = 'Failure, could not reproduce.'
- change = 'Bisect could not reproduce a change.'
-
- print RESULTS_BANNER % {
- 'status': status,
- 'command': self.opts.command,
- 'metrics': metrics,
- 'change': change,
- 'confidence': results_dict['confidence'],
- }
-
- def _PrintWarnings(self):
- """Prints a list of warning strings if there are any."""
- if not self.warnings:
- return
- print
- print 'WARNINGS:'
- for w in set(self.warnings):
- print ' ! %s' % w
+ # Weren't able to sync and retrieve the revision range.
+ error = ('An error occurred attempting to retrieve revision range: '
+ '[%s..%s]' % (good_revision, bad_revision))
+ return BisectResults(error=error)
def _IsPlatformSupported():
@@ -2982,7 +2431,7 @@ class BisectOptions(object):
self.target_build_type = 'Release'
self.builder_host = None
self.builder_port = None
- self.bisect_mode = BISECT_MODE_MEAN
+ self.bisect_mode = bisect_utils.BISECT_MODE_MEAN
self.improvement_direction = 0
@staticmethod
@@ -3047,9 +2496,10 @@ class BisectOptions(object):
'discarded).')
group.add_option('--bisect_mode',
type='choice',
- choices=[BISECT_MODE_MEAN, BISECT_MODE_STD_DEV,
- BISECT_MODE_RETURN_CODE],
- default=BISECT_MODE_MEAN,
+ choices=[bisect_utils.BISECT_MODE_MEAN,
+ bisect_utils.BISECT_MODE_STD_DEV,
+ bisect_utils.BISECT_MODE_RETURN_CODE],
+ default=bisect_utils.BISECT_MODE_MEAN,
help='The bisect mode. Choices are to bisect on the '
'difference in mean, std_dev, or return_code.')
parser.add_option_group(group)
@@ -3167,7 +2617,8 @@ class BisectOptions(object):
if not opts.bad_revision:
raise RuntimeError('missing required parameter: --bad_revision')
- if not opts.metric and opts.bisect_mode != BISECT_MODE_RETURN_CODE:
+ if (not opts.metric and
+ opts.bisect_mode != bisect_utils.BISECT_MODE_RETURN_CODE):
raise RuntimeError('missing required parameter: --metric')
if opts.gs_bucket:
@@ -3194,7 +2645,7 @@ class BisectOptions(object):
if not opts.working_directory:
raise RuntimeError('missing required parameter: --working_directory')
- if opts.bisect_mode != BISECT_MODE_RETURN_CODE:
+ if opts.bisect_mode != bisect_utils.BISECT_MODE_RETURN_CODE:
metric_values = opts.metric.split('/')
if len(metric_values) != 2:
raise RuntimeError('Invalid metric specified: [%s]' % opts.metric)
@@ -3230,7 +2681,7 @@ class BisectOptions(object):
assert hasattr(opts, k), 'Invalid %s attribute in BisectOptions.' % k
setattr(opts, k, v)
- if opts.metric and opts.bisect_mode != BISECT_MODE_RETURN_CODE:
+ if opts.metric and opts.bisect_mode != bisect_utils.BISECT_MODE_RETURN_CODE:
metric_values = opts.metric.split('/')
if len(metric_values) != 2:
raise RuntimeError('Invalid metric specified: [%s]' % opts.metric)
@@ -3254,7 +2705,7 @@ def main():
extra_src = bisect_utils.LoadExtraSrc(opts.extra_src)
if not extra_src:
raise RuntimeError('Invalid or missing --extra_src.')
- _AddAdditionalDepotInfo(extra_src.GetAdditionalDepotInfo())
+ bisect_utils.AddAdditionalDepotInfo(extra_src.GetAdditionalDepotInfo())
if opts.working_directory:
custom_deps = bisect_utils.DEFAULT_GCLIENT_CUSTOM_DEPS
@@ -3280,14 +2731,13 @@ def main():
not opts.working_directory):
raise RuntimeError('You must switch to master branch to run bisection.')
bisect_test = BisectPerformanceMetrics(opts)
+ bisect_printer = BisectPrinter(opts, bisect_test.depot_registry)
try:
- bisect_results = bisect_test.Run(opts.command,
- opts.bad_revision,
- opts.good_revision,
- opts.metric)
- if bisect_results.error:
- raise RuntimeError(bisect_results.error)
- bisect_test.FormatAndPrintResults(bisect_results)
+ results = bisect_test.Run(opts.command, opts.bad_revision,
+ opts.good_revision, opts.metric)
+ if results.error:
+ raise RuntimeError(results.error)
+ bisect_printer.FormatAndPrintResults(results)
return 0
finally:
bisect_test.PerformCleanup()
« no previous file with comments | « no previous file | tools/auto_bisect/bisect_perf_regression_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698