blob: 56f48bc4f2cf2984f9842e2174e7d5013bc0ccc7 [file] [log] [blame]
#!/usr/bin/python
#
# Copyright 2015 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.
"""Loops Custom Tabs tests and outputs the results into a CSV file."""
import logging
import optparse
import os
import re
import sys
import time
_SRC_PATH = os.path.abspath(os.path.join(
os.path.dirname(__file__), '..', '..'))
sys.path.append(os.path.join(_SRC_PATH, 'third_party', 'catapult', 'devil'))
from devil.android import device_errors
from devil.android import device_utils
from devil.android.perf import cache_control
from devil.android.sdk import intent
sys.path.append(os.path.join(_SRC_PATH, 'build', 'android'))
import devil_chromium
def RunOnce(device, url, warmup, no_prerendering, delay_to_may_launch_url,
delay_to_launch_url, cold):
"""Runs a test on a device once.
Args:
device: (DeviceUtils) device to run the tests on.
warmup: (bool) Whether to call warmup.
no_prerendering: (bool) Whether to disable prerendering.
delay_to_may_launch_url: (int) Delay to mayLaunchUrl() in ms.
delay_to_launch_url: (int) Delay to launchUrl() in ms.
cold: (bool) Whether the page cache should be dropped.
Returns:
The output line (str), like this (one line only):
<warmup>,<no_prerendering>,<delay_to_may_launch_url>,<intent_sent_ms>,
<page_load_started_ms>,<page_load_finished_ms>
or None on error.
"""
launch_intent = intent.Intent(
action='android.intent.action.MAIN',
package='org.chromium.customtabsclient.test',
activity='org.chromium.customtabs.test.MainActivity',
extras={'url': url, 'warmup': warmup, 'no_prerendering': no_prerendering,
'delay_to_may_launch_url': delay_to_may_launch_url,
'delay_to_launch_url': delay_to_launch_url})
result_line_re = re.compile(r'W/CUSTOMTABSBENCH.*: (.*)')
logcat_monitor = device.GetLogcatMonitor(clear=True)
logcat_monitor.Start()
device.ForceStop('com.google.android.apps.chrome')
device.ForceStop('org.chromium.customtabsclient.test')
if cold:
if not device.HasRoot():
device.EnableRoot()
cache_control.CacheControl(device).DropRamCaches()
device.StartActivity(launch_intent, blocking=True)
match = None
try:
match = logcat_monitor.WaitFor(result_line_re, timeout=10)
except device_errors.CommandTimeoutError as e:
logging.warning('Timeout waiting for the result line')
return match.group(1) if match is not None else None
def LoopOnDevice(device, url, warmup, no_prerendering, delay_to_may_launch_url,
delay_to_launch_url, cold, output_filename, once=False):
"""Loops the tests on a device.
Args:
device: (DeviceUtils) device to run the tests on.
url: (str) URL to navigate to.
warmup: (bool) Whether to call warmup.
no_prerendering: (bool) Whether to disable prerendering.
delay_to_may_launch_url: (int) Delay to mayLaunchUrl() in ms.
delay_to_launch_url: (int) Delay to launchUrl() in ms.
cold: (bool) Whether the page cache should be dropped.
output_filename: (str) Output filename. '-' for stdout.
once: (bool) Run only once.
"""
while True:
out = sys.stdout if output_filename == '-' else open(output_filename, 'a')
try:
result = RunOnce(device, url, warmup, no_prerendering,
delay_to_may_launch_url, delay_to_launch_url, cold)
if result is not None:
out.write(result + '\n')
out.flush()
if once:
return
time.sleep(10)
finally:
if output_filename != '-':
out.close()
def ProcessOutput(filename):
"""Reads an output file, and returns a processed numpy array.
Args:
filename: (str) file to process.
Returns:
A numpy structured array.
"""
import numpy as np
data = np.genfromtxt(filename, delimiter=',')
result = np.array(np.zeros(len(data)),
dtype=[('warmup', bool), ('no_prerendering', bool),
('delay_to_may_launch_url', np.int32),
('delay_to_launch_url', np.int32),
('commit', np.int32), ('plt', np.int32)])
result['warmup'] = data[:, 0]
result['no_prerendering'] = data[:, 1]
result['delay_to_may_launch_url'] = data[:, 2]
result['delay_to_launch_url'] = data[:, 3]
result['commit'] = data[:, 5] - data[:, 4]
result['plt'] = data[:, 6] - data[:, 4]
return result
def _CreateOptionParser():
parser = optparse.OptionParser(description='Loops Custom Tabs tests on a '
'device, and outputs the navigation timings '
'in a CSV file.')
parser.add_option('--device', help='Device ID')
parser.add_option('--url', help='URL to navigate to.',
default='https://www.android.com')
parser.add_option('--warmup', help='Call warmup.', default=False,
action='store_true')
parser.add_option('--no_prerendering', help='Disable prerendering.',
default=False, action='store_true')
parser.add_option('--delay_to_may_launch_url',
help='Delay before calling mayLaunchUrl() in ms.',
type='int')
parser.add_option('--delay_to_launch_url',
help='Delay before calling launchUrl() in ms.',
type='int')
parser.add_option('--cold', help='Purge the page cache before each run.',
default=False, action='store_true')
parser.add_option('--output_file', help='Output file (append). "-" for '
'stdout')
parser.add_option('--once', help='Run only one iteration.',
action='store_true', default=False)
return parser
def main():
parser = _CreateOptionParser()
options, _ = parser.parse_args()
devil_chromium.Initialize()
devices = device_utils.DeviceUtils.HealthyDevices()
device = devices[0]
if len(devices) != 1 and options.device is None:
logging.error('Several devices attached, must specify one with --device.')
sys.exit(0)
if options.device is not None:
matching_devices = [d for d in devices if str(d) == options.device]
if len(matching_devices) == 0:
logging.error('Device not found.')
sys.exit(0)
device = matching_devices[0]
LoopOnDevice(device, options.url, options.warmup, options.no_prerendering,
options.delay_to_may_launch_url, options.delay_to_launch_url,
options.cold, options.output_file, options.once)
if __name__ == '__main__':
main()