blob: 66e3e3ab8001723807fce3e2bd92f0bd734636c2 [file] [log] [blame]
# Copyright 2014 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.
"""Handles generating profiles and transferring them to/from mobile devices."""
import logging
import optparse
import os
import shutil
import stat
import sys
import tempfile
from telemetry import benchmark
from telemetry.core import browser_options
from telemetry.core import discover
from telemetry.core import util
from telemetry.page import page_runner
from telemetry.page import profile_creator
from telemetry.page import test_expectations
from telemetry.results import results_options
def _DiscoverProfileCreatorClasses():
profile_creators_dir = os.path.abspath(os.path.join(util.GetBaseDir(),
os.pardir, 'perf', 'profile_creators'))
base_dir = os.path.abspath(os.path.join(profile_creators_dir, os.pardir))
profile_creators_unfiltered = discover.DiscoverClasses(
profile_creators_dir, base_dir, profile_creator.ProfileCreator)
# Remove '_creator' suffix from keys.
profile_creators = {}
for test_name, test_class in profile_creators_unfiltered.iteritems():
assert test_name.endswith('_creator')
test_name = test_name[:-len('_creator')]
profile_creators[test_name] = test_class
return profile_creators
def _IsPseudoFile(directory, paths):
"""Filter function for shutil.copytree() to reject socket files and symlinks
since those can't be copied around on bots."""
def IsSocket(full_path):
"""Check if a file at a given path is a socket."""
try:
if stat.S_ISSOCK(os.stat(full_path).st_mode):
return True
except OSError:
# Thrown if we encounter a broken symlink.
pass
return False
ignore_list = []
for path in paths:
full_path = os.path.join(directory, path)
if os.path.isdir(full_path):
continue
if not IsSocket(full_path) and not os.path.islink(full_path):
continue
logging.warning('Ignoring pseudo file: %s' % full_path)
ignore_list.append(path)
return ignore_list
def GenerateProfiles(profile_creator_class, profile_creator_name, options):
"""Generate a profile"""
expectations = test_expectations.TestExpectations()
test = profile_creator_class()
temp_output_directory = tempfile.mkdtemp()
options.output_profile_path = temp_output_directory
results = results_options.CreateResults(
benchmark.BenchmarkMetadata(test.__class__.__name__), options)
page_runner.Run(test, test.page_set, expectations, options, results)
if results.failures:
logging.warning('Some pages failed.')
logging.warning('Failed pages:\n%s',
'\n'.join(results.pages_that_failed))
return 1
# Everything is a-ok, move results to final destination.
generated_profiles_dir = os.path.abspath(options.output_dir)
if not os.path.exists(generated_profiles_dir):
os.makedirs(generated_profiles_dir)
out_path = os.path.join(generated_profiles_dir, profile_creator_name)
if os.path.exists(out_path):
shutil.rmtree(out_path)
shutil.copytree(temp_output_directory, out_path, ignore=_IsPseudoFile)
shutil.rmtree(temp_output_directory)
sys.stderr.write("SUCCESS: Generated profile copied to: '%s'.\n" % out_path)
return 0
def AddCommandLineArgs(parser):
page_runner.AddCommandLineArgs(parser)
profile_creators = _DiscoverProfileCreatorClasses().keys()
legal_profile_creators = '|'.join(profile_creators)
group = optparse.OptionGroup(parser, 'Profile generation options')
group.add_option('--profile-type-to-generate',
dest='profile_type_to_generate',
default=None,
help='Type of profile to generate. '
'Supported values: %s' % legal_profile_creators)
group.add_option('--output-dir',
dest='output_dir',
help='Generated profile is placed in this directory.')
parser.add_option_group(group)
def ProcessCommandLineArgs(parser, args):
page_runner.ProcessCommandLineArgs(parser, args)
if not args.profile_type_to_generate:
parser.error("Must specify --profile-type-to-generate option.")
profile_creators = _DiscoverProfileCreatorClasses().keys()
if args.profile_type_to_generate not in profile_creators:
legal_profile_creators = '|'.join(profile_creators)
parser.error("Invalid profile type, legal values are: %s." %
legal_profile_creators)
if not args.browser_type:
parser.error("Must specify --browser option.")
if not args.output_dir:
parser.error("Must specify --output-dir option.")
if args.browser_options.dont_override_profile:
parser.error("Can't use existing profile when generating profile.")
def Main():
options = browser_options.BrowserFinderOptions()
parser = options.CreateParser(
"%%prog <--profile-type-to-generate=...> <--browser=...> <--output-dir>")
AddCommandLineArgs(parser)
_, _ = parser.parse_args()
ProcessCommandLineArgs(parser, options)
# Generate profile.
profile_creators = _DiscoverProfileCreatorClasses()
profile_creator_class = profile_creators[options.profile_type_to_generate]
return GenerateProfiles(profile_creator_class,
options.profile_type_to_generate, options)