| # Copyright 2014 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| from recipe_engine import recipe_api |
| |
| |
| class PGOApi(recipe_api.RecipeApi): |
| """ |
| PGOApi encapsulate the various step involved in a PGO build. |
| """ |
| |
| def __init__(self, **kwargs): |
| super(PGOApi, self).__init__(**kwargs) |
| |
| def _compile_instrumented_image(self, bot_config, mb_config_path=None): |
| """ |
| Generates the instrumented version of the binaries. |
| """ |
| self.m.chromium.set_config(bot_config['chromium_config_instrument'], |
| **bot_config.get('chromium_config_kwargs')) |
| self.m.chromium.runhooks(name='Runhooks: Instrumentation phase.') |
| self.m.chromium.run_mb( |
| self.m.properties['mastername'], |
| self.m.properties['buildername'], |
| mb_config_path=mb_config_path, |
| use_goma=False, |
| phase=1) |
| # Remove the profile files from the previous builds. |
| self.m.file.rmglob( |
| 'remove previous profiles', self.m.chromium.output_dir, '*.pg[cd]') |
| self.m.chromium.compile(name='Compile: Instrumentation phase.') |
| |
| def _run_pgo_benchmarks(self): |
| """ |
| Run a suite of telemetry benchmarks to generate some profiling data. |
| """ |
| target_arch = self.m.chromium.c.gyp_env.GYP_DEFINES['target_arch'] |
| target_cpu = {'ia32': 'x86'}.get(target_arch) or target_arch |
| args = [ |
| '--browser-type', self.m.chromium.c.build_config_fs.lower(), |
| '--target-cpu', target_cpu, |
| '--build-dir', self.m.chromium.output_dir, |
| ] |
| self.m.python( |
| 'Profiling benchmarks.', |
| self.m.path['checkout'].join('build', 'win', |
| 'run_pgo_profiling_benchmarks.py'), |
| args) |
| |
| def _compile_optimized_image(self, bot_config, mb_config_path=None): |
| """ |
| Generates the optimized version of the binaries. |
| """ |
| self.m.chromium.set_config(bot_config['chromium_config_optimize'], |
| **bot_config.get('chromium_config_kwargs')) |
| self.m.chromium.runhooks(name='Runhooks: Optimization phase.') |
| self.m.chromium.run_mb( |
| self.m.properties['mastername'], |
| self.m.properties['buildername'], |
| mb_config_path=mb_config_path, |
| use_goma=False, |
| phase=2) |
| self.m.chromium.compile(name='Compile: Optimization phase.') |
| |
| def _merge_pgc_files(self): |
| """ |
| Calls the script responsible of merging the PGC files. |
| |
| If this script is missing then this will be done automatically by the |
| compiler during the final compile step. |
| """ |
| merge_script = self.m.path['checkout'].join('build', 'win', |
| 'merge_pgc_files.py') |
| if not self.m.path.exists(merge_script): |
| return |
| |
| target_arch = self.m.chromium.c.gyp_env.GYP_DEFINES['target_arch'] |
| target_cpu = {'ia32': 'x86'}.get(target_arch) or target_arch |
| base_args = [ |
| '--checkout-dir', self.m.path['checkout'], |
| '--target-cpu', target_cpu, |
| '--build-dir', self.m.chromium.output_dir, |
| ] |
| |
| for f in self.m.file.glob_paths('list PGD files', |
| self.m.chromium.output_dir, '*.pgd', |
| test_data=['test1.pgd', 'test2.pgd']): |
| binary_name = self.m.path.splitext(self.m.path.basename(f))[0] |
| args = base_args + ['--binary-name', binary_name] |
| self.m.python('Merge the pgc files for %s.' % binary_name, |
| merge_script, args) |
| self.m.file.rmglob('remove pgc files', self.m.chromium.output_dir, |
| '%s!*.pgc' % binary_name) |
| |
| def compile_pgo(self, bot_config): |
| """ |
| Do a PGO build. This takes care of building an instrumented image, profiling |
| it and then compiling the optimized version of it. |
| """ |
| self.m.gclient.set_config(bot_config['gclient_config']) |
| |
| # Augment the DEPS path if needed. |
| if '%s' in self.m.gclient.c.solutions[0].deps_file: # pragma: no cover |
| self.m.gclient.c.solutions[0].deps_file = ( |
| self.m.gclient.c.solutions[0].deps_file % bot_config['bucket']) |
| |
| if self.m.properties.get('bot_id') != 'fake_slave': |
| self.m.chromium.taskkill() |
| |
| update_step = self.m.bot_update.ensure_checkout() |
| if bot_config.get('patch_root'): |
| self.m.path['checkout'] = self.m.path['start_dir'].join( |
| bot_config.get('patch_root')) |
| |
| # First step: compilation of the instrumented build. |
| self._compile_instrumented_image(bot_config) |
| |
| # Second step: profiling of the instrumented build. |
| self._run_pgo_benchmarks() |
| |
| # Merge the pgc files. |
| self._merge_pgc_files() |
| |
| if bot_config.get('archive_pgd', False): |
| self.archive_profile_database( |
| update_step.presentation.properties['got_revision']) |
| step_result = self.m.step.active_result |
| step_result.presentation.status = self.m.step.WARNING |
| |
| # Third step: Compilation of the optimized build, this will use the |
| # profile data files produced by the previous step. |
| self._compile_optimized_image(bot_config) |
| |
| def archive_profile_database(self, revision): |
| """ |
| Archive the profile database into a cloud bucket and use 'git notes' to |
| annotate the current commit with the URL to this file. |
| """ |
| # Temporarily turn any failure during this step into a warning until the |
| # permissions issues have been fixed. |
| # TODO(sebmarchand): Remove the try/except once it works. |
| try: |
| with self.m.step.nest("archive profile database"): |
| assert self.m.platform.is_win |
| self.m.cipd.set_service_account_credentials( |
| "C:\\creds\\service_accounts\\service-account-pgo-bot.json") |
| target_arch = { |
| 'ia32': '386', |
| 'x64': 'amd64', |
| }[self.m.chromium.c.gyp_env.GYP_DEFINES['target_arch']] |
| package_name = "chromium/pgo/profiles/profile_database/windows-%s" % ( |
| target_arch) |
| pkg = self.m.cipd.PackageDefinition(package_name, |
| self.m.chromium.output_dir, |
| 'copy') |
| |
| # Copy the pgd files in a temp directory so cipd can pick them up. |
| for f in self.m.file.glob_paths('list PGD files', |
| self.m.chromium.output_dir, '*.pgd', |
| test_data=['test.pgd']): |
| pkg.add_file(f) |
| |
| pkg_json = self.m.cipd.create_from_pkg(pkg) |
| instance_id = pkg_json['instance_id'] |
| |
| # Add the git notes for this profile database. |
| git_notes_ref = ('refs/notes/pgo/profile_database/windows-%s' % |
| target_arch) |
| |
| git_config = { |
| 'user.email': 'pgo-bot@chromium.org', |
| 'user.name': 'PGO bot' |
| } |
| self.m.git('fetch', '-f', |
| 'https://chromium.googlesource.com/chromium/src.git', |
| '%s:%s' % (git_notes_ref, git_notes_ref)) |
| self.m.git('notes', '--ref', git_notes_ref, |
| 'add', '-m', instance_id, revision, |
| git_config_options=git_config) |
| self.m.git('push', 'https://chromium.googlesource.com/chromium/src.git', |
| git_notes_ref) |
| except self.m.step.StepFailure: |
| step_result = self.m.step.active_result |
| step_result.presentation.status = self.m.step.WARNING |
| |