1# Copyright 2014 The Chromium Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5import unittest 6 7import telemetry.timeline.bounds as timeline_bounds 8import telemetry.timeline.slice as tracing_slice 9from telemetry.timeline import model 10from telemetry.web_perf.metrics. \ 11 rendering_frame import GetFrameEventsInsideRange 12from telemetry.web_perf.metrics.rendering_frame import MissingData 13from telemetry.web_perf.metrics.rendering_frame import RenderingFrame 14 15 16class RenderingFrameTestData(object): 17 18 def __init__(self): 19 self._begin_frame_id = 0 20 self._events = [] 21 self._renderer_process = model.TimelineModel().GetOrCreateProcess(pid=1) 22 self._main_thread = self._renderer_process.GetOrCreateThread(tid=11) 23 self._compositor_thread = self._renderer_process.GetOrCreateThread(tid=12) 24 25 @property 26 def events(self): 27 return self._events 28 29 @property 30 def renderer_process(self): 31 return self._renderer_process 32 33 def AddSendEvent(self, ts=0, duration=1): 34 self._begin_frame_id += 1 35 event = self._CreateEvent( 36 RenderingFrame.send_begin_frame_event, ts, duration) 37 self._compositor_thread.PushSlice(event) 38 39 def AddBeginMainFrameEvent(self, ts=0, duration=1): 40 event = self._CreateEvent( 41 RenderingFrame.begin_main_frame_event, ts, duration) 42 self._main_thread.PushSlice(event) 43 44 def FinalizeImport(self): 45 self._renderer_process.FinalizeImport() 46 47 def _CreateEvent(self, event_name, ts, duration): 48 event = tracing_slice.Slice(None, 'cc,benchmark', event_name, ts, 49 duration=duration, args={'begin_frame_id': self._begin_frame_id}) 50 self._events.append(event) 51 return event 52 53 54def GenerateTimelineRange(start=0, end=100): 55 timeline_range = timeline_bounds.Bounds() 56 timeline_range.AddValue(start) 57 timeline_range.AddValue(end) 58 return timeline_range 59 60 61class RenderingFrameUnitTest(unittest.TestCase): 62 63 def testRenderingFrame(self): 64 d = RenderingFrameTestData() 65 d.AddSendEvent(ts=10) 66 d.AddBeginMainFrameEvent(ts=20) 67 d.FinalizeImport() 68 69 frame = RenderingFrame(d.events) 70 self.assertEquals(10, frame.queueing_duration) 71 72 def testRenderingFrameMissingSendBeginFrameEvents(self): 73 d = RenderingFrameTestData() 74 d.AddBeginMainFrameEvent(ts=10) 75 d.FinalizeImport() 76 77 self.assertRaises(MissingData, RenderingFrame, d.events) 78 79 def testRenderingFrameDuplicateSendBeginFrameEvents(self): 80 d = RenderingFrameTestData() 81 d.AddSendEvent(ts=10) 82 d.AddBeginMainFrameEvent(ts=20) 83 d.AddSendEvent(ts=30) 84 d.FinalizeImport() 85 86 self.assertRaises(MissingData, RenderingFrame, d.events) 87 88 def testRenderingFrameMissingBeginMainFrameEvents(self): 89 d = RenderingFrameTestData() 90 d.AddSendEvent(ts=10) 91 d.FinalizeImport() 92 93 self.assertRaises(MissingData, RenderingFrame, d.events) 94 95 def testRenderingFrameDuplicateBeginMainFrameEvents(self): 96 d = RenderingFrameTestData() 97 d.AddSendEvent(ts=10) 98 d.AddBeginMainFrameEvent(ts=20) 99 d.AddBeginMainFrameEvent(ts=30) 100 d.AddBeginMainFrameEvent(ts=40) 101 d.FinalizeImport() 102 103 frame = RenderingFrame(d.events) 104 self.assertEquals(30, frame.queueing_duration) 105 106 def testFrameEventMissingBeginFrameId(self): 107 timeline = model.TimelineModel() 108 process = timeline.GetOrCreateProcess(pid=1) 109 main_thread = process.GetOrCreateThread(tid=11) 110 timeline_range = timeline_bounds.Bounds() 111 112 # Create an event without the begin_frame_id argument 113 event = tracing_slice.Slice( 114 None, 'cc,benchmark', RenderingFrame.begin_main_frame_event, 0) 115 main_thread.PushSlice(event) 116 process.FinalizeImport() 117 self.assertRaises(Exception, GetFrameEventsInsideRange, process, 118 timeline_range) 119 120 def testGetFrameEventsInsideRange(self): 121 """Test a basic sequenece, with expected frame queueing delays A and B. 122 123 |----A----| |--B--| 124 Main: [1] [1] [2] 125 126 Compositor: [1] [2] 127 """ 128 d = RenderingFrameTestData() 129 d.AddSendEvent(ts=10) 130 d.AddBeginMainFrameEvent(ts=20) 131 d.AddBeginMainFrameEvent(ts=30) 132 d.AddSendEvent(ts=40) 133 d.AddBeginMainFrameEvent(ts=50) 134 d.FinalizeImport() 135 136 timeline_range = GenerateTimelineRange() 137 frame_events = GetFrameEventsInsideRange(d.renderer_process, timeline_range) 138 139 self.assertEquals(2, len(frame_events)) 140 self.assertEquals(20, frame_events[0].queueing_duration) 141 self.assertEquals(10, frame_events[1].queueing_duration) 142 143 def testFrameEventsMissingDataNotIncluded(self): 144 """Test a sequenece missing an initial SendBeginFrame. 145 146 Only one frame should be returned, with expected frame queueing delay A. 147 |--A--| 148 Main: [0] [0] [2] 149 150 Compositor: [2] 151 """ 152 d = RenderingFrameTestData() 153 d.AddBeginMainFrameEvent(ts=20) 154 d.AddBeginMainFrameEvent(ts=30) 155 d.AddSendEvent(ts=40) 156 d.AddBeginMainFrameEvent(ts=50) 157 d.FinalizeImport() 158 159 timeline_range = GenerateTimelineRange() 160 frame_events = GetFrameEventsInsideRange(d.renderer_process, timeline_range) 161 162 self.assertEquals(1, len(frame_events)) 163 self.assertEquals(10, frame_events[0].queueing_duration) 164