Commit bbb26915 authored by ernstm@chromium.org's avatar ernstm@chromium.org

re-land: Use browser compositor rendering stats in smoothness

PERF SHERRIFS: This patch can change the metrics of smoothness up or down.
The new values should be more accurate than what we had before. If there are
large changes on a platform, we should still sanity check that everything works
as expected.

Switch smoothness benchmark to use rendering stats from the top level
compositor; i.e. if data from a browser compositor is available, use that.
Otherwise use the data from the renderer compositor.

The re-land fixes the problem where a browser compositor was present, but
didn't record rendering stats. That was the case with the reference
builds (that didn't have the patch that enabled recording) and on Android.
The new version checks if the browser compositor rendering stats events
actually have frames in them. If not, the render compositor stats will be used.
There is also a fix on the way to enable the recording on Android
(https://codereview.chromium.org/168193004/).

R=tonyg@chromium.org,nduca@chromium.org
BUG=340753

Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=254811

Review URL: https://codereview.chromium.org/174663008

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@260256 0039d316-1c4b-4281-b951-d872f2087c98
parent 625b1314
......@@ -15,6 +15,7 @@ BEGIN_COMP_NAME = 'INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT'
# This is when the input event has reached swap buffer.
END_COMP_NAME = 'INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT'
def GetScrollInputLatencyEvents(scroll_type, browser_process, timeline_range):
"""Get scroll events' LatencyInfo from the browser process's trace buffer
that are within the timeline_range.
......@@ -39,6 +40,7 @@ def GetScrollInputLatencyEvents(scroll_type, browser_process, timeline_range):
scroll_events.append(ss)
return scroll_events
def ComputeMouseWheelScrollLatency(mouse_wheel_events):
""" Compute the mouse wheel scroll latency.
......@@ -57,6 +59,7 @@ def ComputeMouseWheelScrollLatency(mouse_wheel_events):
mouse_wheel_latency.append(latency / 1000.0)
return mouse_wheel_latency
def ComputeTouchScrollLatency(touch_scroll_events):
""" Compute the touch scroll latency.
......@@ -83,6 +86,24 @@ def ComputeTouchScrollLatency(touch_scroll_events):
touch_scroll_latency.append(latency / 1000.0)
return touch_scroll_latency
def HasRenderingStats(process):
""" Returns True if the process contains at least one
BenchmarkInstrumentation::*RenderingStats event with a frame.
"""
if not process:
return False
for event in process.IterAllSlicesOfName(
'BenchmarkInstrumentation::MainThreadRenderingStats'):
if 'data' in event.args and event.args['data']['frame_count'] == 1:
return True
for event in process.IterAllSlicesOfName(
'BenchmarkInstrumentation::ImplThreadRenderingStats'):
if 'data' in event.args and event.args['data']['frame_count'] == 1:
return True
return False
class RenderingStats(object):
def __init__(self, renderer_process, browser_process, timeline_ranges):
"""
......@@ -96,7 +117,11 @@ class RenderingStats(object):
All *_time values are measured in milliseconds.
"""
assert(len(timeline_ranges) > 0)
self.renderer_process = renderer_process
# Find the top level process with rendering stats (browser or renderer).
if HasRenderingStats(browser_process):
self.top_level_process = browser_process
else:
self.top_level_process = renderer_process
self.frame_timestamps = []
self.frame_times = []
......@@ -153,7 +178,7 @@ class RenderingStats(object):
def initMainThreadStatsFromTimeline(self, timeline_range):
event_name = 'BenchmarkInstrumentation::MainThreadRenderingStats'
events = []
for event in self.renderer_process.IterAllSlicesOfName(event_name):
for event in self.top_level_process.IterAllSlicesOfName(event_name):
if event.start >= timeline_range.min and event.end <= timeline_range.max:
if 'data' not in event.args:
continue
......@@ -184,7 +209,7 @@ class RenderingStats(object):
def initImplThreadStatsFromTimeline(self, timeline_range):
event_name = 'BenchmarkInstrumentation::ImplThreadRenderingStats'
events = []
for event in self.renderer_process.IterAllSlicesOfName(event_name):
for event in self.top_level_process.IterAllSlicesOfName(event_name):
if event.start >= timeline_range.min and event.end <= timeline_range.max:
if 'data' not in event.args:
continue
......
......@@ -9,6 +9,7 @@ from metrics.rendering_stats import UI_COMP_NAME, BEGIN_COMP_NAME, END_COMP_NAME
from metrics.rendering_stats import GetScrollInputLatencyEvents
from metrics.rendering_stats import ComputeMouseWheelScrollLatency
from metrics.rendering_stats import ComputeTouchScrollLatency
from metrics.rendering_stats import HasRenderingStats
from metrics.rendering_stats import RenderingStats
import telemetry.core.timeline.bounds as timeline_bounds
from telemetry.core.timeline import model
......@@ -199,6 +200,30 @@ def AddInputLatencyStats(mock_timer, input_type, start_thread, end_thread,
(data[END_COMP_NAME]['time'] - data[UI_COMP_NAME]['time']) / 1000.0)
class RenderingStatsUnitTest(unittest.TestCase):
def testHasRenderingStats(self):
timeline = model.TimelineModel()
timer = MockTimer()
# A process without rendering stats
process_without_stats = timeline.GetOrCreateProcess(pid = 1)
thread_without_stats = process_without_stats.GetOrCreateThread(tid = 11)
process_without_stats.FinalizeImport()
self.assertFalse(HasRenderingStats(thread_without_stats))
# A process with rendering stats, but no frames in them
process_without_frames = timeline.GetOrCreateProcess(pid = 2)
thread_without_frames = process_without_frames.GetOrCreateThread(tid = 21)
AddMainThreadRenderingStats(timer, thread_without_frames, True, None)
process_without_frames.FinalizeImport()
self.assertFalse(HasRenderingStats(thread_without_frames))
# A process with rendering stats and frames in them
process_with_frames = timeline.GetOrCreateProcess(pid = 3)
thread_with_frames = process_with_frames.GetOrCreateThread(tid = 31)
AddImplThreadRenderingStats(timer, thread_with_frames, True, None)
process_with_frames.FinalizeImport()
self.assertTrue(HasRenderingStats(thread_with_frames))
def testFromTimeline(self):
timeline = model.TimelineModel()
......@@ -220,10 +245,10 @@ class RenderingStatsUnitTest(unittest.TestCase):
ref_stats.AppendNewRange()
for i in xrange(0, 10):
first = (i == 0)
AddMainThreadRenderingStats(timer, renderer_main, first, ref_stats)
AddImplThreadRenderingStats(timer, renderer_compositor, first, ref_stats)
AddMainThreadRenderingStats(timer, browser_main, first, None)
AddImplThreadRenderingStats(timer, browser_compositor, first, None)
AddMainThreadRenderingStats(timer, renderer_main, first, None)
AddImplThreadRenderingStats(timer, renderer_compositor, first, None)
AddMainThreadRenderingStats(timer, browser_main, first, ref_stats)
AddImplThreadRenderingStats(timer, browser_compositor, first, ref_stats)
renderer_main.EndSlice(timer.Get())
# Create 5 main and impl rendering stats events not within any action.
......@@ -240,10 +265,10 @@ class RenderingStatsUnitTest(unittest.TestCase):
ref_stats.AppendNewRange()
for i in xrange(0, 10):
first = (i == 0)
AddMainThreadRenderingStats(timer, renderer_main, first, ref_stats)
AddImplThreadRenderingStats(timer, renderer_compositor, first, ref_stats)
AddMainThreadRenderingStats(timer, browser_main, first, None)
AddImplThreadRenderingStats(timer, browser_compositor, first, None)
AddMainThreadRenderingStats(timer, renderer_main, first, None)
AddImplThreadRenderingStats(timer, renderer_compositor, first, None)
AddMainThreadRenderingStats(timer, browser_main, first, ref_stats)
AddImplThreadRenderingStats(timer, browser_compositor, first, ref_stats)
renderer_main.EndSlice(timer.Get())
# Create 10 main and impl rendering stats events for Action A.
......@@ -252,14 +277,14 @@ class RenderingStatsUnitTest(unittest.TestCase):
ref_stats.AppendNewRange()
for i in xrange(0, 10):
first = (i == 0)
AddMainThreadRenderingStats(timer, renderer_main, first, ref_stats)
AddImplThreadRenderingStats(timer, renderer_compositor, first, ref_stats)
AddMainThreadRenderingStats(timer, browser_main, first, None)
AddImplThreadRenderingStats(timer, browser_compositor, first, None)
AddMainThreadRenderingStats(timer, renderer_main, first, None)
AddImplThreadRenderingStats(timer, renderer_compositor, first, None)
AddMainThreadRenderingStats(timer, browser_main, first, ref_stats)
AddImplThreadRenderingStats(timer, browser_compositor, first, ref_stats)
renderer_main.EndSlice(timer.Get())
renderer_main.FinalizeImport()
renderer_compositor.FinalizeImport()
browser.FinalizeImport()
renderer.FinalizeImport()
timeline_markers = timeline.FindTimelineMarkers(
['ActionA', 'ActionB', 'ActionA'])
......@@ -267,6 +292,9 @@ class RenderingStatsUnitTest(unittest.TestCase):
for marker in timeline_markers ]
stats = RenderingStats(renderer, browser, timeline_ranges)
# Check if we are using the browser compositor's stats
self.assertEquals(stats.top_level_process, browser)
# Compare rendering stats to reference.
self.assertEquals(stats.frame_timestamps, ref_stats.frame_timestamps)
self.assertEquals(stats.frame_times, ref_stats.frame_times)
......@@ -337,8 +365,8 @@ class RenderingStatsUnitTest(unittest.TestCase):
renderer_main, ref_latency_stats)
renderer_main.EndSlice(timer.Get())
browser_main.FinalizeImport()
renderer_main.FinalizeImport()
browser.FinalizeImport()
renderer.FinalizeImport()
mouse_wheel_scroll_events = []
touch_scroll_events = []
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment