| OLD | NEW |
| 1 #!/usr/bin/python | 1 #!/usr/bin/python |
| 2 # | 2 # |
| 3 # Copyright 2015 The Chromium Authors. All rights reserved. | 3 # Copyright 2015 The Chromium Authors. All rights reserved. |
| 4 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be |
| 5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
| 6 | 6 |
| 7 """Loops Custom Tabs tests and outputs the results into a CSV file.""" | 7 """Loops Custom Tabs tests and outputs the results into a CSV file.""" |
| 8 | 8 |
| 9 import collections |
| 9 import contextlib | 10 import contextlib |
| 10 import logging | 11 import logging |
| 11 import optparse | 12 import optparse |
| 12 import os | 13 import os |
| 13 import random | 14 import random |
| 14 import re | 15 import re |
| 15 import subprocess | 16 import subprocess |
| 16 import sys | 17 import sys |
| 17 import time | 18 import time |
| 18 | 19 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 31 sys.path.append(os.path.join(_SRC_PATH, 'tools', 'android', 'loading')) | 32 sys.path.append(os.path.join(_SRC_PATH, 'tools', 'android', 'loading')) |
| 32 import device_setup | 33 import device_setup |
| 33 | 34 |
| 34 | 35 |
| 35 # Local build of Chrome (not Chromium). | 36 # Local build of Chrome (not Chromium). |
| 36 _CHROME_PACKAGE = 'com.google.android.apps.chrome' | 37 _CHROME_PACKAGE = 'com.google.android.apps.chrome' |
| 37 _COMMAND_LINE_PATH = '/data/local/tmp/chrome-command-line' | 38 _COMMAND_LINE_PATH = '/data/local/tmp/chrome-command-line' |
| 38 _TEST_APP_PACKAGE_NAME = 'org.chromium.customtabsclient.test' | 39 _TEST_APP_PACKAGE_NAME = 'org.chromium.customtabsclient.test' |
| 39 | 40 |
| 40 # Command line arguments for Chrome. | 41 # Command line arguments for Chrome. |
| 41 _CHROME_ARGS = [ | 42 CHROME_ARGS = [ |
| 42 # Disable backgound network requests that may pollute WPR archive, pollute | 43 # Disable backgound network requests that may pollute WPR archive, pollute |
| 43 # HTTP cache generation, and introduce noise in loading performance. | 44 # HTTP cache generation, and introduce noise in loading performance. |
| 44 '--disable-background-networking', | 45 '--disable-background-networking', |
| 45 '--disable-default-apps', | 46 '--disable-default-apps', |
| 46 '--no-proxy-server', | 47 '--no-proxy-server', |
| 47 # TODO(droger): Remove once crbug.com/354743 is fixed. | 48 # TODO(droger): Remove once crbug.com/354743 is fixed. |
| 48 '--safebrowsing-disable-auto-update', | 49 '--safebrowsing-disable-auto-update', |
| 49 | 50 |
| 50 # Disables actions that chrome performs only on first run or each launches, | 51 # Disables actions that chrome performs only on first run or each launches, |
| 51 # which can interfere with page load performance, or even block its | 52 # which can interfere with page load performance, or even block its |
| 52 # execution by waiting for user input. | 53 # execution by waiting for user input. |
| 53 '--disable-fre', | 54 '--disable-fre', |
| 54 '--no-default-browser-check', | 55 '--no-default-browser-check', |
| 55 '--no-first-run', | 56 '--no-first-run', |
| 56 ] | 57 ] |
| 57 | 58 |
| 58 | 59 |
| 59 def ResetChromeLocalState(device): | 60 def ResetChromeLocalState(device): |
| 60 """Remove the Chrome Profile and the various disk caches.""" | 61 """Remove the Chrome Profile and the various disk caches.""" |
| 61 profile_dirs = ['app_chrome/Default', 'cache', 'app_chrome/ShaderCache', | 62 profile_dirs = ['app_chrome/Default', 'cache', 'app_chrome/ShaderCache', |
| 62 'app_tabs'] | 63 'app_tabs'] |
| 63 cmd = ['rm', '-rf'] | 64 cmd = ['rm', '-rf'] |
| 64 cmd.extend( | 65 cmd.extend( |
| 65 '/data/data/{}/{}'.format(_CHROME_PACKAGE, d) for d in profile_dirs) | 66 '/data/data/{}/{}'.format(_CHROME_PACKAGE, d) for d in profile_dirs) |
| 66 device.adb.Shell(subprocess.list2cmdline(cmd)) | 67 device.adb.Shell(subprocess.list2cmdline(cmd)) |
| 67 | 68 |
| 68 | 69 |
| 69 def RunOnce(device, url, warmup, speculation_mode, delay_to_may_launch_url, | 70 def RunOnce(device, url, warmup, speculation_mode, delay_to_may_launch_url, |
| 70 delay_to_launch_url, cold, chrome_args): | 71 delay_to_launch_url, cold, chrome_args, reset_chrome_state): |
| 71 """Runs a test on a device once. | 72 """Runs a test on a device once. |
| 72 | 73 |
| 73 Args: | 74 Args: |
| 74 device: (DeviceUtils) device to run the tests on. | 75 device: (DeviceUtils) device to run the tests on. |
| 75 url: (str) URL to load. | 76 url: (str) URL to load. |
| 76 warmup: (bool) Whether to call warmup. | 77 warmup: (bool) Whether to call warmup. |
| 77 speculation_mode: (str) Speculation Mode. | 78 speculation_mode: (str) Speculation Mode. |
| 78 delay_to_may_launch_url: (int) Delay to mayLaunchUrl() in ms. | 79 delay_to_may_launch_url: (int) Delay to mayLaunchUrl() in ms. |
| 79 delay_to_launch_url: (int) Delay to launchUrl() in ms. | 80 delay_to_launch_url: (int) Delay to launchUrl() in ms. |
| 80 cold: (bool) Whether the page cache should be dropped. | 81 cold: (bool) Whether the page cache should be dropped. |
| 81 chrome_args: ([str]) List of arguments to pass to Chrome. | 82 chrome_args: ([str]) List of arguments to pass to Chrome. |
| 83 reset_chrome_state: (bool) Whether to reset the Chrome local state before |
| 84 the run. |
| 82 | 85 |
| 83 Returns: | 86 Returns: |
| 84 The output line (str), like this (one line only): | 87 The output line (str), like this (one line only): |
| 85 <warmup>,<prerender_mode>,<delay_to_may_launch_url>,<delay_to_launch>, | 88 <warmup>,<prerender_mode>,<delay_to_may_launch_url>,<delay_to_launch>, |
| 86 <intent_sent_ms>,<page_load_started_ms>,<page_load_finished_ms>, | 89 <intent_sent_ms>,<page_load_started_ms>,<page_load_finished_ms>, |
| 87 <first_contentful_paint> | 90 <first_contentful_paint> |
| 88 or None on error. | 91 or None on error. |
| 89 """ | 92 """ |
| 90 if not device.HasRoot(): | 93 if not device.HasRoot(): |
| 91 device.EnableRoot() | 94 device.EnableRoot() |
| (...skipping 11 matching lines...) Expand all Loading... |
| 103 'speculation_mode': str(speculation_mode), | 106 'speculation_mode': str(speculation_mode), |
| 104 'delay_to_may_launch_url': delay_to_may_launch_url, | 107 'delay_to_may_launch_url': delay_to_may_launch_url, |
| 105 'delay_to_launch_url': delay_to_launch_url, | 108 'delay_to_launch_url': delay_to_launch_url, |
| 106 'timeout': timeout_s}) | 109 'timeout': timeout_s}) |
| 107 result_line_re = re.compile(r'CUSTOMTABSBENCH.*: (.*)') | 110 result_line_re = re.compile(r'CUSTOMTABSBENCH.*: (.*)') |
| 108 logcat_monitor = device.GetLogcatMonitor(clear=True) | 111 logcat_monitor = device.GetLogcatMonitor(clear=True) |
| 109 logcat_monitor.Start() | 112 logcat_monitor.Start() |
| 110 device.ForceStop(_CHROME_PACKAGE) | 113 device.ForceStop(_CHROME_PACKAGE) |
| 111 device.ForceStop(_TEST_APP_PACKAGE_NAME) | 114 device.ForceStop(_TEST_APP_PACKAGE_NAME) |
| 112 | 115 |
| 113 ResetChromeLocalState(device) | 116 if reset_chrome_state: |
| 117 ResetChromeLocalState(device) |
| 114 | 118 |
| 115 if cold: | 119 if cold: |
| 116 cache_control.CacheControl(device).DropRamCaches() | 120 cache_control.CacheControl(device).DropRamCaches() |
| 117 | 121 |
| 118 device.StartActivity(launch_intent, blocking=True) | 122 device.StartActivity(launch_intent, blocking=True) |
| 119 | 123 |
| 120 match = None | 124 match = None |
| 121 try: | 125 try: |
| 122 match = logcat_monitor.WaitFor(result_line_re, timeout=logcat_timeout) | 126 match = logcat_monitor.WaitFor(result_line_re, timeout=logcat_timeout) |
| 123 except device_errors.CommandTimeoutError as _: | 127 except device_errors.CommandTimeoutError as _: |
| 124 logging.warning('Timeout waiting for the result line') | 128 logging.warning('Timeout waiting for the result line') |
| 125 logcat_monitor.Stop() | 129 logcat_monitor.Stop() |
| 126 logcat_monitor.Close() | 130 logcat_monitor.Close() |
| 127 return match.group(1) if match is not None else None | 131 return match.group(1) if match is not None else None |
| 128 | 132 |
| 129 | 133 |
| 134 Result = collections.namedtuple('Result', ['warmup', 'speculation_mode', |
| 135 'delay_to_may_launch_url', |
| 136 'delay_to_launch_url', |
| 137 'commit', 'plt', |
| 138 'first_contentful_paint']) |
| 139 |
| 140 |
| 141 def ParseResult(result_line): |
| 142 """Parses a result line, and returns it. |
| 143 |
| 144 Args: |
| 145 result_line: (str) A result line, as returned by RunOnce(). |
| 146 |
| 147 Returns: |
| 148 An instance of Result. |
| 149 """ |
| 150 tokens = result_line.strip().split(',') |
| 151 assert len(tokens) == 8 |
| 152 intent_sent_timestamp = int(tokens[4]) |
| 153 return Result(bool(tokens[0]), tokens[1], int(tokens[2]), int(tokens[3]), |
| 154 int(tokens[5]) - intent_sent_timestamp, |
| 155 int(tokens[6]) - intent_sent_timestamp, int(tokens[7])) |
| 156 |
| 157 |
| 130 def LoopOnDevice(device, configs, output_filename, wpr_archive_path=None, | 158 def LoopOnDevice(device, configs, output_filename, wpr_archive_path=None, |
| 131 wpr_record=None, network_condition=None, wpr_log_path=None, | 159 wpr_record=None, network_condition=None, wpr_log_path=None, |
| 132 once=False, should_stop=None): | 160 once=False, should_stop=None): |
| 133 """Loops the tests on a device. | 161 """Loops the tests on a device. |
| 134 | 162 |
| 135 Args: | 163 Args: |
| 136 device: (DeviceUtils) device to run the tests on. | 164 device: (DeviceUtils) device to run the tests on. |
| 137 configs: ([dict]) | 165 configs: ([dict]) |
| 138 output_filename: (str) Output filename. '-' for stdout. | 166 output_filename: (str) Output filename. '-' for stdout. |
| 139 wpr_archive_path: (str) Path to the WPR archive. | 167 wpr_archive_path: (str) Path to the WPR archive. |
| (...skipping 10 matching lines...) Expand all Loading... |
| 150 try: | 178 try: |
| 151 while should_stop is None or not should_stop.is_set(): | 179 while should_stop is None or not should_stop.is_set(): |
| 152 config = configs[random.randint(0, len(configs) - 1)] | 180 config = configs[random.randint(0, len(configs) - 1)] |
| 153 chrome_args = _CHROME_ARGS + wpr_attributes.chrome_args | 181 chrome_args = _CHROME_ARGS + wpr_attributes.chrome_args |
| 154 if config['speculation_mode'] == 'no_state_prefetch': | 182 if config['speculation_mode'] == 'no_state_prefetch': |
| 155 chrome_args.append('--prerender=prefetch') | 183 chrome_args.append('--prerender=prefetch') |
| 156 result = RunOnce(device, config['url'], config['warmup'], | 184 result = RunOnce(device, config['url'], config['warmup'], |
| 157 config['speculation_mode'], | 185 config['speculation_mode'], |
| 158 config['delay_to_may_launch_url'], | 186 config['delay_to_may_launch_url'], |
| 159 config['delay_to_launch_url'], config['cold'], | 187 config['delay_to_launch_url'], config['cold'], |
| 160 chrome_args) | 188 chrome_args, reset_chrome_state=True) |
| 161 if result is not None: | 189 if result is not None: |
| 162 out.write(result + '\n') | 190 out.write(result + '\n') |
| 163 out.flush() | 191 out.flush() |
| 164 if once: | 192 if once: |
| 165 return | 193 return |
| 166 if should_stop is not None: | 194 if should_stop is not None: |
| 167 should_stop.wait(10.) | 195 should_stop.wait(10.) |
| 168 else: | 196 else: |
| 169 time.sleep(10) | 197 time.sleep(10) |
| 170 finally: | 198 finally: |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 282 'delay_to_launch_url': options.delay_to_launch_url, | 310 'delay_to_launch_url': options.delay_to_launch_url, |
| 283 'cold': options.cold, | 311 'cold': options.cold, |
| 284 } | 312 } |
| 285 LoopOnDevice(device, [config], options.output_file, options.wpr_archive, | 313 LoopOnDevice(device, [config], options.output_file, options.wpr_archive, |
| 286 options.record, options.network_condition, options.wpr_log, | 314 options.record, options.network_condition, options.wpr_log, |
| 287 once=options.once) | 315 once=options.once) |
| 288 | 316 |
| 289 | 317 |
| 290 if __name__ == '__main__': | 318 if __name__ == '__main__': |
| 291 main() | 319 main() |
| OLD | NEW |