[Session restore] Rename group name Enabled to Restore.
[chromium-blink-merge.git] / tools / perf / profile_creators / profile_generator.py
blob784f8aadf56d1e55666a292cb0ff5598ca507f9e
1 # Copyright 2014 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
5 """Handles generating profiles and transferring them to/from mobile devices."""
7 import logging
8 import optparse
9 import os
10 import shutil
11 import stat
12 import sys
13 import tempfile
15 from profile_creators import profile_extender
16 from telemetry.core import browser_options
17 from telemetry.core import discover
18 from telemetry.core import util
19 from telemetry.user_story import user_story_runner
22 def _DiscoverProfileExtenderClasses():
23 profile_extenders_dir = os.path.abspath(os.path.join(util.GetBaseDir(),
24 os.pardir, 'perf', 'profile_creators'))
25 base_dir = os.path.abspath(os.path.join(profile_extenders_dir, os.pardir))
27 profile_extenders_unfiltered = discover.DiscoverClasses(
28 profile_extenders_dir, base_dir, profile_extender.ProfileExtender)
30 # Remove 'extender' suffix from keys.
31 profile_extenders = {}
32 for test_name, test_class in profile_extenders_unfiltered.iteritems():
33 assert test_name.endswith('_extender')
34 test_name = test_name[:-len('_extender')]
35 profile_extenders[test_name] = test_class
36 return profile_extenders
39 def _IsPseudoFile(directory, paths):
40 """Filter function for shutil.copytree() to reject socket files and symlinks
41 since those can't be copied around on bots."""
42 def IsSocket(full_path):
43 """Check if a file at a given path is a socket."""
44 try:
45 if stat.S_ISSOCK(os.stat(full_path).st_mode):
46 return True
47 except OSError:
48 # Thrown if we encounter a broken symlink.
49 pass
50 return False
52 ignore_list = []
53 for path in paths:
54 full_path = os.path.join(directory, path)
56 if os.path.isdir(full_path):
57 continue
58 if not IsSocket(full_path) and not os.path.islink(full_path):
59 continue
61 logging.warning('Ignoring pseudo file: %s' % full_path)
62 ignore_list.append(path)
64 return ignore_list
67 def GenerateProfiles(profile_extender_class, profile_creator_name, options):
68 """Generate a profile"""
70 temp_output_directory = tempfile.mkdtemp()
71 options.output_profile_path = temp_output_directory
73 profile_creator_instance = profile_extender_class()
74 try:
75 profile_creator_instance.Run(options)
76 except Exception as e:
77 logging.exception('Profile creation failed.')
78 shutil.rmtree(temp_output_directory)
79 raise e
81 # Everything is a-ok, move results to final destination.
82 generated_profiles_dir = os.path.abspath(options.output_dir)
83 if not os.path.exists(generated_profiles_dir):
84 os.makedirs(generated_profiles_dir)
85 out_path = os.path.join(generated_profiles_dir, profile_creator_name)
86 if os.path.exists(out_path):
87 shutil.rmtree(out_path)
89 shutil.copytree(temp_output_directory, out_path, ignore=_IsPseudoFile)
90 shutil.rmtree(temp_output_directory)
91 sys.stderr.write("SUCCESS: Generated profile copied to: '%s'.\n" % out_path)
93 return 0
96 def AddCommandLineArgs(parser):
97 user_story_runner.AddCommandLineArgs(parser)
99 profile_extenders = _DiscoverProfileExtenderClasses().keys()
100 legal_profile_creators = '|'.join(profile_extenders)
101 group = optparse.OptionGroup(parser, 'Profile generation options')
102 group.add_option('--profile-type-to-generate',
103 dest='profile_type_to_generate',
104 default=None,
105 help='Type of profile to generate. '
106 'Supported values: %s' % legal_profile_creators)
107 parser.add_option_group(group)
110 def ProcessCommandLineArgs(parser, args):
111 user_story_runner.ProcessCommandLineArgs(parser, args)
113 if not args.profile_type_to_generate:
114 parser.error("Must specify --profile-type-to-generate option.")
116 profile_extenders = _DiscoverProfileExtenderClasses().keys()
117 if args.profile_type_to_generate not in profile_extenders:
118 legal_profile_creators = '|'.join(profile_extenders)
119 parser.error("Invalid profile type, legal values are: %s." %
120 legal_profile_creators)
122 if not args.browser_type:
123 parser.error("Must specify --browser option.")
125 if not args.output_dir:
126 parser.error("Must specify --output-dir option.")
128 if args.browser_options.dont_override_profile:
129 parser.error("Can't use existing profile when generating profile.")
132 def Main():
133 options = browser_options.BrowserFinderOptions()
134 parser = options.CreateParser(
135 "%%prog <--profile-type-to-generate=...> <--browser=...> <--output-dir>")
136 AddCommandLineArgs(parser)
137 _, _ = parser.parse_args()
138 ProcessCommandLineArgs(parser, options)
140 # Generate profile.
141 profile_extenders = _DiscoverProfileExtenderClasses()
142 profile_extender_class = profile_extenders[options.profile_type_to_generate]
143 return GenerateProfiles(profile_extender_class,
144 options.profile_type_to_generate, options)