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 |
new file mode 100644 |
index 0000000000000000000000000000000000000000..ec18597b8ce059b7e527be493b62c15cc01aae9c |
--- /dev/null |
+++ b/tools/perf/metrics/rendering_stats_unittest.py |
@@ -0,0 +1,192 @@ |
+# Copyright 2013 The Chromium Authors. All rights reserved. |
+# Use of this source code is governed by a BSD-style license that can be |
+# found in the LICENSE file. |
+ |
+import random |
+import unittest |
+ |
+from metrics.rendering_stats import RenderingStats |
+from telemetry.core.timeline import model |
+ |
+ |
+class MockTimer(object): |
+ """A mock timer class which can generate random durations. |
+ |
+ An instance of this class is used as a global timer to generate random |
+ durations for stats and consistent timestamps for all mock trace events. |
+ The unit of time is milliseconds. |
+ """ |
+ def __init__(self): |
+ self.milliseconds = 0 |
+ |
+ def Get(self): |
+ return self.milliseconds |
+ |
+ def Advance(self, low=0, high=1): |
+ delta = random.uniform(low, high) |
+ self.milliseconds += delta |
+ return delta |
+ |
+ |
+class ReferenceRenderingStats(object): |
+ """ Stores expected data for comparison with actual RenderingStats """ |
+ 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 = [] |
+ |
+ |
+def AddMainThreadRenderingStats(mock_timer, thread, first_frame, |
+ ref_stats = None): |
+ """ Adds a random main thread rendering stats event. |
+ |
+ thread: The timeline model thread to which the event will be added. |
+ first_frame: Is this the first frame within the bounds of an action? |
+ ref_stats: A ReferenceRenderingStats object to record expected values. |
+ """ |
+ # Create randonm data and timestap for main thread rendering stats. |
+ data = { 'frame_count': 0, |
+ 'paint_time': 0.0, |
+ 'painted_pixel_count': 0, |
+ 'record_time': mock_timer.Advance(2, 4) / 1000.0, |
+ 'recorded_pixel_count': 3000*3000 } |
+ timestamp = mock_timer.Get() |
+ |
+ # Add a slice with the event data to the given thread. |
+ thread.PushCompleteSlice( |
+ 'benchmark', 'BenchmarkInstrumentation::MainThreadRenderingStats', |
+ timestamp, 0.0, {'data': data}) |
+ |
+ if not ref_stats: |
+ return |
+ |
+ # Add timestamp only if a frame was output |
+ if data['frame_count'] == 1: |
+ 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) |
+ |
+ 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']) |
+ |
+ |
+def AddImplThreadRenderingStats(mock_timer, thread, first_frame, |
+ ref_stats = None): |
+ """ Adds a random impl thread rendering stats event. |
+ |
+ thread: The timeline model thread to which the event will be added. |
+ first_frame: Is this the first frame within the bounds of an action? |
+ ref_stats: A ReferenceRenderingStats object to record expected values. |
+ """ |
+ # Create randonm data and timestap for impl thread rendering stats. |
+ data = { 'frame_count': 1, |
+ 'rasterize_time': mock_timer.Advance(5, 10) / 1000.0, |
+ 'rasterized_pixel_count': 1280*720 } |
+ timestamp = mock_timer.Get() |
+ |
+ # Add a slice with the event data to the given thread. |
+ thread.PushCompleteSlice( |
+ 'benchmark', 'BenchmarkInstrumentation::ImplThreadRenderingStats', |
+ timestamp, 0.0, {'data': data}) |
+ |
+ if not ref_stats: |
+ return |
+ |
+ # Add timestamp only if a frame was output |
+ if data['frame_count'] == 1: |
+ 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) |
+ |
+ ref_stats.rasterize_time.append(data['rasterize_time'] * 1000.0) |
+ ref_stats.rasterized_pixel_count.append(data['rasterized_pixel_count']) |
+ |
+ |
+class RenderingStatsUnitTest(unittest.TestCase): |
+ def testFromTimeline(self): |
+ timeline = model.TimelineModel() |
+ |
+ # Create a browser process and a renderer process, and a main thread and |
+ # impl thread for each. |
+ browser = timeline.GetOrCreateProcess(pid = 1) |
+ browser_main = browser.GetOrCreateThread(tid = 11) |
+ browser_compositor = browser.GetOrCreateThread(tid = 12) |
+ renderer = timeline.GetOrCreateProcess(pid = 2) |
+ renderer_main = renderer.GetOrCreateThread(tid = 21) |
+ renderer_compositor = renderer.GetOrCreateThread(tid = 22) |
+ |
+ timer = MockTimer() |
+ ref_stats = ReferenceRenderingStats() |
+ |
+ # Create 10 main and impl rendering stats events for Action A. |
+ timer.Advance() |
+ renderer_main.BeginSlice('webkit.console', 'ActionA', timer.Get(), '') |
+ 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) |
+ renderer_main.EndSlice(timer.Get()) |
+ |
+ # Create 5 main and impl rendering stats events not within any action. |
+ for i in xrange(0, 5): |
+ first = (i == 0) |
+ AddMainThreadRenderingStats(timer, renderer_main, first, None) |
+ AddImplThreadRenderingStats(timer, renderer_compositor, first, None) |
+ AddMainThreadRenderingStats(timer, browser_main, first, None) |
+ AddImplThreadRenderingStats(timer, browser_compositor, first, None) |
+ |
+ # Create 10 main and impl rendering stats events for Action B. |
+ timer.Advance() |
+ renderer_main.BeginSlice('webkit.console', 'ActionB', timer.Get(), '') |
+ 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) |
+ renderer_main.EndSlice(timer.Get()) |
+ |
+ # Create 10 main and impl rendering stats events for Action A. |
+ timer.Advance() |
+ renderer_main.BeginSlice('webkit.console', 'ActionA', timer.Get(), '') |
+ 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) |
+ renderer_main.EndSlice(timer.Get()) |
+ |
+ renderer_main.FinalizeImport() |
+ renderer_compositor.FinalizeImport() |
+ |
+ timeline_markers = timeline.FindTimelineMarkers( |
+ ['ActionA', 'ActionB', 'ActionA']) |
+ stats = RenderingStats(renderer, timeline_markers) |
+ |
+ # 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) |