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. 4import sys 5 6from measurements import smooth_gesture_util 7from telemetry.timeline.model import TimelineModel 8from telemetry.page import page_measurement 9from telemetry.page.actions import action_runner 10from telemetry.web_perf import timeline_interaction_record as tir_module 11from telemetry.web_perf.metrics import smoothness 12 13 14RUN_SMOOTH_ACTIONS = 'RunSmoothAllActions' 15 16 17class MissingDisplayFrameRateError(page_measurement.MeasurementFailure): 18 def __init__(self, name): 19 super(MissingDisplayFrameRateError, self).__init__( 20 'Missing display frame rate metrics: ' + name) 21 22class SmoothnessController(object): 23 def __init__(self): 24 self._timeline_model = None 25 self._tracing_timeline_data = None 26 self._interaction = None 27 28 def Start(self, page, tab): 29 # FIXME: Remove webkit.console when blink.console lands in chromium and 30 # the ref builds are updated. crbug.com/386847 31 custom_categories = ['webkit.console', 'blink.console', 'benchmark'] 32 custom_categories += page.GetSyntheticDelayCategories() 33 tab.browser.StartTracing(','.join(custom_categories), 60) 34 if tab.browser.platform.IsRawDisplayFrameRateSupported(): 35 tab.browser.platform.StartRawDisplayFrameRateMeasurement() 36 # Start the smooth marker for all smooth actions. 37 runner = action_runner.ActionRunner(tab) 38 self._interaction = runner.BeginInteraction( 39 RUN_SMOOTH_ACTIONS, is_smooth=True) 40 41 def Stop(self, tab): 42 # End the smooth marker for all smooth actions. 43 self._interaction.End() 44 # Stop tracing for smoothness metric. 45 if tab.browser.platform.IsRawDisplayFrameRateSupported(): 46 tab.browser.platform.StopRawDisplayFrameRateMeasurement() 47 self._tracing_timeline_data = tab.browser.StopTracing() 48 self._timeline_model = TimelineModel( 49 timeline_data=self._tracing_timeline_data) 50 51 def AddResults(self, tab, results): 52 # Add results of smoothness metric. This computes the smoothness metric for 53 # the time ranges of gestures, if there is at least one, else the the time 54 # ranges from the first action to the last action. 55 56 renderer_thread = self._timeline_model.GetRendererThreadFromTabId( 57 tab.id) 58 run_smooth_actions_record = None 59 smooth_records = [] 60 for event in renderer_thread.async_slices: 61 if not tir_module.IsTimelineInteractionRecord(event.name): 62 continue 63 r = tir_module.TimelineInteractionRecord.FromAsyncEvent(event) 64 if r.logical_name == RUN_SMOOTH_ACTIONS: 65 assert run_smooth_actions_record is None, ( 66 'SmoothnessController cannot issue more than 1 %s record' % 67 RUN_SMOOTH_ACTIONS) 68 run_smooth_actions_record = r 69 elif r.is_smooth: 70 smooth_records.append( 71 smooth_gesture_util.GetAdjustedInteractionIfContainGesture( 72 self._timeline_model, r)) 73 74 # If there is no other smooth records, we make measurements on time range 75 # marked smoothness_controller itself. 76 # TODO(nednguyen): when crbug.com/239179 is marked fixed, makes sure that 77 # page sets are responsible for issueing the markers themselves. 78 if len(smooth_records) == 0: 79 if run_smooth_actions_record is None: 80 sys.stderr.write('Raw tracing data:\n') 81 sys.stderr.write(repr(self._tracing_timeline_data.EventData())) 82 sys.stderr.write('\n') 83 raise Exception('SmoothnessController failed to issue markers for the ' 84 'whole interaction.') 85 else: 86 smooth_records = [run_smooth_actions_record] 87 88 # Create an interaction_record for this legacy measurement. Since we don't 89 # wrap the results that is sent to smoothnes metric, the logical_name will 90 # not be used. 91 smoothness_metric = smoothness.SmoothnessMetric() 92 smoothness_metric.AddResults( 93 self._timeline_model, renderer_thread, smooth_records, results) 94 if tab.browser.platform.IsRawDisplayFrameRateSupported(): 95 for r in tab.browser.platform.GetRawDisplayFrameRateMeasurements(): 96 if r.value is None: 97 raise MissingDisplayFrameRateError(r.name) 98 results.Add(r.name, r.unit, r.value) 99 100 def CleanUp(self, tab): 101 if tab.browser.platform.IsRawDisplayFrameRateSupported(): 102 tab.browser.platform.StopRawDisplayFrameRateMeasurement() 103 if tab.browser.is_tracing_running: 104 tab.browser.StopTracing() 105