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

Side by Side Diff: tools/bisect-perf-regression.py

Issue 295133002: Check build status by parsing tryserver buildbot JSON. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 6 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | tools/post_perf_builder_job.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2013 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2013 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """Performance Test Bisect Tool 6 """Performance Test Bisect Tool
7 7
8 This script bisects a series of changelists using binary search. It starts at 8 This script bisects a series of changelists using binary search. It starts at
9 a bad revision where a performance metric has regressed, and asks for a last 9 a bad revision where a performance metric has regressed, and asks for a last
10 known-good revision. It will then binary search across this revision range by 10 known-good revision. It will then binary search across this revision range by
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
47 import shutil 47 import shutil
48 import StringIO 48 import StringIO
49 import subprocess 49 import subprocess
50 import sys 50 import sys
51 import time 51 import time
52 import zipfile 52 import zipfile
53 53
54 sys.path.append(os.path.join(os.path.dirname(__file__), 'telemetry')) 54 sys.path.append(os.path.join(os.path.dirname(__file__), 'telemetry'))
55 55
56 import bisect_utils 56 import bisect_utils
57 import post_perf_builder_job 57 import post_perf_builder_job as bisect_builder
58 from telemetry.page import cloud_storage 58 from telemetry.page import cloud_storage
59 59
60 # The additional repositories that might need to be bisected. 60 # The additional repositories that might need to be bisected.
61 # If the repository has any dependant repositories (such as skia/src needs 61 # If the repository has any dependant repositories (such as skia/src needs
62 # skia/include and skia/gyp to be updated), specify them in the 'depends' 62 # skia/include and skia/gyp to be updated), specify them in the 'depends'
63 # so that they're synced appropriately. 63 # so that they're synced appropriately.
64 # Format is: 64 # Format is:
65 # src: path to the working directory. 65 # src: path to the working directory.
66 # recurse: True if this repositry will get bisected. 66 # recurse: True if this repositry will get bisected.
67 # depends: A list of other repositories that are actually part of the same 67 # depends: A list of other repositories that are actually part of the same
(...skipping 1509 matching lines...) Expand 10 before | Expand all | Expand 10 after
1577 downloaded_file = os.path.join( 1577 downloaded_file = os.path.join(
1578 abs_build_dir, 1578 abs_build_dir,
1579 GetZipFileName(revision, self.opts.target_arch, patch_sha)) 1579 GetZipFileName(revision, self.opts.target_arch, patch_sha))
1580 1580
1581 fetch_build_func = lambda: FetchFromCloudStorage(self.opts.gs_bucket, 1581 fetch_build_func = lambda: FetchFromCloudStorage(self.opts.gs_bucket,
1582 source_file, 1582 source_file,
1583 abs_build_dir) 1583 abs_build_dir)
1584 1584
1585 if not fetch_build_func(): 1585 if not fetch_build_func():
1586 if not self.PostBuildRequestAndWait(revision, 1586 if not self.PostBuildRequestAndWait(revision,
1587 condition=fetch_build_func, 1587 fetch_build=fetch_build_func,
1588 patch=patch): 1588 patch=patch):
1589 raise RuntimeError('Somewthing went wrong while processing build' 1589 raise RuntimeError('Somewthing went wrong while processing build'
1590 'request for: %s' % revision) 1590 'request for: %s' % revision)
1591 # Generic name for the archive, created when archive file is extracted. 1591 # Generic name for the archive, created when archive file is extracted.
1592 output_dir = os.path.join( 1592 output_dir = os.path.join(
1593 abs_build_dir, GetZipFileName(target_arch=self.opts.target_arch)) 1593 abs_build_dir, GetZipFileName(target_arch=self.opts.target_arch))
1594 # Unzip build archive directory. 1594 # Unzip build archive directory.
1595 try: 1595 try:
1596 RmTreeAndMkDir(output_dir, skip_makedir=True) 1596 RmTreeAndMkDir(output_dir, skip_makedir=True)
1597 ExtractZip(downloaded_file, abs_build_dir) 1597 ExtractZip(downloaded_file, abs_build_dir)
(...skipping 11 matching lines...) Expand all
1609 self.BackupOrRestoreOutputdirectory(restore=True) 1609 self.BackupOrRestoreOutputdirectory(restore=True)
1610 # Cleanup any leftovers from unzipping. 1610 # Cleanup any leftovers from unzipping.
1611 if os.path.exists(output_dir): 1611 if os.path.exists(output_dir):
1612 RmTreeAndMkDir(output_dir, skip_makedir=True) 1612 RmTreeAndMkDir(output_dir, skip_makedir=True)
1613 finally: 1613 finally:
1614 # Delete downloaded archive 1614 # Delete downloaded archive
1615 if os.path.exists(downloaded_file): 1615 if os.path.exists(downloaded_file):
1616 os.remove(downloaded_file) 1616 os.remove(downloaded_file)
1617 return False 1617 return False
1618 1618
1619 def PostBuildRequestAndWait(self, revision, condition, patch=None): 1619 def WaitUntilBuildIsReady(self, fetch_build, bot_name, builder_host,
1620 builder_port, build_request_id, max_timeout):
1621 """Waits until build is produced by bisect builder on tryserver.
1622
1623 Args:
1624 fetch_build: Function to check and download build from cloud storage.
1625 bot_name: Builder bot name on tryserver.
1626 builder_host Tryserver hostname.
1627 builder_port: Tryserver port.
1628 build_request_id: A unique ID of the build request posted to tryserver.
1629 max_timeout: Maximum time to wait for the build.
1630
1631 Returns:
1632 True if build exists and download is successful, otherwise throws
1633 RuntimeError exception when time elapse.
1634 """
1635 # Build number on the tryserver.
1636 build_num = None
1637 # Interval to check build on cloud storage.
1638 poll_interval = 60
1639 # Interval to check build status on tryserver.
1640 status_check_interval = 600
1641 last_status_check = time.time()
1642 start_time = time.time()
1643 while True:
1644 # Checks for build on gs://chrome-perf and download if exists.
1645 res = fetch_build()
1646 if res:
1647 return (res, 'Build successfully found')
1648 elapsed_status_check = time.time() - last_status_check
1649 # To avoid overloading tryserver with status check requests, we check
1650 # build status for every 10 mins.
1651 if elapsed_status_check > status_check_interval:
1652 last_status_check = time.time()
1653 if not build_num:
1654 # Get the build number on tryserver for the current build.
1655 build_num = bisect_builder.GetBuildNumFromBuilder(
1656 build_request_id, bot_name, builder_host, builder_port)
1657 # Check the status of build using the build number.
1658 # Note: Build is treated as PENDING if build number is not found
1659 # on the the tryserver.
1660 build_status, status_link = bisect_builder.GetBuildStatus(
1661 build_num, bot_name, builder_host, builder_port)
1662 if build_status == bisect_builder.FAILED:
1663 return (False, 'Failed to produce build, log: %s' % status_link)
1664 elapsed_time = time.time() - start_time
1665 if elapsed_time > max_timeout:
1666 return (False, 'Timed out: %ss without build' % max_timeout)
1667
1668 print 'Time elapsed: %ss without build.' % elapsed_time
1669 time.sleep(poll_interval)
1670
1671 def PostBuildRequestAndWait(self, revision, fetch_build, patch=None):
1620 """POSTs the build request job to the tryserver instance.""" 1672 """POSTs the build request job to the tryserver instance."""
1621 1673
1622 def GetBuilderNameAndBuildTime(target_arch='ia32'): 1674 def GetBuilderNameAndBuildTime(target_arch='ia32'):
1623 """Gets builder bot name and buildtime in seconds based on platform.""" 1675 """Gets builder bot name and buildtime in seconds based on platform."""
1624 # Bot names should match the one listed in tryserver.chromium's 1676 # Bot names should match the one listed in tryserver.chromium's
1625 # master.cfg which produces builds for bisect. 1677 # master.cfg which produces builds for bisect.
1626 if IsWindows(): 1678 if IsWindows():
1627 if Is64BitWindows() and target_arch == 'x64': 1679 if Is64BitWindows() and target_arch == 'x64':
1628 return ('win_perf_bisect_builder', MAX_WIN_BUILD_TIME) 1680 return ('win_perf_bisect_builder', MAX_WIN_BUILD_TIME)
1629 return ('win_perf_bisect_builder', MAX_WIN_BUILD_TIME) 1681 return ('win_perf_bisect_builder', MAX_WIN_BUILD_TIME)
1630 if IsLinux(): 1682 if IsLinux():
1631 return ('linux_perf_bisect_builder', MAX_LINUX_BUILD_TIME) 1683 return ('linux_perf_bisect_builder', MAX_LINUX_BUILD_TIME)
1632 if IsMac(): 1684 if IsMac():
1633 return ('mac_perf_bisect_builder', MAX_MAC_BUILD_TIME) 1685 return ('mac_perf_bisect_builder', MAX_MAC_BUILD_TIME)
1634 raise NotImplementedError('Unsupported Platform "%s".' % sys.platform) 1686 raise NotImplementedError('Unsupported Platform "%s".' % sys.platform)
1635 if not condition: 1687 if not fetch_build:
1636 return False 1688 return False
1637 1689
1638 bot_name, build_timeout = GetBuilderNameAndBuildTime(self.opts.target_arch) 1690 bot_name, build_timeout = GetBuilderNameAndBuildTime(self.opts.target_arch)
1639 1691 builder_host = self.opts.builder_host
1640 # Create a unique ID for each build request posted to try server builders. 1692 builder_port = self.opts.builder_port
1693 # Create a unique ID for each build request posted to tryserver builders.
1641 # This ID is added to "Reason" property in build's json. 1694 # This ID is added to "Reason" property in build's json.
1642 # TODO: Use this id to track the build status. 1695 build_request_id = GetSHA1HexDigest(
1643 build_request_id = GetSHA1HexDigest('%s-%s' % (revision, patch)) 1696 '%s-%s-%s' % (revision, patch, time.time()))
1644 1697
1645 # Creates a try job description. 1698 # Creates a try job description.
1646 job_args = {'host': self.opts.builder_host, 1699 job_args = {'host': builder_host,
1647 'port': self.opts.builder_port, 1700 'port': builder_port,
1648 'revision': 'src@%s' % revision, 1701 'revision': 'src@%s' % revision,
1649 'bot': bot_name, 1702 'bot': bot_name,
1650 'name': build_request_id 1703 'name': build_request_id
1651 } 1704 }
1652 # Update patch information if supplied. 1705 # Update patch information if supplied.
1653 if patch: 1706 if patch:
1654 job_args['patch'] = patch 1707 job_args['patch'] = patch
1655 # Posts job to build the revision on the server. 1708 # Posts job to build the revision on the server.
1656 if post_perf_builder_job.PostTryJob(job_args): 1709 if bisect_builder.PostTryJob(job_args):
1657 poll_interval = 60 1710 status, error_msg = self.WaitUntilBuildIsReady(fetch_build,
1658 start_time = time.time() 1711 bot_name,
1659 while True: 1712 builder_host,
1660 res = condition() 1713 builder_port,
1661 if res: 1714 build_request_id,
1662 return res 1715 build_timeout)
1663 elapsed_time = time.time() - start_time 1716 if not status:
1664 if elapsed_time > build_timeout: 1717 raise RuntimeError('%s [revision: %s]' % (error_msg, revision))
1665 raise RuntimeError('Timed out while waiting %ds for %s build.' % 1718 return True
1666 (build_timeout, revision))
1667 print ('Time elapsed: %ss, still waiting for %s build' %
1668 (elapsed_time, revision))
1669 time.sleep(poll_interval)
1670 return False 1719 return False
1671 1720
1672 def IsDownloadable(self, depot): 1721 def IsDownloadable(self, depot):
1673 """Checks if build is downloadable based on target platform and depot.""" 1722 """Checks if build is downloadable based on target platform and depot."""
1674 if self.opts.target_platform in ['chromium'] and self.opts.gs_bucket: 1723 if self.opts.target_platform in ['chromium'] and self.opts.gs_bucket:
1675 return (depot == 'chromium' or 1724 return (depot == 'chromium' or
1676 'chromium' in DEPOT_DEPS_NAME[depot]['from'] or 1725 'chromium' in DEPOT_DEPS_NAME[depot]['from'] or
1677 'v8' in DEPOT_DEPS_NAME[depot]['from']) 1726 'v8' in DEPOT_DEPS_NAME[depot]['from'])
1678 return False 1727 return False
1679 1728
(...skipping 2234 matching lines...) Expand 10 before | Expand all | Expand 10 after
3914 # The perf dashboard scrapes the "results" step in order to comment on 3963 # The perf dashboard scrapes the "results" step in order to comment on
3915 # bugs. If you change this, please update the perf dashboard as well. 3964 # bugs. If you change this, please update the perf dashboard as well.
3916 bisect_utils.OutputAnnotationStepStart('Results') 3965 bisect_utils.OutputAnnotationStepStart('Results')
3917 print 'Error: %s' % e.message 3966 print 'Error: %s' % e.message
3918 if opts.output_buildbot_annotations: 3967 if opts.output_buildbot_annotations:
3919 bisect_utils.OutputAnnotationStepClosed() 3968 bisect_utils.OutputAnnotationStepClosed()
3920 return 1 3969 return 1
3921 3970
3922 if __name__ == '__main__': 3971 if __name__ == '__main__':
3923 sys.exit(main()) 3972 sys.exit(main())
OLDNEW
« no previous file with comments | « no previous file | tools/post_perf_builder_job.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698