blob: dd29cf4f78c1b253a3fb9dbbf50e50ff655962d6 [file] [log] [blame]
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright 2019 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Performs bisection on LLVM based off a .JSON file."""
from __future__ import print_function
import os
import subprocess
import sys
import time
import traceback
import chroot
from llvm_bisection import BisectionExitStatus
import llvm_bisection
from update_all_tryjobs_with_auto import GetPathToUpdateAllTryjobsWithAutoScript
# Used to re-try for 'llvm_bisection.py' to attempt to launch more tryjobs.
BISECTION_RETRY_TIME_SECS = 10 * 60
# Wait time to then poll each tryjob whose 'status' value is 'pending'.
POLL_RETRY_TIME_SECS = 30 * 60
# The number of attempts for 'llvm_bisection.py' to launch more tryjobs.
#
# It is reset (break out of the `for` loop/ exit the program) if successfully
# launched more tryjobs or bisection is finished (no more revisions between
# start and end of the bisection).
BISECTION_ATTEMPTS = 3
# The limit for updating all tryjobs whose 'status' is 'pending'.
#
# If the time that has passed for polling exceeds this value, then the program
# will exit with the appropriate exit code.
POLLING_LIMIT_SECS = 18 * 60 * 60
def main():
"""Bisects LLVM using the result of `cros buildresult` of each tryjob.
Raises:
AssertionError: The script was run inside the chroot.
"""
chroot.VerifyOutsideChroot()
args_output = llvm_bisection.GetCommandLineArgs()
exec_update_tryjobs = [
GetPathToUpdateAllTryjobsWithAutoScript(), '--chroot_path',
args_output.chroot_path, '--last_tested', args_output.last_tested
]
if os.path.isfile(args_output.last_tested):
print('Resuming bisection for %s' % args_output.last_tested)
else:
print('Starting a new bisection for %s' % args_output.last_tested)
while True:
if os.path.isfile(args_output.last_tested):
update_start_time = time.time()
# Update all tryjobs whose status is 'pending' to the result of `cros
# buildresult`.
while True:
print('\nAttempting to update all tryjobs whose "status" is '
'"pending":')
print('-' * 40)
update_ret = subprocess.call(exec_update_tryjobs)
print('-' * 40)
# Successfully updated all tryjobs whose 'status' was 'pending'/ no
# updates were needed (all tryjobs already have been updated).
if update_ret == 0:
break
delta_time = time.time() - update_start_time
if delta_time > POLLING_LIMIT_SECS:
print('Unable to update tryjobs whose status is "pending" to '
'the result of `cros buildresult`.')
# Something is wrong with updating the tryjobs's 'status' via
# `cros buildresult` (e.g. network issue, etc.).
sys.exit(1)
print('Sleeping for %d minutes.' % (POLL_RETRY_TIME_SECS // 60))
time.sleep(POLL_RETRY_TIME_SECS)
# Launch more tryjobs if possible to narrow down the bad commit/revision or
# terminate the bisection because the bad commit/revision was found.
for cur_try in range(1, BISECTION_ATTEMPTS + 1):
try:
print('\nAttempting to launch more tryjobs if possible:')
print('-' * 40)
bisection_ret = llvm_bisection.main(args_output)
print('-' * 40)
# Exit code 126 means that there are no more revisions to test between
# 'start' and 'end', so bisection is complete.
if bisection_ret == BisectionExitStatus.BISECTION_COMPLETE.value:
sys.exit(0)
# Successfully launched more tryjobs.
break
except Exception:
traceback.print_exc()
print('-' * 40)
# Exceeded the number of times to launch more tryjobs.
if cur_try == BISECTION_ATTEMPTS:
print('Unable to continue bisection.')
sys.exit(1)
num_retries_left = BISECTION_ATTEMPTS - cur_try
print('Retries left to continue bisection %d.' % num_retries_left)
print('Sleeping for %d minutes.' % (BISECTION_RETRY_TIME_SECS // 60))
time.sleep(BISECTION_RETRY_TIME_SECS)
if __name__ == '__main__':
main()