Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / tools / telemetry / telemetry / benchmark.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 import logging
6 import optparse
7 import os
8 import shutil
9 import sys
10 import zipfile
11
12 from telemetry import decorators
13 from telemetry.core import browser_finder
14 from telemetry.core import command_line
15 from telemetry.core import util
16 from telemetry.page import page_runner
17 from telemetry.page import page_set
18 from telemetry.page import page_test
19 from telemetry.page import test_expectations
20 from telemetry.results import results_options
21 from telemetry.util import cloud_storage
22
23 Disabled = decorators.Disabled
24 Enabled = decorators.Enabled
25
26
27 class InvalidOptionsError(Exception):
28   """Raised for invalid benchmark options."""
29   pass
30
31
32 class BenchmarkMetadata(object):
33   def __init__(self, name):
34     self._name = name
35
36   @property
37   def name(self):
38     return self._name
39
40 class Benchmark(command_line.Command):
41   """Base class for a Telemetry benchmark.
42
43   A test packages a PageTest and a PageSet together.
44   """
45   options = {}
46
47   @classmethod
48   def Name(cls):
49     name = cls.__module__.split('.')[-1]
50     if hasattr(cls, 'tag'):
51       name += '.' + cls.tag
52     if hasattr(cls, 'page_set'):
53       name += '.' + cls.page_set.Name()
54     return name
55
56   @classmethod
57   def AddCommandLineArgs(cls, parser):
58     cls.PageTestClass().AddCommandLineArgs(parser)
59
60     if hasattr(cls, 'AddTestCommandLineArgs'):
61       group = optparse.OptionGroup(parser, '%s test options' % cls.Name())
62       cls.AddTestCommandLineArgs(group)
63       parser.add_option_group(group)
64
65   @classmethod
66   def SetArgumentDefaults(cls, parser):
67     cls.PageTestClass().SetArgumentDefaults(parser)
68     default_values = parser.get_default_values()
69     invalid_options = [
70         o for o in cls.options if not hasattr(default_values, o)]
71     if invalid_options:
72       raise InvalidOptionsError('Invalid benchmark options: %s',
73                                 ', '.join(invalid_options))
74     parser.set_defaults(**cls.options)
75
76   @classmethod
77   def ProcessCommandLineArgs(cls, parser, args):
78     cls.PageTestClass().ProcessCommandLineArgs(parser, args)
79
80   def CustomizeBrowserOptions(self, options):
81     """Add browser options that are required by this benchmark."""
82
83   def GetMetadata(self):
84     return BenchmarkMetadata(self.Name())
85
86   def Run(self, finder_options):
87     """Run this test with the given options."""
88     self.CustomizeBrowserOptions(finder_options.browser_options)
89
90     pt = self.PageTestClass()()
91     pt.__name__ = self.__class__.__name__
92
93     if hasattr(self, '_disabled_strings'):
94       pt._disabled_strings = self._disabled_strings
95     if hasattr(self, '_enabled_strings'):
96       pt._enabled_strings = self._enabled_strings
97
98     expectations = self.CreateExpectations()
99     us = self.CreateUserStorySet(finder_options)
100
101     self._DownloadGeneratedProfileArchive(finder_options)
102
103     benchmark_metadata = self.GetMetadata()
104     results = results_options.CreateResults(benchmark_metadata, finder_options)
105     try:
106       page_runner.Run(pt, us, expectations, finder_options, results)
107     except page_test.TestNotSupportedOnPlatformFailure as failure:
108       logging.warning(str(failure))
109
110     results.PrintSummary()
111     return len(results.failures)
112
113   def _DownloadGeneratedProfileArchive(self, options):
114     """Download and extract profile directory archive if one exists."""
115     archive_name = getattr(self, 'generated_profile_archive', None)
116
117     # If attribute not specified, nothing to do.
118     if not archive_name:
119       return
120
121     # If profile dir specified on command line, nothing to do.
122     if options.browser_options.profile_dir:
123       logging.warning("Profile directory specified on command line: %s, this"
124           "overrides the benchmark's default profile directory.",
125           options.browser_options.profile_dir)
126       return
127
128     # Download profile directory from cloud storage.
129     found_browser = browser_finder.FindBrowser(options)
130     test_data_dir = os.path.join(util.GetChromiumSrcDir(), 'tools', 'perf',
131         'generated_profiles',
132         found_browser.target_os)
133     generated_profile_archive_path = os.path.normpath(
134         os.path.join(test_data_dir, archive_name))
135
136     try:
137       cloud_storage.GetIfChanged(generated_profile_archive_path,
138           cloud_storage.PUBLIC_BUCKET)
139     except (cloud_storage.CredentialsError,
140             cloud_storage.PermissionError) as e:
141       if os.path.exists(generated_profile_archive_path):
142         # If the profile directory archive exists, assume the user has their
143         # own local copy simply warn.
144         logging.warning('Could not download Profile archive: %s',
145             generated_profile_archive_path)
146       else:
147         # If the archive profile directory doesn't exist, this is fatal.
148         logging.error('Can not run without required profile archive: %s. '
149                       'If you believe you have credentials, follow the '
150                       'instructions below.',
151                       generated_profile_archive_path)
152         logging.error(str(e))
153         sys.exit(-1)
154
155     # Unzip profile directory.
156     extracted_profile_dir_path = (
157         os.path.splitext(generated_profile_archive_path)[0])
158     if not os.path.isfile(generated_profile_archive_path):
159       raise Exception("Profile directory archive not downloaded: ",
160           generated_profile_archive_path)
161     with zipfile.ZipFile(generated_profile_archive_path) as f:
162       try:
163         f.extractall(os.path.dirname(generated_profile_archive_path))
164       except e:
165         # Cleanup any leftovers from unzipping.
166         if os.path.exists(extracted_profile_dir_path):
167           shutil.rmtree(extracted_profile_dir_path)
168         logging.error("Error extracting profile directory zip file: %s", e)
169         sys.exit(-1)
170
171     # Run with freshly extracted profile directory.
172     logging.info("Using profile archive directory: %s",
173         extracted_profile_dir_path)
174     options.browser_options.profile_dir = extracted_profile_dir_path
175
176   @classmethod
177   def PageTestClass(cls):
178     """Get the PageTest for this Benchmark.
179
180     If the Benchmark has no PageTest, raises NotImplementedError.
181     """
182     if not hasattr(cls, 'test'):
183       raise NotImplementedError('This test has no "test" attribute.')
184     if not issubclass(cls.test, page_test.PageTest):
185       raise TypeError('"%s" is not a PageTest.' % cls.test.__name__)
186     return cls.test
187
188   def CreatePageSet(self, options):  # pylint: disable=W0613
189     """Get the page set this test will run on.
190
191     By default, it will create a page set from the this test's page_set
192     attribute. Override to generate a custom page set.
193     """
194     if not hasattr(self, 'page_set'):
195       raise NotImplementedError('This test has no "page_set" attribute.')
196     if not issubclass(self.page_set, page_set.PageSet):
197       raise TypeError('"%s" is not a PageSet.' % self.page_set.__name__)
198     return self.page_set()
199
200   def CreateUserStorySet(self, options):
201     return self.CreatePageSet(options)
202
203   @classmethod
204   def CreateExpectations(cls):
205     """Get the expectations this test will run with.
206
207     By default, it will create an empty expectations set. Override to generate
208     custom expectations.
209     """
210     return test_expectations.TestExpectations()
211
212
213 def AddCommandLineArgs(parser):
214   page_runner.AddCommandLineArgs(parser)
215
216
217 def ProcessCommandLineArgs(parser, args):
218   page_runner.ProcessCommandLineArgs(parser, args)