Index: tools/perf/metrics/rendering_stats_unittest.py |
diff --git a/tools/perf/metrics/rendering_stats_unittest.py b/tools/perf/metrics/rendering_stats_unittest.py |
index 2cbe2d29720bf4009def0a4b83eeef713d3acab7..fd2dc402e9d174115a7ab2d71c0b1c2347ead5e7 100644 |
--- a/tools/perf/metrics/rendering_stats_unittest.py |
+++ b/tools/perf/metrics/rendering_stats_unittest.py |
@@ -5,9 +5,14 @@ |
import random |
import unittest |
+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 RenderingStats |
import telemetry.core.timeline.bounds as timeline_bounds |
from telemetry.core.timeline import model |
+import telemetry.core.timeline.async_slice as tracing_async_slice |
class MockTimer(object): |
@@ -51,6 +56,13 @@ class ReferenceRenderingStats(object): |
self.rasterize_times.append([]) |
self.rasterized_pixel_counts.append([]) |
+class ReferenceInputLatencyStats(object): |
+ """ Stores expected data for comparison with actual input latency stats """ |
+ def __init__(self): |
+ self.mouse_wheel_scroll_latency = [] |
+ self.touch_scroll_latency = [] |
+ self.mouse_wheel_scroll_events = [] |
+ self.touch_scroll_events = [] |
def AddMainThreadRenderingStats(mock_timer, thread, first_frame, |
ref_stats = None): |
@@ -128,6 +140,58 @@ def AddImplThreadRenderingStats(mock_timer, thread, first_frame, |
ref_stats.rasterized_pixel_counts[-1].append(data['rasterized_pixel_count']) |
+def AddInputLatencyStats(mock_timer, input_type, start_thread, end_thread, |
+ ref_latency_stats = None): |
+ """ Adds a random input latency stats event. |
+ |
+ input_type: The input type for which the latency slice is generated. |
+ start_thread: The start thread on which the async slice is added. |
+ end_thread: The end thread on which the async slice is ended. |
+ ref_latency_stats: A ReferenceInputLatencyStats object for expected values. |
+ """ |
+ |
+ mock_timer.Advance() |
+ ui_comp_time = mock_timer.Get() * 1000.0 |
+ mock_timer.Advance() |
+ begin_comp_time = mock_timer.Get() * 1000.0 |
+ mock_timer.Advance(10, 20) |
+ end_comp_time = mock_timer.Get() * 1000.0 |
+ |
+ data = { UI_COMP_NAME: {'time': ui_comp_time}, |
+ BEGIN_COMP_NAME: {'time': begin_comp_time}, |
+ END_COMP_NAME: {'time': end_comp_time} } |
+ |
+ timestamp = mock_timer.Get() |
+ |
+ async_slice = tracing_async_slice.AsyncSlice( |
+ 'benchmark', 'InputLatency', timestamp) |
+ |
+ async_sub_slice = tracing_async_slice.AsyncSlice( |
+ 'benchmark', 'InputLatency', timestamp) |
+ async_sub_slice.args = {'data': data, 'step': input_type} |
+ async_sub_slice.parent_slice = async_slice |
+ async_sub_slice.start_thread = start_thread |
+ async_sub_slice.end_thread = end_thread |
+ |
+ async_slice.sub_slices.append(async_sub_slice) |
+ async_slice.start_thread = start_thread |
+ async_slice.end_thread = end_thread |
+ start_thread.AddAsyncSlice(async_slice) |
+ |
+ if not ref_latency_stats: |
+ return |
+ |
+ if input_type == 'MouseWheel': |
+ ref_latency_stats.mouse_wheel_scroll_events.append(async_sub_slice) |
+ ref_latency_stats.mouse_wheel_scroll_latency.append( |
+ (data[END_COMP_NAME]['time'] - data[BEGIN_COMP_NAME]['time']) / 1000.0) |
+ |
+ |
+ if input_type == 'GestureScrollUpdate': |
+ ref_latency_stats.touch_scroll_events.append(async_sub_slice) |
+ ref_latency_stats.touch_scroll_latency.append( |
+ (data[END_COMP_NAME]['time'] - data[UI_COMP_NAME]['time']) / 1000.0) |
+ |
class RenderingStatsUnitTest(unittest.TestCase): |
def testFromTimeline(self): |
timeline = model.TimelineModel() |
@@ -195,7 +259,7 @@ class RenderingStatsUnitTest(unittest.TestCase): |
['ActionA', 'ActionB', 'ActionA']) |
timeline_ranges = [ timeline_bounds.Bounds.CreateFromEvent(marker) |
for marker in timeline_markers ] |
- stats = RenderingStats(renderer, timeline_ranges) |
+ stats = RenderingStats(renderer, browser, timeline_ranges) |
# Compare rendering stats to reference. |
self.assertEquals(stats.frame_timestamps, ref_stats.frame_timestamps) |
@@ -209,3 +273,78 @@ class RenderingStatsUnitTest(unittest.TestCase): |
self.assertEquals(stats.record_times, ref_stats.record_times) |
self.assertEquals(stats.recorded_pixel_counts, |
ref_stats.recorded_pixel_counts) |
+ |
+ def testScrollLatencyFromTimeline(self): |
+ timeline = model.TimelineModel() |
+ |
+ # Create a browser process and a renderer process. |
+ browser = timeline.GetOrCreateProcess(pid = 1) |
+ browser_main = browser.GetOrCreateThread(tid = 11) |
+ renderer = timeline.GetOrCreateProcess(pid = 2) |
+ renderer_main = renderer.GetOrCreateThread(tid = 21) |
+ |
+ timer = MockTimer() |
+ ref_latency_stats = ReferenceInputLatencyStats() |
+ |
+ # Create 10 input latency stats events for Action A. |
+ timer.Advance() |
+ renderer_main.BeginSlice('webkit.console', 'ActionA', timer.Get(), '') |
+ for _ in xrange(0, 10): |
+ AddInputLatencyStats(timer, 'MouseWheel', browser_main, |
+ renderer_main, ref_latency_stats) |
+ AddInputLatencyStats(timer, 'GestureScrollUpdate', browser_main, |
+ renderer_main, ref_latency_stats) |
+ renderer_main.EndSlice(timer.Get()) |
+ |
+ # Create 5 input latency stats events not within any action. |
+ for _ in xrange(0, 5): |
+ AddInputLatencyStats(timer, 'MouseWheel', browser_main, |
+ renderer_main, None) |
+ AddInputLatencyStats(timer, 'GestureScrollUpdate', browser_main, |
+ renderer_main, None) |
+ |
+ # Create 10 input latency stats events for Action B. |
+ timer.Advance() |
+ renderer_main.BeginSlice('webkit.console', 'ActionB', timer.Get(), '') |
+ for _ in xrange(0, 10): |
+ AddInputLatencyStats(timer, 'MouseWheel', browser_main, |
+ renderer_main, ref_latency_stats) |
+ AddInputLatencyStats(timer, 'GestureScrollUpdate', browser_main, |
+ renderer_main, ref_latency_stats) |
+ renderer_main.EndSlice(timer.Get()) |
+ |
+ # Create 10 input latency stats events for Action A. |
+ timer.Advance() |
+ renderer_main.BeginSlice('webkit.console', 'ActionA', timer.Get(), '') |
+ for _ in xrange(0, 10): |
+ AddInputLatencyStats(timer, 'MouseWheel', browser_main, |
+ renderer_main, ref_latency_stats) |
+ AddInputLatencyStats(timer, 'GestureScrollUpdate', browser_main, |
+ renderer_main, ref_latency_stats) |
+ renderer_main.EndSlice(timer.Get()) |
+ |
+ browser_main.FinalizeImport() |
+ renderer_main.FinalizeImport() |
+ |
+ mouse_wheel_scroll_events = [] |
+ touch_scroll_events = [] |
+ |
+ timeline_markers = timeline.FindTimelineMarkers( |
+ ['ActionA', 'ActionB', 'ActionA']) |
+ for timeline_range in [ timeline_bounds.Bounds.CreateFromEvent(marker) |
+ for marker in timeline_markers ]: |
+ if timeline_range.is_empty: |
+ continue |
+ tmp_mouse_events, tmp_touch_events = GetScrollInputLatencyEvents( |
+ browser, timeline_range) |
+ mouse_wheel_scroll_events.extend(tmp_mouse_events) |
+ touch_scroll_events.extend(tmp_touch_events) |
+ |
+ self.assertEquals(mouse_wheel_scroll_events, |
+ ref_latency_stats.mouse_wheel_scroll_events) |
+ self.assertEquals(touch_scroll_events, |
+ ref_latency_stats.touch_scroll_events) |
+ self.assertEquals(ComputeMouseWheelScrollLatency(mouse_wheel_scroll_events), |
+ ref_latency_stats.mouse_wheel_scroll_latency) |
+ self.assertEquals(ComputeTouchScrollLatency(touch_scroll_events), |
+ ref_latency_stats.touch_scroll_latency) |