summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/perf/page_sets/top_25.json8
-rw-r--r--tools/perf/perf_tools/memory_benchmark.py26
-rw-r--r--tools/telemetry/telemetry/all_page_interactions.py20
-rw-r--r--tools/telemetry/telemetry/browser_options.py4
-rw-r--r--tools/telemetry/telemetry/click_to_navigate_interaction.py4
-rw-r--r--tools/telemetry/telemetry/compound_interaction.py15
-rw-r--r--tools/telemetry/telemetry/compound_interaction_unittest.py5
-rw-r--r--tools/telemetry/telemetry/discover.py40
-rw-r--r--tools/telemetry/telemetry/inspector_page_unittest.py7
-rw-r--r--tools/telemetry/telemetry/multi_page_benchmark.py6
-rwxr-xr-xtools/telemetry/telemetry/multi_page_benchmark_runner.py47
-rw-r--r--tools/telemetry/telemetry/multi_page_benchmark_unittest.py24
-rw-r--r--tools/telemetry/telemetry/multi_page_benchmark_unittest_base.py2
-rw-r--r--tools/telemetry/telemetry/page_interaction.py11
-rw-r--r--tools/telemetry/telemetry/page_runner.py7
-rw-r--r--tools/telemetry/telemetry/page_test.py45
16 files changed, 197 insertions, 74 deletions
diff --git a/tools/perf/page_sets/top_25.json b/tools/perf/page_sets/top_25.json
index 7ffa9f9..8ae04c3 100644
--- a/tools/perf/page_sets/top_25.json
+++ b/tools/perf/page_sets/top_25.json
@@ -61,18 +61,18 @@
"credentials": "facebook",
"scroll_is_infinite": true,
"stress_memory": {
- "action": "compound",
+ "action": "compound_interaction",
"actions": [
{
- "action": "click_to_navigate",
+ "action": "click_to_navigate_interaction",
"selector": "a[href=\"http://www.facebook.com/WomenforObama\"]"
},
{
- "action": "click_to_navigate",
+ "action": "click_to_navigate_interaction",
"selector": "a[href=\"http://www.facebook.com/WomenforObama/info\"]"
},
{
- "action": "click_to_navigate",
+ "action": "click_to_navigate_interaction",
"selector": "a[href=\"http://www.facebook.com/?ref=tn_tnmn\"]"
}
]
diff --git a/tools/perf/perf_tools/memory_benchmark.py b/tools/perf/perf_tools/memory_benchmark.py
new file mode 100644
index 0000000..c3e974b
--- /dev/null
+++ b/tools/perf/perf_tools/memory_benchmark.py
@@ -0,0 +1,26 @@
+# Copyright (c) 2012 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.
+from telemetry import multi_page_benchmark
+
+MEMORY_HISTOGRAMS = [
+ {'name': 'V8.MemoryExternalFragmentationTotal', 'units': 'percent'},
+ {'name': 'V8.MemoryHeapSampleTotalCommitted', 'units': 'kb'},
+ {'name': 'V8.MemoryHeapSampleTotalUsed', 'units': 'kb'}]
+
+class MemoryBenchmark(multi_page_benchmark.MultiPageBenchmark):
+ def __init__(self):
+ super(MemoryBenchmark, self).__init__('stress_memory')
+
+ def CustomizeBrowserOptions(self, options):
+ options.AppendExtraBrowserArg('--dom-automation')
+
+ def CanRunForPage(self, page):
+ return hasattr(page, 'stress_memory')
+
+ def MeasurePage(self, page, tab, results):
+ for histogram in MEMORY_HISTOGRAMS:
+ name = histogram['name']
+ data = tab.runtime.Evaluate(
+ 'window.domAutomationController.getHistogram("%s")' % name)
+ results.Add(name, histogram['units'], data, data_type='histogram')
diff --git a/tools/telemetry/telemetry/all_page_interactions.py b/tools/telemetry/telemetry/all_page_interactions.py
new file mode 100644
index 0000000..1e7d29f
--- /dev/null
+++ b/tools/telemetry/telemetry/all_page_interactions.py
@@ -0,0 +1,20 @@
+# Copyright (c) 2012 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.
+import os
+
+from telemetry import discover
+from telemetry import page_interaction
+
+_page_interaction_classes = discover.Discover(os.path.dirname(__file__),
+ 'interaction',
+ page_interaction.PageInteraction)
+
+def GetAllClasses():
+ return list(_page_interaction_classes.values())
+
+def FindClassWithName(name):
+ return _page_interaction_classes.get(name)
+
+def RegisterClassForTest(name, clazz):
+ _page_interaction_classes[name] = clazz
diff --git a/tools/telemetry/telemetry/browser_options.py b/tools/telemetry/telemetry/browser_options.py
index 25eff1f..01601c4 100644
--- a/tools/telemetry/telemetry/browser_options.py
+++ b/tools/telemetry/telemetry/browser_options.py
@@ -146,3 +146,7 @@ class BrowserOptions(optparse.Values):
return ret
parser.parse_args = ParseArgs
return parser
+
+ def AppendExtraBrowserArg(self, arg):
+ if arg not in self.extra_browser_args:
+ self.extra_browser_args.append(arg)
diff --git a/tools/telemetry/telemetry/click_to_navigate_interaction.py b/tools/telemetry/telemetry/click_to_navigate_interaction.py
index 0360fd8..3eafcf8 100644
--- a/tools/telemetry/telemetry/click_to_navigate_interaction.py
+++ b/tools/telemetry/telemetry/click_to_navigate_interaction.py
@@ -13,6 +13,4 @@ class ClickToNavigateInteraction(page_interaction.PageInteraction):
def DoClick():
tab.runtime.Execute(code)
tab.page.PerformActionAndWaitForNavigate(DoClick)
-
-
-page_interaction.RegisterClass('click_to_navigate', ClickToNavigateInteraction)
+ tab.WaitForDocumentReadyStateToBeComplete()
diff --git a/tools/telemetry/telemetry/compound_interaction.py b/tools/telemetry/telemetry/compound_interaction.py
index 2ff48b0..5e93cf8 100644
--- a/tools/telemetry/telemetry/compound_interaction.py
+++ b/tools/telemetry/telemetry/compound_interaction.py
@@ -6,12 +6,17 @@ from telemetry import page_interaction
class CompoundInteraction(page_interaction.PageInteraction):
def __init__(self, attributes=None):
super(CompoundInteraction, self).__init__(attributes)
-
- def PerformInteraction(self, page, tab):
+ self._interaction_list = []
+ from telemetry import all_page_interactions
for interaction_data in self.actions:
- interaction = page_interaction.FindClassWithName(
+ interaction = all_page_interactions.FindClassWithName(
interaction_data['action'])(interaction_data)
- interaction.PerformInteraction(page, tab)
+ self._interaction_list.append(interaction)
+ def CustomizeBrowserOptions(self, options):
+ for interaction in self._interaction_list:
+ interaction.CustomizeBrowserOptions(options)
-page_interaction.RegisterClass('compound', CompoundInteraction)
+ def PerformInteraction(self, page, tab):
+ for interaction in self._interaction_list:
+ interaction.PerformInteraction(page, tab)
diff --git a/tools/telemetry/telemetry/compound_interaction_unittest.py b/tools/telemetry/telemetry/compound_interaction_unittest.py
index 9b0c9115..23ab392 100644
--- a/tools/telemetry/telemetry/compound_interaction_unittest.py
+++ b/tools/telemetry/telemetry/compound_interaction_unittest.py
@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+from telemetry import all_page_interactions
from telemetry import compound_interaction
from telemetry import page_interaction
from telemetry import tab_test_case
@@ -23,8 +24,8 @@ class CompoundInteractionTest(tab_test_case.TabTestCase):
def PerformInteraction(self, page, tab):
CompoundInteractionTest.interaction2_called = True
- page_interaction.RegisterClass('mock1', MockInteraction1)
- page_interaction.RegisterClass('mock2', MockInteraction2)
+ all_page_interactions.RegisterClassForTest('mock1', MockInteraction1)
+ all_page_interactions.RegisterClassForTest('mock2', MockInteraction2)
i = compound_interaction.CompoundInteraction({
'action': 'compound',
diff --git a/tools/telemetry/telemetry/discover.py b/tools/telemetry/telemetry/discover.py
new file mode 100644
index 0000000..5ddc52b
--- /dev/null
+++ b/tools/telemetry/telemetry/discover.py
@@ -0,0 +1,40 @@
+# Copyright (c) 2012 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.
+import inspect
+import logging
+import os
+import traceback
+
+def Discover(start_dir, suffix, clazz):
+ """Discover all classes in |start_dir| which subclass |clazz|.
+
+ Args:
+ start_dir: The directory to recursively search.
+ suffix: file name suffix for files to import, without the '.py' ending.
+ clazz: The base class to search for.
+
+ Returns:
+ dict of {module_name: class}.
+ """
+ top_level_dir = os.path.join(start_dir, '..')
+ classes = {}
+ for dirpath, _, filenames in os.walk(start_dir):
+ for filename in filenames:
+ if not filename.endswith(suffix + '.py'):
+ continue
+ name, _ = os.path.splitext(filename)
+ relpath = os.path.relpath(dirpath, top_level_dir)
+ fqn = relpath.replace('/', '.') + '.' + name
+ try:
+ module = __import__(fqn, fromlist=[True])
+ except Exception:
+ logging.error('While importing [%s]\n' % fqn)
+ traceback.print_exc()
+ continue
+ for name, obj in inspect.getmembers(module):
+ if inspect.isclass(obj):
+ if clazz in inspect.getmro(obj):
+ name = module.__name__.split('.')[-1]
+ classes[name] = obj
+ return classes
diff --git a/tools/telemetry/telemetry/inspector_page_unittest.py b/tools/telemetry/telemetry/inspector_page_unittest.py
index 33c476e..8bb9b99 100644
--- a/tools/telemetry/telemetry/inspector_page_unittest.py
+++ b/tools/telemetry/telemetry/inspector_page_unittest.py
@@ -8,7 +8,6 @@ from telemetry import tab_test_case
class InspectorPageTest(tab_test_case.TabTestCase):
def __init__(self, *args):
super(InspectorPageTest, self).__init__(*args)
- self._custom_action_called = False
def testPageNavigateToNormalUrl(self):
self._tab.page.Navigate('http://www.google.com')
@@ -34,13 +33,13 @@ class InspectorPageTest(tab_test_case.TabTestCase):
self.assertEquals(self._tab.runtime.Evaluate('document.location.pathname;'),
'/page_with_link.html')
- self._custom_action_called = False
+ custom_action_called = [False]
def CustomAction():
- self._custom_action_called = True
+ custom_action_called[0] = True
self._tab.runtime.Execute('document.getElementById("clickme").click();')
self._tab.page.PerformActionAndWaitForNavigate(CustomAction)
- self.assertTrue(self._custom_action_called)
+ self.assertTrue(custom_action_called[0])
self.assertEquals(self._tab.runtime.Evaluate('document.location.pathname;'),
'/blank.html')
diff --git a/tools/telemetry/telemetry/multi_page_benchmark.py b/tools/telemetry/telemetry/multi_page_benchmark.py
index a17a031..b24374c 100644
--- a/tools/telemetry/telemetry/multi_page_benchmark.py
+++ b/tools/telemetry/telemetry/multi_page_benchmark.py
@@ -138,7 +138,7 @@ class MultiPageBenchmark(page_test.PageTest):
To add test-specific options:
class BodyChildElementBenchmark(MultiPageBenchmark):
- def AddOptions(parser):
+ def AddCommandLineOptions(parser):
parser.add_option('--element', action='store', default='body')
def MeasurePage(self, page, tab, results):
@@ -146,8 +146,8 @@ class MultiPageBenchmark(page_test.PageTest):
'document.querySelector('%s').children.length')
results.Add('children', 'count', child_count)
"""
- def __init__(self):
- super(MultiPageBenchmark, self).__init__('_RunTest')
+ def __init__(self, interaction_name=''):
+ super(MultiPageBenchmark, self).__init__('_RunTest', interaction_name)
def _RunTest(self, page, tab, results):
results.WillMeasurePage(page)
diff --git a/tools/telemetry/telemetry/multi_page_benchmark_runner.py b/tools/telemetry/telemetry/multi_page_benchmark_runner.py
index 48837ee..89fc5e5 100755
--- a/tools/telemetry/telemetry/multi_page_benchmark_runner.py
+++ b/tools/telemetry/telemetry/multi_page_benchmark_runner.py
@@ -3,59 +3,26 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import csv
-import inspect
import logging
import os
import sys
-import traceback
+from telemetry import all_page_interactions # pylint: disable=W0611
from telemetry import browser_finder
from telemetry import browser_options
+from telemetry import discover
from telemetry import multi_page_benchmark
from telemetry import page_runner
from telemetry import page_set
-
-def _Discover(start_dir, clazz):
- """Discover all classes in |start_dir| which subclass |clazz|.
-
- Args:
- start_dir: The directory to recursively search.
- clazz: The base class to search for.
-
- Returns:
- dict of {module_name: class}.
- """
- top_level_dir = os.path.join(start_dir, '..')
- classes = {}
- for dirpath, _, filenames in os.walk(start_dir):
- for filename in filenames:
- if not filename.endswith('.py'):
- continue
- name, _ = os.path.splitext(filename)
- relpath = os.path.relpath(dirpath, top_level_dir)
- fqn = relpath.replace('/', '.') + '.' + name
- try:
- module = __import__(fqn, fromlist=[True])
- except Exception:
- logging.error('While importing [%s]\n' % fqn)
- traceback.print_exc()
- continue
- for name, obj in inspect.getmembers(module):
- if inspect.isclass(obj):
- if clazz in inspect.getmro(obj):
- name = module.__name__.split('.')[-1]
- classes[name] = obj
- return classes
-
-
def Main(benchmark_dir):
"""Turns a MultiPageBenchmark into a command-line program.
Args:
benchmark_dir: Path to directory containing MultiPageBenchmarks.
"""
- benchmarks = _Discover(benchmark_dir, multi_page_benchmark.MultiPageBenchmark)
+ benchmarks = discover.Discover(benchmark_dir, '',
+ multi_page_benchmark.MultiPageBenchmark)
# Naively find the benchmark. If we use the browser options parser, we run
# the risk of failing to parse if we use a benchmark-specific parameter.
@@ -70,7 +37,7 @@ def Main(benchmark_dir):
benchmark = None
if benchmark_name is not None:
benchmark = benchmarks[benchmark_name]()
- benchmark.AddOptions(parser)
+ benchmark.AddCommandLineOptions(parser)
_, args = parser.parse_args()
@@ -103,4 +70,8 @@ Use --browser=list to figure out which are available.\n"""
if len(results.page_failures):
logging.warning('Failed pages: %s', '\n'.join(
[failure['page'].url for failure in results.page_failures]))
+
+ if len(results.skipped_pages):
+ logging.warning('Skipped pages: %s', '\n'.join(
+ [skipped['page'].url for skipped in results.skipped_pages]))
return min(255, len(results.page_failures))
diff --git a/tools/telemetry/telemetry/multi_page_benchmark_unittest.py b/tools/telemetry/telemetry/multi_page_benchmark_unittest.py
index 675f355..45a387c 100644
--- a/tools/telemetry/telemetry/multi_page_benchmark_unittest.py
+++ b/tools/telemetry/telemetry/multi_page_benchmark_unittest.py
@@ -6,6 +6,7 @@ import os
from telemetry import multi_page_benchmark
from telemetry import multi_page_benchmark_unittest_base
from telemetry import page as page_module
+from telemetry import page_interaction
from telemetry import page_set
from telemetry import wpr_modes
@@ -14,7 +15,7 @@ class BenchThatFails(multi_page_benchmark.MultiPageBenchmark):
raise multi_page_benchmark.MeasurementFailure('Intentional failure.')
class BenchThatHasDefaults(multi_page_benchmark.MultiPageBenchmark):
- def AddOptions(self, parser):
+ def AddCommandLineOptions(self, parser):
parser.add_option('-x', dest='x', default=3)
def MeasurePage(self, page, tab, results):
@@ -38,6 +39,13 @@ class BenchQueryParams(multi_page_benchmark.MultiPageBenchmark):
query = tab.runtime.Evaluate('window.location.search')
assert query.strip() == '?foo=1'
+class BenchWithInteraction(multi_page_benchmark.MultiPageBenchmark):
+ def __init__(self):
+ super(BenchWithInteraction, self).__init__('test_interaction')
+
+ def MeasurePage(self, page, tab, results):
+ pass
+
class MultiPageBenchmarkUnitTest(
multi_page_benchmark_unittest_base.MultiPageBenchmarkUnitTestBase):
@@ -102,3 +110,17 @@ class MultiPageBenchmarkUnitTest(
finally:
if os.path.isfile(test_archive):
os.remove(test_archive)
+
+ def testInteractions(self):
+ interaction_called = [False]
+ class MockInteraction(page_interaction.PageInteraction):
+ def PerformInteraction(self, page, tab):
+ interaction_called[0] = True
+ from telemetry import all_page_interactions
+ all_page_interactions.RegisterClassForTest('mock', MockInteraction)
+
+ ps = self.CreatePageSetFromFileInUnittestDataDir('blank.html')
+ setattr(ps.pages[0], 'test_interaction', {'action': 'mock'})
+ benchmark = BenchWithInteraction()
+ self.RunBenchmark(benchmark, ps)
+ self.assertTrue(interaction_called[0])
diff --git a/tools/telemetry/telemetry/multi_page_benchmark_unittest_base.py b/tools/telemetry/telemetry/multi_page_benchmark_unittest_base.py
index 617d77f..128ff3f 100644
--- a/tools/telemetry/telemetry/multi_page_benchmark_unittest_base.py
+++ b/tools/telemetry/telemetry/multi_page_benchmark_unittest_base.py
@@ -35,7 +35,7 @@ class MultiPageBenchmarkUnitTestBase(unittest.TestCase):
options = options_for_unittests.Get()
assert options
temp_parser = options.CreateParser()
- benchmark.AddOptions(temp_parser)
+ benchmark.AddCommandLineOptions(temp_parser)
defaults = temp_parser.get_default_values()
for k, v in defaults.__dict__.items():
if hasattr(options, k):
diff --git a/tools/telemetry/telemetry/page_interaction.py b/tools/telemetry/telemetry/page_interaction.py
index 108db76..57b2d7b 100644
--- a/tools/telemetry/telemetry/page_interaction.py
+++ b/tools/telemetry/telemetry/page_interaction.py
@@ -24,14 +24,3 @@ class PageInteraction(object):
def CleanUp(self, page, tab):
pass
-
-_page_interaction_classes = {}
-def GetAllClasses():
- return list(_page_interaction_classes.values())
-
-def FindClassWithName(name):
- return _page_interaction_classes.get(name)
-
-def RegisterClass(name, interaction_class):
- assert name not in _page_interaction_classes
- _page_interaction_classes[name] = interaction_class
diff --git a/tools/telemetry/telemetry/page_runner.py b/tools/telemetry/telemetry/page_runner.py
index 827d266..9ad5351 100644
--- a/tools/telemetry/telemetry/page_runner.py
+++ b/tools/telemetry/telemetry/page_runner.py
@@ -73,6 +73,9 @@ http://goto/read-src-internal, or create a new archive using --record.
if not os.path.exists(credentials_path):
credentials_path = None
+ for page in self.page_set:
+ test.CustomizeBrowserOptionsForPage(page, possible_browser.options)
+
with possible_browser.Create() as b:
b.credentials.credentials_path = credentials_path
test.SetUpBrowser(b)
@@ -101,6 +104,10 @@ http://goto/read-src-internal, or create a new archive using --record.
self._RunPage(options, page, tab, test, results)
def _RunPage(self, options, page, tab, test, results):
+ if not test.CanRunForPage(page):
+ results.AddSkippedPage(page, 'Test cannot run', '')
+ return
+
logging.info('Running %s' % page.url)
page_state = PageState()
diff --git a/tools/telemetry/telemetry/page_test.py b/tools/telemetry/telemetry/page_test.py
index 2d4d24f..a55ee9e 100644
--- a/tools/telemetry/telemetry/page_test.py
+++ b/tools/telemetry/telemetry/page_test.py
@@ -9,24 +9,31 @@ class Failure(Exception):
class PageTestResults(object):
def __init__(self):
self.page_failures = []
+ self.skipped_pages = []
def AddFailure(self, page, message, details):
self.page_failures.append({'page': page,
'message': message,
'details': details})
+ def AddSkippedPage(self, page, message, details):
+ self.skipped_pages.append({'page': page,
+ 'message': message,
+ 'details': details})
+
class PageTest(object):
"""A class styled on unittest.TestCase for creating page-specific tests."""
- def __init__(self, test_method_name):
+ def __init__(self, test_method_name, interaction_name_to_run=''):
self.options = None
try:
self._test_method = getattr(self, test_method_name)
except AttributeError:
raise ValueError, 'No such method %s.%s' % (
self.__class_, test_method_name) # pylint: disable=E1101
+ self._interaction_name_to_run = interaction_name_to_run
- def AddOptions(self, parser):
+ def AddCommandLineOptions(self, parser):
"""Override to expose command-line options for this benchmark.
The provided parser is an optparse.OptionParser instance and accepts all
@@ -38,13 +45,47 @@ class PageTest(object):
"""Override to add test-specific options to the BrowserOptions object"""
pass
+ def CustomizeBrowserOptionsForPage(self, page, options):
+ """Add options specific to the test and the given page."""
+ if not self.CanRunForPage(page):
+ return
+ interaction = self.GetInteraction(page)
+ if interaction:
+ interaction.CustomizeBrowserOptions(options)
+
def SetUpBrowser(self, browser):
"""Override to customize the browser right after it has launched."""
pass
+ def CanRunForPage(self, page): #pylint: disable=W0613
+ """Override to customize if the test can be ran for the given page."""
+ return True
+
+ def WillRunInteraction(self, page, tab):
+ """Override to do operations before running the interaction on the page."""
+ pass
+
+ def DidRunInteraction(self, page, tab):
+ """Override to do operations after running the interaction on the page."""
+ pass
+
def Run(self, options, page, tab, results):
self.options = options
+ interaction = self.GetInteraction(page)
+ if interaction:
+ tab.WaitForDocumentReadyStateToBeComplete()
+ self.WillRunInteraction(page, tab)
+ interaction.PerformInteraction(page, tab)
+ self.DidRunInteraction(page, tab)
try:
self._test_method(page, tab, results)
finally:
self.options = None
+
+ def GetInteraction(self, page):
+ if not self._interaction_name_to_run:
+ return None
+ interaction_data = getattr(page, self._interaction_name_to_run)
+ from telemetry import all_page_interactions
+ return all_page_interactions.FindClassWithName(
+ interaction_data['action'])(interaction_data)