summaryrefslogtreecommitdiffstats
path: root/tools/perf/measurements/smoothness_controller.py
blob: fd38609fa07853f51337dce0c8c4bd0e243eb92c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# 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.core.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

  def Start(self, page, tab):
    custom_categories = ['webkit.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)
    runner.BeginInteraction(RUN_SMOOTH_ACTIONS, [tir_module.IS_SMOOTH])

  def Stop(self, tab):
    # End the smooth marker for all smooth actions.
    runner = action_runner.ActionRunner(tab)
    runner.EndInteraction(RUN_SMOOTH_ACTIONS, [tir_module.IS_SMOOTH])
    # 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.GetRendererThreadFromTab(tab)
    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()