Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / tools / telemetry / telemetry / page / profile_generator.py
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.
4
5 """Handles generating profiles and transferring them to/from mobile devices."""
6
7 import logging
8 import optparse
9 import os
10 import shutil
11 import stat
12 import sys
13 import tempfile
14
15 from telemetry import benchmark
16 from telemetry.core import browser_options
17 from telemetry.core import discover
18 from telemetry.core import util
19 from telemetry.page import page_runner
20 from telemetry.page import profile_creator
21 from telemetry.page import test_expectations
22 from telemetry.results import results_options
23
24
25 def _DiscoverProfileCreatorClasses():
26   profile_creators_dir = os.path.abspath(os.path.join(util.GetBaseDir(),
27       os.pardir, 'perf', 'profile_creators'))
28   base_dir = os.path.abspath(os.path.join(profile_creators_dir, os.pardir))
29
30   profile_creators_unfiltered = discover.DiscoverClasses(
31       profile_creators_dir, base_dir, profile_creator.ProfileCreator)
32
33   # Remove '_creator' suffix from keys.
34   profile_creators = {}
35   for test_name, test_class in profile_creators_unfiltered.iteritems():
36     assert test_name.endswith('_creator')
37     test_name = test_name[:-len('_creator')]
38     profile_creators[test_name] = test_class
39   return profile_creators
40
41
42 def _IsPseudoFile(directory, paths):
43   """Filter function for shutil.copytree() to reject socket files and symlinks
44   since those can't be copied around on bots."""
45   def IsSocket(full_path):
46     """Check if a file at a given path is a socket."""
47     try:
48       if stat.S_ISSOCK(os.stat(full_path).st_mode):
49         return True
50     except OSError:
51       # Thrown if we encounter a broken symlink.
52       pass
53     return False
54
55   ignore_list = []
56   for path in paths:
57     full_path = os.path.join(directory, path)
58
59     if os.path.isdir(full_path):
60       continue
61     if not IsSocket(full_path) and not os.path.islink(full_path):
62       continue
63
64     logging.warning('Ignoring pseudo file: %s' % full_path)
65     ignore_list.append(path)
66
67   return ignore_list
68
69 def GenerateProfiles(profile_creator_class, profile_creator_name, options):
70   """Generate a profile"""
71   expectations = test_expectations.TestExpectations()
72   test = profile_creator_class()
73
74   temp_output_directory = tempfile.mkdtemp()
75   options.output_profile_path = temp_output_directory
76
77   results = results_options.CreateResults(
78       benchmark.BenchmarkMetadata(test.__class__.__name__), options)
79   page_runner.Run(test, test.page_set, expectations, options, results)
80
81   if results.failures:
82     logging.warning('Some pages failed.')
83     logging.warning('Failed pages:\n%s',
84                     '\n'.join(results.pages_that_failed))
85     return 1
86
87   # Everything is a-ok, move results to final destination.
88   generated_profiles_dir = os.path.abspath(options.output_dir)
89   if not os.path.exists(generated_profiles_dir):
90     os.makedirs(generated_profiles_dir)
91   out_path = os.path.join(generated_profiles_dir, profile_creator_name)
92   if os.path.exists(out_path):
93     shutil.rmtree(out_path)
94
95   shutil.copytree(temp_output_directory, out_path, ignore=_IsPseudoFile)
96   shutil.rmtree(temp_output_directory)
97   sys.stderr.write("SUCCESS: Generated profile copied to: '%s'.\n" % out_path)
98
99   return 0
100
101
102 def AddCommandLineArgs(parser):
103   page_runner.AddCommandLineArgs(parser)
104
105   profile_creators = _DiscoverProfileCreatorClasses().keys()
106   legal_profile_creators = '|'.join(profile_creators)
107   group = optparse.OptionGroup(parser, 'Profile generation options')
108   group.add_option('--profile-type-to-generate',
109       dest='profile_type_to_generate',
110       default=None,
111       help='Type of profile to generate. '
112            'Supported values: %s' % legal_profile_creators)
113   group.add_option('--output-dir',
114       dest='output_dir',
115       help='Generated profile is placed in this directory.')
116   parser.add_option_group(group)
117
118
119 def ProcessCommandLineArgs(parser, args):
120   page_runner.ProcessCommandLineArgs(parser, args)
121
122   if not args.profile_type_to_generate:
123     parser.error("Must specify --profile-type-to-generate option.")
124
125   profile_creators = _DiscoverProfileCreatorClasses().keys()
126   if args.profile_type_to_generate not in profile_creators:
127     legal_profile_creators = '|'.join(profile_creators)
128     parser.error("Invalid profile type, legal values are: %s." %
129         legal_profile_creators)
130
131   if not args.browser_type:
132     parser.error("Must specify --browser option.")
133
134   if not args.output_dir:
135     parser.error("Must specify --output-dir option.")
136
137   if args.browser_options.dont_override_profile:
138     parser.error("Can't use existing profile when generating profile.")
139
140
141 def Main():
142   options = browser_options.BrowserFinderOptions()
143   parser = options.CreateParser(
144       "%%prog <--profile-type-to-generate=...> <--browser=...> <--output-dir>")
145   AddCommandLineArgs(parser)
146   _, _ = parser.parse_args()
147   ProcessCommandLineArgs(parser, options)
148
149   # Generate profile.
150   profile_creators = _DiscoverProfileCreatorClasses()
151   profile_creator_class = profile_creators[options.profile_type_to_generate]
152   return GenerateProfiles(profile_creator_class,
153       options.profile_type_to_generate, options)