Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 import math | 5 import math |
| 6 from telemetry.value import scalar | 6 from telemetry.value import list_of_scalar_values |
| 7 from telemetry.web_perf.metrics import timeline_based_metric | 7 from telemetry.web_perf.metrics import timeline_based_metric |
| 8 | 8 |
| 9 | 9 |
| 10 class LayoutMetric(timeline_based_metric.TimelineBasedMetric): | 10 class LayoutMetric(timeline_based_metric.TimelineBasedMetric): |
| 11 """Computes metrics that measure layout performance, specifically, | 11 """Reports directly durations of FrameView::performLayout events. |
| 12 avg and stddev of CPU time of layout-related trace events: | |
| 13 | 12 |
| 14 layout_total_{avg,stddev}: FrameView::layout | 13 layout_load: Layout events caused by page load. |
| 15 layout_{avg,stddev}: FrameView::performLayout | 14 layout_animation: Layout events caused by user interaction. |
| 16 pre_layout_{avg,stddev}: FrameView::performPreLayoutTasks | |
| 17 post_layout_{avg,stddev}: FrameView::performPostLayoutTasks | |
| 18 layer_positions_{avg,stddev}: RenderLayer::updateLayerPositionsAfterLayout | |
| 19 | 15 |
| 20 Layout happens no more than once per frame, so per-frame-ness is implied. | 16 Layout happens no more than once per frame, so per-frame-ness is implied. |
| 21 Not all pages have interactions, so interaction records are not required. | |
| 22 """ | 17 """ |
| 23 EVENTS = { | |
| 24 'FrameView::layout': 'layout_total', | |
| 25 'FrameView::performLayout': 'layout', | |
| 26 'FrameView::performPreLayoutTasks': 'pre_layout', | |
| 27 'FrameView::performPostLayoutTasks': 'post_layout', | |
| 28 'RenderLayer::updateLayerPositionsAfterLayout': 'layer_positions', | |
| 29 } | |
| 30 | 18 |
| 31 def __init__(self): | 19 def __init__(self): |
| 32 super(LayoutMetric, self).__init__() | 20 super(LayoutMetric, self).__init__() |
| 33 | 21 |
| 34 def AddResults(self, _model, renderer_thread, _interaction_records, results): | 22 def AddResults(self, _model, renderer_thread, interactions, results): |
| 35 self._AddResults(renderer_thread.parent.IterAllSlices(), results) | 23 self._AddResultsInternal(renderer_thread.parent.IterAllSlices(), |
| 24 interactions, results) | |
| 36 | 25 |
| 37 def _AddResults(self, events, results): | 26 def _AddResultsInternal(self, events, interactions, results): |
| 38 metrics = dict((long_name, (short_name, [])) for long_name, short_name in | 27 layouts = [] |
| 39 self.EVENTS.iteritems()) | |
| 40 | |
| 41 for event in events: | 28 for event in events: |
| 42 if event.name in metrics: | 29 if ((event.name == 'FrameView::performLayout') and |
| 43 metrics[event.name][1].append(event.end - event.start) | 30 ((not interactions) or any( |
| 44 | 31 interaction.start <= event.start < interaction.end |
| 45 for long_name, (short_name, durations) in metrics.iteritems(): | 32 for interaction in interactions))): |
| 46 count = len(durations) | 33 layouts.append(event.end - event.start) |
| 47 avg = 0.0 | 34 if not layouts: |
| 48 stddev = 0.0 | 35 return |
| 49 if count: | 36 description = 'List of durations of layouts' |
| 50 avg = sum(durations) / count | 37 label = 'layout' |
| 51 stddev = math.sqrt(sum((d - avg) ** 2 for d in durations) / count) | 38 if interactions: |
| 52 results.AddValue(scalar.ScalarValue(results.current_page, | 39 if interactions[0].label == 'load': |
|
nednguyen
2015/03/31 22:49:03
This sounds about right. However, to check whether
benjhayden
2015/04/01 20:22:45
Let's punt the load event to another CL.
nednguyen
2015/04/01 20:25:50
I like this. Fixing the TODO is add the Load inter
| |
| 53 short_name + '_avg', 'ms', avg, | 40 # Loading a page should take no more than 1000ms, so load layout may |
| 54 description='Average duration of %s events' % long_name)) | 41 # take some hundreds of ms total. |
| 55 results.AddValue(scalar.ScalarValue(results.current_page, | 42 label += '_load' |
|
nednguyen
2015/03/31 22:49:03
label is supposed to be just interaction record la
benjhayden
2015/04/01 20:22:45
It sounds like you're saying that the result label
nednguyen
2015/04/01 20:25:50
label is interaction record label, name is for the
| |
| 56 short_name + '_stddev', 'ms', stddev, | 43 else: |
| 57 description='stddev of duration of %s events' % long_name)) | 44 # We don't care if the interactions are Smoothness or Click or Swipe or |
| 45 # Scroll or whatever, all we care about is that the layout events were | |
| 46 # caused by user interaction rather than load. | |
| 47 # Animations should take no more than 150ms to paint the first frame | |
| 48 # after an interaction begins, then no more than 16ms for each frame | |
| 49 # after that. So the first layout after an interaction begins should | |
| 50 # cost no more than 100ms or so, and every layout after that should cost | |
| 51 # no more than 5ms or so. | |
| 52 label += '_animation' | |
| 53 description += ' that start in response to user interaction' | |
| 54 results.AddValue(list_of_scalar_values.ListOfScalarValues( | |
| 55 results.current_page, label, 'ms', layouts, description=description)) | |
| OLD | NEW |