| Index: tools/gen_bench_expectations_from_codereview.py
|
| diff --git a/tools/gen_bench_expectations_from_codereview.py b/tools/gen_bench_expectations_from_codereview.py
|
| index 3d40aa67eb04d3dd4d87a40305e9ebd4ec648c5c..4c41c9a72e3cdda6580676b23ecfc342002c7422 100644
|
| --- a/tools/gen_bench_expectations_from_codereview.py
|
| +++ b/tools/gen_bench_expectations_from_codereview.py
|
| @@ -10,21 +10,27 @@
|
|
|
| import collections
|
| import compare_codereview
|
| +import json
|
| import os
|
| import re
|
| import shutil
|
| -import subprocess
|
| import sys
|
| +import urllib2
|
|
|
| +import fix_pythonpath # pylint: disable=W0611
|
| +from common.py.utils import shell_utils
|
|
|
| -BENCH_DATA_URL = 'gs://chromium-skia-gm/perfdata/%s/%s/*'
|
| +
|
| +BENCH_DATA_URL = 'gs://chromium-skia-gm/perfdata/%s/%s/bench_*_data_*'
|
| +BUILD_STATUS_SUCCESS = 0
|
| +BUILD_STATUS_WARNINGS = 1
|
| CHECKOUT_PATH = os.path.realpath(os.path.join(
|
| os.path.dirname(os.path.abspath(__file__)), os.pardir))
|
| TMP_BENCH_DATA_DIR = os.path.join(CHECKOUT_PATH, '.bench_data')
|
|
|
|
|
| TryBuild = collections.namedtuple(
|
| - 'TryBuild', ['builder_name', 'build_number', 'is_finished'])
|
| + 'TryBuild', ['builder_name', 'build_number', 'is_finished', 'json_url'])
|
|
|
|
|
| def find_all_builds(codereview_url):
|
| @@ -40,12 +46,19 @@ def find_all_builds(codereview_url):
|
| try_builds = []
|
| for builder, data in results.iteritems():
|
| if builder.startswith('Perf'):
|
| - build_num = data.url.split('/')[-1] if data.url else None
|
| + build_num = None
|
| + json_url = None
|
| + if data.url:
|
| + split_url = data.url.split('/')
|
| + build_num = split_url[-1]
|
| + split_url.insert(split_url.index('builders'), 'json')
|
| + json_url = '/'.join(split_url)
|
| is_finished = (data.status not in ('pending', 'try-pending') and
|
| build_num is not None)
|
| try_builds.append(TryBuild(builder_name=builder,
|
| build_number=build_num,
|
| - is_finished=is_finished))
|
| + is_finished=is_finished,
|
| + json_url=json_url))
|
| return try_builds
|
|
|
|
|
| @@ -85,9 +98,7 @@ def get_bench_data(builder, build_num, dest_dir):
|
| dest_dir: string; destination directory for the bench data.
|
| """
|
| url = BENCH_DATA_URL % (builder, build_num)
|
| - subprocess.check_call(['gsutil', 'cp', '-R', url, dest_dir],
|
| - stdout=subprocess.PIPE,
|
| - stderr=subprocess.PIPE)
|
| + shell_utils.run(['gsutil', 'cp', '-R', url, dest_dir])
|
|
|
|
|
| def find_revision_from_downloaded_data(dest_dir):
|
| @@ -111,8 +122,32 @@ class TrybotNotFinishedError(Exception):
|
| pass
|
|
|
|
|
| +def _step_succeeded(try_build, step_name):
|
| + """Return True if the given step succeeded and False otherwise.
|
| +
|
| + This function talks to the build master's JSON interface, which is slow.
|
| +
|
| + TODO(borenet): There are now a few places which talk to the master's JSON
|
| + interface. Maybe it'd be worthwhile to create a module which does this.
|
| +
|
| + Args:
|
| + try_build: TryBuild instance; the build we're concerned about.
|
| + step_name: string; name of the step we're concerned about.
|
| + """
|
| + step_url = '/'.join((try_build.json_url, 'steps', step_name))
|
| + step_data = json.load(urllib2.urlopen(step_url))
|
| + # step_data['results'] may not be present if the step succeeded. If present,
|
| + # it is a list whose first element is a result code, per the documentation:
|
| + # http://docs.buildbot.net/latest/developer/results.html
|
| + result = step_data.get('results', [BUILD_STATUS_SUCCESS])[0]
|
| + if result in (BUILD_STATUS_SUCCESS, BUILD_STATUS_WARNINGS):
|
| + return True
|
| + return False
|
| +
|
| +
|
| def gen_bench_expectations_from_codereview(codereview_url,
|
| - error_on_unfinished=True):
|
| + error_on_unfinished=True,
|
| + error_on_try_failure=True):
|
| """Generate bench expectations from a code review.
|
|
|
| Scans the given code review for Perf trybot runs. Downloads the results of
|
| @@ -122,6 +157,8 @@ def gen_bench_expectations_from_codereview(codereview_url,
|
| Args:
|
| url: string; URL of the code review.
|
| error_on_unfinished: bool; throw an error if any trybot has not finished.
|
| + error_on_try_failure: bool; throw an error if any trybot failed an
|
| + important step.
|
| """
|
| try_builds = find_all_builds(codereview_url)
|
|
|
| @@ -129,14 +166,32 @@ def gen_bench_expectations_from_codereview(codereview_url,
|
| if error_on_unfinished and not _all_trybots_finished(try_builds):
|
| raise TrybotNotFinishedError('Not all trybots have finished.')
|
|
|
| + failed_run = []
|
| failed_data_pull = []
|
| failed_gen_expectations = []
|
|
|
| + # Don't even try to do anything if BenchPictures, PostBench, or
|
| + # UploadBenchResults failed.
|
| + for try_build in try_builds:
|
| + for step in ('BenchPictures', 'PostBench', 'UploadBenchResults'):
|
| + if not _step_succeeded(try_build, step):
|
| + msg = '%s failed on %s!' % (step, try_build.builder_name)
|
| + if error_on_try_failure:
|
| + raise Exception(msg)
|
| + print 'WARNING: %s Skipping.' % msg
|
| + failed_run.append(try_build.builder_name)
|
| +
|
| if os.path.isdir(TMP_BENCH_DATA_DIR):
|
| shutil.rmtree(TMP_BENCH_DATA_DIR)
|
|
|
| for try_build in try_builds:
|
| try_builder = try_build.builder_name
|
| +
|
| + # Even if we're not erroring out on try failures, we can't generate new
|
| + # expectations for failed bots.
|
| + if try_builder in failed_run:
|
| + continue
|
| +
|
| builder = try_builder.replace('-Trybot', '')
|
|
|
| # Download the data.
|
| @@ -144,7 +199,7 @@ def gen_bench_expectations_from_codereview(codereview_url,
|
| os.makedirs(dest_dir)
|
| try:
|
| get_bench_data(try_builder, try_build.build_number, dest_dir)
|
| - except subprocess.CalledProcessError:
|
| + except shell_utils.CommandFailedException:
|
| failed_data_pull.append(try_builder)
|
| continue
|
|
|
| @@ -160,12 +215,12 @@ def gen_bench_expectations_from_codereview(codereview_url,
|
| output_file = os.path.join(CHECKOUT_PATH, 'expectations', 'bench',
|
| 'bench_expectations_%s.txt' % builder)
|
| try:
|
| - subprocess.check_call(['python',
|
| - os.path.join(CHECKOUT_PATH, 'bench',
|
| - 'gen_bench_expectations.py'),
|
| - '-b', builder, '-o', output_file,
|
| - '-d', dest_dir, '-r', revision])
|
| - except subprocess.CalledProcessError:
|
| + shell_utils.run(['python',
|
| + os.path.join(CHECKOUT_PATH, 'bench',
|
| + 'gen_bench_expectations.py'),
|
| + '-b', builder, '-o', output_file,
|
| + '-d', dest_dir, '-r', revision])
|
| + except shell_utils.CommandFailedException:
|
| failed_gen_expectations.append(builder)
|
|
|
| failure = ''
|
|
|