Home | History | Annotate | Download | only in measurements
      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.
      4 import sys
      5 
      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
     16 
     17 
     18 RUN_SMOOTH_ACTIONS = 'RunSmoothAllActions'
     19 
     20 # Descriptions for results from platform.GetRawDisplayFrameRateMeasurements().
     21 DESCRIPTIONS = {
     22     'avg_surface_fps': 'Average frames per second as measured by the '
     23                        'platform\'s SurfaceFlinger.'
     24 }
     25 
     26 
     27 class MissingDisplayFrameRateError(page_test.MeasurementFailure):
     28   def __init__(self, name):
     29     super(MissingDisplayFrameRateError, self).__init__(
     30       'Missing display frame rate metrics: ' + name)
     31 
     32 class SmoothnessController(object):
     33   def __init__(self):
     34     self._timeline_model = None
     35     self._tracing_timeline_data = None
     36     self._interaction = None
     37 
     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()
     51 
     52   def Start(self, tab):
     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)
     57 
     58   def Stop(self, tab):
     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)
     67 
     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.
     72 
     73     renderer_thread = self._timeline_model.GetRendererThreadFromTabId(
     74         tab.id)
     75     run_smooth_actions_record = None
     76     smooth_records = []
     77     for event in renderer_thread.async_slices:
     78       if not tir_module.IsTimelineInteractionRecord(event.name):
     79         continue
     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' %
     84           RUN_SMOOTH_ACTIONS)
     85         run_smooth_actions_record = r
     86       elif r.is_smooth:
     87         smooth_records.append(
     88           smooth_gesture_util.GetAdjustedInteractionIfContainGesture(
     89             self._timeline_model, r))
     90 
     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.')
    102       else:
    103         smooth_records = [run_smooth_actions_record]
    104 
    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
    107     # not be used.
    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():
    113         if r.value is None:
    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)))
    119         else:
    120           results.AddValue(scalar.ScalarValue(
    121               results.current_page, r.name, r.unit, r.value,
    122               description=DESCRIPTIONS.get(r.name)))
    123 
    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()
    129