Kuang-che Wu | 1fcc022 | 2018-07-07 16:43:22 +0800 | [diff] [blame] | 1 | #!/usr/bin/env python2 |
| 2 | # -*- coding: utf-8 -*- |
| 3 | # Copyright 2018 The Chromium OS Authors. All rights reserved. |
| 4 | # Use of this source code is governed by a BSD-style license that can be |
| 5 | # found in the LICENSE file. |
| 6 | """Diagnose ChromeOS autotest regressions. |
| 7 | |
| 8 | This is integrated bisection utility. Given ChromeOS, Chrome, Android source |
Kuang-che Wu | 927231f | 2018-07-24 14:21:56 +0800 | [diff] [blame] | 9 | tree, and necessary parameters, this script can determine which components to |
Kuang-che Wu | 1fcc022 | 2018-07-07 16:43:22 +0800 | [diff] [blame] | 10 | bisect, and hopefully output the culprit CL of regression. |
| 11 | |
| 12 | Sometimes the script failed to figure out the final CL for various reasons, it |
| 13 | will cut down the search range as narrow as it can. |
| 14 | """ |
| 15 | from __future__ import print_function |
| 16 | import argparse |
| 17 | import fnmatch |
| 18 | import glob |
| 19 | import logging |
| 20 | import os |
| 21 | |
| 22 | from bisect_kit import cli |
| 23 | from bisect_kit import common |
| 24 | from bisect_kit import configure |
Kuang-che Wu | 1fcc022 | 2018-07-07 16:43:22 +0800 | [diff] [blame] | 25 | from bisect_kit import cros_lab_util |
| 26 | from bisect_kit import cros_util |
| 27 | from bisect_kit import diagnoser_cros |
Kuang-che Wu | e121fae | 2018-11-09 16:18:39 +0800 | [diff] [blame] | 28 | from bisect_kit import errors |
Kuang-che Wu | 1fcc022 | 2018-07-07 16:43:22 +0800 | [diff] [blame] | 29 | from bisect_kit import util |
Kuang-che Wu | d8fc957 | 2018-10-03 21:00:41 +0800 | [diff] [blame] | 30 | import setup_cros_bisect |
Kuang-che Wu | 1fcc022 | 2018-07-07 16:43:22 +0800 | [diff] [blame] | 31 | |
| 32 | logger = logging.getLogger(__name__) |
| 33 | |
| 34 | # What chrome binaries to build for given autotest. |
| 35 | # This dict is created manually by inspecting output of |
| 36 | # 'grep -r ChromeBinaryTest autotest/files/client/site_tests' |
| 37 | # If you change this dict, build_and_deploy_chrome_helper.sh may need update |
| 38 | # as well. |
| 39 | CHROME_BINARIES_OF_TEST = { |
| 40 | 'graphics_Chrome.ozone_gl_unittests': ['ozone_gl_unittests'], |
| 41 | 'security_SandboxLinuxUnittests': ['sandbox_linux_unittests'], |
| 42 | 'video_HangoutHardwarePerf*': [ |
| 43 | 'video_decode_accelerator_unittest', |
| 44 | 'video_encode_accelerator_unittest', |
| 45 | ], |
| 46 | 'video_JDAPerf*': ['jpeg_decode_accelerator_unittest'], |
| 47 | 'video_JEAPerf': ['jpeg_encode_accelerator_unittest'], |
| 48 | 'video_JpegDecodeAccelerator': ['jpeg_decode_accelerator_unittest'], |
| 49 | 'video_JpegEncodeAccelerator': ['jpeg_encode_accelerator_unittest'], |
| 50 | 'video_VDAPerf': ['video_decode_accelerator_unittest'], |
| 51 | 'video_VDASanity': ['video_decode_accelerator_unittest'], |
| 52 | 'video_VEAPerf': ['video_encode_accelerator_unittest'], |
| 53 | 'video_VideoDecodeAccelerator*': ['video_decode_accelerator_unittest'], |
| 54 | 'video_VideoEncodeAccelerator*': ['video_encode_accelerator_unittest'], |
| 55 | } |
| 56 | |
| 57 | |
Kuang-che Wu | a41525a | 2018-10-17 23:52:24 +0800 | [diff] [blame] | 58 | def grab_dut(config): |
Kuang-che Wu | 1fcc022 | 2018-07-07 16:43:22 +0800 | [diff] [blame] | 59 | # Assume "DEPENDENCIES" is identical between the period of |
| 60 | # `old` and `new` version. |
Kuang-che Wu | a41525a | 2018-10-17 23:52:24 +0800 | [diff] [blame] | 61 | autotest_dir = os.path.join(config['chromeos_root'], |
Kuang-che Wu | 1fcc022 | 2018-07-07 16:43:22 +0800 | [diff] [blame] | 62 | cros_util.prebuilt_autotest_dir) |
Kuang-che Wu | a41525a | 2018-10-17 23:52:24 +0800 | [diff] [blame] | 63 | info = cros_util.get_autotest_test_info(autotest_dir, config['test_name']) |
Kuang-che Wu | 0f1c3b0 | 2019-01-10 01:21:01 +0800 | [diff] [blame^] | 64 | assert info, 'incorrect test name? %s' % config['test_name'] |
Kuang-che Wu | 1fcc022 | 2018-07-07 16:43:22 +0800 | [diff] [blame] | 65 | |
Kuang-che Wu | a41525a | 2018-10-17 23:52:24 +0800 | [diff] [blame] | 66 | reason = 'bisect-kit: %s' % config['session'] |
Kuang-che Wu | f65c61d | 2018-10-19 17:48:30 +0800 | [diff] [blame] | 67 | if config.get('allocated_dut'): |
| 68 | host_name = cros_lab_util.dut_host_name(config['allocated_dut']) |
| 69 | logger.info('try to allocate the same host (%s) as last run', host_name) |
| 70 | host = cros_lab_util.allocate_host(reason, host=host_name) |
| 71 | else: |
| 72 | extra_labels = [] |
| 73 | dependencies = info.variables.get('DEPENDENCIES', '') |
| 74 | for label in dependencies.split(','): |
| 75 | label = label.strip() |
| 76 | # Skip non-machine labels |
| 77 | if label in ['cleanup-reboot']: |
| 78 | continue |
| 79 | extra_labels.append(label) |
| 80 | |
| 81 | host = cros_lab_util.allocate_host( |
| 82 | reason, |
| 83 | model=config['model'], |
| 84 | sku=config['sku'], |
| 85 | extra_labels=extra_labels) |
| 86 | |
Kuang-che Wu | 1fcc022 | 2018-07-07 16:43:22 +0800 | [diff] [blame] | 87 | if not host: |
| 88 | logger.error('unable to allocate dut') |
| 89 | return None |
| 90 | |
| 91 | logger.info('allocated host %s', host) |
| 92 | return host |
| 93 | |
| 94 | |
| 95 | def may_depend_on_extra_chrome_binaries(autotest_dir, test_name): |
| 96 | info = cros_util.get_autotest_test_info(autotest_dir, test_name) |
Kuang-che Wu | 0f1c3b0 | 2019-01-10 01:21:01 +0800 | [diff] [blame^] | 97 | assert info, 'incorrect test name? %s' % test_name |
Kuang-che Wu | 1fcc022 | 2018-07-07 16:43:22 +0800 | [diff] [blame] | 98 | dirpath = os.path.dirname(info.path) |
| 99 | for pypath in glob.glob(os.path.join(dirpath, '*.py')): |
| 100 | if 'ChromeBinaryTest' in open(pypath).read(): |
| 101 | return True |
| 102 | return False |
| 103 | |
| 104 | |
Kuang-che Wu | a41525a | 2018-10-17 23:52:24 +0800 | [diff] [blame] | 105 | def determine_chrome_binaries(chromeos_root, test_name): |
Kuang-che Wu | 1fcc022 | 2018-07-07 16:43:22 +0800 | [diff] [blame] | 106 | chrome_binaries = None |
| 107 | for name_pattern, binaries in CHROME_BINARIES_OF_TEST.items(): |
Kuang-che Wu | a41525a | 2018-10-17 23:52:24 +0800 | [diff] [blame] | 108 | if fnmatch.fnmatch(test_name, name_pattern): |
Kuang-che Wu | 1fcc022 | 2018-07-07 16:43:22 +0800 | [diff] [blame] | 109 | chrome_binaries = binaries |
| 110 | break |
| 111 | |
Kuang-che Wu | a41525a | 2018-10-17 23:52:24 +0800 | [diff] [blame] | 112 | autotest_dir = os.path.join(chromeos_root, cros_util.prebuilt_autotest_dir) |
Kuang-che Wu | 1fcc022 | 2018-07-07 16:43:22 +0800 | [diff] [blame] | 113 | if chrome_binaries: |
| 114 | logger.info('This test depends on chrome binary: %s', chrome_binaries) |
Kuang-che Wu | a41525a | 2018-10-17 23:52:24 +0800 | [diff] [blame] | 115 | elif may_depend_on_extra_chrome_binaries(autotest_dir, test_name): |
Kuang-che Wu | 74768d3 | 2018-09-07 12:03:24 +0800 | [diff] [blame] | 116 | logger.warning( |
| 117 | '%s code used ChromeBinaryTest but the binary is unknown; ' |
Kuang-che Wu | a41525a | 2018-10-17 23:52:24 +0800 | [diff] [blame] | 118 | 'please update CHROME_BINARIES_OF_TEST table', test_name) |
Kuang-che Wu | 1fcc022 | 2018-07-07 16:43:22 +0800 | [diff] [blame] | 119 | return chrome_binaries |
| 120 | |
| 121 | |
Kuang-che Wu | a41525a | 2018-10-17 23:52:24 +0800 | [diff] [blame] | 122 | class DiagnoseCommandLine(object): |
| 123 | """Diagnose command line interface.""" |
Kuang-che Wu | d8fc957 | 2018-10-03 21:00:41 +0800 | [diff] [blame] | 124 | |
Kuang-che Wu | a41525a | 2018-10-17 23:52:24 +0800 | [diff] [blame] | 125 | def __init__(self): |
| 126 | common.init() |
| 127 | self.argument_parser = self.create_argument_parser() |
| 128 | self.states = None |
Kuang-che Wu | 1fcc022 | 2018-07-07 16:43:22 +0800 | [diff] [blame] | 129 | |
Kuang-che Wu | a41525a | 2018-10-17 23:52:24 +0800 | [diff] [blame] | 130 | @property |
| 131 | def config(self): |
| 132 | return self.states.config |
| 133 | |
| 134 | def check_options(self, opts, path_factory): |
| 135 | if not opts.chromeos_mirror: |
| 136 | opts.chromeos_mirror = path_factory.get_chromeos_mirror() |
| 137 | logger.info('chromeos_mirror = %s', opts.chromeos_mirror) |
| 138 | if not opts.chromeos_root: |
| 139 | opts.chromeos_root = path_factory.get_chromeos_tree() |
| 140 | logger.info('chromeos_root = %s', opts.chromeos_root) |
| 141 | if not opts.chrome_mirror: |
| 142 | opts.chrome_mirror = path_factory.get_chrome_cache() |
| 143 | logger.info('chrome_mirror = %s', opts.chrome_mirror) |
| 144 | if not opts.chrome_root: |
| 145 | opts.chrome_root = path_factory.get_chrome_tree() |
| 146 | logger.info('chrome_root = %s', opts.chrome_root) |
| 147 | |
Kuang-che Wu | 248c518 | 2018-10-19 17:08:11 +0800 | [diff] [blame] | 148 | if opts.dut == cros_lab_util.LAB_DUT: |
| 149 | if not opts.model and not opts.sku: |
| 150 | self.argument_parser.error( |
| 151 | 'either --model or --sku need to be specified if DUT is "%s"' % |
| 152 | cros_lab_util.LAB_DUT) |
| 153 | # Board name cannot be deduced from auto allocated devices because they |
| 154 | # may be provisioned with image of unexpected board. |
| 155 | if not opts.board: |
Kuang-che Wu | a41525a | 2018-10-17 23:52:24 +0800 | [diff] [blame] | 156 | self.argument_parser.error('--board need to be specified if DUT is "%s"' |
| 157 | % cros_lab_util.LAB_DUT) |
Kuang-che Wu | 248c518 | 2018-10-19 17:08:11 +0800 | [diff] [blame] | 158 | else: |
| 159 | if not opts.board: |
Kuang-che Wu | a41525a | 2018-10-17 23:52:24 +0800 | [diff] [blame] | 160 | opts.board = cros_util.query_dut_board(opts.dut) |
| 161 | |
| 162 | if cros_util.is_cros_short_version(opts.old): |
| 163 | opts.old = cros_util.version_to_full(opts.board, opts.old) |
| 164 | if cros_util.is_cros_short_version(opts.new): |
| 165 | opts.new = cros_util.version_to_full(opts.board, opts.new) |
| 166 | |
| 167 | if opts.metric: |
| 168 | if opts.old_value is None: |
| 169 | self.argument_parser.error('--old_value is not provided') |
| 170 | if opts.new_value is None: |
| 171 | self.argument_parser.error('--new_value is not provided') |
Kuang-che Wu | 1fcc022 | 2018-07-07 16:43:22 +0800 | [diff] [blame] | 172 | else: |
Kuang-che Wu | a41525a | 2018-10-17 23:52:24 +0800 | [diff] [blame] | 173 | if opts.old_value is not None: |
| 174 | self.argument_parser.error( |
| 175 | '--old_value is provided but --metric is not') |
| 176 | if opts.new_value is not None: |
| 177 | self.argument_parser.error( |
| 178 | '--new_value is provided but --metric is not') |
Kuang-che Wu | 1fcc022 | 2018-07-07 16:43:22 +0800 | [diff] [blame] | 179 | |
Kuang-che Wu | a41525a | 2018-10-17 23:52:24 +0800 | [diff] [blame] | 180 | def cmd_init(self, opts): |
| 181 | path_factory = setup_cros_bisect.DefaultProjectPathFactory( |
| 182 | opts.mirror_base, opts.work_base, opts.session) |
| 183 | self.check_options(opts, path_factory) |
Kuang-che Wu | 1fcc022 | 2018-07-07 16:43:22 +0800 | [diff] [blame] | 184 | |
Kuang-che Wu | a41525a | 2018-10-17 23:52:24 +0800 | [diff] [blame] | 185 | config = dict( |
| 186 | session=opts.session, |
| 187 | mirror_base=opts.mirror_base, |
| 188 | work_base=opts.work_base, |
| 189 | chromeos_root=opts.chromeos_root, |
| 190 | chromeos_mirror=opts.chromeos_mirror, |
| 191 | chrome_root=opts.chrome_root, |
| 192 | chrome_mirror=opts.chrome_mirror, |
| 193 | android_root=opts.android_root, |
| 194 | android_mirror=opts.android_mirror, |
Kuang-che Wu | 248c518 | 2018-10-19 17:08:11 +0800 | [diff] [blame] | 195 | dut=opts.dut, |
| 196 | model=opts.model, |
| 197 | sku=opts.sku, |
| 198 | board=opts.board, |
Kuang-che Wu | a41525a | 2018-10-17 23:52:24 +0800 | [diff] [blame] | 199 | old=opts.old, |
| 200 | new=opts.new, |
| 201 | test_name=opts.test_name, |
| 202 | metric=opts.metric, |
Kuang-che Wu | a41525a | 2018-10-17 23:52:24 +0800 | [diff] [blame] | 203 | old_value=opts.old_value, |
| 204 | new_value=opts.new_value, |
Kuang-che Wu | a41525a | 2018-10-17 23:52:24 +0800 | [diff] [blame] | 205 | noisy=opts.noisy, |
| 206 | test_that_args=opts.args, |
| 207 | always_reflash=opts.always_reflash, |
| 208 | ) |
Kuang-che Wu | 1fcc022 | 2018-07-07 16:43:22 +0800 | [diff] [blame] | 209 | |
Kuang-che Wu | a41525a | 2018-10-17 23:52:24 +0800 | [diff] [blame] | 210 | self.states.init(config) |
Kuang-che Wu | 1fcc022 | 2018-07-07 16:43:22 +0800 | [diff] [blame] | 211 | |
Kuang-che Wu | a41525a | 2018-10-17 23:52:24 +0800 | [diff] [blame] | 212 | # Unpack old autotest prebuilt, assume following information don't change |
| 213 | # between versions: |
| 214 | # - what chrome binaries to run |
| 215 | # - dependency labels for DUT allocation |
| 216 | common_switch_cmd, _common_eval_cmd = self._build_cmds() |
| 217 | util.check_call(*(common_switch_cmd + [self.config['old']])) |
Kuang-che Wu | 1fcc022 | 2018-07-07 16:43:22 +0800 | [diff] [blame] | 218 | |
Kuang-che Wu | a41525a | 2018-10-17 23:52:24 +0800 | [diff] [blame] | 219 | self.states.save() |
Kuang-che Wu | 1fcc022 | 2018-07-07 16:43:22 +0800 | [diff] [blame] | 220 | |
Kuang-che Wu | a41525a | 2018-10-17 23:52:24 +0800 | [diff] [blame] | 221 | def _build_cmds(self): |
| 222 | # prebuilt version will be specified later. |
| 223 | common_switch_cmd = [ |
| 224 | './switch_autotest_prebuilt.py', |
| 225 | '--chromeos_root', self.config['chromeos_root'], |
| 226 | '--test_name', self.config['test_name'], |
| 227 | '--board', self.config['board'], |
Kuang-che Wu | 1fcc022 | 2018-07-07 16:43:22 +0800 | [diff] [blame] | 228 | ] # yapf: disable |
Kuang-che Wu | 1fcc022 | 2018-07-07 16:43:22 +0800 | [diff] [blame] | 229 | |
Kuang-che Wu | a41525a | 2018-10-17 23:52:24 +0800 | [diff] [blame] | 230 | common_eval_cmd = [ |
| 231 | './eval_cros_autotest.py', |
| 232 | '--chromeos_root', self.config['chromeos_root'], |
| 233 | '--test_name', self.config['test_name'], |
| 234 | ] # yapf: disable |
| 235 | if self.config['metric']: |
| 236 | common_eval_cmd += [ |
| 237 | '--metric', self.config['metric'], |
| 238 | '--old_value', str(self.config['old_value']), |
| 239 | '--new_value', str(self.config['new_value']), |
| 240 | ] # yapf: disable |
| 241 | if self.config['test_that_args']: |
| 242 | common_eval_cmd += ['--args', self.config['test_that_args']] |
Kuang-che Wu | d4603d7 | 2018-11-29 17:51:21 +0800 | [diff] [blame] | 243 | if self.config['test_name'].startswith('telemetry_'): |
| 244 | common_eval_cmd += ['--chrome_root', self.config['chrome_root']] |
Kuang-che Wu | a41525a | 2018-10-17 23:52:24 +0800 | [diff] [blame] | 245 | return common_switch_cmd, common_eval_cmd |
Kuang-che Wu | 1fcc022 | 2018-07-07 16:43:22 +0800 | [diff] [blame] | 246 | |
Kuang-che Wu | a41525a | 2018-10-17 23:52:24 +0800 | [diff] [blame] | 247 | def cmd_run(self, opts): |
| 248 | del opts # unused |
Kuang-che Wu | 1fcc022 | 2018-07-07 16:43:22 +0800 | [diff] [blame] | 249 | |
Kuang-che Wu | a41525a | 2018-10-17 23:52:24 +0800 | [diff] [blame] | 250 | self.states.load() |
Kuang-che Wu | 1fcc022 | 2018-07-07 16:43:22 +0800 | [diff] [blame] | 251 | |
Kuang-che Wu | 8b65409 | 2018-11-09 17:56:25 +0800 | [diff] [blame] | 252 | try: |
| 253 | path_factory = setup_cros_bisect.DefaultProjectPathFactory( |
| 254 | self.config['mirror_base'], self.config['work_base'], |
| 255 | self.config['session']) |
| 256 | common_switch_cmd, common_eval_cmd = self._build_cmds() |
| 257 | |
| 258 | chrome_binaries = determine_chrome_binaries(self.config['chromeos_root'], |
| 259 | self.config['test_name']) |
| 260 | |
| 261 | with cros_lab_util.dut_manager(self.config['dut'], |
| 262 | lambda: grab_dut(self.config)) as dut: |
| 263 | if not dut: |
| 264 | raise errors.NoDutAvailable('unable to allocate DUT') |
| 265 | assert cros_util.is_dut(dut) |
| 266 | if self.config['dut'] == cros_lab_util.LAB_DUT: |
| 267 | self.config['allocated_dut'] = dut |
| 268 | self.states.save() |
| 269 | common_eval_cmd.append(dut) |
| 270 | |
| 271 | diagnoser = diagnoser_cros.CrosDiagnoser( |
| 272 | self.states, self.config['session'], path_factory, |
| 273 | self.config['chromeos_root'], self.config['chromeos_mirror'], |
| 274 | self.config['android_root'], self.config['android_mirror'], |
| 275 | self.config['chrome_root'], self.config['chrome_mirror'], |
| 276 | self.config['board'], self.config['noisy'], dut) |
| 277 | |
| 278 | eval_cmd = common_eval_cmd + ['--prebuilt', '--reinstall'] |
| 279 | # Do not specify version for autotest prebuilt switching here. The trick |
| 280 | # is that version number is obtained via bisector's environment variable |
| 281 | # CROS_VERSION. |
| 282 | extra_switch_cmd = common_switch_cmd |
| 283 | diagnoser.narrow_down_chromeos_prebuilt( |
| 284 | self.config['old'], |
| 285 | self.config['new'], |
| 286 | eval_cmd, |
| 287 | extra_switch_cmd=extra_switch_cmd) |
| 288 | |
| 289 | diagnoser.switch_chromeos_to_old(force=self.config['always_reflash']) |
| 290 | util.check_call(*(common_switch_cmd + [diagnoser.cros_old])) |
| 291 | util.check_call('ssh', dut, 'rm', '-rf', '/usr/local/autotest') |
| 292 | |
| 293 | try: |
| 294 | if diagnoser.narrow_down_android(eval_cmd): |
| 295 | return |
| 296 | except errors.VerificationFailed: |
| 297 | raise |
| 298 | except Exception: |
| 299 | logger.exception('exception in android bisector before verification; ' |
| 300 | 'assume culprit is not inside android and continue') |
| 301 | # Assume it's ok to leave random version of android prebuilt on DUT. |
| 302 | |
| 303 | # Don't --reinstall to keep chrome binaries override. |
| 304 | eval_cmd = common_eval_cmd + ['--prebuilt'] |
| 305 | try: |
| 306 | if diagnoser.narrow_down_chrome( |
Kuang-che Wu | 50d8ff4 | 2018-11-26 12:48:30 +0800 | [diff] [blame] | 307 | eval_cmd, chrome_binaries=chrome_binaries): |
Kuang-che Wu | 8b65409 | 2018-11-09 17:56:25 +0800 | [diff] [blame] | 308 | return |
| 309 | except errors.VerifyOldFailed: |
| 310 | logger.fatal('expect old chrome has old behavior but failed') |
| 311 | raise |
| 312 | except Exception: |
| 313 | logger.exception('exception in chrome bisector before verification; ' |
| 314 | 'assume culprit is not inside chrome and continue') |
| 315 | |
| 316 | eval_cmd = common_eval_cmd + ['--reinstall'] |
| 317 | diagnoser.narrow_down_chromeos_localbuild(eval_cmd) |
| 318 | logger.info('%s done', __file__) |
| 319 | except Exception as e: |
| 320 | logger.exception('got exception; stop') |
| 321 | exception_name = e.__class__.__name__ |
| 322 | self.states.add_history( |
| 323 | 'failed', '%s: %s' % (exception_name, e), exception=exception_name) |
| 324 | |
| 325 | def cmd_log(self, opts): |
| 326 | self.states.load() |
Kuang-che Wu | a41525a | 2018-10-17 23:52:24 +0800 | [diff] [blame] | 327 | path_factory = setup_cros_bisect.DefaultProjectPathFactory( |
| 328 | self.config['mirror_base'], self.config['work_base'], |
| 329 | self.config['session']) |
Kuang-che Wu | 8b65409 | 2018-11-09 17:56:25 +0800 | [diff] [blame] | 330 | diagnoser = diagnoser_cros.CrosDiagnoser( |
| 331 | self.states, self.config['session'], path_factory, |
| 332 | self.config['chromeos_root'], self.config['chromeos_mirror'], |
| 333 | self.config['android_root'], self.config['android_mirror'], |
| 334 | self.config['chrome_root'], self.config['chrome_mirror'], |
| 335 | self.config['board'], self.config['noisy'], None) |
Kuang-che Wu | 1fcc022 | 2018-07-07 16:43:22 +0800 | [diff] [blame] | 336 | |
Kuang-che Wu | 8b65409 | 2018-11-09 17:56:25 +0800 | [diff] [blame] | 337 | diagnoser.cmd_log(opts.json) |
Kuang-che Wu | a41525a | 2018-10-17 23:52:24 +0800 | [diff] [blame] | 338 | |
Kuang-che Wu | e80bb87 | 2018-11-15 19:45:25 +0800 | [diff] [blame] | 339 | def cmd_view(self, opts): |
| 340 | self.states.load() |
| 341 | path_factory = setup_cros_bisect.DefaultProjectPathFactory( |
| 342 | self.config['mirror_base'], self.config['work_base'], |
| 343 | self.config['session']) |
| 344 | diagnoser = diagnoser_cros.CrosDiagnoser( |
| 345 | self.states, self.config['session'], path_factory, |
| 346 | self.config['chromeos_root'], self.config['chromeos_mirror'], |
| 347 | self.config['android_root'], self.config['android_mirror'], |
| 348 | self.config['chrome_root'], self.config['chrome_mirror'], |
| 349 | self.config['board'], self.config['noisy'], None) |
| 350 | diagnoser.cmd_view(opts.json, opts.verbose) |
| 351 | |
Kuang-che Wu | a41525a | 2018-10-17 23:52:24 +0800 | [diff] [blame] | 352 | def create_argument_parser(self): |
| 353 | parser = argparse.ArgumentParser() |
| 354 | common.add_common_arguments(parser) |
| 355 | parser.add_argument('--session_base', default='bisect.sessions') |
| 356 | parser.add_argument('--session', help='Session name', required=True) |
| 357 | subparsers = parser.add_subparsers( |
| 358 | dest='command', title='commands', metavar='<command>') |
| 359 | |
| 360 | parser_init = subparsers.add_parser('init', help='Initialize') |
| 361 | group = parser_init.add_argument_group( |
| 362 | title='Source tree path options', |
| 363 | description=''' |
| 364 | Specify the paths of chromeos/chrome/android mirror and checkout. They |
| 365 | have the same default values as setup_cros_bisect.py, so usually you can |
| 366 | omit them and it just works. |
| 367 | ''') |
| 368 | group.add_argument( |
| 369 | '--mirror_base', |
| 370 | metavar='MIRROR_BASE', |
| 371 | default=configure.get('MIRROR_BASE', |
| 372 | setup_cros_bisect.DEFAULT_MIRROR_BASE), |
| 373 | help='Directory for mirrors (default: %(default)s)') |
| 374 | group.add_argument( |
| 375 | '--work_base', |
| 376 | metavar='WORK_BASE', |
| 377 | default=configure.get('WORK_BASE', setup_cros_bisect.DEFAULT_WORK_BASE), |
| 378 | help='Directory for bisection working directories ' |
| 379 | '(default: %(default)s)') |
| 380 | group.add_argument( |
| 381 | '--chromeos_root', |
| 382 | metavar='CHROMEOS_ROOT', |
| 383 | type=cli.argtype_dir_path, |
| 384 | default=configure.get('CHROMEOS_ROOT'), |
| 385 | help='ChromeOS tree root') |
| 386 | group.add_argument( |
| 387 | '--chromeos_mirror', |
| 388 | type=cli.argtype_dir_path, |
| 389 | default=configure.get('CHROMEOS_MIRROR'), |
| 390 | help='ChromeOS repo mirror path') |
| 391 | group.add_argument( |
| 392 | '--android_root', |
| 393 | metavar='ANDROID_ROOT', |
| 394 | type=cli.argtype_dir_path, |
| 395 | default=configure.get('ANDROID_ROOT'), |
| 396 | help='Android tree root') |
| 397 | group.add_argument( |
| 398 | '--android_mirror', |
| 399 | type=cli.argtype_dir_path, |
| 400 | default=configure.get('ANDROID_MIRROR'), |
| 401 | help='Android repo mirror path') |
| 402 | group.add_argument( |
| 403 | '--chrome_root', |
| 404 | metavar='CHROME_ROOT', |
| 405 | type=cli.argtype_dir_path, |
| 406 | default=configure.get('CHROME_ROOT'), |
| 407 | help='Chrome tree root') |
| 408 | group.add_argument( |
| 409 | '--chrome_mirror', |
| 410 | metavar='CHROME_MIRROR', |
| 411 | type=cli.argtype_dir_path, |
| 412 | default=configure.get('CHROME_MIRROR'), |
| 413 | help="chrome's gclient cache dir") |
| 414 | |
Kuang-che Wu | 248c518 | 2018-10-19 17:08:11 +0800 | [diff] [blame] | 415 | group = parser_init.add_argument_group(title='DUT allocation options') |
| 416 | group.add_argument( |
| 417 | '--dut', |
| 418 | metavar='DUT', |
| 419 | required=True, |
| 420 | help='Address of DUT (Device Under Test). If "%s", DUT will be ' |
| 421 | 'automatically allocated from the lab' % cros_lab_util.LAB_DUT) |
| 422 | group.add_argument( |
| 423 | '--model', |
| 424 | metavar='MODEL', |
| 425 | help='"model" criteria if DUT is auto allocated from the lab') |
| 426 | group.add_argument( |
| 427 | '--sku', |
| 428 | metavar='SKU', |
| 429 | help='"sku" criteria if DUT is auto allocated from the lab') |
| 430 | |
Kuang-che Wu | a41525a | 2018-10-17 23:52:24 +0800 | [diff] [blame] | 431 | group = parser_init.add_argument_group(title='Essential options') |
| 432 | group.add_argument( |
Kuang-che Wu | 248c518 | 2018-10-19 17:08:11 +0800 | [diff] [blame] | 433 | '--board', |
| 434 | metavar='BOARD', |
| 435 | default=configure.get('BOARD'), |
| 436 | help='ChromeOS board name; auto detected if DUT is not auto allocated') |
| 437 | group.add_argument( |
Kuang-che Wu | a41525a | 2018-10-17 23:52:24 +0800 | [diff] [blame] | 438 | '--old', |
| 439 | type=cros_util.argtype_cros_version, |
| 440 | required=True, |
| 441 | help='ChromeOS version with old behavior') |
| 442 | group.add_argument( |
| 443 | '--new', |
| 444 | type=cros_util.argtype_cros_version, |
| 445 | required=True, |
| 446 | help='ChromeOS version with new behavior') |
| 447 | group.add_argument('--test_name', required=True, help='Test name') |
| 448 | |
| 449 | group = parser_init.add_argument_group(title='Options for benchmark test') |
| 450 | group.add_argument('--metric', help='Metric name of benchmark test') |
| 451 | group.add_argument( |
| 452 | '--old_value', |
| 453 | type=float, |
| 454 | help='For benchmark test, old value of metric') |
| 455 | group.add_argument( |
| 456 | '--new_value', |
| 457 | type=float, |
| 458 | help='For benchmark test, new value of metric') |
| 459 | |
Kuang-che Wu | a41525a | 2018-10-17 23:52:24 +0800 | [diff] [blame] | 460 | group = parser_init.add_argument_group(title='Options passed to test_that') |
| 461 | group.add_argument( |
| 462 | '--args', |
| 463 | help='Extra args passed to "test_that --args"; Overrides the default') |
| 464 | |
| 465 | group = parser_init.add_argument_group(title='Bisect behavior options') |
| 466 | group.add_argument( |
| 467 | '--noisy', |
| 468 | help='Enable noisy binary search. Example value: "old=1/10,new=2/3"') |
| 469 | group.add_argument( |
| 470 | '--always_reflash', |
| 471 | action='store_true', |
| 472 | help='Do not trust ChromeOS version number of DUT and always reflash. ' |
| 473 | 'This is usually only needed when resume because previous bisect was ' |
| 474 | 'interrupted and the DUT may be in an unexpected state') |
| 475 | parser_init.set_defaults(func=self.cmd_init) |
| 476 | |
| 477 | parser_run = subparsers.add_parser('run', help='Start auto bisection') |
| 478 | parser_run.set_defaults(func=self.cmd_run) |
| 479 | |
Kuang-che Wu | 8b65409 | 2018-11-09 17:56:25 +0800 | [diff] [blame] | 480 | parser_log = subparsers.add_parser( |
| 481 | 'log', help='Prints what has been done so far') |
| 482 | parser_log.add_argument( |
| 483 | '--json', action='store_true', help='Machine readable output') |
| 484 | parser_log.set_defaults(func=self.cmd_log) |
| 485 | |
Kuang-che Wu | e80bb87 | 2018-11-15 19:45:25 +0800 | [diff] [blame] | 486 | parser_view = subparsers.add_parser( |
| 487 | 'view', help='Prints summary of current status') |
| 488 | parser_view.add_argument('--verbose', '-v', action='store_true') |
| 489 | parser_view.add_argument( |
| 490 | '--json', action='store_true', help='Machine readable output') |
| 491 | parser_view.set_defaults(func=self.cmd_view) |
| 492 | |
Kuang-che Wu | a41525a | 2018-10-17 23:52:24 +0800 | [diff] [blame] | 493 | return parser |
| 494 | |
| 495 | def main(self, args=None): |
| 496 | opts = self.argument_parser.parse_args(args) |
| 497 | common.config_logging(opts) |
| 498 | |
| 499 | session_base = configure.get('SESSION_BASE', common.DEFAULT_SESSION_BASE) |
| 500 | session_file = os.path.join(session_base, opts.session, |
| 501 | self.__class__.__name__) |
Kuang-che Wu | 8b65409 | 2018-11-09 17:56:25 +0800 | [diff] [blame] | 502 | self.states = diagnoser_cros.DiagnoseStates(session_file) |
Kuang-che Wu | a41525a | 2018-10-17 23:52:24 +0800 | [diff] [blame] | 503 | opts.func(opts) |
Kuang-che Wu | 1fcc022 | 2018-07-07 16:43:22 +0800 | [diff] [blame] | 504 | |
| 505 | |
| 506 | if __name__ == '__main__': |
Kuang-che Wu | a41525a | 2018-10-17 23:52:24 +0800 | [diff] [blame] | 507 | DiagnoseCommandLine().main() |