Commit aca3d7a9 authored by nduca@chromium.org's avatar nduca@chromium.org

Introduce TracingController and TracingControllerBackend skeleton

BUG=356763

Review URL: https://codereview.chromium.org/414253004

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@287874 0039d316-1c4b-4281-b951-d872f2087c98
parent 4b943995
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
# found in the LICENSE file. # found in the LICENSE file.
from measurements import timeline_controller from measurements import timeline_controller
from metrics import timeline from metrics import timeline
from telemetry.core.backends.chrome import tracing_backend from telemetry.core.platform import tracing_category_filter
from telemetry.page import page_measurement from telemetry.page import page_measurement
class ThreadTimes(page_measurement.PageMeasurement): class ThreadTimes(page_measurement.PageMeasurement):
...@@ -22,11 +22,10 @@ class ThreadTimes(page_measurement.PageMeasurement): ...@@ -22,11 +22,10 @@ class ThreadTimes(page_measurement.PageMeasurement):
self._timeline_controller = timeline_controller.TimelineController() self._timeline_controller = timeline_controller.TimelineController()
if self.options.report_silk_details: if self.options.report_silk_details:
# We need the other traces in order to have any details to report. # We need the other traces in order to have any details to report.
self.timeline_controller.trace_categories = \ self.timeline_controller.trace_categories = None
tracing_backend.DEFAULT_TRACE_CATEGORIES
else: else:
self._timeline_controller.trace_categories = \ self._timeline_controller.trace_categories = \
tracing_backend.MINIMAL_TRACE_CATEGORIES tracing_category_filter.CreateNoOverheadFilter().filter_string
self._timeline_controller.SetUp(page, tab) self._timeline_controller.SetUp(page, tab)
def WillRunActions(self, page, tab): def WillRunActions(self, page, tab):
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
# found in the LICENSE file. # found in the LICENSE file.
from measurements import smooth_gesture_util from measurements import smooth_gesture_util
from telemetry.core.backends.chrome import tracing_backend from telemetry.core.platform import tracing_category_filter
from telemetry.timeline.model import TimelineModel from telemetry.timeline.model import TimelineModel
from telemetry.page.actions import action_runner from telemetry.page.actions import action_runner
from telemetry.web_perf import timeline_interaction_record as tir_module from telemetry.web_perf import timeline_interaction_record as tir_module
...@@ -15,7 +15,7 @@ RUN_SMOOTH_ACTIONS = 'RunSmoothAllActions' ...@@ -15,7 +15,7 @@ RUN_SMOOTH_ACTIONS = 'RunSmoothAllActions'
class TimelineController(object): class TimelineController(object):
def __init__(self): def __init__(self):
super(TimelineController, self).__init__() super(TimelineController, self).__init__()
self.trace_categories = tracing_backend.DEFAULT_TRACE_CATEGORIES self.trace_categories = None
self._model = None self._model = None
self._renderer_process = None self._renderer_process = None
self._smooth_records = [] self._smooth_records = []
...@@ -30,12 +30,11 @@ class TimelineController(object): ...@@ -30,12 +30,11 @@ class TimelineController(object):
self._renderer_process = None self._renderer_process = None
if not tab.browser.supports_tracing: if not tab.browser.supports_tracing:
raise Exception('Not supported') raise Exception('Not supported')
if self.trace_categories: category_filter = tracing_category_filter.TracingCategoryFilter(
categories = [self.trace_categories] + \ filter_string=self.trace_categories)
page.GetSyntheticDelayCategories() for delay in page.GetSyntheticDelayCategories():
else: category_filter.AddSyntheticDelay(delay)
categories = page.GetSyntheticDelayCategories() tab.browser.StartTracing(category_filter)
tab.browser.StartTracing(','.join(categories))
def Start(self, tab): def Start(self, tab):
# Start the smooth marker for all actions. # Start the smooth marker for all actions.
......
...@@ -3,25 +3,9 @@ ...@@ -3,25 +3,9 @@
# found in the LICENSE file. # found in the LICENSE file.
import logging import logging
import re
from telemetry.core.backends.chrome import inspector_websocket from telemetry.core.backends.chrome import inspector_websocket
from telemetry.core.platform import tracing_category_filter
# All tracing categories not disabled-by-default
DEFAULT_TRACE_CATEGORIES = None
# Categories for absolute minimum overhead tracing. This contains no
# sub-traces of thread tasks, so it's only useful for capturing the
# cpu-time spent on threads (as well as needed benchmark traces)
# FIXME: Remove webkit.console when blink.console lands in chromium and
# the ref builds are updated. crbug.com/386847
MINIMAL_TRACE_CATEGORIES = ("toplevel,"
"benchmark,"
"webkit.console,"
"blink.console,"
"trace_event_overhead")
class TracingUnsupportedException(Exception): class TracingUnsupportedException(Exception):
...@@ -32,77 +16,6 @@ class TracingTimeoutException(Exception): ...@@ -32,77 +16,6 @@ class TracingTimeoutException(Exception):
pass pass
class CategoryFilter(object):
def __init__(self, filter_string):
self.excluded = set()
self.included = set()
self.disabled = set()
self.synthetic_delays = set()
self.contains_wildcards = False
if not filter_string:
return
if '*' in filter_string or '?' in filter_string:
self.contains_wildcards = True
filter_set = set(filter_string.split(','))
delay_re = re.compile(r'DELAY[(][A-Za-z0-9._;]+[)]')
for category in filter_set:
if category == '':
continue
if delay_re.match(category):
self.synthetic_delays.add(category)
elif category[0] == '-':
category = category[1:]
self.excluded.add(category)
elif category.startswith('disabled-by-default-'):
self.disabled.add(category)
else:
self.included.add(category)
def IsSubset(self, other):
""" Determine if filter A (self) is a subset of filter B (other).
Returns True if A is a subset of B, False if A is not a subset of B,
and None if we can't tell for sure.
"""
# We don't handle filters with wildcards in this test.
if self.contains_wildcards or other.contains_wildcards:
return None
# Disabled categories get into a trace if and only if they are contained in
# the 'disabled' set. Return False if A's disabled set is not a subset of
# B's disabled set.
if not self.disabled <= other.disabled:
return False
# If A defines more or different synthetic delays than B, then A is not a
# subset.
if not self.synthetic_delays <= other.synthetic_delays:
return False
if self.included and other.included:
# A and B have explicit include lists. If A includes something that B
# doesn't, return False.
if not self.included <= other.included:
return False
elif self.included:
# Only A has an explicit include list. If A includes something that B
# excludes, return False.
if self.included.intersection(other.excluded):
return False
elif other.included:
# Only B has an explicit include list. We don't know which categories are
# contained in the default list, so return None.
return None
else:
# None of the filter have explicit include list. If B excludes categories
# that A doesn't exclude, return False.
if not other.excluded <= self.excluded:
return False
return True
class TracingBackend(object): class TracingBackend(object):
def __init__(self, devtools_port): def __init__(self, devtools_port):
self._inspector_websocket = inspector_websocket.InspectorWebsocket( self._inspector_websocket = inspector_websocket.InspectorWebsocket(
...@@ -126,7 +39,8 @@ class TracingBackend(object): ...@@ -126,7 +39,8 @@ class TracingBackend(object):
""" """
self._nesting += 1 self._nesting += 1
if self.is_tracing_running: if self.is_tracing_running:
new_category_filter = CategoryFilter(custom_categories) new_category_filter = tracing_category_filter.TracingCategoryFilter(
filter_string=custom_categories)
is_subset = new_category_filter.IsSubset(self._category_filter) is_subset = new_category_filter.IsSubset(self._category_filter)
assert(is_subset != False) assert(is_subset != False)
if is_subset == None: if is_subset == None:
...@@ -135,7 +49,8 @@ class TracingBackend(object): ...@@ -135,7 +49,8 @@ class TracingBackend(object):
return False return False
self._CheckNotificationSupported() self._CheckNotificationSupported()
req = {'method': 'Tracing.start'} req = {'method': 'Tracing.start'}
self._category_filter = CategoryFilter(custom_categories) self._category_filter = tracing_category_filter.TracingCategoryFilter(
filter_string=custom_categories)
if custom_categories: if custom_categories:
req['params'] = {'categories': custom_categories} req['params'] = {'categories': custom_categories}
self._inspector_websocket.SyncRequest(req, timeout) self._inspector_websocket.SyncRequest(req, timeout)
......
...@@ -8,95 +8,10 @@ import logging ...@@ -8,95 +8,10 @@ import logging
import unittest import unittest
from telemetry.core import util from telemetry.core import util
from telemetry.core.backends.chrome import tracing_backend
from telemetry.timeline import tracing_timeline_data from telemetry.timeline import tracing_timeline_data
from telemetry.timeline.model import TimelineModel from telemetry.timeline.model import TimelineModel
from telemetry.unittest import tab_test_case from telemetry.unittest import tab_test_case
class CategoryFilterTest(unittest.TestCase):
def testIsSubset(self):
b = tracing_backend.CategoryFilter(None)
a = tracing_backend.CategoryFilter(None)
self.assertEquals(a.IsSubset(b), True)
b = tracing_backend.CategoryFilter(None)
a = tracing_backend.CategoryFilter("test1,test2")
self.assertEquals(a.IsSubset(b), True)
b = tracing_backend.CategoryFilter(None)
a = tracing_backend.CategoryFilter("-test1,-test2")
self.assertEquals(a.IsSubset(b), True)
b = tracing_backend.CategoryFilter("test1,test2")
a = tracing_backend.CategoryFilter(None)
self.assertEquals(a.IsSubset(b), None)
b = tracing_backend.CategoryFilter(None)
a = tracing_backend.CategoryFilter("test*")
self.assertEquals(a.IsSubset(b), None)
b = tracing_backend.CategoryFilter("test?")
a = tracing_backend.CategoryFilter(None)
self.assertEquals(a.IsSubset(b), None)
b = tracing_backend.CategoryFilter("test1")
a = tracing_backend.CategoryFilter("test1,test2")
self.assertEquals(a.IsSubset(b), False)
b = tracing_backend.CategoryFilter("-test1")
a = tracing_backend.CategoryFilter("test1")
self.assertEquals(a.IsSubset(b), False)
b = tracing_backend.CategoryFilter("test1,test2")
a = tracing_backend.CategoryFilter("test2,test1")
self.assertEquals(a.IsSubset(b), True)
b = tracing_backend.CategoryFilter("-test1,-test2")
a = tracing_backend.CategoryFilter("-test2")
self.assertEquals(a.IsSubset(b), False)
b = tracing_backend.CategoryFilter("disabled-by-default-test1")
a = tracing_backend.CategoryFilter(
"disabled-by-default-test1,disabled-by-default-test2")
self.assertEquals(a.IsSubset(b), False)
b = tracing_backend.CategoryFilter("disabled-by-default-test1")
a = tracing_backend.CategoryFilter("disabled-by-default-test2")
self.assertEquals(a.IsSubset(b), False)
def testIsSubsetWithSyntheticDelays(self):
b = tracing_backend.CategoryFilter("DELAY(foo;0.016)")
a = tracing_backend.CategoryFilter("DELAY(foo;0.016)")
self.assertEquals(a.IsSubset(b), True)
b = tracing_backend.CategoryFilter("DELAY(foo;0.016)")
a = tracing_backend.CategoryFilter(None)
self.assertEquals(a.IsSubset(b), True)
b = tracing_backend.CategoryFilter(None)
a = tracing_backend.CategoryFilter("DELAY(foo;0.016)")
self.assertEquals(a.IsSubset(b), False)
b = tracing_backend.CategoryFilter("DELAY(foo;0.016)")
a = tracing_backend.CategoryFilter("DELAY(foo;0.032)")
self.assertEquals(a.IsSubset(b), False)
b = tracing_backend.CategoryFilter("DELAY(foo;0.016;static)")
a = tracing_backend.CategoryFilter("DELAY(foo;0.016;oneshot)")
self.assertEquals(a.IsSubset(b), False)
b = tracing_backend.CategoryFilter("DELAY(foo;0.016),DELAY(bar;0.1)")
a = tracing_backend.CategoryFilter("DELAY(bar;0.1),DELAY(foo;0.016)")
self.assertEquals(a.IsSubset(b), True)
b = tracing_backend.CategoryFilter("DELAY(foo;0.016),DELAY(bar;0.1)")
a = tracing_backend.CategoryFilter("DELAY(bar;0.1)")
self.assertEquals(a.IsSubset(b), True)
b = tracing_backend.CategoryFilter("DELAY(foo;0.016),DELAY(bar;0.1)")
a = tracing_backend.CategoryFilter("DELAY(foo;0.032),DELAY(bar;0.1)")
self.assertEquals(a.IsSubset(b), False)
class TracingBackendTest(tab_test_case.TabTestCase): class TracingBackendTest(tab_test_case.TabTestCase):
def _StartServer(self): def _StartServer(self):
......
...@@ -14,9 +14,10 @@ from telemetry.core import tab_list ...@@ -14,9 +14,10 @@ from telemetry.core import tab_list
from telemetry.core import wpr_modes from telemetry.core import wpr_modes
from telemetry.core import wpr_server from telemetry.core import wpr_server
from telemetry.core.backends import browser_backend from telemetry.core.backends import browser_backend
from telemetry.core.platform import tracing_category_filter
from telemetry.core.platform import tracing_options
from telemetry.core.platform.profiler import profiler_finder from telemetry.core.platform.profiler import profiler_finder
class Browser(object): class Browser(object):
"""A running browser instance that can be controlled in a limited way. """A running browser instance that can be controlled in a limited way.
...@@ -41,7 +42,7 @@ class Browser(object): ...@@ -41,7 +42,7 @@ class Browser(object):
self._tabs = tab_list.TabList(backend.tab_list_backend) self._tabs = tab_list.TabList(backend.tab_list_backend)
self.credentials = browser_credentials.BrowserCredentials() self.credentials = browser_credentials.BrowserCredentials()
self.platform.SetFullPerformanceModeEnabled(True) self._platform_backend.DidCreateBrowser(self, self._browser_backend)
def __enter__(self): def __enter__(self):
self.Start() self.Start()
...@@ -96,7 +97,7 @@ class Browser(object): ...@@ -96,7 +97,7 @@ class Browser(object):
@property @property
def supports_tracing(self): def supports_tracing(self):
return self._browser_backend.supports_tracing return self.platform.tracing_controller.IsChromeTracingSupported(self)
def is_profiler_active(self, profiler_name): def is_profiler_active(self, profiler_name):
return profiler_name in [profiler.name() for return profiler_name in [profiler.name() for
...@@ -273,16 +274,28 @@ class Browser(object): ...@@ -273,16 +274,28 @@ class Browser(object):
self._active_profilers = [] self._active_profilers = []
return output_files return output_files
def StartTracing(self, custom_categories=None, timeout=10): def StartTracing(self, custom_categories=None, timeout=10):
return self._browser_backend.StartTracing(custom_categories, timeout) """Note: this function is deprecated. Prefer platform.tracing_controller."""
if not isinstance(custom_categories,
tracing_category_filter.TracingCategoryFilter):
category_filter = tracing_category_filter.TracingCategoryFilter(
filter_string=custom_categories)
else:
category_filter = custom_categories
options = tracing_options.TracingOptions()
options.enable_chrome_trace = True
return self.platform.tracing_controller.Start(
options, category_filter, timeout)
@property @property
def is_tracing_running(self): def is_tracing_running(self):
return self._browser_backend.is_tracing_running """Note: this function is deprecated. Prefer platform.tracing_controller."""
return self.platform.tracing_controller.is_tracing_running
def StopTracing(self): def StopTracing(self):
""" Stops tracing and returns the result as TimelineData object. """ """Note: this function is deprecated. Prefer platform.tracing_controller."""
return self._browser_backend.StopTracing() return self.platform.tracing_controller.Stop()
def Start(self): def Start(self):
browser_options = self._browser_backend.browser_options browser_options = self._browser_backend.browser_options
...@@ -298,6 +311,7 @@ class Browser(object): ...@@ -298,6 +311,7 @@ class Browser(object):
self._browser_backend.SetBrowser(self) self._browser_backend.SetBrowser(self)
self._browser_backend.Start() self._browser_backend.Start()
self._platform_backend.DidStartBrowser(self, self._browser_backend)
def Close(self): def Close(self):
"""Closes this browser.""" """Closes this browser."""
...@@ -305,7 +319,8 @@ class Browser(object): ...@@ -305,7 +319,8 @@ class Browser(object):
profiler_class.WillCloseBrowser(self._browser_backend, profiler_class.WillCloseBrowser(self._browser_backend,
self._platform_backend) self._platform_backend)
self.platform.SetFullPerformanceModeEnabled(False) if self._browser_backend.IsBrowserRunning():
self._platform_backend.WillCloseBrowser(self, self._browser_backend)
if self._wpr_server: if self._wpr_server:
self._wpr_server.Close() self._wpr_server.Close()
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
import sys import sys
from telemetry.core.platform import tracing_controller
_host_platform = None _host_platform = None
...@@ -43,6 +45,12 @@ class Platform(object): ...@@ -43,6 +45,12 @@ class Platform(object):
def __init__(self, platform_backend): def __init__(self, platform_backend):
self._platform_backend = platform_backend self._platform_backend = platform_backend
self._platform_backend.SetPlatform(self) self._platform_backend.SetPlatform(self)
self._tracing_controller = tracing_controller.TracingController(
self._platform_backend.tracing_controller_backend)
@property
def tracing_controller(self):
return self._tracing_controller
def IsRawDisplayFrameRateSupported(self): def IsRawDisplayFrameRateSupported(self):
"""Platforms may be able to collect GL surface stats.""" """Platforms may be able to collect GL surface stats."""
...@@ -78,16 +86,6 @@ class Platform(object): ...@@ -78,16 +86,6 @@ class Platform(object):
"""Returns a list of RawDisplayFrameRateMeasurement.""" """Returns a list of RawDisplayFrameRateMeasurement."""
return self._platform_backend.GetRawDisplayFrameRateMeasurements() return self._platform_backend.GetRawDisplayFrameRateMeasurements()
def SetFullPerformanceModeEnabled(self, enabled):
"""Platforms may tweak their CPU governor, system status, etc.
Most platforms can operate in a battery saving mode. While good for battery
life, this can cause confusing performance results and add noise. Turning
full performance mode on disables these features, which is useful for
performance testing.
"""
return self._platform_backend.SetFullPerformanceModeEnabled(enabled)
def CanMonitorThermalThrottling(self): def CanMonitorThermalThrottling(self):
"""Platforms may be able to detect thermal throttling. """Platforms may be able to detect thermal throttling.
......
...@@ -2,6 +2,11 @@ ...@@ -2,6 +2,11 @@
# Use of this source code is governed by a BSD-style license that can be # Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file. # found in the LICENSE file.
import weakref
from telemetry.core.platform import tracing_controller_backend
# pylint: disable=W0613 # pylint: disable=W0613
# pylint: disable=W0212 # pylint: disable=W0212
...@@ -39,6 +44,9 @@ MAVERICKS = OSVersion('mavericks', 10.9) ...@@ -39,6 +44,9 @@ MAVERICKS = OSVersion('mavericks', 10.9)
class PlatformBackend(object): class PlatformBackend(object):
def __init__(self): def __init__(self):
self._platform = None self._platform = None
self._running_browser_backends = weakref.WeakSet()
self._tracing_controller_backend = \
tracing_controller_backend.TracingControllerBackend(self)
def SetPlatform(self, platform): def SetPlatform(self, platform):
assert self._platform == None assert self._platform == None
...@@ -48,6 +56,41 @@ class PlatformBackend(object): ...@@ -48,6 +56,41 @@ class PlatformBackend(object):
def platform(self): def platform(self):
return self._platform return self._platform
@property
def running_browser_backends(self):
return list(self._running_browser_backends)
@property
def tracing_controller_backend(self):
return self._tracing_controller_backend
def DidCreateBrowser(self, browser, browser_backend):
self.SetFullPerformanceModeEnabled(True)
def DidStartBrowser(self, browser, browser_backend):
assert browser not in self._running_browser_backends
self._running_browser_backends.add(browser_backend)
self._tracing_controller_backend.DidStartBrowser(
browser, browser_backend)
def WillCloseBrowser(self, browser, browser_backend):
self._tracing_controller_backend.WillCloseBrowser(
browser, browser_backend)
is_last_browser = len(self._running_browser_backends) == 1
if is_last_browser:
self.SetFullPerformanceModeEnabled(False)
self._running_browser_backends.remove(browser_backend)
def GetBackendForBrowser(self, browser):
matches = [x for x in self._running_browser_backends
if x.browser == browser]
if len(matches) == 0:
raise Exception('No browser found')
assert len(matches) == 1
return matches[0]
def IsRawDisplayFrameRateSupported(self): def IsRawDisplayFrameRateSupported(self):
return False return False
......
# 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.
import re
def CreateNoOverheadFilter():
"""Returns a filter with the least overhead possible.
This contains no sub-traces of thread tasks, so it's only useful for
capturing the cpu-time spent on threads (as well as needed benchmark
traces).
FIXME: Remove webkit.console when blink.console lands in chromium and
the ref builds are updated. crbug.com/386847
"""
categories = [
"toplevel",
"benchmark",
"webkit.console",
"blink.console",
"trace_event_overhead"
]
return TracingCategoryFilter(filter_string=','.join(categories))
def CreateMinimalOverheadFilter():
"""Returns a filter with the best-effort amount of overhead."""
return TracingCategoryFilter(filter_string='')
def CreateDebugOverheadFilter():
"""Returns a filter with as many traces enabled as is useful."""
return TracingCategoryFilter(filter_string='*,disabled-by-default-cc.debug')
_delay_re = re.compile(r'DELAY[(][A-Za-z0-9._;]+[)]')
class TracingCategoryFilter(object):
"""A set of included and excluded categories that should be traced.
The TraceCategoryFilter allows fine tuning of what data is traced. Basic
choice of which tracers to use is done by TracingOptions.
Providing filter_string=None gives the default category filter, which leaves
what to trace up to the individual trace systems.
"""
def __init__(self, filter_string=None):
self._included_categories = set()
self._excluded_categories = set()
self._disabled_by_default_categories = set()
self._synthetic_delays = set()
self.contains_wildcards = False
if filter_string == None:
return
if '*' in filter_string or '?' in filter_string:
self.contains_wildcards = True
filter_set = set(filter_string.split(','))
for category in filter_set:
if category == '':
continue
if _delay_re.match(category):
self._synthetic_delays.add(category)
continue
if category[0] == '-':
self._excluded_categories.add(category[1:])
continue
if category.startswith('disabled-by-default-'):
self._disabled_by_default_categories.add(category)
continue
self.included_categories.add(category)
@property
def included_categories(self):
return self._included_categories
@property
def excluded_categories(self):
return self._excluded_categories
@property
def disabled_by_default_categories(self):
return self._disabled_by_default_categories
@property
def synthetic_delays(self):
return self._synthetic_delays
@property
def filter_string(self):
return self._GetFilterString(stable_output=False)
@property
def stable_filter_string(self):
return self._GetFilterString(stable_output=True)
def _GetFilterString(self, stable_output):
# Note: This outputs fields in an order that intentionally matches
# trace_event_impl's CategoryFilter string order.
lists = []
lists.append(self._included_categories)
lists.append(self._disabled_by_default_categories)
lists.append(['-%s' % x for x in self._excluded_categories])
lists.append(self._synthetic_delays)
categories = []
for l in lists:
if stable_output:
l = list(l)
l.sort()
categories.extend(l)
return ','.join(categories)
def AddIncludedCategory(self, category_glob):
"""Explicitly enables anything matching category_glob."""
assert not category_glob.startswith('disabled-by-default-')
if category_glob not in self._included_categories:
self._included_categories.append(category_glob)
def AddExcludedCategory(self, category_glob):
"""Explicitly disables anything matching category_glob."""
assert not category_glob.startswith('disabled-by-default-')
if category_glob not in self._excluded_categories:
self._excluded_categories.append(category_glob)
def AddSyntheticDelay(self, delay):
assert _delay_re.match(delay)
self._synthetic_delays.add(delay)
def IsSubset(self, other):
""" Determine if filter A (self) is a subset of filter B (other).
Returns True if A is a subset of B, False if A is not a subset of B,
and None if we can't tell for sure.
"""
# We don't handle filters with wildcards in this test.
if self.contains_wildcards or other.contains_wildcards:
return None
# Disabled categories get into a trace if and only if they are contained in
# the 'disabled' set. Return False if A's disabled set is not a subset of
# B's disabled set.
if not self.disabled_by_default_categories <= \
other.disabled_by_default_categories:
return False
# If A defines more or different synthetic delays than B, then A is not a
# subset.
if not self.synthetic_delays <= other.synthetic_delays:
return False
if self.included_categories and other.included_categories:
# A and B have explicit include lists. If A includes something that B
# doesn't, return False.
if not self.included_categories <= other.included_categories:
return False
elif self.included_categories:
# Only A has an explicit include list. If A includes something that B
# excludes, return False.
if self.included_categories.intersection(other.excluded_categories):
return False
elif other.included_categories:
# Only B has an explicit include list. We don't know which categories are
# contained in the default list, so return None.
return None
else:
# None of the filter have explicit include list. If B excludes categories
# that A doesn't exclude, return False.
if not other.excluded_categories <= self.excluded_categories:
return False
return True
# 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.
import unittest
from telemetry.core.platform import tracing_category_filter
class TracingCategoryFilterTests(unittest.TestCase):
def testBasic(self):
f = tracing_category_filter.TracingCategoryFilter(
'x,-y,disabled-by-default-z,DELAY(7;foo)')
self.assertEquals(set(['x']), set(f.included_categories))
self.assertEquals(set(['y']), set(f.excluded_categories))
self.assertEquals(set(['disabled-by-default-z']),
set(f.disabled_by_default_categories))
self.assertEquals(set(['DELAY(7;foo)']), set(f.synthetic_delays))
self.assertTrue('x' in f.filter_string)
self.assertEquals(
'x,disabled-by-default-z,-y,DELAY(7;foo)',
f.stable_filter_string)
class CategoryFilterTest(unittest.TestCase):
def testIsSubset(self):
b = tracing_category_filter.TracingCategoryFilter()
a = tracing_category_filter.TracingCategoryFilter()
self.assertEquals(a.IsSubset(b), True)
b = tracing_category_filter.TracingCategoryFilter()
a = tracing_category_filter.TracingCategoryFilter("test1,test2")
self.assertEquals(a.IsSubset(b), True)
b = tracing_category_filter.TracingCategoryFilter()
a = tracing_category_filter.TracingCategoryFilter("-test1,-test2")
self.assertEquals(a.IsSubset(b), True)
b = tracing_category_filter.TracingCategoryFilter("test1,test2")
a = tracing_category_filter.TracingCategoryFilter()
self.assertEquals(a.IsSubset(b), None)
b = tracing_category_filter.TracingCategoryFilter()
a = tracing_category_filter.TracingCategoryFilter("test*")
self.assertEquals(a.IsSubset(b), None)
b = tracing_category_filter.TracingCategoryFilter("test?")
a = tracing_category_filter.TracingCategoryFilter()
self.assertEquals(a.IsSubset(b), None)
b = tracing_category_filter.TracingCategoryFilter("test1")
a = tracing_category_filter.TracingCategoryFilter("test1,test2")
self.assertEquals(a.IsSubset(b), False)
b = tracing_category_filter.TracingCategoryFilter("-test1")
a = tracing_category_filter.TracingCategoryFilter("test1")
self.assertEquals(a.IsSubset(b), False)
b = tracing_category_filter.TracingCategoryFilter("test1,test2")
a = tracing_category_filter.TracingCategoryFilter("test2,test1")
self.assertEquals(a.IsSubset(b), True)
b = tracing_category_filter.TracingCategoryFilter("-test1,-test2")
a = tracing_category_filter.TracingCategoryFilter("-test2")
self.assertEquals(a.IsSubset(b), False)
b = tracing_category_filter.TracingCategoryFilter(
"disabled-by-default-test1")
a = tracing_category_filter.TracingCategoryFilter(
"disabled-by-default-test1,disabled-by-default-test2")
self.assertEquals(a.IsSubset(b), False)
b = tracing_category_filter.TracingCategoryFilter(
"disabled-by-default-test1")
a = tracing_category_filter.TracingCategoryFilter(
"disabled-by-default-test2")
self.assertEquals(a.IsSubset(b), False)
def testIsSubsetWithSyntheticDelays(self):
b = tracing_category_filter.TracingCategoryFilter("DELAY(foo;0.016)")
a = tracing_category_filter.TracingCategoryFilter("DELAY(foo;0.016)")
self.assertEquals(a.IsSubset(b), True)
b = tracing_category_filter.TracingCategoryFilter("DELAY(foo;0.016)")
a = tracing_category_filter.TracingCategoryFilter()
self.assertEquals(a.IsSubset(b), True)
b = tracing_category_filter.TracingCategoryFilter()
a = tracing_category_filter.TracingCategoryFilter("DELAY(foo;0.016)")
self.assertEquals(a.IsSubset(b), False)
b = tracing_category_filter.TracingCategoryFilter("DELAY(foo;0.016)")
a = tracing_category_filter.TracingCategoryFilter("DELAY(foo;0.032)")
self.assertEquals(a.IsSubset(b), False)
b = tracing_category_filter.TracingCategoryFilter(
"DELAY(foo;0.016;static)")
a = tracing_category_filter.TracingCategoryFilter(
"DELAY(foo;0.016;oneshot)")
self.assertEquals(a.IsSubset(b), False)
b = tracing_category_filter.TracingCategoryFilter(
"DELAY(foo;0.016),DELAY(bar;0.1)")
a = tracing_category_filter.TracingCategoryFilter(
"DELAY(bar;0.1),DELAY(foo;0.016)")
self.assertEquals(a.IsSubset(b), True)
b = tracing_category_filter.TracingCategoryFilter(
"DELAY(foo;0.016),DELAY(bar;0.1)")
a = tracing_category_filter.TracingCategoryFilter(
"DELAY(bar;0.1)")
self.assertEquals(a.IsSubset(b), True)
b = tracing_category_filter.TracingCategoryFilter(
"DELAY(foo;0.016),DELAY(bar;0.1)")
a = tracing_category_filter.TracingCategoryFilter(
"DELAY(foo;0.032),DELAY(bar;0.1)")
self.assertEquals(a.IsSubset(b), False)
# 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.
class TracingController(object):
def __init__(self, tracing_controller_backend):
"""Provides control of the tracing systems supported by telemetry."""
self._tracing_controller_backend = tracing_controller_backend
def Start(self, trace_options, category_filter, timeout=10):
"""Starts tracing.
trace_options specifies which tracing systems to activate. Category filter
allows fine-tuning of the data that are collected by the selected tracing
systems.
Some tracers are process-specific, e.g. chrome tracing, but are not
guaranteed to be supported. In order to support tracing of these kinds of
tracers, Start will succeed *always*, even if the tracing systems you have
requested are not supported.
If you absolutely require a particular tracer to exist, then check
for its support after you have started the process in question. Or, have
your code fail gracefully when the data you require is not present in the
resulting trace.
"""
self._tracing_controller_backend.Start(
trace_options, category_filter, timeout)
def Stop(self):
"""Stops tracing and returns a TraceValue."""
return self._tracing_controller_backend.Stop()
@property
def is_tracing_running(self):
return self._tracing_controller_backend.is_tracing_running
def IsChromeTracingSupported(self, browser):
"""Returns whether chrome tracing is supported on the given browser."""
return self._tracing_controller_backend.IsChromeTracingSupported(browser)
# 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.
from telemetry.core.platform import tracing_category_filter
from telemetry.core.platform import tracing_options
class TracingControllerBackend(object):
def __init__(self, platform_backend):
self._platform_backend = platform_backend
self._current_trace_options = None
self._current_category_filter = None
def Start(self, trace_options, category_filter, timeout):
if self.is_tracing_running:
return False
assert isinstance(category_filter,
tracing_category_filter.TracingCategoryFilter)
assert isinstance(trace_options,
tracing_options.TracingOptions)
if len(self.running_browser_backends) != 1:
# Note: it is possible to implement tracing for both the case of 0 and >1.
# For >1, we just need to merge the trace files at StopTracing.
#
# For 0, we want to modify chrome's trace-startup to support leaving
# tracing on indefinitely. Then have the backend notify the platform
# and the tracing controller that it is starting a browser, have
# the controller add in the trace-startup command, and then when we get
# the Stop message or the DidStopBrowser(), issue the stop tracing command
# on the right backend.
raise NotImplementedError()
self._current_trace_options = trace_options
self._current_category_filter = category_filter
if trace_options.enable_chrome_trace:
browser_backend = self.running_browser_backends[0]
browser_backend.StartTracing(
category_filter.filter_string, timeout)
def Stop(self):
if not self.is_tracing_running:
raise Exception('Not tracing')
if len(self.running_browser_backends) != 1:
raise NotImplementedError()
result = None
if self._current_trace_options.enable_chrome_trace:
browser_backend = self.running_browser_backends[0]
result = browser_backend.StopTracing()
self._current_trace_options = None
self._current_category_filter = None
return result
def IsChromeTracingSupported(self, browser):
browser_backend = self._platform_backend.GetBackendForBrowser(browser)
return browser_backend.supports_tracing
@property
def is_tracing_running(self):
return self._current_trace_options != None
@property
def running_browser_backends(self):
return self._platform_backend.running_browser_backends
def DidStartBrowser(self, browser, browser_backend):
pass
def WillCloseBrowser(self, browser, browser_backend):
pass
\ No newline at end of file
# 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.
class TracingOptions(object):
"""Tracing options control which core tracing systems should be enabled.
This simply turns on those systems. If those systems have additional options,
e.g. what to trace, then they are typically configured by adding
categories to the TracingCategoryFilter.
"""
def __init__(self):
self.enable_chrome_trace = False
\ No newline at end of file
...@@ -10,7 +10,7 @@ from telemetry.core import bitmap ...@@ -10,7 +10,7 @@ from telemetry.core import bitmap
from telemetry.core import video from telemetry.core import video
from telemetry.core import util from telemetry.core import util
from telemetry.core import exceptions from telemetry.core import exceptions
from telemetry.core.backends.chrome import tracing_backend from telemetry.core.platform import tracing_category_filter
from telemetry.timeline import model from telemetry.timeline import model
from telemetry.unittest import tab_test_case from telemetry.unittest import tab_test_case
...@@ -23,6 +23,13 @@ class FakePlatformBackend(object): ...@@ -23,6 +23,13 @@ class FakePlatformBackend(object):
def __init__(self): def __init__(self):
self.platform = FakePlatform() self.platform = FakePlatform()
def DidStartBrowser(self, _, _2):
pass
def WillCloseBrowser(self, _, _2):
pass
class FakePlatform(object): class FakePlatform(object):
def __init__(self): def __init__(self):
self._is_video_capture_running = False self._is_video_capture_running = False
...@@ -35,9 +42,6 @@ class FakePlatform(object): ...@@ -35,9 +42,6 @@ class FakePlatform(object):
self._is_video_capture_running = False self._is_video_capture_running = False
return video.Video(tempfile.NamedTemporaryFile()) return video.Video(tempfile.NamedTemporaryFile())
def SetFullPerformanceModeEnabled(self, enabled):
pass
@property @property
def is_video_capture_running(self): def is_video_capture_running(self):
return self._is_video_capture_running return self._is_video_capture_running
...@@ -100,7 +104,7 @@ class TabTest(tab_test_case.TabTestCase): ...@@ -100,7 +104,7 @@ class TabTest(tab_test_case.TabTestCase):
def testHighlight(self): def testHighlight(self):
self.assertEquals(self._tab.url, 'about:blank') self.assertEquals(self._tab.url, 'about:blank')
self._browser.StartTracing(tracing_backend.DEFAULT_TRACE_CATEGORIES) self._browser.StartTracing()
self._tab.Highlight(bitmap.WEB_PAGE_TEST_ORANGE) self._tab.Highlight(bitmap.WEB_PAGE_TEST_ORANGE)
self._tab.ClearHighlight(bitmap.WEB_PAGE_TEST_ORANGE) self._tab.ClearHighlight(bitmap.WEB_PAGE_TEST_ORANGE)
trace_data = self._browser.StopTracing() trace_data = self._browser.StopTracing()
...@@ -127,7 +131,8 @@ class TabTest(tab_test_case.TabTestCase): ...@@ -127,7 +131,8 @@ class TabTest(tab_test_case.TabTestCase):
third_tab.WaitForDocumentReadyStateToBeInteractiveOrBetter() third_tab.WaitForDocumentReadyStateToBeInteractiveOrBetter()
third_tab.Close() third_tab.Close()
self._browser.StartTracing(tracing_backend.MINIMAL_TRACE_CATEGORIES) self._browser.StartTracing(
tracing_category_filter.CreateNoOverheadFilter())
first_tab.ExecuteJavaScript('console.time("first-tab-marker");') first_tab.ExecuteJavaScript('console.time("first-tab-marker");')
first_tab.ExecuteJavaScript('console.timeEnd("first-tab-marker");') first_tab.ExecuteJavaScript('console.timeEnd("first-tab-marker");')
second_tab.ExecuteJavaScript('console.time("second-tab-marker");') second_tab.ExecuteJavaScript('console.time("second-tab-marker");')
......
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
from telemetry import benchmark from telemetry import benchmark
from telemetry.core import exceptions from telemetry.core import exceptions
from telemetry.core import util from telemetry.core import util
from telemetry.core.backends.chrome import tracing_backend
from telemetry.timeline import model from telemetry.timeline import model
from telemetry.page.actions import action_runner as action_runner_module from telemetry.page.actions import action_runner as action_runner_module
from telemetry.page.actions import page_action from telemetry.page.actions import page_action
...@@ -28,7 +27,7 @@ class ActionRunnerInteractionTest(tab_test_case.TabTestCase): ...@@ -28,7 +27,7 @@ class ActionRunnerInteractionTest(tab_test_case.TabTestCase):
action_runner = action_runner_module.ActionRunner(self._tab) action_runner = action_runner_module.ActionRunner(self._tab)
self.Navigate('interaction_enabled_page.html') self.Navigate('interaction_enabled_page.html')
action_runner.Wait(1) action_runner.Wait(1)
self._browser.StartTracing(tracing_backend.DEFAULT_TRACE_CATEGORIES) self._browser.StartTracing()
interaction = action_runner.BeginInteraction('InteractionName', interaction = action_runner.BeginInteraction('InteractionName',
**interaction_kwargs) **interaction_kwargs)
interaction.End() interaction.End()
......
...@@ -7,7 +7,7 @@ import os ...@@ -7,7 +7,7 @@ import os
from collections import defaultdict from collections import defaultdict
from telemetry.core import util from telemetry.core import util
from telemetry.core.backends.chrome import tracing_backend from telemetry.core.platform import tracing_category_filter
from telemetry.timeline import model as model_module from telemetry.timeline import model as model_module
from telemetry.web_perf import timeline_interaction_record as tir_module from telemetry.web_perf import timeline_interaction_record as tir_module
from telemetry.web_perf.metrics import fast_metric from telemetry.web_perf.metrics import fast_metric
...@@ -153,16 +153,19 @@ class TimelineBasedMeasurement(page_measurement.PageMeasurement): ...@@ -153,16 +153,19 @@ class TimelineBasedMeasurement(page_measurement.PageMeasurement):
def WillNavigateToPage(self, page, tab): def WillNavigateToPage(self, page, tab):
if not tab.browser.supports_tracing: if not tab.browser.supports_tracing:
raise Exception('Not supported') raise Exception('Not supported')
assert self.options.overhead_level in ALL_OVERHEAD_LEVELS assert self.options.overhead_level in ALL_OVERHEAD_LEVELS
if self.options.overhead_level == NO_OVERHEAD_LEVEL: if self.options.overhead_level == NO_OVERHEAD_LEVEL:
categories = tracing_backend.MINIMAL_TRACE_CATEGORIES category_filter = tracing_category_filter.CreateNoOverheadFilter()
elif self.options.overhead_level == \ elif self.options.overhead_level == MINIMAL_OVERHEAD_LEVEL:
MINIMAL_OVERHEAD_LEVEL: category_filter = tracing_category_filter.CreateMinimalOverheadFilter()
categories = ''
else: else:
categories = '*,disabled-by-default-cc.debug' category_filter = tracing_category_filter.CreateDebugOverheadFilter()
categories = ','.join([categories] + page.GetSyntheticDelayCategories())
tab.browser.StartTracing(categories) for delay in page.GetSyntheticDelayCategories():
category_filter.AddSyntheticDelay(delay)
tab.browser.StartTracing(category_filter)
def MeasurePage(self, page, tab, results): def MeasurePage(self, page, tab, results):
""" Collect all possible metrics and added them to results. """ """ Collect all possible metrics and added them to results. """
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment