blob: 2e291d7709135a5186f132fbe67de5443c5f1e8a [file] [log] [blame]
#!/usr/bin/python
#
# Copyright 2016 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.
"""Loads a web page with speculative prefetch, and collects loading metrics."""
import argparse
import logging
import os
import random
import sys
import time
_SRC_PATH = os.path.abspath(os.path.join(
os.path.dirname(__file__), os.pardir, os.pardir))
sys.path.append(os.path.join(
_SRC_PATH, 'tools', 'android', 'customtabs_benchmark', 'scripts'))
import customtabs_benchmark
import chrome_setup
import device_setup
sys.path.append(os.path.join(_SRC_PATH, 'tools', 'android', 'loading'))
import controller
from options import OPTIONS
sys.path.append(os.path.join(_SRC_PATH, 'build', 'android'))
import devil_chromium
sys.path.append(os.path.join(_SRC_PATH, 'third_party', 'catapult', 'devil'))
from devil.android import flag_changer
from devil.android.sdk import intent
import prefetch_predictor_common
def _CreateArgumentParser():
"""Creates and returns the argument parser."""
parser = argparse.ArgumentParser(
('Loads a URL with the resource_prefetch_predictor and prints loading '
'metrics.'), parents=[OPTIONS.GetParentParser()])
parser.add_argument('--device', help='Device ID')
parser.add_argument('--database',
help=('File containing the predictor database, as '
'obtained from generate_database.py.'))
parser.add_argument('--url', help='URL to load.')
parser.add_argument('--prefetch_delays_ms',
help='List of prefetch delays in ms. -1 to disable '
'prefetch. Runs will randomly select one delay in the '
'list.')
parser.add_argument('--output_filename',
help='CSV file to append the result to.')
parser.add_argument('--network_condition',
help='Network condition for emulation.')
parser.add_argument('--wpr_archive', help='WPR archive path.')
parser.add_argument('--once', help='Only run once.', action='store_true')
return parser
def _Setup(device, database_filename):
"""Sets up a device and returns an instance of RemoteChromeController."""
chrome_controller = prefetch_predictor_common.Setup(device)
chrome_package = OPTIONS.ChromePackage()
device.ForceStop(chrome_package.package)
chrome_controller.ResetBrowserState()
device_database_filename = prefetch_predictor_common.DatabaseDevicePath()
owner = group = None
# Make sure that the speculative prefetch predictor is enabled to ensure
# that the disk database is re-created.
with flag_changer.CustomCommandLineFlags(
device, chrome_package.cmdline_file, ['--disable-fre']):
# Launch Chrome for the first time to recreate the local state.
launch_intent = intent.Intent(
action='android.intent.action.MAIN',
package=chrome_package.package,
activity=chrome_package.activity)
device.StartActivity(launch_intent, blocking=True)
time.sleep(5)
device.ForceStop(chrome_package.package)
assert device.FileExists(device_database_filename)
stats = device.StatPath(device_database_filename)
owner = stats['st_owner']
group = stats['st_group']
# Now push the database. Needs to be done after the first launch, otherwise
# the profile directory is owned by root. Also change the owner of the
# database, since adb push sets it to root.
database_content = open(database_filename, 'r').read()
device.WriteFile(device_database_filename, database_content, force_push=True)
device.RunShellCommand(
['chown', '%s:%s' % (owner, group), device_database_filename],
as_root=True, check_return=True)
def _RunOnce(device, database_filename, url, prefetch_delay_ms,
output_filename, wpr_archive, network_condition):
_Setup(device, database_filename)
disable_prefetch = prefetch_delay_ms == -1
# Startup tracing to ease debugging.
chrome_args = (chrome_setup.CHROME_ARGS
+ ['--trace-startup', '--trace-startup-duration=20'])
# Speculative Prefetch is enabled through an experiment.
chrome_args.extend([
'--force-fieldtrials=trial/group',
'--force-fieldtrial-params=trial.group:mode/external-prefetching',
'--enable-features=SpeculativeResourcePrefetching<trial'])
chrome_controller = controller.RemoteChromeController(device)
device.ForceStop(OPTIONS.ChromePackage().package)
chrome_controller.AddChromeArguments(chrome_args)
with device_setup.RemoteWprHost(
device, wpr_archive, record=False,
network_condition_name=network_condition) as wpr:
logging.info('WPR arguments: ' + ' '.join(wpr.chrome_args))
chrome_args += wpr.chrome_args
prefetch_mode = 'disabled' if disable_prefetch else 'speculative_prefetch'
result = customtabs_benchmark.RunOnce(
device, url, warmup=True, speculation_mode=prefetch_mode,
delay_to_may_launch_url=2000,
delay_to_launch_url=prefetch_delay_ms, cold=False,
chrome_args=chrome_args, reset_chrome_state=False)
data_point = customtabs_benchmark.ParseResult(result)
with open(output_filename, 'a') as f:
f.write(','.join(str(x) for x in data_point) + '\n')
def main():
logging.basicConfig(level=logging.INFO)
devil_chromium.Initialize()
parser = _CreateArgumentParser()
args = parser.parse_args()
OPTIONS.SetParsedArgs(args)
if os.path.exists(args.output_filename):
logging.error('Output file %s already exists.' % args.output_filename)
sys.exit(1)
device = prefetch_predictor_common.FindDevice(args.device)
if device is None:
logging.error('Could not find device: %s.', args.device)
sys.exit(1)
delays = [int(x) for x in args.prefetch_delays_ms.split(',')]
with open(args.output_filename, 'w') as f:
f.write(','.join(customtabs_benchmark.RESULT_FIELDS) + '\n')
while True:
delay = delays[random.randint(0, len(delays) - 1)]
_RunOnce(device, args.database, args.url, delay, args.output_filename,
args.wpr_archive, args.network_condition)
if args.once:
return
if __name__ == '__main__':
main()