| OLD | NEW |
| 1 # Copyright 2013 The Chromium Authors. All rights reserved. | 1 # Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 import random | 5 import random |
| 6 import unittest | 6 import unittest |
| 7 | 7 |
| 8 from metrics import smoothness | 8 from metrics import smoothness |
| 9 from metrics import statistics | 9 from metrics import statistics |
| 10 from metrics.gpu_rendering_stats import GpuRenderingStats | 10 from metrics.rendering_stats import RenderingStats |
| 11 from telemetry.core.backends.chrome.tracing_backend import RawTraceResultImpl | 11 from telemetry.core.backends.chrome.tracing_backend import RawTraceResultImpl |
| 12 from telemetry.core.backends.chrome.trace_result import TraceResult | 12 from telemetry.core.backends.chrome.trace_result import TraceResult |
| 13 from telemetry.page import page | 13 from telemetry.page import page |
| 14 from telemetry.page.page_measurement_results import PageMeasurementResults | 14 from telemetry.page.page_measurement_results import PageMeasurementResults |
| 15 | 15 |
| 16 | 16 |
| 17 class MockTimer(object): | 17 class MockTimer(object): |
| 18 """A mock timer class which can generate random durations. | 18 """A mock timer class which can generate random durations. |
| 19 | 19 |
| 20 An instance of this class is used as a global timer to generate random | 20 An instance of this class is used as a global timer to generate random |
| (...skipping 10 matching lines...) Expand all Loading... |
| 31 | 31 |
| 32 class MockFrame(object): | 32 class MockFrame(object): |
| 33 """Mocks rendering, texture and latency stats for a single frame.""" | 33 """Mocks rendering, texture and latency stats for a single frame.""" |
| 34 def __init__(self, mock_timer): | 34 def __init__(self, mock_timer): |
| 35 """ Initialize the stats to random values """ | 35 """ Initialize the stats to random values """ |
| 36 self.start = mock_timer.microseconds | 36 self.start = mock_timer.microseconds |
| 37 self.main_stats = {} | 37 self.main_stats = {} |
| 38 self.impl_stats = {} | 38 self.impl_stats = {} |
| 39 self.texture_stats = {} | 39 self.texture_stats = {} |
| 40 self.latency_stats = {} | 40 self.latency_stats = {} |
| 41 self.main_stats['animation_frame_count'] = 0 | 41 self.main_stats['frame_count'] = 0 |
| 42 self.main_stats['screen_frame_count'] = 0 | |
| 43 self.main_stats['paint_time'] = mock_timer.Advance() | 42 self.main_stats['paint_time'] = mock_timer.Advance() |
| 43 self.main_stats['painted_pixel_count'] = random.randint(0, 2000000) |
| 44 self.main_stats['record_time'] = mock_timer.Advance() | 44 self.main_stats['record_time'] = mock_timer.Advance() |
| 45 self.main_stats['commit_time'] = mock_timer.Advance() | |
| 46 self.main_stats['commit_count'] = 1 | |
| 47 self.main_stats['painted_pixel_count'] = random.randint(0, 2000000) | |
| 48 self.main_stats['recorded_pixel_count'] = random.randint(0, 2000000) | 45 self.main_stats['recorded_pixel_count'] = random.randint(0, 2000000) |
| 49 self.main_stats['image_gathering_count'] = random.randint(0, 100) | 46 self.impl_stats['frame_count'] = 1 |
| 50 self.main_stats['image_gathering_time'] = mock_timer.Advance() | |
| 51 self.impl_stats['screen_frame_count'] = 1 | |
| 52 self.impl_stats['dropped_frame_count'] = random.randint(0, 4) | |
| 53 self.impl_stats['rasterize_time'] = mock_timer.Advance() | 47 self.impl_stats['rasterize_time'] = mock_timer.Advance() |
| 54 self.impl_stats['rasterize_time_for_now_bins_on_pending_tree'] = ( | |
| 55 mock_timer.Advance()) | |
| 56 self.impl_stats['best_rasterize_time'] = mock_timer.Advance() | |
| 57 self.impl_stats['rasterized_pixel_count'] = random.randint(0, 2000000) | 48 self.impl_stats['rasterized_pixel_count'] = random.randint(0, 2000000) |
| 58 self.impl_stats['impl_thread_scroll_count'] = random.randint(0, 4) | |
| 59 self.impl_stats['main_thread_scroll_count'] = random.randint(0, 4) | |
| 60 self.impl_stats['drawn_layer_count'] = random.randint(0, 10) | |
| 61 self.impl_stats['missing_tile_count'] = random.randint(0, 10000) | |
| 62 self.impl_stats['deferred_image_decode_count'] = random.randint(0, 100) | |
| 63 self.impl_stats['deferred_image_cache_hit_count'] = random.randint(0, 50) | |
| 64 self.impl_stats['tile_analysis_count'] = random.randint(0, 10000) | |
| 65 self.impl_stats['solid_color_tile_analysis_count'] = random.randint(0, 1000) | |
| 66 self.impl_stats['deferred_image_decode_time'] = mock_timer.Advance() | |
| 67 self.impl_stats['tile_analysis_time'] = mock_timer.Advance() | |
| 68 self.end = mock_timer.microseconds | 49 self.end = mock_timer.microseconds |
| 69 self.duration = self.end - self.start | 50 self.duration = self.end - self.start |
| 70 | 51 |
| 71 def AppendTraceEventForMainThreadStats(self, trace_events): | 52 def AppendTraceEventForMainThreadStats(self, trace_events): |
| 72 """Appends a trace event with the main thread stats. | 53 """Appends a trace event with the main thread stats. |
| 73 | 54 |
| 74 The trace event is a dict with the following keys: | 55 The trace event is a dict with the following keys: |
| 75 'name', | 56 'name', |
| 76 'tts' (thread timestamp), | 57 'tts' (thread timestamp), |
| 77 'pid' (process id), | 58 'pid' (process id), |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 141 'tid': 11, | 122 'tid': 11, |
| 142 'ph': 'S', | 123 'ph': 'S', |
| 143 'id': '0xabcde'}) | 124 'id': '0xabcde'}) |
| 144 | 125 |
| 145 # Generate 100 random mock frames and append their trace events. | 126 # Generate 100 random mock frames and append their trace events. |
| 146 for _ in xrange(0, 100): | 127 for _ in xrange(0, 100): |
| 147 mock_frame = MockFrame(mock_timer) | 128 mock_frame = MockFrame(mock_timer) |
| 148 mock_frame.AppendTraceEventForMainThreadStats(trace_events) | 129 mock_frame.AppendTraceEventForMainThreadStats(trace_events) |
| 149 mock_frame.AppendTraceEventForImplThreadStats(trace_events) | 130 mock_frame.AppendTraceEventForImplThreadStats(trace_events) |
| 150 total_time_seconds += mock_frame.duration / 1e6 | 131 total_time_seconds += mock_frame.duration / 1e6 |
| 151 num_frames_sent += mock_frame.main_stats['screen_frame_count'] | 132 num_frames_sent += mock_frame.main_stats['frame_count'] |
| 152 num_frames_sent += mock_frame.impl_stats['screen_frame_count'] | 133 num_frames_sent += mock_frame.impl_stats['frame_count'] |
| 153 current_frame_time = mock_timer.microseconds / 1000.0 | 134 current_frame_time = mock_timer.microseconds / 1000.0 |
| 154 if previous_frame_time: | 135 if previous_frame_time: |
| 155 difference = current_frame_time - previous_frame_time | 136 difference = current_frame_time - previous_frame_time |
| 156 difference = round(difference, 2) | 137 difference = round(difference, 2) |
| 157 expected_frame_times.append(difference) | 138 expected_frame_times.append(difference) |
| 158 previous_frame_time = current_frame_time | 139 previous_frame_time = current_frame_time |
| 159 | 140 |
| 160 # Append finish trace events for the timeline and gesture markers, in the | 141 # Append finish trace events for the timeline and gesture markers, in the |
| 161 # reverse order from how they were added, with some time in between. | 142 # reverse order from how they were added, with some time in between. |
| 162 trace_events.append({'name': smoothness.SYNTHETIC_GESTURE_MARKER, | 143 trace_events.append({'name': smoothness.SYNTHETIC_GESTURE_MARKER, |
| (...skipping 15 matching lines...) Expand all Loading... |
| 178 'tid': 11, | 159 'tid': 11, |
| 179 'ph': 'F', | 160 'ph': 'F', |
| 180 'id': '0x12345'}) | 161 'id': '0x12345'}) |
| 181 | 162 |
| 182 # Create a timeline object from the trace. | 163 # Create a timeline object from the trace. |
| 183 trace_impl = RawTraceResultImpl(trace_events) | 164 trace_impl = RawTraceResultImpl(trace_events) |
| 184 trace_result = TraceResult(trace_impl) | 165 trace_result = TraceResult(trace_impl) |
| 185 timeline = trace_result.AsTimelineModel() | 166 timeline = trace_result.AsTimelineModel() |
| 186 | 167 |
| 187 # Find the timeline marker and gesture marker in the timeline, | 168 # Find the timeline marker and gesture marker in the timeline, |
| 188 # and create a GpuRenderingStats object. | 169 # and create a RenderingStats object. |
| 189 smoothness_marker = smoothness.FindTimelineMarker( | 170 smoothness_marker = smoothness.FindTimelineMarker( |
| 190 timeline, smoothness.TIMELINE_MARKER) | 171 timeline, smoothness.TIMELINE_MARKER) |
| 191 gesture_marker = smoothness.FindTimelineMarker( | 172 gesture_marker = smoothness.FindTimelineMarker( |
| 192 timeline, smoothness.SYNTHETIC_GESTURE_MARKER) | 173 timeline, smoothness.SYNTHETIC_GESTURE_MARKER) |
| 193 stats = GpuRenderingStats( | 174 stats = RenderingStats( |
| 194 smoothness_marker, gesture_marker, {}, True) | 175 smoothness_marker, gesture_marker, {}, True) |
| 195 | 176 |
| 196 # Make a results object and add results to it from the smoothness metric. | 177 # Make a results object and add results to it from the smoothness metric. |
| 197 res = PageMeasurementResults() | 178 res = PageMeasurementResults() |
| 198 res.WillMeasurePage(page.Page('http://foo.com/', None)) | 179 res.WillMeasurePage(page.Page('http://foo.com/', None)) |
| 199 smoothness.CalcResults(stats, res) | 180 smoothness.CalcResults(stats, res) |
| 200 res.DidMeasurePage() | 181 res.DidMeasurePage() |
| 201 | 182 |
| 202 self.assertEquals( | 183 self.assertEquals( |
| 203 expected_frame_times, | 184 expected_frame_times, |
| 204 res.page_results[0]['frame_times'].value) | 185 res.page_results[0]['frame_times'].value) |
| 205 self.assertAlmostEquals( | 186 self.assertAlmostEquals( |
| 206 1000.0 * (total_time_seconds / num_frames_sent), | 187 1000.0 * (total_time_seconds / num_frames_sent), |
| 207 res.page_results[0]['mean_frame_time'].value, | 188 res.page_results[0]['mean_frame_time'].value, |
| 208 places=2) | 189 places=2) |
| 209 | 190 |
| 210 # We don't verify the correctness of the discrepancy computation itself, | 191 # We don't verify the correctness of the discrepancy computation itself, |
| 211 # because we have a separate unit test for that purpose. | 192 # because we have a separate unit test for that purpose. |
| 212 self.assertAlmostEquals( | 193 self.assertAlmostEquals( |
| 213 statistics.FrameDiscrepancy(stats.screen_frame_timestamps, True), | 194 statistics.FrameDiscrepancy(stats.frame_timestamps, True), |
| 214 res.page_results[0]['jank'].value, | 195 res.page_results[0]['jank'].value, |
| 215 places=4) | 196 places=4) |
| 216 | 197 |
| 217 # We do not verify the correctness of Percentile here; Percentile should | 198 # We do not verify the correctness of Percentile here; Percentile should |
| 218 # have its own test. | 199 # have its own test. |
| 219 # The 17 here represents a threshold of 17 ms; this should match the value | 200 # The 17 here represents a threshold of 17 ms; this should match the value |
| 220 # in the smoothness metric. | 201 # in the smoothness metric. |
| 221 self.assertEquals( | 202 self.assertEquals( |
| 222 statistics.Percentile(expected_frame_times, 95.0) < 17.0, | 203 statistics.Percentile(expected_frame_times, 95.0) < 17.0, |
| 223 res.page_results[0]['mostly_smooth'].value) | 204 res.page_results[0]['mostly_smooth'].value) |
| 224 | |
| OLD | NEW |