diff options
author | simonhatch@chromium.org <simonhatch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-15 19:29:50 +0000 |
---|---|---|
committer | simonhatch@chromium.org <simonhatch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-15 19:29:50 +0000 |
commit | 2deb10df4b5547e74f4ff89652421f7ab780f018 (patch) | |
tree | 527f63ab984f058e8722f3811c75d202a09fb5b5 | |
parent | 7bfc16ace99007fd1f2d75096651110be691c693 (diff) | |
download | chromium_src-2deb10df4b5547e74f4ff89652421f7ab780f018.zip chromium_src-2deb10df4b5547e74f4ff89652421f7ab780f018.tar.gz chromium_src-2deb10df4b5547e74f4ff89652421f7ab780f018.tar.bz2 |
Added windows support for bisect script. Added build_preference parameter to bisect script to specify build system.
BUG=
NOTRY=true
Review URL: https://chromiumcodereview.appspot.com/12712009
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@188451 0039d316-1c4b-4281-b951-d872f2087c98
-rwxr-xr-x | tools/bisect-perf-regression.py | 227 | ||||
-rw-r--r-- | tools/bisect_utils.py | 10 | ||||
-rw-r--r-- | tools/run-bisect-perf-regression.cfg | 19 | ||||
-rwxr-xr-x | tools/run-bisect-perf-regression.py | 7 |
4 files changed, 216 insertions, 47 deletions
diff --git a/tools/bisect-perf-regression.py b/tools/bisect-perf-regression.py index 0776836..27ad54a 100755 --- a/tools/bisect-perf-regression.py +++ b/tools/bisect-perf-regression.py @@ -35,6 +35,7 @@ An example usage (using git hashes): """ +import errno import imp import math import optparse @@ -175,6 +176,15 @@ def IsStringInt(string_to_check): return False +def IsWindows(): + """Checks whether or not the script is running on Windows. + + Returns: + True if running on Windows. + """ + return os.name == 'nt' + + def RunProcess(command, print_output=False): """Run an arbitrary command, returning its output and return code. @@ -186,8 +196,11 @@ def RunProcess(command, print_output=False): Returns: A tuple of the output and return code. """ + if print_output: + print 'Running: [%s]' % ' '.join(command) + # On Windows, use shell=True to get PATH interpretation. - shell = (os.name == 'nt') + shell = IsWindows() proc = subprocess.Popen(command, shell=shell, stdout=subprocess.PIPE, @@ -227,6 +240,37 @@ def RunGit(command): return RunProcess(command) +def BuildWithMake(threads, targets, print_output): + cmd = ['make', 'BUILDTYPE=Release', '-j%d' % threads] + targets + + (output, return_code) = RunProcess(cmd, print_output) + + return not return_code + + +def BuildWithNinja(threads, targets, print_output): + cmd = ['ninja', '-C', os.path.join('out', 'Release'), + '-j%d' % threads] + targets + + (output, return_code) = RunProcess(cmd, print_output) + + return not return_code + + +def BuildWithVisualStudio(targets, print_output): + path_to_devenv = os.path.abspath( + os.path.join(os.environ['VS100COMNTOOLS'], '..', 'IDE', 'devenv.com')) + path_to_sln = os.path.join(os.getcwd(), 'chrome', 'chrome.sln') + cmd = [path_to_devenv, '/build', 'Release', path_to_sln] + + for t in targets: + cmd.extend(['/Project', t]) + + (output, return_code) = RunProcess(cmd, print_output) + + return not return_code + + class SourceControl(object): """SourceControl is an abstraction over the underlying source control system used for chromium. For now only git is supported, but in the @@ -243,11 +287,9 @@ class SourceControl(object): revision: The git SHA1 or svn CL (depending on workflow). Returns: - A tuple of the output and return code. + The return code of the call. """ - args = ['gclient', 'sync', '--revision', revision] - - return RunProcess(args) + return bisect_utils.RunGClient(['sync', '--revision', revision]) class GitSourceControl(SourceControl): @@ -297,9 +339,9 @@ class GitSourceControl(SourceControl): if use_gclient: results = self.SyncToRevisionWithGClient(revision) else: - results = RunGit(['checkout', revision]) + results = RunGit(['checkout', revision])[1] - return not results[1] + return not results def ResolveToRevision(self, revision_to_check, depot, search): """If an SVN revision is supplied, try to resolve it to a git SHA1. @@ -500,40 +542,35 @@ class BisectPerformanceMetrics(object): Returns: True if the build was successful. """ - if self.opts.debug_ignore_build: return True - gyp_var = os.getenv('GYP_GENERATORS') - - num_threads = 16 - + targets = ['chrome', 'performance_ui_tests'] + threads = 16 if self.opts.use_goma: - num_threads = 100 - - if gyp_var != None and 'ninja' in gyp_var: - args = ['ninja', - '-C', - 'out/Release', - '-j%d' % num_threads, - 'chrome', - 'performance_ui_tests'] - else: - args = ['make', - 'BUILDTYPE=Release', - '-j%d' % num_threads, - 'chrome', - 'performance_ui_tests'] + threads = 300 cwd = os.getcwd() os.chdir(self.src_cwd) - (output, return_code) = RunProcess(args, - self.opts.output_buildbot_annotations) + if self.opts.build_preference == 'make': + build_success = BuildWithMake(threads, targets, + self.opts.output_buildbot_annotations) + elif self.opts.build_preference == 'ninja': + if IsWindows(): + targets = [t + '.exe' for t in targets] + build_success = BuildWithNinja(threads, targets, + self.opts.output_buildbot_annotations) + elif self.opts.build_preference == 'msvs': + assert IsWindows(), 'msvs is only supported on Windows.' + build_success = BuildWithVisualStudio(targets, + self.opts.output_buildbot_annotations) + else: + assert False, 'No build system defined.' os.chdir(cwd) - return not return_code + return build_success def RunGClientHooks(self): """Runs gclient with runhooks command. @@ -545,9 +582,7 @@ class BisectPerformanceMetrics(object): if self.opts.debug_ignore_build: return True - results = RunProcess(['gclient', 'runhooks']) - - return not results[1] + return not bisect_utils.RunGClient(['runhooks']) def ParseMetricValuesFromOutput(self, metric, text): """Parses output from performance_ui_tests and retrieves the results for @@ -644,6 +679,9 @@ class BisectPerformanceMetrics(object): if self.opts.debug_ignore_perf_test: return ({'debug' : 0.0}, 0) + if IsWindows(): + command_to_run = command_to_run.replace('/', r'\\') + args = shlex.split(command_to_run) cwd = os.getcwd() @@ -735,10 +773,11 @@ class BisectPerformanceMetrics(object): # Having these pyc files around between runs can confuse the # perf tests and cause them to crash. - cmd = ['find', '.', '-name', '*.pyc', '-exec', 'rm', '-f', '{}', ';'] - (output, return_code) = RunProcess(cmd) - - assert not output, "Cleaning *.pyc failed." + for (path, dir, files) in os.walk(os.getcwd()): + for cur_file in files: + if cur_file.endswith('.pyc'): + path_to_file = os.path.join(path, cur_file) + os.remove(path_to_file) def SyncBuildAndRunRevision(self, revision, depot, command_to_run, metric): """Performs a full sync/build/run of the specified revision. @@ -1311,6 +1350,100 @@ def DetermineAndCreateSourceControl(): return None +def SetNinjaBuildSystemDefault(): + """Makes ninja the default build system to be used by + the bisection script.""" + gyp_var = os.getenv('GYP_GENERATORS') + + if not gyp_var or not 'ninja' in gyp_var: + if gyp_var: + os.environ['GYP_GENERATORS'] = gyp_var + ',ninja' + else: + os.environ['GYP_GENERATORS'] = 'ninja' + + if IsWindows(): + os.environ['GYP_DEFINES'] = 'component=shared_library '\ + 'incremental_chrome_dll=1 disable_nacl=1 fastbuild=1 '\ + 'chromium_win_pch=0' + + +def CheckPlatformSupported(opts): + """Checks that this platform and build system are supported. + + Args: + opts: The options parsed from the command line. + + Returns: + True if the platform and build system are supported. + """ + # Haven't tested the script out on any other platforms yet. + supported = ['posix', 'nt'] + if not os.name in supported: + print "Sorry, this platform isn't supported yet." + print + return False + + if IsWindows(): + if not opts.build_preference: + opts.build_preference = 'msvs' + + if opts.build_preference == 'msvs': + if not os.getenv('VS100COMNTOOLS'): + print 'Error: Path to visual studio could not be determined.' + print + return False + elif opts.build_preference == 'ninja': + SetNinjaBuildSystemDefault() + else: + assert False, 'Error: %s build not supported' % opts.build_preference + else: + if not opts.build_preference: + opts.build_preference = 'make' + + if opts.build_preference == 'ninja': + SetNinjaBuildSystemDefault() + elif opts.build_preference != 'make': + assert False, 'Error: %s build not supported' % opts.build_preference + + bisect_utils.RunGClient(['runhooks']) + + return True + + +def RmTreeAndMkDir(path_to_dir): + """Removes the directory tree specified, and then creates an empty + directory in the same location. + + Args: + path_to_dir: Path to the directory tree. + + Returns: + True if successful, False if an error occurred. + """ + try: + if os.path.exists(path_to_dir): + shutil.rmtree(path_to_dir) + except OSError, e: + if e.errno != errno.ENOENT: + return False + + try: + os.mkdir(path_to_dir) + except OSError, e: + if e.errno != errno.EEXIST: + return False + + return True + + +def RemoveBuildFiles(): + """Removes build files from previous runs.""" + if RmTreeAndMkDir(os.path.join('out', 'Release')): + if RmTreeAndMkDir(os.path.join('build', 'Release')): + return True + return False + + def main(): usage = ('%prog [options] [-- chromium-options]\n' @@ -1358,6 +1491,12 @@ def main(): 'truncated mean. Values will be clamped to range [0, 25]. ' 'Default value is 10 (highest/lowest 10% will be ' 'discarded).') + parser.add_option('--build_preference', + type='choice', + choices=['msvs', 'ninja', 'make'], + help='The preferred build system to use. On linux/mac ' + 'the options are make/ninja. On Windows, the options ' + 'are msvs/ninja.') parser.add_option('--use_goma', action="store_true", help='Add a bunch of extra threads for goma.') @@ -1403,12 +1542,6 @@ def main(): opts.truncate_percent = min(max(opts.truncate_percent, 0), 25) opts.truncate_percent = opts.truncate_percent / 100.0 - # Haven't tested the script out on any other platforms yet. - if not os.name in ['posix']: - print "Sorry, this platform isn't supported yet." - print - return 1 - metric_values = opts.metric.split('/') if len(metric_values) != 2: print "Invalid metric specified: [%s]" % (opts.metric,) @@ -1421,6 +1554,14 @@ def main(): os.chdir(os.path.join(os.getcwd(), 'src')) + if not RemoveBuildFiles(): + print "Something went wrong removing the build files." + print + return 1 + + if not CheckPlatformSupported(opts): + return 1 + # Check what source control method they're using. Only support git workflow # at the moment. source_control = DetermineAndCreateSourceControl() diff --git a/tools/bisect_utils.py b/tools/bisect_utils.py index 353867d..0439d76 100644 --- a/tools/bisect_utils.py +++ b/tools/bisect_utils.py @@ -28,6 +28,7 @@ solutions = [ }, ] """ +GCLIENT_SPEC = ''.join([l for l in GCLIENT_SPEC.splitlines()]) def OutputAnnotationStepStart(name): @@ -76,8 +77,15 @@ def RunGClient(params): Returns: The return code of the call. """ + if os.name == 'nt': + # "HOME" isn't normally defined on windows, but is needed + # for git to find the user's .netrc file. + if not os.getenv('HOME'): + os.environ['HOME'] = os.environ['USERPROFILE'] + + shell = os.name == 'nt' cmd = ['gclient'] + params - return subprocess.call(cmd) + return subprocess.call(cmd, shell=shell) def RunGClientAndCreateConfig(): diff --git a/tools/run-bisect-perf-regression.cfg b/tools/run-bisect-perf-regression.cfg index ea39f5e..792083c 100644 --- a/tools/run-bisect-perf-regression.cfg +++ b/tools/run-bisect-perf-regression.cfg @@ -22,7 +22,6 @@ Args: 'repeat_count': The number of times to repeat the performance test. 'truncate_percent': Discard the highest/lowest % values from performance test. - Sample config: config = { @@ -32,7 +31,21 @@ config = { 'bad_revision': '179782', 'metric': 'times/t', 'repeat_count': '10', - 'truncate_percent': 10, + 'truncate_percent': '10', +} + +On Windows: + - If you're calling a python script you will need to add "python" to +the command: + +config = { + 'command': 'python tools/perf/run_multipage_benchmarks -v --browser=release'\ + ' kraken tools/perf/page_sets/kraken.json', + 'good_revision': '185319', + 'bad_revision': '185364', + 'metric': 'Total/Total', + 'repeat_count': '10', + 'truncate_percent': '10', } """ @@ -43,5 +56,5 @@ config = { 'bad_revision': '', 'metric': '', 'repeat_count':'', - 'truncate_percent':'' + 'truncate_percent':'', } diff --git a/tools/run-bisect-perf-regression.py b/tools/run-bisect-perf-regression.py index 8807942..306b345 100755 --- a/tools/run-bisect-perf-regression.py +++ b/tools/run-bisect-perf-regression.py @@ -72,6 +72,11 @@ def RunBisectionScript(config, working_directory, path_to_file, path_to_goma): if config['truncate_percent']: cmd.extend(['-t', config['truncate_percent']]) + if os.name == 'nt': + cmd.extend(['--build_preference', 'ninja']) + else: + cmd.extend(['--build_preference', 'make']) + goma_file = '' if path_to_goma: path_to_goma = os.path.abspath(path_to_goma) @@ -92,6 +97,8 @@ def RunBisectionScript(config, working_directory, path_to_file, path_to_goma): print return return_code + cmd = [str(c) for c in cmd] + return_code = subprocess.call(cmd) if path_to_goma: |