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.
6 from measurements import smooth_gesture_util
7 from telemetry.core.platform import tracing_category_filter
8 from telemetry.core.platform import tracing_options
9 from telemetry.timeline.model import TimelineModel
10 from telemetry.page import page_test
11 from telemetry.page.actions import action_runner
12 from telemetry.value import list_of_scalar_values
13 from telemetry.value import scalar
14 from telemetry.web_perf import timeline_interaction_record as tir_module
15 from telemetry.web_perf.metrics import smoothness
18 RUN_SMOOTH_ACTIONS = 'RunSmoothAllActions'
20 # Descriptions for results from platform.GetRawDisplayFrameRateMeasurements().
22 'avg_surface_fps': 'Average frames per second as measured by the '
23 'platform\'s SurfaceFlinger.'
27 class MissingDisplayFrameRateError(page_test.MeasurementFailure):
28 def __init__(self, name):
29 super(MissingDisplayFrameRateError, self).__init__(
30 'Missing display frame rate metrics: ' + name)
32 class SmoothnessController(object):
34 self._timeline_model = None
35 self._tracing_timeline_data = None
36 self._interaction = None
38 def SetUp(self, page, tab):
39 # FIXME: Remove webkit.console when blink.console lands in chromium and
40 # the ref builds are updated. crbug.com/386847
41 custom_categories = ['webkit.console', 'blink.console', 'benchmark']
42 custom_categories += page.GetSyntheticDelayCategories()
43 category_filter = tracing_category_filter.TracingCategoryFilter()
44 for c in custom_categories:
45 category_filter.AddIncludedCategory(c)
46 options = tracing_options.TracingOptions()
47 options.enable_chrome_trace = True
48 tab.browser.platform.tracing_controller.Start(options, category_filter, 60)
49 if tab.browser.platform.IsRawDisplayFrameRateSupported():
50 tab.browser.platform.StartRawDisplayFrameRateMeasurement()
53 # Start the smooth marker for all smooth actions.
54 runner = action_runner.ActionRunner(tab)
55 self._interaction = runner.BeginInteraction(
56 RUN_SMOOTH_ACTIONS, is_smooth=True)
59 # End the smooth marker for all smooth actions.
60 self._interaction.End()
61 # Stop tracing for smoothness metric.
62 if tab.browser.platform.IsRawDisplayFrameRateSupported():
63 tab.browser.platform.StopRawDisplayFrameRateMeasurement()
64 self._tracing_timeline_data = tab.browser.platform.tracing_controller.Stop()
65 self._timeline_model = TimelineModel(
66 timeline_data=self._tracing_timeline_data)
68 def AddResults(self, tab, results):
69 # Add results of smoothness metric. This computes the smoothness metric for
70 # the time ranges of gestures, if there is at least one, else the the time
71 # ranges from the first action to the last action.
73 renderer_thread = self._timeline_model.GetRendererThreadFromTabId(
75 run_smooth_actions_record = None
77 for event in renderer_thread.async_slices:
78 if not tir_module.IsTimelineInteractionRecord(event.name):
80 r = tir_module.TimelineInteractionRecord.FromAsyncEvent(event)
81 if r.label == RUN_SMOOTH_ACTIONS:
82 assert run_smooth_actions_record is None, (
83 'SmoothnessController cannot issue more than 1 %s record' %
85 run_smooth_actions_record = r
87 smooth_records.append(
88 smooth_gesture_util.GetAdjustedInteractionIfContainGesture(
89 self._timeline_model, r))
91 # If there is no other smooth records, we make measurements on time range
92 # marked smoothness_controller itself.
93 # TODO(nednguyen): when crbug.com/239179 is marked fixed, makes sure that
94 # page sets are responsible for issueing the markers themselves.
95 if len(smooth_records) == 0:
96 if run_smooth_actions_record is None:
97 sys.stderr.write('Raw tracing data:\n')
98 sys.stderr.write(repr(self._tracing_timeline_data.EventData()))
99 sys.stderr.write('\n')
100 raise Exception('SmoothnessController failed to issue markers for the '
101 'whole interaction.')
103 smooth_records = [run_smooth_actions_record]
105 # Create an interaction_record for this legacy measurement. Since we don't
106 # wrap the results that are sent to smoothness metric, the label will
108 smoothness_metric = smoothness.SmoothnessMetric()
109 smoothness_metric.AddResults(
110 self._timeline_model, renderer_thread, smooth_records, results)
111 if tab.browser.platform.IsRawDisplayFrameRateSupported():
112 for r in tab.browser.platform.GetRawDisplayFrameRateMeasurements():
114 raise MissingDisplayFrameRateError(r.name)
115 if isinstance(r.value, list):
116 results.AddValue(list_of_scalar_values.ListOfScalarValues(
117 results.current_page, r.name, r.unit, r.value,
118 description=DESCRIPTIONS.get(r.name)))
120 results.AddValue(scalar.ScalarValue(
121 results.current_page, r.name, r.unit, r.value,
122 description=DESCRIPTIONS.get(r.name)))
124 def CleanUp(self, tab):
125 if tab.browser.platform.IsRawDisplayFrameRateSupported():
126 tab.browser.platform.StopRawDisplayFrameRateMeasurement()
127 if tab.browser.platform.tracing_controller.is_tracing_running:
128 tab.browser.platform.tracing_controller.Stop()