diff options
Diffstat (limited to 'binary_search_tool/binary_search_perforce.py')
-rwxr-xr-x | binary_search_tool/binary_search_perforce.py | 978 |
1 files changed, 521 insertions, 457 deletions
diff --git a/binary_search_tool/binary_search_perforce.py b/binary_search_tool/binary_search_perforce.py index f2a3c8d5..01756b8e 100755 --- a/binary_search_tool/binary_search_perforce.py +++ b/binary_search_tool/binary_search_perforce.py @@ -1,15 +1,13 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -# Copyright 2020 The Chromium OS Authors. All rights reserved. +# Copyright 2020 The ChromiumOS Authors # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. """Module of binary serch for perforce.""" -from __future__ import division -from __future__ import print_function -import math import argparse +import math import os import re import sys @@ -18,496 +16,562 @@ import tempfile from cros_utils import command_executer from cros_utils import logger + verbose = True def _GetP4ClientSpec(client_name, p4_paths): - p4_string = '' - for p4_path in p4_paths: - if ' ' not in p4_path: - p4_string += ' -a %s' % p4_path - else: - p4_string += ' -a "' + (' //' + client_name + '/').join(p4_path) + '"' - - return p4_string - - -def GetP4Command(client_name, p4_port, p4_paths, checkoutdir, p4_snapshot=''): - command = '' - - if p4_snapshot: - command += 'mkdir -p ' + checkoutdir + p4_string = "" for p4_path in p4_paths: - real_path = p4_path[1] - if real_path.endswith('...'): - real_path = real_path.replace('/...', '') - command += ( - '; mkdir -p ' + checkoutdir + '/' + os.path.dirname(real_path)) - command += ('&& rsync -lr ' + p4_snapshot + '/' + real_path + ' ' + - checkoutdir + '/' + os.path.dirname(real_path)) + if " " not in p4_path: + p4_string += " -a %s" % p4_path + else: + p4_string += ( + ' -a "' + (" //" + client_name + "/").join(p4_path) + '"' + ) + + return p4_string + + +def GetP4Command(client_name, p4_port, p4_paths, checkoutdir, p4_snapshot=""): + command = "" + + if p4_snapshot: + command += "mkdir -p " + checkoutdir + for p4_path in p4_paths: + real_path = p4_path[1] + if real_path.endswith("..."): + real_path = real_path.replace("/...", "") + command += ( + "; mkdir -p " + + checkoutdir + + "/" + + os.path.dirname(real_path) + ) + command += ( + "&& rsync -lr " + + p4_snapshot + + "/" + + real_path + + " " + + checkoutdir + + "/" + + os.path.dirname(real_path) + ) + return command + + command += " export P4CONFIG=.p4config" + command += " && mkdir -p " + checkoutdir + command += " && cd " + checkoutdir + command += " && cp ${HOME}/.p4config ." + command += " && chmod u+w .p4config" + command += ' && echo "P4PORT=' + p4_port + '" >> .p4config' + command += ' && echo "P4CLIENT=' + client_name + '" >> .p4config' + command += " && g4 client " + _GetP4ClientSpec(client_name, p4_paths) + command += " && g4 sync " + command += " && cd -" return command - command += ' export P4CONFIG=.p4config' - command += ' && mkdir -p ' + checkoutdir - command += ' && cd ' + checkoutdir - command += ' && cp ${HOME}/.p4config .' - command += ' && chmod u+w .p4config' - command += ' && echo "P4PORT=' + p4_port + '" >> .p4config' - command += ' && echo "P4CLIENT=' + client_name + '" >> .p4config' - command += (' && g4 client ' + _GetP4ClientSpec(client_name, p4_paths)) - command += ' && g4 sync ' - command += ' && cd -' - return command - class BinarySearchPoint(object): - """Class of binary search point.""" + """Class of binary search point.""" - def __init__(self, revision, status, tag=None): - self.revision = revision - self.status = status - self.tag = tag + def __init__(self, revision, status, tag=None): + self.revision = revision + self.status = status + self.tag = tag class BinarySearcherForPass(object): - """Class of pass level binary searcher.""" - - def __init__(self, logger_to_set=None): - self.current = 0 - self.lo = 0 - self.hi = 0 - self.total = 0 - if logger_to_set is not None: - self.logger = logger_to_set - else: - self.logger = logger.GetLogger() - - def GetNext(self): - # For the first run, update self.hi with total pass/transformation count - if self.hi == 0: - self.hi = self.total - self.current = (self.hi + self.lo) // 2 - message = ('Bisecting between: (%d, %d)' % (self.lo, self.hi)) - self.logger.LogOutput(message, print_to_console=verbose) - message = ('Current limit number: %d' % self.current) - self.logger.LogOutput(message, print_to_console=verbose) - return self.current - - def SetStatus(self, status): - """Set lo/hi status based on test script result - - If status == 0, it means that runtime error is not introduced until current - pass/transformation, so we need to increase lower bound for binary search. - - If status == 1, it means that runtime error still happens with current pass/ - transformation, so we need to decrease upper bound for binary search. - - Returns: - True if we find the bad pass/transformation, or cannot find bad one after - decreasing to the first pass/transformation. Otherwise False. - """ - assert status in (0, 1, 125), status - - if self.current == 0: - message = ('Runtime error occurs before first pass/transformation. ' - 'Stop binary searching.') - self.logger.LogOutput(message, print_to_console=verbose) - return True - - if status == 0: - message = ('Runtime error is not reproduced, increasing lower bound.') - self.logger.LogOutput(message, print_to_console=verbose) - self.lo = self.current + 1 - elif status == 1: - message = ('Runtime error is reproduced, decreasing upper bound..') - self.logger.LogOutput(message, print_to_console=verbose) - self.hi = self.current - - if self.lo >= self.hi: - return True - - return False + """Class of pass level binary searcher.""" + + def __init__(self, logger_to_set=None): + self.current = 0 + self.lo = 0 + self.hi = 0 + self.total = 0 + if logger_to_set is not None: + self.logger = logger_to_set + else: + self.logger = logger.GetLogger() + + def GetNext(self): + # For the first run, update self.hi with total pass/transformation count + if self.hi == 0: + self.hi = self.total + self.current = (self.hi + self.lo) // 2 + message = "Bisecting between: (%d, %d)" % (self.lo, self.hi) + self.logger.LogOutput(message, print_to_console=verbose) + message = "Current limit number: %d" % self.current + self.logger.LogOutput(message, print_to_console=verbose) + return self.current + + def SetStatus(self, status): + """Set lo/hi status based on test script result + + If status == 0, it means that runtime error is not introduced until current + pass/transformation, so we need to increase lower bound for binary search. + + If status == 1, it means that runtime error still happens with current pass/ + transformation, so we need to decrease upper bound for binary search. + + Returns: + True if we find the bad pass/transformation, or cannot find bad one after + decreasing to the first pass/transformation. Otherwise False. + """ + assert status in (0, 1, 125), status + + if self.current == 0: + message = ( + "Runtime error occurs before first pass/transformation. " + "Stop binary searching." + ) + self.logger.LogOutput(message, print_to_console=verbose) + return True + + if status == 0: + message = "Runtime error is not reproduced, increasing lower bound." + self.logger.LogOutput(message, print_to_console=verbose) + self.lo = self.current + 1 + elif status == 1: + message = "Runtime error is reproduced, decreasing upper bound.." + self.logger.LogOutput(message, print_to_console=verbose) + self.hi = self.current + + if self.lo >= self.hi: + return True + + return False class BinarySearcher(object): - """Class of binary searcher.""" - - def __init__(self, logger_to_set=None): - self.sorted_list = [] - self.index_log = [] - self.status_log = [] - self.skipped_indices = [] - self.current = 0 - self.points = {} - self.lo = 0 - self.hi = 0 - if logger_to_set is not None: - self.logger = logger_to_set - else: - self.logger = logger.GetLogger() - - def SetSortedList(self, sorted_list): - assert sorted_list - self.sorted_list = sorted_list - self.index_log = [] - self.hi = len(sorted_list) - 1 - self.lo = 0 - self.points = {} - for i in range(len(self.sorted_list)): - bsp = BinarySearchPoint(self.sorted_list[i], -1, 'Not yet done.') - self.points[i] = bsp - - def SetStatus(self, status, tag=None): - message = ('Revision: %s index: %d returned: %d' % - (self.sorted_list[self.current], self.current, status)) - self.logger.LogOutput(message, print_to_console=verbose) - assert status in (0, 1, 125), status - self.index_log.append(self.current) - self.status_log.append(status) - bsp = BinarySearchPoint(self.sorted_list[self.current], status, tag) - self.points[self.current] = bsp - - if status == 125: - self.skipped_indices.append(self.current) - - if status in (0, 1): - if status == 0: - self.lo = self.current + 1 - elif status == 1: - self.hi = self.current - self.logger.LogOutput('lo: %d hi: %d\n' % (self.lo, self.hi)) - self.current = (self.lo + self.hi) // 2 - - if self.lo == self.hi: - message = ('Search complete. First bad version: %s' - ' at index: %d' % (self.sorted_list[self.current], self.lo)) - self.logger.LogOutput(message) - return True - - for index in range(self.lo, self.hi): - if index not in self.skipped_indices: - return False - self.logger.LogOutput( - 'All skipped indices between: %d and %d\n' % (self.lo, self.hi), - print_to_console=verbose) - return True - - # Does a better job with chromeos flakiness. - def GetNextFlakyBinary(self): - t = (self.lo, self.current, self.hi) - q = [t] - while q: - element = q.pop(0) - if element[1] in self.skipped_indices: - # Go top - to_add = (element[0], (element[0] + element[1]) // 2, element[1]) - q.append(to_add) - # Go bottom - to_add = (element[1], (element[1] + element[2]) // 2, element[2]) - q.append(to_add) - else: - self.current = element[1] - return - assert q, 'Queue should never be 0-size!' - - def GetNextFlakyLinear(self): - current_hi = self.current - current_lo = self.current - while True: - if current_hi < self.hi and current_hi not in self.skipped_indices: - self.current = current_hi - break - if current_lo >= self.lo and current_lo not in self.skipped_indices: - self.current = current_lo - break - if current_lo < self.lo and current_hi >= self.hi: - break - - current_hi += 1 - current_lo -= 1 - - def GetNext(self): - self.current = (self.hi + self.lo) // 2 - # Try going forward if current is skipped. - if self.current in self.skipped_indices: - self.GetNextFlakyBinary() - - # TODO: Add an estimated time remaining as well. - message = ('Estimated tries: min: %d max: %d\n' % (1 + math.log( - self.hi - self.lo, 2), self.hi - self.lo - len(self.skipped_indices))) - self.logger.LogOutput(message, print_to_console=verbose) - message = ('lo: %d hi: %d current: %d version: %s\n' % - (self.lo, self.hi, self.current, self.sorted_list[self.current])) - self.logger.LogOutput(message, print_to_console=verbose) - self.logger.LogOutput(str(self), print_to_console=verbose) - return self.sorted_list[self.current] - - def SetLoRevision(self, lo_revision): - self.lo = self.sorted_list.index(lo_revision) - - def SetHiRevision(self, hi_revision): - self.hi = self.sorted_list.index(hi_revision) - - def GetAllPoints(self): - to_return = '' - for i in range(len(self.sorted_list)): - to_return += ( - '%d %d %s\n' % (self.points[i].status, i, self.points[i].revision)) - - return to_return - - def __str__(self): - to_return = '' - to_return += 'Current: %d\n' % self.current - to_return += str(self.index_log) + '\n' - revision_log = [] - for index in self.index_log: - revision_log.append(self.sorted_list[index]) - to_return += str(revision_log) + '\n' - to_return += str(self.status_log) + '\n' - to_return += 'Skipped indices:\n' - to_return += str(self.skipped_indices) + '\n' - to_return += self.GetAllPoints() - return to_return + """Class of binary searcher.""" + + def __init__(self, logger_to_set=None): + self.sorted_list = [] + self.index_log = [] + self.status_log = [] + self.skipped_indices = [] + self.current = 0 + self.points = {} + self.lo = 0 + self.hi = 0 + if logger_to_set is not None: + self.logger = logger_to_set + else: + self.logger = logger.GetLogger() + + def SetSortedList(self, sorted_list): + assert sorted_list + self.sorted_list = sorted_list + self.index_log = [] + self.hi = len(sorted_list) - 1 + self.lo = 0 + self.points = {} + for i in range(len(self.sorted_list)): + bsp = BinarySearchPoint(self.sorted_list[i], -1, "Not yet done.") + self.points[i] = bsp + + def SetStatus(self, status, tag=None): + message = "Revision: %s index: %d returned: %d" % ( + self.sorted_list[self.current], + self.current, + status, + ) + self.logger.LogOutput(message, print_to_console=verbose) + assert status in (0, 1, 125), status + self.index_log.append(self.current) + self.status_log.append(status) + bsp = BinarySearchPoint(self.sorted_list[self.current], status, tag) + self.points[self.current] = bsp + + if status == 125: + self.skipped_indices.append(self.current) + + if status in (0, 1): + if status == 0: + self.lo = self.current + 1 + elif status == 1: + self.hi = self.current + self.logger.LogOutput("lo: %d hi: %d\n" % (self.lo, self.hi)) + self.current = (self.lo + self.hi) // 2 + + if self.lo == self.hi: + message = ( + "Search complete. First bad version: %s" + " at index: %d" + % ( + self.sorted_list[self.current], + self.lo, + ) + ) + self.logger.LogOutput(message) + return True + + for index in range(self.lo, self.hi): + if index not in self.skipped_indices: + return False + self.logger.LogOutput( + "All skipped indices between: %d and %d\n" % (self.lo, self.hi), + print_to_console=verbose, + ) + return True + + # Does a better job with chromeos flakiness. + def GetNextFlakyBinary(self): + t = (self.lo, self.current, self.hi) + q = [t] + while q: + element = q.pop(0) + if element[1] in self.skipped_indices: + # Go top + to_add = ( + element[0], + (element[0] + element[1]) // 2, + element[1], + ) + q.append(to_add) + # Go bottom + to_add = ( + element[1], + (element[1] + element[2]) // 2, + element[2], + ) + q.append(to_add) + else: + self.current = element[1] + return + assert q, "Queue should never be 0-size!" + + def GetNextFlakyLinear(self): + current_hi = self.current + current_lo = self.current + while True: + if current_hi < self.hi and current_hi not in self.skipped_indices: + self.current = current_hi + break + if current_lo >= self.lo and current_lo not in self.skipped_indices: + self.current = current_lo + break + if current_lo < self.lo and current_hi >= self.hi: + break + + current_hi += 1 + current_lo -= 1 + + def GetNext(self): + self.current = (self.hi + self.lo) // 2 + # Try going forward if current is skipped. + if self.current in self.skipped_indices: + self.GetNextFlakyBinary() + + # TODO: Add an estimated time remaining as well. + message = "Estimated tries: min: %d max: %d\n" % ( + 1 + math.log(self.hi - self.lo, 2), + self.hi - self.lo - len(self.skipped_indices), + ) + self.logger.LogOutput(message, print_to_console=verbose) + message = "lo: %d hi: %d current: %d version: %s\n" % ( + self.lo, + self.hi, + self.current, + self.sorted_list[self.current], + ) + self.logger.LogOutput(message, print_to_console=verbose) + self.logger.LogOutput(str(self), print_to_console=verbose) + return self.sorted_list[self.current] + + def SetLoRevision(self, lo_revision): + self.lo = self.sorted_list.index(lo_revision) + + def SetHiRevision(self, hi_revision): + self.hi = self.sorted_list.index(hi_revision) + + def GetAllPoints(self): + to_return = "" + for i in range(len(self.sorted_list)): + to_return += "%d %d %s\n" % ( + self.points[i].status, + i, + self.points[i].revision, + ) + + return to_return + + def __str__(self): + to_return = "" + to_return += "Current: %d\n" % self.current + to_return += str(self.index_log) + "\n" + revision_log = [] + for index in self.index_log: + revision_log.append(self.sorted_list[index]) + to_return += str(revision_log) + "\n" + to_return += str(self.status_log) + "\n" + to_return += "Skipped indices:\n" + to_return += str(self.skipped_indices) + "\n" + to_return += self.GetAllPoints() + return to_return class RevisionInfo(object): - """Class of reversion info.""" + """Class of reversion info.""" - def __init__(self, date, client, description): - self.date = date - self.client = client - self.description = description - self.status = -1 + def __init__(self, date, client, description): + self.date = date + self.client = client + self.description = description + self.status = -1 class VCSBinarySearcher(object): - """Class of VCS binary searcher.""" + """Class of VCS binary searcher.""" - def __init__(self): - self.bs = BinarySearcher() - self.rim = {} - self.current_ce = None - self.checkout_dir = None - self.current_revision = None + def __init__(self): + self.bs = BinarySearcher() + self.rim = {} + self.current_ce = None + self.checkout_dir = None + self.current_revision = None - def Initialize(self): - pass + def Initialize(self): + pass - def GetNextRevision(self): - pass + def GetNextRevision(self): + pass - def CheckoutRevision(self, current_revision): - pass + def CheckoutRevision(self, current_revision): + pass - def SetStatus(self, status): - pass + def SetStatus(self, status): + pass - def Cleanup(self): - pass + def Cleanup(self): + pass - def SetGoodRevision(self, revision): - if revision is None: - return - assert revision in self.bs.sorted_list - self.bs.SetLoRevision(revision) + def SetGoodRevision(self, revision): + if revision is None: + return + assert revision in self.bs.sorted_list + self.bs.SetLoRevision(revision) - def SetBadRevision(self, revision): - if revision is None: - return - assert revision in self.bs.sorted_list - self.bs.SetHiRevision(revision) + def SetBadRevision(self, revision): + if revision is None: + return + assert revision in self.bs.sorted_list + self.bs.SetHiRevision(revision) class P4BinarySearcher(VCSBinarySearcher): - """Class of P4 binary searcher.""" - - def __init__(self, p4_port, p4_paths, test_command): - VCSBinarySearcher.__init__(self) - self.p4_port = p4_port - self.p4_paths = p4_paths - self.test_command = test_command - self.checkout_dir = tempfile.mkdtemp() - self.ce = command_executer.GetCommandExecuter() - self.client_name = 'binary-searcher-$HOSTNAME-$USER' - self.job_log_root = '/home/asharif/www/coreboot_triage/' - self.changes = None - - def Initialize(self): - self.Cleanup() - command = GetP4Command(self.client_name, self.p4_port, self.p4_paths, 1, - self.checkout_dir) - self.ce.RunCommand(command) - command = 'cd %s && g4 changes ...' % self.checkout_dir - _, out, _ = self.ce.RunCommandWOutput(command) - self.changes = re.findall(r'Change (\d+)', out) - change_infos = re.findall( - r'Change (\d+) on ([\d/]+) by ' - r"([^\s]+) ('[^']*')", out) - for change_info in change_infos: - ri = RevisionInfo(change_info[1], change_info[2], change_info[3]) - self.rim[change_info[0]] = ri - # g4 gives changes in reverse chronological order. - self.changes.reverse() - self.bs.SetSortedList(self.changes) - - def SetStatus(self, status): - self.rim[self.current_revision].status = status - return self.bs.SetStatus(status) - - def GetNextRevision(self): - next_revision = self.bs.GetNext() - self.current_revision = next_revision - return next_revision - - def CleanupCLs(self): - if not os.path.isfile(self.checkout_dir + '/.p4config'): - command = 'cd %s' % self.checkout_dir - command += ' && cp ${HOME}/.p4config .' - command += ' && echo "P4PORT=' + self.p4_port + '" >> .p4config' - command += ' && echo "P4CLIENT=' + self.client_name + '" >> .p4config' - self.ce.RunCommand(command) - command = 'cd %s' % self.checkout_dir - command += '; g4 changes -c %s' % self.client_name - _, out, _ = self.ce.RunCommandWOutput(command) - changes = re.findall(r'Change (\d+)', out) - if changes: - command = 'cd %s' % self.checkout_dir - for change in changes: - command += '; g4 revert -c %s' % change - self.ce.RunCommand(command) - - def CleanupClient(self): - command = 'cd %s' % self.checkout_dir - command += '; g4 revert ...' - command += '; g4 client -d %s' % self.client_name - self.ce.RunCommand(command) - - def Cleanup(self): - self.CleanupCLs() - self.CleanupClient() - - def __str__(self): - to_return = '' - for change in self.changes: - ri = self.rim[change] - if ri.status == -1: - to_return = '%s\t%d\n' % (change, ri.status) - else: - to_return += ('%s\t%d\t%s\t%s\t%s\t%s\t%s\t%s\n' % - (change, ri.status, ri.date, ri.client, ri.description, - self.job_log_root + change + '.cmd', self.job_log_root + - change + '.out', self.job_log_root + change + '.err')) - return to_return + """Class of P4 binary searcher.""" + + def __init__(self, p4_port, p4_paths, test_command): + VCSBinarySearcher.__init__(self) + self.p4_port = p4_port + self.p4_paths = p4_paths + self.test_command = test_command + self.checkout_dir = tempfile.mkdtemp() + self.ce = command_executer.GetCommandExecuter() + self.client_name = "binary-searcher-$HOSTNAME-$USER" + self.job_log_root = "/home/asharif/www/coreboot_triage/" + self.changes = None + + def Initialize(self): + self.Cleanup() + command = GetP4Command( + self.client_name, self.p4_port, self.p4_paths, 1, self.checkout_dir + ) + self.ce.RunCommand(command) + command = "cd %s && g4 changes ..." % self.checkout_dir + _, out, _ = self.ce.RunCommandWOutput(command) + self.changes = re.findall(r"Change (\d+)", out) + change_infos = re.findall( + r"Change (\d+) on ([\d/]+) by " r"([^\s]+) ('[^']*')", out + ) + for change_info in change_infos: + ri = RevisionInfo(change_info[1], change_info[2], change_info[3]) + self.rim[change_info[0]] = ri + # g4 gives changes in reverse chronological order. + self.changes.reverse() + self.bs.SetSortedList(self.changes) + + def SetStatus(self, status): + self.rim[self.current_revision].status = status + return self.bs.SetStatus(status) + + def GetNextRevision(self): + next_revision = self.bs.GetNext() + self.current_revision = next_revision + return next_revision + + def CleanupCLs(self): + if not os.path.isfile(self.checkout_dir + "/.p4config"): + command = "cd %s" % self.checkout_dir + command += " && cp ${HOME}/.p4config ." + command += ' && echo "P4PORT=' + self.p4_port + '" >> .p4config' + command += ( + ' && echo "P4CLIENT=' + self.client_name + '" >> .p4config' + ) + self.ce.RunCommand(command) + command = "cd %s" % self.checkout_dir + command += "; g4 changes -c %s" % self.client_name + _, out, _ = self.ce.RunCommandWOutput(command) + changes = re.findall(r"Change (\d+)", out) + if changes: + command = "cd %s" % self.checkout_dir + for change in changes: + command += "; g4 revert -c %s" % change + self.ce.RunCommand(command) + + def CleanupClient(self): + command = "cd %s" % self.checkout_dir + command += "; g4 revert ..." + command += "; g4 client -d %s" % self.client_name + self.ce.RunCommand(command) + + def Cleanup(self): + self.CleanupCLs() + self.CleanupClient() + + def __str__(self): + to_return = "" + for change in self.changes: + ri = self.rim[change] + if ri.status == -1: + to_return = "%s\t%d\n" % (change, ri.status) + else: + to_return += "%s\t%d\t%s\t%s\t%s\t%s\t%s\t%s\n" % ( + change, + ri.status, + ri.date, + ri.client, + ri.description, + self.job_log_root + change + ".cmd", + self.job_log_root + change + ".out", + self.job_log_root + change + ".err", + ) + return to_return class P4GCCBinarySearcher(P4BinarySearcher): - """Class of P4 gcc binary searcher.""" - - # TODO: eventually get these patches from g4 instead of creating them manually - def HandleBrokenCLs(self, current_revision): - cr = int(current_revision) - problematic_ranges = [] - problematic_ranges.append([44528, 44539]) - problematic_ranges.append([44528, 44760]) - problematic_ranges.append([44335, 44882]) - command = 'pwd' - for pr in problematic_ranges: - if cr in range(pr[0], pr[1]): - patch_file = '/home/asharif/triage_tool/%d-%d.patch' % (pr[0], pr[1]) - with open(patch_file, encoding='utf-8') as f: - patch = f.read() - files = re.findall('--- (//.*)', patch) - command += '; cd %s' % self.checkout_dir - for f in files: - command += '; g4 open %s' % f - command += '; patch -p2 < %s' % patch_file - self.current_ce.RunCommand(command) - - def CheckoutRevision(self, current_revision): - job_logger = logger.Logger( - self.job_log_root, current_revision, True, subdir='') - self.current_ce = command_executer.GetCommandExecuter(job_logger) - - self.CleanupCLs() - # Change the revision of only the gcc part of the toolchain. - command = ( - 'cd %s/gcctools/google_vendor_src_branch/gcc ' - '&& g4 revert ...; g4 sync @%s' % (self.checkout_dir, current_revision)) - self.current_ce.RunCommand(command) - - self.HandleBrokenCLs(current_revision) + """Class of P4 gcc binary searcher.""" + + # TODO: eventually get these patches from g4 instead of creating them manually + def HandleBrokenCLs(self, current_revision): + cr = int(current_revision) + problematic_ranges = [] + problematic_ranges.append([44528, 44539]) + problematic_ranges.append([44528, 44760]) + problematic_ranges.append([44335, 44882]) + command = "pwd" + for pr in problematic_ranges: + if cr in range(pr[0], pr[1]): + patch_file = "/home/asharif/triage_tool/%d-%d.patch" % ( + pr[0], + pr[1], + ) + with open(patch_file, encoding="utf-8") as f: + patch = f.read() + files = re.findall("--- (//.*)", patch) + command += "; cd %s" % self.checkout_dir + for f in files: + command += "; g4 open %s" % f + command += "; patch -p2 < %s" % patch_file + self.current_ce.RunCommand(command) + + def CheckoutRevision(self, current_revision): + job_logger = logger.Logger( + self.job_log_root, current_revision, True, subdir="" + ) + self.current_ce = command_executer.GetCommandExecuter(job_logger) + + self.CleanupCLs() + # Change the revision of only the gcc part of the toolchain. + command = ( + "cd %s/gcctools/google_vendor_src_branch/gcc " + "&& g4 revert ...; g4 sync @%s" + % (self.checkout_dir, current_revision) + ) + self.current_ce.RunCommand(command) + + self.HandleBrokenCLs(current_revision) def Main(argv): - """The main function.""" - # Common initializations - ### command_executer.InitCommandExecuter(True) - ce = command_executer.GetCommandExecuter() - - parser = argparse.ArgumentParser() - parser.add_argument( - '-n', - '--num_tries', - dest='num_tries', - default='100', - help='Number of tries.') - parser.add_argument( - '-g', - '--good_revision', - dest='good_revision', - help='Last known good revision.') - parser.add_argument( - '-b', - '--bad_revision', - dest='bad_revision', - help='Last known bad revision.') - parser.add_argument( - '-s', '--script', dest='script', help='Script to run for every version.') - options = parser.parse_args(argv) - # First get all revisions - p4_paths = [ - '//depot2/gcctools/google_vendor_src_branch/gcc/gcc-4.4.3/...', - '//depot2/gcctools/google_vendor_src_branch/binutils/' - 'binutils-2.20.1-mobile/...', - '//depot2/gcctools/google_vendor_src_branch/' - 'binutils/binutils-20100303/...' - ] - p4gccbs = P4GCCBinarySearcher('perforce2:2666', p4_paths, '') - - # Main loop: - terminated = False - num_tries = int(options.num_tries) - script = os.path.expanduser(options.script) - - try: - p4gccbs.Initialize() - p4gccbs.SetGoodRevision(options.good_revision) - p4gccbs.SetBadRevision(options.bad_revision) - while not terminated and num_tries > 0: - current_revision = p4gccbs.GetNextRevision() - - # Now run command to get the status - ce = command_executer.GetCommandExecuter() - command = '%s %s' % (script, p4gccbs.checkout_dir) - status = ce.RunCommand(command) - message = ( - 'Revision: %s produced: %d status\n' % (current_revision, status)) - logger.GetLogger().LogOutput(message, print_to_console=verbose) - terminated = p4gccbs.SetStatus(status) - num_tries -= 1 - logger.GetLogger().LogOutput(str(p4gccbs), print_to_console=verbose) - - if not terminated: - logger.GetLogger().LogOutput( - 'Tries: %d expired.' % num_tries, print_to_console=verbose) - logger.GetLogger().LogOutput(str(p4gccbs.bs), print_to_console=verbose) - except (KeyboardInterrupt, SystemExit): - logger.GetLogger().LogOutput('Cleaning up...') - finally: - logger.GetLogger().LogOutput(str(p4gccbs.bs), print_to_console=verbose) - p4gccbs.Cleanup() - - -if __name__ == '__main__': - Main(sys.argv[1:]) + """The main function.""" + # Common initializations + ### command_executer.InitCommandExecuter(True) + ce = command_executer.GetCommandExecuter() + + parser = argparse.ArgumentParser() + parser.add_argument( + "-n", + "--num_tries", + dest="num_tries", + default="100", + help="Number of tries.", + ) + parser.add_argument( + "-g", + "--good_revision", + dest="good_revision", + help="Last known good revision.", + ) + parser.add_argument( + "-b", + "--bad_revision", + dest="bad_revision", + help="Last known bad revision.", + ) + parser.add_argument( + "-s", "--script", dest="script", help="Script to run for every version." + ) + options = parser.parse_args(argv) + # First get all revisions + p4_paths = [ + "//depot2/gcctools/google_vendor_src_branch/gcc/gcc-4.4.3/...", + "//depot2/gcctools/google_vendor_src_branch/binutils/" + "binutils-2.20.1-mobile/...", + "//depot2/gcctools/google_vendor_src_branch/" + "binutils/binutils-20100303/...", + ] + p4gccbs = P4GCCBinarySearcher("perforce2:2666", p4_paths, "") + + # Main loop: + terminated = False + num_tries = int(options.num_tries) + script = os.path.expanduser(options.script) + + try: + p4gccbs.Initialize() + p4gccbs.SetGoodRevision(options.good_revision) + p4gccbs.SetBadRevision(options.bad_revision) + while not terminated and num_tries > 0: + current_revision = p4gccbs.GetNextRevision() + + # Now run command to get the status + ce = command_executer.GetCommandExecuter() + command = "%s %s" % (script, p4gccbs.checkout_dir) + status = ce.RunCommand(command) + message = "Revision: %s produced: %d status\n" % ( + current_revision, + status, + ) + logger.GetLogger().LogOutput(message, print_to_console=verbose) + terminated = p4gccbs.SetStatus(status) + num_tries -= 1 + logger.GetLogger().LogOutput(str(p4gccbs), print_to_console=verbose) + + if not terminated: + logger.GetLogger().LogOutput( + "Tries: %d expired." % num_tries, print_to_console=verbose + ) + logger.GetLogger().LogOutput(str(p4gccbs.bs), print_to_console=verbose) + except (KeyboardInterrupt, SystemExit): + logger.GetLogger().LogOutput("Cleaning up...") + finally: + logger.GetLogger().LogOutput(str(p4gccbs.bs), print_to_console=verbose) + p4gccbs.Cleanup() + + +if __name__ == "__main__": + Main(sys.argv[1:]) |