| # 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 sys |
| |
| from measurements import smooth_gesture_util |
| from telemetry.timeline.model import TimelineModel |
| from telemetry.page import page_measurement |
| from telemetry.page.actions import action_runner |
| from telemetry.web_perf import timeline_interaction_record as tir_module |
| from telemetry.web_perf.metrics import smoothness |
| |
| |
| RUN_SMOOTH_ACTIONS = 'RunSmoothAllActions' |
| |
| |
| class MissingDisplayFrameRateError(page_measurement.MeasurementFailure): |
| def __init__(self, name): |
| super(MissingDisplayFrameRateError, self).__init__( |
| 'Missing display frame rate metrics: ' + name) |
| |
| class SmoothnessController(object): |
| def __init__(self): |
| self._timeline_model = None |
| self._tracing_timeline_data = None |
| self._interaction = None |
| |
| def Start(self, page, tab): |
| # FIXME: Remove webkit.console when blink.console lands in chromium and |
| # the ref builds are updated. crbug.com/386847 |
| custom_categories = ['webkit.console', 'blink.console', 'benchmark'] |
| custom_categories += page.GetSyntheticDelayCategories() |
| tab.browser.StartTracing(','.join(custom_categories), 60) |
| if tab.browser.platform.IsRawDisplayFrameRateSupported(): |
| tab.browser.platform.StartRawDisplayFrameRateMeasurement() |
| # Start the smooth marker for all smooth actions. |
| runner = action_runner.ActionRunner(tab) |
| self._interaction = runner.BeginInteraction( |
| RUN_SMOOTH_ACTIONS, is_smooth=True) |
| |
| def Stop(self, tab): |
| # End the smooth marker for all smooth actions. |
| self._interaction.End() |
| # Stop tracing for smoothness metric. |
| if tab.browser.platform.IsRawDisplayFrameRateSupported(): |
| tab.browser.platform.StopRawDisplayFrameRateMeasurement() |
| self._tracing_timeline_data = tab.browser.StopTracing() |
| self._timeline_model = TimelineModel( |
| timeline_data=self._tracing_timeline_data) |
| |
| def AddResults(self, tab, results): |
| # Add results of smoothness metric. This computes the smoothness metric for |
| # the time ranges of gestures, if there is at least one, else the the time |
| # ranges from the first action to the last action. |
| |
| renderer_thread = self._timeline_model.GetRendererThreadFromTabId( |
| tab.id) |
| run_smooth_actions_record = None |
| smooth_records = [] |
| for event in renderer_thread.async_slices: |
| if not tir_module.IsTimelineInteractionRecord(event.name): |
| continue |
| r = tir_module.TimelineInteractionRecord.FromAsyncEvent(event) |
| if r.logical_name == RUN_SMOOTH_ACTIONS: |
| assert run_smooth_actions_record is None, ( |
| 'SmoothnessController cannot issue more than 1 %s record' % |
| RUN_SMOOTH_ACTIONS) |
| run_smooth_actions_record = r |
| elif r.is_smooth: |
| smooth_records.append( |
| smooth_gesture_util.GetAdjustedInteractionIfContainGesture( |
| self._timeline_model, r)) |
| |
| # If there is no other smooth records, we make measurements on time range |
| # marked smoothness_controller itself. |
| # TODO(nednguyen): when crbug.com/239179 is marked fixed, makes sure that |
| # page sets are responsible for issueing the markers themselves. |
| if len(smooth_records) == 0: |
| if run_smooth_actions_record is None: |
| sys.stderr.write('Raw tracing data:\n') |
| sys.stderr.write(repr(self._tracing_timeline_data.EventData())) |
| sys.stderr.write('\n') |
| raise Exception('SmoothnessController failed to issue markers for the ' |
| 'whole interaction.') |
| else: |
| smooth_records = [run_smooth_actions_record] |
| |
| # Create an interaction_record for this legacy measurement. Since we don't |
| # wrap the results that is sent to smoothnes metric, the logical_name will |
| # not be used. |
| smoothness_metric = smoothness.SmoothnessMetric() |
| smoothness_metric.AddResults( |
| self._timeline_model, renderer_thread, smooth_records, results) |
| if tab.browser.platform.IsRawDisplayFrameRateSupported(): |
| for r in tab.browser.platform.GetRawDisplayFrameRateMeasurements(): |
| if r.value is None: |
| raise MissingDisplayFrameRateError(r.name) |
| results.Add(r.name, r.unit, r.value) |
| |
| def CleanUp(self, tab): |
| if tab.browser.platform.IsRawDisplayFrameRateSupported(): |
| tab.browser.platform.StopRawDisplayFrameRateMeasurement() |
| if tab.browser.is_tracing_running: |
| tab.browser.StopTracing() |