Index: tools/bisect-perf-regression.py |
diff --git a/tools/bisect-perf-regression.py b/tools/bisect-perf-regression.py |
index 5367345d6af2abcccf3277c8a312c6bdc15ba431..bb5ef19bfc6dfe6da079d177fceaffc6f6a968cc 100755 |
--- a/tools/bisect-perf-regression.py |
+++ b/tools/bisect-perf-regression.py |
@@ -482,7 +482,7 @@ def FetchFromCloudStorage(bucket_name, source_path, destination_path): |
destination_path: Destination file path. |
Returns: |
- True if the fetching succeeds, otherwise False. |
+ Downloaded file path if exisits, otherwise None. |
""" |
target_file = os.path.join(destination_path, os.path.basename(source_path)) |
try: |
@@ -490,7 +490,7 @@ def FetchFromCloudStorage(bucket_name, source_path, destination_path): |
print 'Fetching file from gs//%s/%s ...' % (bucket_name, source_path) |
cloud_storage.Get(bucket_name, source_path, destination_path) |
if os.path.exists(target_file): |
- return True |
+ return target_file |
else: |
print ('File gs://%s/%s not found in cloud storage.' % ( |
bucket_name, source_path)) |
@@ -498,7 +498,7 @@ def FetchFromCloudStorage(bucket_name, source_path, destination_path): |
print 'Something went wrong while fetching file from cloud: %s' % e |
if os.path.exists(target_file): |
os.remove(target_file) |
- return False |
+ return None |
# This is copied from Chromium's project build/scripts/common/chromium_utils.py. |
@@ -1553,12 +1553,42 @@ class BisectPerformanceMetrics(object): |
return destination_dir |
return None |
+ def GetBuildArchiveForRevision(self, revision, gs_bucket, target_arch, |
+ patch_sha, out_dir): |
+ """Checks and downloads build archive for a given revision. |
+ |
+ Checks for build archive with Git hash or SVN revision. If either of the |
+ file exists, then downloads the archive file. |
+ |
+ Args: |
+ revision: A Git hash revision. |
+ gs_bucket: Cloud storage bucket name |
+ target_arch: 32 or 64 bit build target |
+ patch: A DEPS patch (used while bisecting 3rd party repositories). |
+ out_dir: Build output directory where downloaded file is stored. |
+ |
+ Returns: |
+ Downloaded archive file path if exists, otherwise None. |
+ """ |
+ # Source archive file path on cloud storage using Git revision. |
+ source_file = GetRemoteBuildPath(revision, target_arch, patch_sha) |
+ downloaded_archive = FetchFromCloudStorage(gs_bucket, source_file, out_dir) |
+ if not downloaded_archive: |
+ # Get SVN revision for the given SHA. |
+ svn_revision = self.source_control.SVNFindRev(revision) |
+ if svn_revision: |
+ # Source archive file path on cloud storage using SVN revision. |
+ source_file = GetRemoteBuildPath(svn_revision, target_arch, patch_sha) |
+ return FetchFromCloudStorage(gs_bucket, source_file, out_dir) |
+ return downloaded_archive |
+ |
def DownloadCurrentBuild(self, revision, build_type='Release', patch=None): |
"""Downloads the build archive for the given revision. |
Args: |
- revision: The SVN revision to build. |
+ revision: The Git revision to download or build. |
build_type: Target build type ('Release', 'Debug', 'Release_x64' etc.) |
+ patch: A DEPS patch (used while bisecting 3rd party repositories). |
Returns: |
True if download succeeds, otherwise False. |
@@ -1572,27 +1602,25 @@ class BisectPerformanceMetrics(object): |
# 'DEPS.sha' and add patch_sha evaluated above to it. |
patch = '%s\n%s' % (patch, DEPS_SHA_PATCH % {'deps_sha': patch_sha}) |
- # Source archive file path on cloud storage. |
- source_file = GetRemoteBuildPath(revision, self.opts.target_arch, patch_sha) |
- |
# Get Build output directory |
abs_build_dir = os.path.abspath( |
self.builder.GetBuildOutputDirectory(self.opts, self.src_cwd)) |
- # Downloaded archive file path. |
- downloaded_file = os.path.join( |
- abs_build_dir, |
- GetZipFileName(revision, self.opts.target_arch, patch_sha)) |
- |
- fetch_build_func = lambda: FetchFromCloudStorage(self.opts.gs_bucket, |
- source_file, |
- abs_build_dir) |
- |
- if not fetch_build_func(): |
- if not self.PostBuildRequestAndWait(revision, |
- fetch_build=fetch_build_func, |
- patch=patch): |
- raise RuntimeError('Somewthing went wrong while processing build' |
- 'request for: %s' % revision) |
+ |
+ fetch_build_func = lambda: self.GetBuildArchiveForRevision( |
+ revision, self.opts.gs_bucket, self.opts.target_arch, |
+ patch_sha, abs_build_dir) |
+ |
+ # Downloaded archive file path, downloads build archive for given revision. |
+ downloaded_file = fetch_build_func() |
+ |
+ # When build archive doesn't exists, post a build request to tryserver |
+ # and wait for the build to be produced. |
+ if not downloaded_file: |
+ downloaded_file = self.PostBuildRequestAndWait( |
+ revision, fetch_build=fetch_build_func, patch=patch) |
+ if not downloaded_file: |
+ return False |
+ |
# Generic name for the archive, created when archive file is extracted. |
output_dir = os.path.join( |
abs_build_dir, GetZipFileName(target_arch=self.opts.target_arch)) |
@@ -1634,8 +1662,7 @@ class BisectPerformanceMetrics(object): |
max_timeout: Maximum time to wait for the build. |
Returns: |
- True if build exists and download is successful, otherwise throws |
- RuntimeError exception when time elapse. |
+ Downloaded archive file path if exists, otherwise None. |
""" |
# Build number on the tryserver. |
build_num = None |
@@ -1665,16 +1692,36 @@ class BisectPerformanceMetrics(object): |
build_status, status_link = bisect_builder.GetBuildStatus( |
build_num, bot_name, builder_host, builder_port) |
if build_status == bisect_builder.FAILED: |
- return (False, 'Failed to produce build, log: %s' % status_link) |
+ return (None, 'Failed to produce build, log: %s' % status_link) |
elapsed_time = time.time() - start_time |
if elapsed_time > max_timeout: |
- return (False, 'Timed out: %ss without build' % max_timeout) |
+ return (None, 'Timed out: %ss without build' % max_timeout) |
print 'Time elapsed: %ss without build.' % elapsed_time |
time.sleep(poll_interval) |
def PostBuildRequestAndWait(self, revision, fetch_build, patch=None): |
- """POSTs the build request job to the tryserver instance.""" |
+ """POSTs the build request job to the tryserver instance. |
+ |
+ A try job build request is posted to tryserver.chromium.perf master, |
+ and waits for the binaries to be produced and archived on cloud storage. |
+ Once the build is ready and stored onto cloud, build archive is downloaded |
+ into the output folder. |
+ |
+ Args: |
+ revision: A Git hash revision. |
+ fetch_build: Function to check and download build from cloud storage. |
+ patch: A DEPS patch (used while bisecting 3rd party repositories). |
+ |
+ Returns: |
+ Downloaded archive file path when requested build exists and download is |
+ successful, otherwise None. |
+ """ |
+ # Get SVN revision for the given SHA. |
+ svn_revision = self.source_control.SVNFindRev(revision) |
+ if not svn_revision: |
+ raise RuntimeError( |
+ 'Failed to determine SVN revision for %s' % revision) |
def GetBuilderNameAndBuildTime(target_arch='ia32'): |
"""Gets builder bot name and buildtime in seconds based on platform.""" |
@@ -1698,12 +1745,12 @@ class BisectPerformanceMetrics(object): |
# Create a unique ID for each build request posted to tryserver builders. |
# This ID is added to "Reason" property in build's json. |
build_request_id = GetSHA1HexDigest( |
- '%s-%s-%s' % (revision, patch, time.time())) |
+ '%s-%s-%s' % (svn_revision, patch, time.time())) |
# Creates a try job description. |
job_args = {'host': builder_host, |
'port': builder_port, |
- 'revision': 'src@%s' % revision, |
+ 'revision': 'src@%s' % svn_revision, |
'bot': bot_name, |
'name': build_request_id |
} |
@@ -1712,16 +1759,18 @@ class BisectPerformanceMetrics(object): |
job_args['patch'] = patch |
# Posts job to build the revision on the server. |
if bisect_builder.PostTryJob(job_args): |
- status, error_msg = self.WaitUntilBuildIsReady(fetch_build, |
- bot_name, |
- builder_host, |
- builder_port, |
- build_request_id, |
- build_timeout) |
- if not status: |
- raise RuntimeError('%s [revision: %s]' % (error_msg, revision)) |
- return True |
- return False |
+ target_file, error_msg = self.WaitUntilBuildIsReady(fetch_build, |
+ bot_name, |
+ builder_host, |
+ builder_port, |
+ build_request_id, |
+ build_timeout) |
+ if not target_file: |
+ print '%s [revision: %s]' % (error_msg, svn_revision) |
+ return None |
+ return target_file |
+ print 'Failed to post build request for revision: [%s]' % svn_revision |
+ return None |
def IsDownloadable(self, depot): |
"""Checks if build is downloadable based on target platform and depot.""" |
@@ -1921,13 +1970,7 @@ class BisectPerformanceMetrics(object): |
if depot != 'chromium': |
# Create a DEPS patch with new revision for dependency repository. |
(revision, deps_patch) = self.CreateDEPSPatch(depot, revision) |
- # Get SVN revision for the given SHA, since builds are archived using SVN |
- # revision. |
- chromium_revision = self.source_control.SVNFindRev(revision) |
- if not chromium_revision: |
- raise RuntimeError( |
- 'Failed to determine SVN revision for %s' % revision) |
- if self.DownloadCurrentBuild(chromium_revision, patch=deps_patch): |
+ if self.DownloadCurrentBuild(revision, patch=deps_patch): |
os.chdir(cwd) |
if deps_patch: |
# Reverts the changes to DEPS file. |
@@ -1935,12 +1978,9 @@ class BisectPerformanceMetrics(object): |
revision, |
cwd=self.src_cwd) |
return True |
- raise RuntimeError('Failed to download build archive for revision %s.\n' |
- 'Unfortunately, bisection couldn\'t continue any ' |
- 'further. Please try running script without ' |
- '--gs_bucket flag to produce local builds.' % revision) |
- |
+ return False |
+ # These codes are executed when bisect bots builds binaries locally. |
build_success = self.builder.Build(depot, self.opts) |
os.chdir(cwd) |
return build_success |