1116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch# Copyright 2014 The Chromium Authors. All rights reserved.
2116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch# Use of this source code is governed by a BSD-style license that can be
3116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch# found in the LICENSE file.
4116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
5116680a4aac90f2aa7413d9095a592090648e557Ben Murdochimport unittest
6116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
7116680a4aac90f2aa7413d9095a592090648e557Ben Murdochimport telemetry.timeline.bounds as timeline_bounds
8116680a4aac90f2aa7413d9095a592090648e557Ben Murdochimport telemetry.timeline.slice as tracing_slice
96e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)from telemetry.timeline import model
106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)from telemetry.web_perf.metrics. \
116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    rendering_frame import GetFrameEventsInsideRange
12116680a4aac90f2aa7413d9095a592090648e557Ben Murdochfrom telemetry.web_perf.metrics.rendering_frame import MissingData
13116680a4aac90f2aa7413d9095a592090648e557Ben Murdochfrom telemetry.web_perf.metrics.rendering_frame import RenderingFrame
14116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
15116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
16116680a4aac90f2aa7413d9095a592090648e557Ben Murdochclass RenderingFrameTestData(object):
17116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
18116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  def __init__(self):
19116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    self._begin_frame_id = 0
20116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    self._events = []
21116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    self._renderer_process = model.TimelineModel().GetOrCreateProcess(pid=1)
22116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    self._main_thread = self._renderer_process.GetOrCreateThread(tid=11)
23116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    self._compositor_thread = self._renderer_process.GetOrCreateThread(tid=12)
24116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
25116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  @property
26116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  def events(self):
27116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return self._events
28116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
29116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  @property
30116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  def renderer_process(self):
31116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return self._renderer_process
32116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
33116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  def AddSendEvent(self, ts=0, duration=1):
34116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    self._begin_frame_id += 1
35116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    event = self._CreateEvent(
36116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        RenderingFrame.send_begin_frame_event, ts, duration)
37116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    self._compositor_thread.PushSlice(event)
38116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
39116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  def AddBeginMainFrameEvent(self, ts=0, duration=1):
40116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    event = self._CreateEvent(
41116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        RenderingFrame.begin_main_frame_event, ts, duration)
42116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    self._main_thread.PushSlice(event)
43116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
44116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  def FinalizeImport(self):
45116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    self._renderer_process.FinalizeImport()
46116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
47116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  def _CreateEvent(self, event_name, ts, duration):
48116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    event = tracing_slice.Slice(None, 'cc,benchmark', event_name, ts,
49116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        duration=duration, args={'begin_frame_id': self._begin_frame_id})
50116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    self._events.append(event)
51116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return event
52116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
53116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
54116680a4aac90f2aa7413d9095a592090648e557Ben Murdochdef GenerateTimelineRange(start=0, end=100):
55116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  timeline_range = timeline_bounds.Bounds()
56116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  timeline_range.AddValue(start)
57116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  timeline_range.AddValue(end)
58116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return timeline_range
59116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
60116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
61116680a4aac90f2aa7413d9095a592090648e557Ben Murdochclass RenderingFrameUnitTest(unittest.TestCase):
62116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
63116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  def testRenderingFrame(self):
64116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    d = RenderingFrameTestData()
65116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    d.AddSendEvent(ts=10)
66116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    d.AddBeginMainFrameEvent(ts=20)
67116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    d.FinalizeImport()
68116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
69116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    frame = RenderingFrame(d.events)
70116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    self.assertEquals(10, frame.queueing_duration)
71116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
72116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  def testRenderingFrameMissingSendBeginFrameEvents(self):
73116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    d = RenderingFrameTestData()
74116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    d.AddBeginMainFrameEvent(ts=10)
75116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    d.FinalizeImport()
76116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
77116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    self.assertRaises(MissingData, RenderingFrame, d.events)
78116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
79116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  def testRenderingFrameDuplicateSendBeginFrameEvents(self):
80116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    d = RenderingFrameTestData()
81116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    d.AddSendEvent(ts=10)
82116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    d.AddBeginMainFrameEvent(ts=20)
83116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    d.AddSendEvent(ts=30)
84116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    d.FinalizeImport()
85116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
86116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    self.assertRaises(MissingData, RenderingFrame, d.events)
87116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
88116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  def testRenderingFrameMissingBeginMainFrameEvents(self):
89116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    d = RenderingFrameTestData()
90116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    d.AddSendEvent(ts=10)
91116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    d.FinalizeImport()
92116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
93116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    self.assertRaises(MissingData, RenderingFrame, d.events)
94116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
95116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  def testRenderingFrameDuplicateBeginMainFrameEvents(self):
96116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    d = RenderingFrameTestData()
97116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    d.AddSendEvent(ts=10)
98116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    d.AddBeginMainFrameEvent(ts=20)
99116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    d.AddBeginMainFrameEvent(ts=30)
100116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    d.AddBeginMainFrameEvent(ts=40)
101116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    d.FinalizeImport()
102116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
103116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    frame = RenderingFrame(d.events)
104116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    self.assertEquals(30, frame.queueing_duration)
105116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
106116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  def testFrameEventMissingBeginFrameId(self):
107116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    timeline = model.TimelineModel()
108116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    process = timeline.GetOrCreateProcess(pid=1)
109116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    main_thread = process.GetOrCreateThread(tid=11)
110116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    timeline_range = timeline_bounds.Bounds()
111116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
112116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    # Create an event without the begin_frame_id argument
113116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    event = tracing_slice.Slice(
114116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        None, 'cc,benchmark', RenderingFrame.begin_main_frame_event, 0)
115116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    main_thread.PushSlice(event)
116116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    process.FinalizeImport()
117116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    self.assertRaises(Exception, GetFrameEventsInsideRange, process,
118116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                      timeline_range)
119116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
120116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  def testGetFrameEventsInsideRange(self):
121116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    """Test a basic sequenece, with expected frame queueing delays A and B.
122116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
123116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                 |----A----|    |--B--|
124116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch         Main:        [1]  [1]        [2]
125116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
126116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    Compositor:  [1]            [2]
127116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    """
128116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    d = RenderingFrameTestData()
129116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    d.AddSendEvent(ts=10)
130116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    d.AddBeginMainFrameEvent(ts=20)
131116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    d.AddBeginMainFrameEvent(ts=30)
132116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    d.AddSendEvent(ts=40)
133116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    d.AddBeginMainFrameEvent(ts=50)
134116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    d.FinalizeImport()
135116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
136116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    timeline_range = GenerateTimelineRange()
137116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    frame_events = GetFrameEventsInsideRange(d.renderer_process, timeline_range)
138116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
139116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    self.assertEquals(2, len(frame_events))
140116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    self.assertEquals(20, frame_events[0].queueing_duration)
141116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    self.assertEquals(10, frame_events[1].queueing_duration)
142116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
143116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  def testFrameEventsMissingDataNotIncluded(self):
144116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    """Test a sequenece missing an initial SendBeginFrame.
145116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
146116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    Only one frame should be returned, with expected frame queueing delay A.
147116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                           |--A--|
148116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          Main:  [0]  [0]        [2]
149116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
150116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    Compositor:            [2]
151116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    """
152116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    d = RenderingFrameTestData()
153116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    d.AddBeginMainFrameEvent(ts=20)
154116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    d.AddBeginMainFrameEvent(ts=30)
155116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    d.AddSendEvent(ts=40)
156116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    d.AddBeginMainFrameEvent(ts=50)
157116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    d.FinalizeImport()
158116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
159116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    timeline_range = GenerateTimelineRange()
160116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    frame_events = GetFrameEventsInsideRange(d.renderer_process, timeline_range)
161116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
162116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    self.assertEquals(1, len(frame_events))
163116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    self.assertEquals(10, frame_events[0].queueing_duration)
164