Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / tools / perf / metrics / rendering_stats_unittest.py
index 6a225fc..11f82b5 100644 (file)
@@ -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):
@@ -34,13 +39,32 @@ class ReferenceRenderingStats(object):
   def __init__(self):
     self.frame_timestamps = []
     self.frame_times = []
-    self.paint_time = []
-    self.painted_pixel_count = []
-    self.record_time = []
-    self.recorded_pixel_count = []
-    self.rasterize_time = []
-    self.rasterized_pixel_count = []
-
+    self.paint_times = []
+    self.painted_pixel_counts = []
+    self.record_times = []
+    self.recorded_pixel_counts = []
+    self.rasterize_times = []
+    self.rasterized_pixel_counts = []
+
+  def AppendNewRange(self):
+    self.frame_timestamps.append([])
+    self.frame_times.append([])
+    self.paint_times.append([])
+    self.painted_pixel_counts.append([])
+    self.record_times.append([])
+    self.recorded_pixel_counts.append([])
+    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.js_touch_scroll_latency = []
+    self.mouse_wheel_scroll_events = []
+    self.touch_scroll_events = []
+    self.js_touch_scroll_events = []
 
 def AddMainThreadRenderingStats(mock_timer, thread, first_frame,
                                 ref_stats = None):
@@ -72,14 +96,14 @@ def AddMainThreadRenderingStats(mock_timer, thread, first_frame,
     if not first_frame:
       # Add frame_time if this is not the first frame in within the bounds of an
       # action.
-      prev_timestamp = ref_stats.frame_timestamps[-1]
-      ref_stats.frame_times.append(round(timestamp - prev_timestamp, 2))
-    ref_stats.frame_timestamps.append(timestamp)
+      prev_timestamp = ref_stats.frame_timestamps[-1][-1]
+      ref_stats.frame_times[-1].append(round(timestamp - prev_timestamp, 2))
+    ref_stats.frame_timestamps[-1].append(timestamp)
 
-  ref_stats.paint_time.append(data['paint_time'] * 1000.0)
-  ref_stats.painted_pixel_count.append(data['painted_pixel_count'])
-  ref_stats.record_time.append(data['record_time'] * 1000.0)
-  ref_stats.recorded_pixel_count.append(data['recorded_pixel_count'])
+  ref_stats.paint_times[-1].append(data['paint_time'] * 1000.0)
+  ref_stats.painted_pixel_counts[-1].append(data['painted_pixel_count'])
+  ref_stats.record_times[-1].append(data['record_time'] * 1000.0)
+  ref_stats.recorded_pixel_counts[-1].append(data['recorded_pixel_count'])
 
 
 def AddImplThreadRenderingStats(mock_timer, thread, first_frame,
@@ -110,13 +134,69 @@ def AddImplThreadRenderingStats(mock_timer, thread, first_frame,
     if not first_frame:
       # Add frame_time if this is not the first frame in within the bounds of an
       # action.
-      prev_timestamp = ref_stats.frame_timestamps[-1]
-      ref_stats.frame_times.append(round(timestamp - prev_timestamp, 2))
-    ref_stats.frame_timestamps.append(timestamp)
+      prev_timestamp = ref_stats.frame_timestamps[-1][-1]
+      ref_stats.frame_times[-1].append(round(timestamp - prev_timestamp, 2))
+    ref_stats.frame_timestamps[-1].append(timestamp)
+
+  ref_stats.rasterize_times[-1].append(data['rasterize_time'] * 1000.0)
+  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()
 
-  ref_stats.rasterize_time.append(data['rasterize_time'] * 1000.0)
-  ref_stats.rasterized_pixel_count.append(data['rasterized_pixel_count'])
+  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)
+
+  if input_type == 'TouchMove':
+    ref_latency_stats.js_touch_scroll_events.append(async_sub_slice)
+    ref_latency_stats.js_touch_scroll_latency.append(
+        (data[END_COMP_NAME]['time'] - data[UI_COMP_NAME]['time']) / 1000.0)
 
 class RenderingStatsUnitTest(unittest.TestCase):
   def testFromTimeline(self):
@@ -137,6 +217,7 @@ class RenderingStatsUnitTest(unittest.TestCase):
     # Create 10 main and impl rendering stats events for Action A.
     timer.Advance()
     renderer_main.BeginSlice('webkit.console', 'ActionA', timer.Get(), '')
+    ref_stats.AppendNewRange()
     for i in xrange(0, 10):
       first = (i == 0)
       AddMainThreadRenderingStats(timer, renderer_main, first, ref_stats)
@@ -156,6 +237,7 @@ class RenderingStatsUnitTest(unittest.TestCase):
     # Create 10 main and impl rendering stats events for Action B.
     timer.Advance()
     renderer_main.BeginSlice('webkit.console', 'ActionB', timer.Get(), '')
+    ref_stats.AppendNewRange()
     for i in xrange(0, 10):
       first = (i == 0)
       AddMainThreadRenderingStats(timer, renderer_main, first, ref_stats)
@@ -167,6 +249,7 @@ class RenderingStatsUnitTest(unittest.TestCase):
     # Create 10 main and impl rendering stats events for Action A.
     timer.Advance()
     renderer_main.BeginSlice('webkit.console', 'ActionA', timer.Get(), '')
+    ref_stats.AppendNewRange()
     for i in xrange(0, 10):
       first = (i == 0)
       AddMainThreadRenderingStats(timer, renderer_main, first, ref_stats)
@@ -182,16 +265,110 @@ 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)
     self.assertEquals(stats.frame_times, ref_stats.frame_times)
-    self.assertEquals(stats.rasterize_time, ref_stats.rasterize_time)
-    self.assertEquals(stats.rasterized_pixel_count,
-                      ref_stats.rasterized_pixel_count)
-    self.assertEquals(stats.paint_time, ref_stats.paint_time)
-    self.assertEquals(stats.painted_pixel_count, ref_stats.painted_pixel_count)
-    self.assertEquals(stats.record_time, ref_stats.record_time)
-    self.assertEquals(stats.recorded_pixel_count,
-                      ref_stats.recorded_pixel_count)
+    self.assertEquals(stats.rasterize_times, ref_stats.rasterize_times)
+    self.assertEquals(stats.rasterized_pixel_counts,
+                      ref_stats.rasterized_pixel_counts)
+    self.assertEquals(stats.paint_times, ref_stats.paint_times)
+    self.assertEquals(stats.painted_pixel_counts,
+                      ref_stats.painted_pixel_counts)
+    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)
+      AddInputLatencyStats(timer, 'TouchMove', 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)
+      AddInputLatencyStats(timer, 'TouchMove', 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)
+      AddInputLatencyStats(timer, 'TouchMove', 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)
+      AddInputLatencyStats(timer, 'TouchMove', 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 = []
+    js_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 = GetScrollInputLatencyEvents(
+          'MouseWheel', browser, timeline_range)
+      tmp_touch_scroll_events = GetScrollInputLatencyEvents(
+          'GestureScrollUpdate', browser, timeline_range)
+      tmp_js_touch_scroll_events = GetScrollInputLatencyEvents(
+          'TouchMove', browser, timeline_range)
+      mouse_wheel_scroll_events.extend(tmp_mouse_events)
+      touch_scroll_events.extend(tmp_touch_scroll_events)
+      js_touch_scroll_events.extend(tmp_js_touch_scroll_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(js_touch_scroll_events,
+                      ref_latency_stats.js_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)
+    self.assertEquals(ComputeTouchScrollLatency(js_touch_scroll_events),
+                      ref_latency_stats.js_touch_scroll_latency)