Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(313)

Unified Diff: tools/perf/metrics/speedindex.py

Issue 805393003: [Telemetry] Remove old paint-rect speed index implementation. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Report none value when not supported Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | tools/perf/metrics/speedindex_unittest.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/perf/metrics/speedindex.py
diff --git a/tools/perf/metrics/speedindex.py b/tools/perf/metrics/speedindex.py
index 389cd7e0c767565ab1fe4c272d7a6ce31b8e0724..4ada00809ee1b14a6f16270998d97434d4f2c82e 100644
--- a/tools/perf/metrics/speedindex.py
+++ b/tools/perf/metrics/speedindex.py
@@ -3,6 +3,7 @@
# found in the LICENSE file.
import collections
+import logging
from metrics import Metric
from telemetry.image_processing import image_util
@@ -36,12 +37,15 @@ class SpeedIndexMetric(Metric):
a PageTest, so that all the events can be captured. If it's called
in DidNavigateToPage, that will be too late.
"""
- self._impl = (VideoSpeedIndexImpl() if tab.video_capture_supported else
- PaintRectSpeedIndexImpl())
+ if not tab.video_capture_supported:
+ return
+ self._impl = VideoSpeedIndexImpl()
self._impl.Start(tab)
def Stop(self, _, tab):
- """Stop timeline recording."""
+ """Stop recording."""
+ if not tab.video_capture_supported:
+ return
assert self._impl, 'Must call Start() before Stop()'
assert self.IsFinished(tab), 'Must wait for IsFinished() before Stop()'
self._impl.Stop(tab)
@@ -50,9 +54,16 @@ class SpeedIndexMetric(Metric):
# pylint: disable=W0221
def AddResults(self, tab, results, chart_name=None):
"""Calculate the speed index and add it to the results."""
- index = self._impl.CalculateSpeedIndex(tab)
- # Release the tab so that it can be disconnected.
- self._impl = None
+ try:
+ if tab.video_capture_supported:
+ index = self._impl.CalculateSpeedIndex(tab)
+ none_value_reason = None
+ else:
+ index = None
+ none_value_reason = 'Video capture is not supported.'
+ finally:
+ self._impl = None # Release the tab so that it can be disconnected.
+
results.AddValue(scalar.ScalarValue(
results.current_page, '%s_speed_index' % chart_name, 'ms', index,
description='Speed Index. This focuses on time when visible parts of '
@@ -70,15 +81,10 @@ class SpeedIndexMetric(Metric):
'there are two implementations: for Android and for '
'Desktop. The Android version uses video capture; the '
'Desktop one uses paint events and has extra overhead to '
- 'catch paint events.'))
+ 'catch paint events.', none_value_reason=none_value_reason))
def IsFinished(self, tab):
- """Decide whether the timeline recording should be stopped.
-
- When the timeline recording is stopped determines which paint events
- are used in the speed index metric calculation. In general, the recording
- should continue if there has just been some data received, because
- this suggests that painting may continue.
+ """Decide whether the recording should be stopped.
A page may repeatedly request resources in an infinite loop; a timeout
should be placed in any measurement that uses this metric, e.g.:
@@ -182,145 +188,3 @@ class VideoSpeedIndexImpl(SpeedIndexImpl):
def GetTimeCompletenessList(self, tab):
assert self._time_completeness_list, 'Must call Stop() first.'
return self._time_completeness_list
-
-
-class PaintRectSpeedIndexImpl(SpeedIndexImpl):
-
- def __init__(self):
- super(PaintRectSpeedIndexImpl, self).__init__()
-
- def Start(self, tab):
- tab.StartTimelineRecording()
-
- def Stop(self, tab):
- tab.StopTimelineRecording()
-
- def GetTimeCompletenessList(self, tab):
- events = tab.timeline_model.GetAllEvents()
- viewport = self._GetViewportSize(tab)
- paint_events = self._IncludedPaintEvents(events)
- time_area_dict = self._TimeAreaDict(paint_events, viewport)
- total_area = sum(time_area_dict.values())
- assert total_area > 0.0, 'Total paint event area must be greater than 0.'
- completeness = 0.0
- time_completeness_list = []
-
- # TODO(tonyg): This sets the start time to the start of the first paint
- # event. That can't be correct. The start time should be navigationStart.
- # Since the previous screen is not cleared at navigationStart, we should
- # probably assume the completeness is 0 until the first paint and add the
- # time of navigationStart as the start. We need to confirm what WPT does.
- time_completeness_list.append(
- (tab.timeline_model.GetAllEvents()[0].start, completeness))
-
- for time, area in sorted(time_area_dict.items()):
- completeness += float(area) / total_area
- # Visual progress is rounded to the nearest percentage point as in WPT.
- time_completeness_list.append((time, round(completeness, 2)))
- return time_completeness_list
-
- def _GetViewportSize(self, tab):
- """Returns dimensions of the viewport."""
- return tab.EvaluateJavaScript('[ window.innerWidth, window.innerHeight ]')
-
- def _IncludedPaintEvents(self, events):
- """Get all events that are counted in the calculation of the speed index.
-
- There's one category of paint event that's filtered out: paint events
- that occur before the first 'ResourceReceiveResponse' and 'Layout' events.
-
- Previously in the WPT speed index, paint events that contain children paint
- events were also filtered out.
- """
- def FirstLayoutTime(events):
- """Get the start time of the first layout after a resource received."""
- has_received_response = False
- for event in events:
- if event.name == 'ResourceReceiveResponse':
- has_received_response = True
- elif has_received_response and event.name == 'Layout':
- return event.start
- assert False, 'There were no layout events after resource receive events.'
-
- first_layout_time = FirstLayoutTime(events)
- paint_events = [e for e in events
- if e.start >= first_layout_time and e.name == 'Paint']
- return paint_events
-
- def _TimeAreaDict(self, paint_events, viewport):
- """Make a dict from time to adjusted area value for events at that time.
-
- The adjusted area value of each paint event is determined by how many paint
- events cover the same rectangle, and whether it's a full-window paint event.
- "Adjusted area" can also be thought of as "points" of visual completeness --
- each rectangle has a certain number of points and these points are
- distributed amongst the paint events that paint that rectangle.
-
- Args:
- paint_events: A list of paint events
- viewport: A tuple (width, height) of the window.
-
- Returns:
- A dictionary of times of each paint event (in milliseconds) to the
- adjusted area that the paint event is worth.
- """
- width, height = viewport
- fullscreen_area = width * height
-
- def ClippedArea(rectangle):
- """Returns rectangle area clipped to viewport size."""
- _, x0, y0, x1, y1 = rectangle
- clipped_width = max(0, min(width, x1) - max(0, x0))
- clipped_height = max(0, min(height, y1) - max(0, y0))
- return clipped_width * clipped_height
-
- grouped = self._GroupEventByRectangle(paint_events)
- event_area_dict = collections.defaultdict(int)
-
- for rectangle, events in grouped.items():
- # The area points for each rectangle are divided up among the paint
- # events in that rectangle.
- area = ClippedArea(rectangle)
- update_count = len(events)
- adjusted_area = float(area) / update_count
-
- # Paint events for the largest-area rectangle are counted as 50%.
- if area == fullscreen_area:
- adjusted_area /= 2
-
- for event in events:
- # The end time for an event is used for that event's time.
- event_time = event.end
- event_area_dict[event_time] += adjusted_area
-
- return event_area_dict
-
- def _GetRectangle(self, paint_event):
- """Get the specific rectangle on the screen for a paint event.
-
- Each paint event belongs to a frame (as in html <frame> or <iframe>).
- This, together with location and dimensions, comprises a rectangle.
- In the WPT source, this 'rectangle' is also called a 'region'.
- """
- def GetBox(quad):
- """Gets top-left and bottom-right coordinates from paint event.
-
- In the timeline data from devtools, paint rectangle dimensions are
- represented x-y coordinates of four corners, clockwise from the top-left.
- See: function WebInspector.TimelinePresentationModel.quadFromRectData
- in file src/out/Debug/obj/gen/devtools/TimelinePanel.js.
- """
- x0, y0, _, _, x1, y1, _, _ = quad
- return (x0, y0, x1, y1)
-
- assert paint_event.name == 'Paint'
- frame = paint_event.args['frameId']
- return (frame,) + GetBox(paint_event.args['data']['clip'])
-
- def _GroupEventByRectangle(self, paint_events):
- """Group all paint events according to the rectangle that they update."""
- result = collections.defaultdict(list)
- for event in paint_events:
- assert event.name == 'Paint'
- result[self._GetRectangle(event)].append(event)
- return result
« no previous file with comments | « no previous file | tools/perf/metrics/speedindex_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698