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

Unified Diff: tools/bisect-builds.py

Issue 10459050: Add option (u)nknown to bisect-builds.py. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years, 7 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 | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/bisect-builds.py
===================================================================
--- tools/bisect-builds.py (revision 139824)
+++ tools/bisect-builds.py (working copy)
@@ -341,13 +341,52 @@
"""Ask the user whether build |rev| is good or bad."""
# Loop until we get a response that we can parse.
while True:
- response = raw_input('Revision %s is [(g)ood/(b)ad/(q)uit]: ' % str(rev))
- if response and response in ('g', 'b'):
- return response == 'g'
+ response = raw_input('Revision %s is [(g)ood/(b)ad/(u)nknown/(q)uit]: ' %
+ str(rev))
+ if response and response in ('g', 'b', 'u'):
+ return response
if response and response == 'q':
raise SystemExit()
+class DownloadJob(object):
+ """DownloadJob represents a task to download a given Chromium revision."""
+ def __init__(self, context, name, rev, zipfile):
+ super(DownloadJob, self).__init__()
+ # Store off the input parameters.
+ self.context = context
+ self.name = name
+ self.rev = rev
+ self.zipfile = zipfile
+ self.quit_event = threading.Event()
+ self.progress_event = threading.Event()
+
+ def Start(self):
+ """Starts the download."""
+ fetchargs = (self.context,
+ self.rev,
+ self.zipfile,
+ self.quit_event,
+ self.progress_event)
+ self.thread = threading.Thread(target=FetchRevision,
+ name=self.name,
+ args=fetchargs)
+ self.thread.start()
+
+ def Stop(self):
+ """Stops the download which must have been started previously."""
+ self.quit_event.set()
+ self.thread.join()
+ os.unlink(self.zipfile)
+
+ def WaitFor(self):
+ """Prints a message and waits for the download to complete. The download
+ must have been started previously."""
+ print "Downloading revision %s..." % str(self.rev)
+ self.progress_event.set() # Display progress of download.
+ self.thread.join()
+
+
def Bisect(platform,
official_builds,
good_rev=0,
@@ -355,7 +394,7 @@
num_runs=1,
try_args=(),
profile=None,
- predicate=AskIsGoodBuild):
+ evaluate=AskIsGoodBuild):
"""Given known good and known bad revisions, run a binary search on all
archived revisions to determine the last known good revision.
@@ -366,8 +405,8 @@
@param num_runs Number of times to run each build for asking good/bad.
@param try_args A tuple of arguments to pass to the test application.
@param profile The name of the user profile to run with.
- @param predicate A predicate function which returns True iff the argument
- chromium revision is good.
+ @param evaluate A function which returns 'g' if the argument build is good,
+ 'b' if it's bad or 'u' if unknown.
Threading is used to fetch Chromium revisions in the background, speeding up
the user's experience. For example, suppose the bounds of the search are
@@ -411,11 +450,9 @@
pivot = bad / 2
rev = revlist[pivot]
zipfile = _GetDownloadPath(rev)
- progress_event = threading.Event()
- progress_event.set()
- print "Downloading revision %s..." % str(rev)
- FetchRevision(context, rev, zipfile,
- quit_event=None, progress_event=progress_event)
+ initial_fetch = DownloadJob(context, 'initial_fetch', rev, zipfile)
+ initial_fetch.Start()
+ initial_fetch.WaitFor()
# Binary search time!
while zipfile and bad - good > 1:
@@ -425,38 +462,20 @@
# - up_pivot is the next revision to check if the current revision turns
# out to be good.
down_pivot = int((pivot - good) / 2) + good
- down_thread = None
+ down_fetch = None
if down_pivot != pivot and down_pivot != good:
down_rev = revlist[down_pivot]
- down_zipfile = _GetDownloadPath(down_rev)
- down_quit_event = threading.Event()
- down_progress_event = threading.Event()
- fetchargs = (context,
- down_rev,
- down_zipfile,
- down_quit_event,
- down_progress_event)
- down_thread = threading.Thread(target=FetchRevision,
- name='down_fetch',
- args=fetchargs)
- down_thread.start()
+ down_fetch = DownloadJob(context, 'down_fetch', down_rev,
+ _GetDownloadPath(down_rev))
+ down_fetch.Start()
up_pivot = int((bad - pivot) / 2) + pivot
- up_thread = None
+ up_fetch = None
if up_pivot != pivot and up_pivot != bad:
up_rev = revlist[up_pivot]
- up_zipfile = _GetDownloadPath(up_rev)
- up_quit_event = threading.Event()
- up_progress_event = threading.Event()
- fetchargs = (context,
- up_rev,
- up_zipfile,
- up_quit_event,
- up_progress_event)
- up_thread = threading.Thread(target=FetchRevision,
- name='up_fetch',
- args=fetchargs)
- up_thread.start()
+ up_fetch = DownloadJob(context, 'up_fetch', up_rev,
+ _GetDownloadPath(up_rev))
+ up_fetch.Start()
# Run test on the pivot revision.
(status, stdout, stderr) = RunRevision(context,
@@ -468,34 +487,58 @@
os.unlink(zipfile)
zipfile = None
- # Call the predicate function to see if the current revision is good or bad.
+ # Call the evaluate function to see if the current revision is good or bad.
# On that basis, kill one of the background downloads and complete the
# other, as described in the comments above.
try:
- if predicate(rev, official_builds, status, stdout, stderr):
+ answer = evaluate(rev, official_builds, status, stdout, stderr)
+ if answer == 'g':
good = pivot
- if down_thread:
- down_quit_event.set() # Kill the download of older revision.
- down_thread.join()
- os.unlink(down_zipfile)
- if up_thread:
- print "Downloading revision %s..." % str(up_rev)
- up_progress_event.set() # Display progress of download.
- up_thread.join() # Wait for newer revision to finish downloading.
+ if down_fetch:
+ down_fetch.Stop() # Kill the download of the older revision.
+ if up_fetch:
+ up_fetch.WaitFor()
pivot = up_pivot
- zipfile = up_zipfile
- else:
+ zipfile = up_fetch.zipfile
+ elif answer == 'b':
bad = pivot
- if up_thread:
- up_quit_event.set() # Kill download of newer revision.
- up_thread.join()
- os.unlink(up_zipfile)
- if down_thread:
- print "Downloading revision %s..." % str(down_rev)
- down_progress_event.set() # Display progress of download.
- down_thread.join() # Wait for older revision to finish downloading.
+ if up_fetch:
+ up_fetch.Stop() # Kill the download of the newer revision.
+ if down_fetch:
+ down_fetch.WaitFor()
pivot = down_pivot
- zipfile = down_zipfile
+ zipfile = down_fetch.zipfile
+ elif answer == 'u':
+ # Nuke the revision from the revlist and choose a new pivot.
+ revlist.pop(pivot)
+ bad -= 1 # Assumes bad >= pivot.
+
+ fetch = None
+ if bad - good > 1:
+ # Alternate between using down_pivot or up_pivot for the new pivot
+ # point, without affecting the range. Do this instead of setting the
+ # pivot to the midpoint of the new range because adjacent revisions
+ # are likely affected by the same issue that caused the (u)nknown
+ # response.
+ if up_fetch and down_fetch:
+ fetch = [up_fetch, down_fetch][len(revlist) % 2]
+ elif up_fetch:
+ fetch = up_fetch
+ else:
+ fetch = down_fetch
+ fetch.WaitFor()
+ if fetch == up_fetch:
+ pivot = up_pivot - 1 # Subtracts 1 because revlist was resized.
+ else:
+ pivot = down_pivot
+ zipfile = fetch.zipfile
+
+ if down_fetch and fetch != down_fetch:
+ down_fetch.Stop()
+ if up_fetch and fetch != up_fetch:
+ up_fetch.Stop()
+ else:
+ assert False, "Unexpected return value from evaluate(): " + answer
except SystemExit:
print "Cleaning up..."
for f in [_GetDownloadPath(revlist[down_pivot]),
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698