| 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 logging | 9 import logging |
| 10 import optparse | 10 import optparse |
| 11 import os | 11 import os |
| 12 import re | 12 import re |
| 13 import subprocess | 13 import subprocess |
| 14 import sys | 14 import sys |
| 15 import time | 15 import time |
| 16 | 16 |
| 17 _SRC_PATH = os.path.abspath(os.path.join( | 17 _SRC_PATH = os.path.abspath(os.path.join( |
| 18 os.path.dirname(__file__), os.pardir, os.pardir, os.pardir, os.pardir)) | 18 os.path.dirname(__file__), os.pardir, os.pardir, os.pardir, os.pardir)) |
| 19 | 19 |
| 20 sys.path.append(os.path.join(_SRC_PATH, 'third_party', 'catapult', 'devil')) | 20 sys.path.append(os.path.join(_SRC_PATH, 'third_party', 'catapult', 'devil')) |
| 21 from devil.android import device_errors | 21 from devil.android import device_errors |
| 22 from devil.android import device_utils | 22 from devil.android import device_utils |
| 23 from devil.android.perf import cache_control | 23 from devil.android.perf import cache_control |
| 24 from devil.android.sdk import intent | 24 from devil.android.sdk import intent |
| 25 | 25 |
| 26 sys.path.append(os.path.join(_SRC_PATH, 'build', 'android')) | 26 sys.path.append(os.path.join(_SRC_PATH, 'build', 'android')) |
| 27 import devil_chromium | 27 import devil_chromium |
| 28 | 28 |
| 29 sys.path.append(os.path.join(_SRC_PATH, 'tools', 'android', 'loading')) |
| 30 import device_setup |
| 31 |
| 29 | 32 |
| 30 # Local build of Chrome (not Chromium). | 33 # Local build of Chrome (not Chromium). |
| 31 _CHROME_PACKAGE = 'com.google.android.apps.chrome' | 34 _CHROME_PACKAGE = 'com.google.android.apps.chrome' |
| 32 | 35 |
| 33 | 36 |
| 37 # Command line arguments for Chrome. |
| 38 _CHROME_ARGS = [ |
| 39 # Disable backgound network requests that may pollute WPR archive, pollute |
| 40 # HTTP cache generation, and introduce noise in loading performance. |
| 41 '--disable-background-networking', |
| 42 '--disable-default-apps', |
| 43 '--no-proxy-server', |
| 44 # TODO(droger): Remove once crbug.com/354743 is fixed. |
| 45 '--safebrowsing-disable-auto-update', |
| 46 |
| 47 # Disables actions that chrome performs only on first run or each launches, |
| 48 # which can interfere with page load performance, or even block its |
| 49 # execution by waiting for user input. |
| 50 '--disable-fre', |
| 51 '--no-default-browser-check', |
| 52 '--no-first-run', |
| 53 ] |
| 54 |
| 55 |
| 34 def ResetChromeLocalState(device): | 56 def ResetChromeLocalState(device): |
| 35 """Remove the Chrome Profile and the various disk caches.""" | 57 """Remove the Chrome Profile and the various disk caches.""" |
| 36 profile_dirs = ['app_chrome/Default', 'cache', 'app_chrome/ShaderCache', | 58 profile_dirs = ['app_chrome/Default', 'cache', 'app_chrome/ShaderCache', |
| 37 'app_tabs'] | 59 'app_tabs'] |
| 38 cmd = ['rm', '-rf'] | 60 cmd = ['rm', '-rf'] |
| 39 cmd.extend( | 61 cmd.extend( |
| 40 '/data/data/{}/{}'.format(_CHROME_PACKAGE, d) for d in profile_dirs) | 62 '/data/data/{}/{}'.format(_CHROME_PACKAGE, d) for d in profile_dirs) |
| 41 device.adb.Shell(subprocess.list2cmdline(cmd)) | 63 device.adb.Shell(subprocess.list2cmdline(cmd)) |
| 42 | 64 |
| 43 | 65 |
| 44 def RunOnce(device, url, warmup, no_prerendering, delay_to_may_launch_url, | 66 def RunOnce(device, url, warmup, prerender_mode, delay_to_may_launch_url, |
| 45 delay_to_launch_url, cold): | 67 delay_to_launch_url, cold): |
| 46 """Runs a test on a device once. | 68 """Runs a test on a device once. |
| 47 | 69 |
| 48 Args: | 70 Args: |
| 49 device: (DeviceUtils) device to run the tests on. | 71 device: (DeviceUtils) device to run the tests on. |
| 50 warmup: (bool) Whether to call warmup. | 72 warmup: (bool) Whether to call warmup. |
| 51 no_prerendering: (bool) Whether to disable prerendering. | 73 prerender_mode: (str) Prerender mode (disabled, enabled or prefetch). |
| 52 delay_to_may_launch_url: (int) Delay to mayLaunchUrl() in ms. | 74 delay_to_may_launch_url: (int) Delay to mayLaunchUrl() in ms. |
| 53 delay_to_launch_url: (int) Delay to launchUrl() in ms. | 75 delay_to_launch_url: (int) Delay to launchUrl() in ms. |
| 54 cold: (bool) Whether the page cache should be dropped. | 76 cold: (bool) Whether the page cache should be dropped. |
| 55 | 77 |
| 56 Returns: | 78 Returns: |
| 57 The output line (str), like this (one line only): | 79 The output line (str), like this (one line only): |
| 58 <warmup>,<no_prerendering>,<delay_to_may_launch_url>,<delay_to_launch>, | 80 <warmup>,<prerender_mode>,<delay_to_may_launch_url>,<delay_to_launch>, |
| 59 <intent_sent_ms>,<page_load_started_ms>,<page_load_finished_ms> | 81 <intent_sent_ms>,<page_load_started_ms>,<page_load_finished_ms> |
| 60 or None on error. | 82 or None on error. |
| 61 """ | 83 """ |
| 62 launch_intent = intent.Intent( | 84 launch_intent = intent.Intent( |
| 63 action='android.intent.action.MAIN', | 85 action='android.intent.action.MAIN', |
| 64 package='org.chromium.customtabsclient.test', | 86 package='org.chromium.customtabsclient.test', |
| 65 activity='org.chromium.customtabs.test.MainActivity', | 87 activity='org.chromium.customtabs.test.MainActivity', |
| 66 extras={'url': url, 'warmup': warmup, 'no_prerendering': no_prerendering, | 88 extras={'url': url, 'warmup': warmup, 'prerender_mode': prerender_mode, |
| 67 'delay_to_may_launch_url': delay_to_may_launch_url, | 89 'delay_to_may_launch_url': delay_to_may_launch_url, |
| 68 'delay_to_launch_url': delay_to_launch_url}) | 90 'delay_to_launch_url': delay_to_launch_url}) |
| 69 result_line_re = re.compile(r'CUSTOMTABSBENCH.*: (.*)') | 91 result_line_re = re.compile(r'CUSTOMTABSBENCH.*: (.*)') |
| 70 logcat_monitor = device.GetLogcatMonitor(clear=True) | 92 logcat_monitor = device.GetLogcatMonitor(clear=True) |
| 71 logcat_monitor.Start() | 93 logcat_monitor.Start() |
| 72 device.ForceStop(_CHROME_PACKAGE) | 94 device.ForceStop(_CHROME_PACKAGE) |
| 73 device.ForceStop('org.chromium.customtabsclient.test') | 95 device.ForceStop('org.chromium.customtabsclient.test') |
| 74 ResetChromeLocalState(device) | 96 ResetChromeLocalState(device) |
| 75 | 97 |
| 76 if cold: | 98 if cold: |
| 77 if not device.HasRoot(): | 99 if not device.HasRoot(): |
| 78 device.EnableRoot() | 100 device.EnableRoot() |
| 79 cache_control.CacheControl(device).DropRamCaches() | 101 cache_control.CacheControl(device).DropRamCaches() |
| 80 device.StartActivity(launch_intent, blocking=True) | 102 device.StartActivity(launch_intent, blocking=True) |
| 81 match = None | 103 match = None |
| 82 try: | 104 try: |
| 83 match = logcat_monitor.WaitFor(result_line_re, timeout=10) | 105 match = logcat_monitor.WaitFor(result_line_re, timeout=10) |
| 84 except device_errors.CommandTimeoutError as e: | 106 except device_errors.CommandTimeoutError as e: |
| 85 logging.warning('Timeout waiting for the result line') | 107 logging.warning('Timeout waiting for the result line') |
| 86 return match.group(1) if match is not None else None | 108 return match.group(1) if match is not None else None |
| 87 | 109 |
| 88 | 110 |
| 89 def LoopOnDevice(device, url, warmup, no_prerendering, delay_to_may_launch_url, | 111 def LoopOnDevice(device, url, warmup, prerender_mode, delay_to_may_launch_url, |
| 90 delay_to_launch_url, cold, output_filename, once=False): | 112 delay_to_launch_url, cold, output_filename, once=False): |
| 91 """Loops the tests on a device. | 113 """Loops the tests on a device. |
| 92 | 114 |
| 93 Args: | 115 Args: |
| 94 device: (DeviceUtils) device to run the tests on. | 116 device: (DeviceUtils) device to run the tests on. |
| 95 url: (str) URL to navigate to. | 117 url: (str) URL to navigate to. |
| 96 warmup: (bool) Whether to call warmup. | 118 warmup: (bool) Whether to call warmup. |
| 97 no_prerendering: (bool) Whether to disable prerendering. | 119 prerender_mode: (str) Prerender mode (disabled, enabled or prefetch). |
| 98 delay_to_may_launch_url: (int) Delay to mayLaunchUrl() in ms. | 120 delay_to_may_launch_url: (int) Delay to mayLaunchUrl() in ms. |
| 99 delay_to_launch_url: (int) Delay to launchUrl() in ms. | 121 delay_to_launch_url: (int) Delay to launchUrl() in ms. |
| 100 cold: (bool) Whether the page cache should be dropped. | 122 cold: (bool) Whether the page cache should be dropped. |
| 101 output_filename: (str) Output filename. '-' for stdout. | 123 output_filename: (str) Output filename. '-' for stdout. |
| 102 once: (bool) Run only once. | 124 once: (bool) Run only once. |
| 103 """ | 125 """ |
| 104 while True: | 126 while True: |
| 105 out = sys.stdout if output_filename == '-' else open(output_filename, 'a') | 127 out = sys.stdout if output_filename == '-' else open(output_filename, 'a') |
| 106 try: | 128 try: |
| 107 result = RunOnce(device, url, warmup, no_prerendering, | 129 result = RunOnce(device, url, warmup, prerender_mode, |
| 108 delay_to_may_launch_url, delay_to_launch_url, cold) | 130 delay_to_may_launch_url, delay_to_launch_url, cold) |
| 109 if result is not None: | 131 if result is not None: |
| 110 out.write(result + '\n') | 132 out.write(result + '\n') |
| 111 out.flush() | 133 out.flush() |
| 112 if once: | 134 if once: |
| 113 return | 135 return |
| 114 time.sleep(10) | 136 time.sleep(10) |
| 115 finally: | 137 finally: |
| 116 if output_filename != '-': | 138 if output_filename != '-': |
| 117 out.close() | 139 out.close() |
| 118 | 140 |
| 119 | 141 |
| 120 def ProcessOutput(filename): | 142 def ProcessOutput(filename): |
| 121 """Reads an output file, and returns a processed numpy array. | 143 """Reads an output file, and returns a processed numpy array. |
| 122 | 144 |
| 123 Args: | 145 Args: |
| 124 filename: (str) file to process. | 146 filename: (str) file to process. |
| 125 | 147 |
| 126 Returns: | 148 Returns: |
| 127 A numpy structured array. | 149 A numpy structured array. |
| 128 """ | 150 """ |
| 129 import numpy as np | 151 import numpy as np |
| 130 data = np.genfromtxt(filename, delimiter=',') | 152 data = np.genfromtxt(filename, delimiter=',') |
| 131 result = np.array(np.zeros(len(data)), | 153 result = np.array(np.zeros(len(data)), |
| 132 dtype=[('warmup', bool), ('no_prerendering', bool), | 154 dtype=[('warmup', bool), ('prerender_mode', np.int32), |
| 133 ('delay_to_may_launch_url', np.int32), | 155 ('delay_to_may_launch_url', np.int32), |
| 134 ('delay_to_launch_url', np.int32), | 156 ('delay_to_launch_url', np.int32), |
| 135 ('commit', np.int32), ('plt', np.int32)]) | 157 ('commit', np.int32), ('plt', np.int32)]) |
| 136 result['warmup'] = data[:, 0] | 158 result['warmup'] = data[:, 0] |
| 137 result['no_prerendering'] = data[:, 1] | 159 result['prerender_mode'] = data[:, 1] |
| 138 result['delay_to_may_launch_url'] = data[:, 2] | 160 result['delay_to_may_launch_url'] = data[:, 2] |
| 139 result['delay_to_launch_url'] = data[:, 3] | 161 result['delay_to_launch_url'] = data[:, 3] |
| 140 result['commit'] = data[:, 5] - data[:, 4] | 162 result['commit'] = data[:, 5] - data[:, 4] |
| 141 result['plt'] = data[:, 6] - data[:, 4] | 163 result['plt'] = data[:, 6] - data[:, 4] |
| 142 return result | 164 return result |
| 143 | 165 |
| 144 | 166 |
| 145 def _CreateOptionParser(): | 167 def _CreateOptionParser(): |
| 146 parser = optparse.OptionParser(description='Loops Custom Tabs tests on a ' | 168 parser = optparse.OptionParser(description='Loops Custom Tabs tests on a ' |
| 147 'device, and outputs the navigation timings ' | 169 'device, and outputs the navigation timings ' |
| 148 'in a CSV file.') | 170 'in a CSV file.') |
| 149 parser.add_option('--device', help='Device ID') | 171 parser.add_option('--device', help='Device ID') |
| 150 parser.add_option('--url', help='URL to navigate to.', | 172 parser.add_option('--url', help='URL to navigate to.', |
| 151 default='https://www.android.com') | 173 default='https://www.android.com') |
| 152 parser.add_option('--warmup', help='Call warmup.', default=False, | 174 parser.add_option('--warmup', help='Call warmup.', default=False, |
| 153 action='store_true') | 175 action='store_true') |
| 154 parser.add_option('--no_prerendering', help='Disable prerendering.', | 176 parser.add_option('--prerender_mode', default='enabled', |
| 155 default=False, action='store_true') | 177 help='The prerender mode (disabled, enabled or prefetch).', |
| 178 choices=['disabled', 'enabled', 'prefetch']) |
| 156 parser.add_option('--delay_to_may_launch_url', | 179 parser.add_option('--delay_to_may_launch_url', |
| 157 help='Delay before calling mayLaunchUrl() in ms.', | 180 help='Delay before calling mayLaunchUrl() in ms.', |
| 158 type='int') | 181 type='int') |
| 159 parser.add_option('--delay_to_launch_url', | 182 parser.add_option('--delay_to_launch_url', |
| 160 help='Delay before calling launchUrl() in ms.', | 183 help='Delay before calling launchUrl() in ms.', |
| 161 type='int') | 184 type='int') |
| 162 parser.add_option('--cold', help='Purge the page cache before each run.', | 185 parser.add_option('--cold', help='Purge the page cache before each run.', |
| 163 default=False, action='store_true') | 186 default=False, action='store_true') |
| 164 parser.add_option('--output_file', help='Output file (append). "-" for ' | 187 parser.add_option('--output_file', help='Output file (append). "-" for ' |
| 165 'stdout') | 188 'stdout') |
| (...skipping 10 matching lines...) Expand all Loading... |
| 176 device = devices[0] | 199 device = devices[0] |
| 177 if len(devices) != 1 and options.device is None: | 200 if len(devices) != 1 and options.device is None: |
| 178 logging.error('Several devices attached, must specify one with --device.') | 201 logging.error('Several devices attached, must specify one with --device.') |
| 179 sys.exit(0) | 202 sys.exit(0) |
| 180 if options.device is not None: | 203 if options.device is not None: |
| 181 matching_devices = [d for d in devices if str(d) == options.device] | 204 matching_devices = [d for d in devices if str(d) == options.device] |
| 182 if len(matching_devices) == 0: | 205 if len(matching_devices) == 0: |
| 183 logging.error('Device not found.') | 206 logging.error('Device not found.') |
| 184 sys.exit(0) | 207 sys.exit(0) |
| 185 device = matching_devices[0] | 208 device = matching_devices[0] |
| 186 LoopOnDevice(device, options.url, options.warmup, options.no_prerendering, | 209 |
| 187 options.delay_to_may_launch_url, options.delay_to_launch_url, | 210 with device_setup.FlagReplacer( |
| 188 options.cold, options.output_file, options.once) | 211 device, '/data/local/tmp/chrome-command-line', |
| 212 _CHROME_ARGS + ['--prerender=' + options.prerender_mode]): |
| 213 LoopOnDevice(device, options.url, options.warmup, |
| 214 options.prerender_mode, |
| 215 options.delay_to_may_launch_url, options.delay_to_launch_url, |
| 216 options.cold, options.output_file, options.once) |
| 189 | 217 |
| 190 | 218 |
| 191 if __name__ == '__main__': | 219 if __name__ == '__main__': |
| 192 main() | 220 main() |
| OLD | NEW |