Home | History | Annotate | Download | only in metrics
      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 
      5 import random
      6 import unittest
      7 
      8 from telemetry.timeline import async_slice
      9 from telemetry.timeline import bounds
     10 from telemetry.timeline import model
     11 from telemetry.util import perf_tests_helper
     12 from telemetry.util import statistics
     13 from telemetry.web_perf.metrics import rendering_stats
     14 
     15 
     16 class MockTimer(object):
     17   """A mock timer class which can generate random durations.
     18 
     19   An instance of this class is used as a global timer to generate random
     20   durations for stats and consistent timestamps for all mock trace events.
     21   The unit of time is milliseconds.
     22   """
     23 
     24   def __init__(self):
     25     self.milliseconds = 0
     26 
     27   def Advance(self, low=0.1, high=1):
     28     delta = random.uniform(low, high)
     29     self.milliseconds += delta
     30     return delta
     31 
     32   def AdvanceAndGet(self, low=0.1, high=1):
     33     self.Advance(low, high)
     34     return self.milliseconds
     35 
     36 
     37 class ReferenceRenderingStats(object):
     38   """ Stores expected data for comparison with actual RenderingStats """
     39 
     40   def __init__(self):
     41     self.frame_timestamps = []
     42     self.frame_times = []
     43     self.approximated_pixel_percentages = []
     44     self.checkerboarded_pixel_percentages = []
     45 
     46   def AppendNewRange(self):
     47     self.frame_timestamps.append([])
     48     self.frame_times.append([])
     49     self.approximated_pixel_percentages.append([])
     50     self.checkerboarded_pixel_percentages.append([])
     51 
     52 
     53 class ReferenceInputLatencyStats(object):
     54   """ Stores expected data for comparison with actual input latency stats """
     55 
     56   def __init__(self):
     57     self.input_event_latency = []
     58     self.input_event = []
     59 
     60 
     61 def AddSurfaceFlingerStats(mock_timer, thread, first_frame,
     62                            ref_stats=None):
     63   """ Adds a random surface flinger stats event.
     64 
     65   thread: The timeline model thread to which the event will be added.
     66   first_frame: Is this the first frame within the bounds of an action?
     67   ref_stats: A ReferenceRenderingStats object to record expected values.
     68   """
     69   # Create randonm data and timestap for impl thread rendering stats.
     70   data = {'frame_count': 1,
     71           'refresh_period': 16.6666}
     72   timestamp = mock_timer.AdvanceAndGet()
     73 
     74   # Add a slice with the event data to the given thread.
     75   thread.PushCompleteSlice(
     76       'SurfaceFlinger', 'vsync_before',
     77       timestamp, duration=0.0, thread_timestamp=None, thread_duration=None,
     78       args={'data': data})
     79 
     80   if not ref_stats:
     81     return
     82 
     83   # Add timestamp only if a frame was output
     84   if data['frame_count'] == 1:
     85     if not first_frame:
     86       # Add frame_time if this is not the first frame in within the bounds of an
     87       # action.
     88       prev_timestamp = ref_stats.frame_timestamps[-1][-1]
     89       ref_stats.frame_times[-1].append(timestamp - prev_timestamp)
     90     ref_stats.frame_timestamps[-1].append(timestamp)
     91 
     92 
     93 def AddDisplayRenderingStats(mock_timer, thread, first_frame,
     94                              ref_stats=None):
     95   """ Adds a random display rendering stats event.
     96 
     97   thread: The timeline model thread to which the event will be added.
     98   first_frame: Is this the first frame within the bounds of an action?
     99   ref_stats: A ReferenceRenderingStats object to record expected values.
    100   """
    101   # Create randonm data and timestap for main thread rendering stats.
    102   data = {'frame_count': 1}
    103   timestamp = mock_timer.AdvanceAndGet()
    104 
    105   # Add a slice with the event data to the given thread.
    106   thread.PushCompleteSlice(
    107       'benchmark', 'BenchmarkInstrumentation::DisplayRenderingStats',
    108       timestamp, duration=0.0, thread_timestamp=None, thread_duration=None,
    109       args={'data': data})
    110 
    111   if not ref_stats:
    112     return
    113 
    114   # Add timestamp only if a frame was output
    115   if not first_frame:
    116     # Add frame_time if this is not the first frame in within the bounds of an
    117     # action.
    118     prev_timestamp = ref_stats.frame_timestamps[-1][-1]
    119     ref_stats.frame_times[-1].append(timestamp - prev_timestamp)
    120   ref_stats.frame_timestamps[-1].append(timestamp)
    121 
    122 
    123 def AddImplThreadRenderingStats(mock_timer, thread, first_frame,
    124                                 ref_stats=None):
    125   """ Adds a random impl thread rendering stats event.
    126 
    127   thread: The timeline model thread to which the event will be added.
    128   first_frame: Is this the first frame within the bounds of an action?
    129   ref_stats: A ReferenceRenderingStats object to record expected values.
    130   """
    131   # Create randonm data and timestap for impl thread rendering stats.
    132   data = {'frame_count': 1,
    133           'visible_content_area': random.uniform(0, 100),
    134           'approximated_visible_content_area': random.uniform(0, 5),
    135           'checkerboarded_visible_content_area': random.uniform(0, 5)}
    136   timestamp = mock_timer.AdvanceAndGet()
    137 
    138   # Add a slice with the event data to the given thread.
    139   thread.PushCompleteSlice(
    140       'benchmark', 'BenchmarkInstrumentation::ImplThreadRenderingStats',
    141       timestamp, duration=0.0, thread_timestamp=None, thread_duration=None,
    142       args={'data': data})
    143 
    144   if not ref_stats:
    145     return
    146 
    147   # Add timestamp only if a frame was output
    148   if data['frame_count'] == 1:
    149     if not first_frame:
    150       # Add frame_time if this is not the first frame in within the bounds of an
    151       # action.
    152       prev_timestamp = ref_stats.frame_timestamps[-1][-1]
    153       ref_stats.frame_times[-1].append(timestamp - prev_timestamp)
    154     ref_stats.frame_timestamps[-1].append(timestamp)
    155 
    156   ref_stats.approximated_pixel_percentages[-1].append(
    157       round(statistics.DivideIfPossibleOrZero(
    158           data['approximated_visible_content_area'],
    159           data['visible_content_area']) * 100.0, 3))
    160 
    161   ref_stats.checkerboarded_pixel_percentages[-1].append(
    162       round(statistics.DivideIfPossibleOrZero(
    163           data['checkerboarded_visible_content_area'],
    164           data['visible_content_area']) * 100.0, 3))
    165 
    166 def AddInputLatencyStats(mock_timer, start_thread, end_thread,
    167                          ref_latency_stats=None):
    168   """ Adds a random input latency stats event.
    169 
    170   start_thread: The start thread on which the async slice is added.
    171   end_thread: The end thread on which the async slice is ended.
    172   ref_latency_stats: A ReferenceInputLatencyStats object for expected values.
    173   """
    174 
    175   original_comp_time = mock_timer.AdvanceAndGet(2, 4) * 1000.0
    176   ui_comp_time = mock_timer.AdvanceAndGet(2, 4) * 1000.0
    177   begin_comp_time = mock_timer.AdvanceAndGet(2, 4) * 1000.0
    178   forward_comp_time = mock_timer.AdvanceAndGet(2, 4) * 1000.0
    179   end_comp_time = mock_timer.AdvanceAndGet(10, 20) * 1000.0
    180 
    181   data = {rendering_stats.ORIGINAL_COMP_NAME: {'time': original_comp_time},
    182           rendering_stats.UI_COMP_NAME: {'time': ui_comp_time},
    183           rendering_stats.BEGIN_COMP_NAME: {'time': begin_comp_time},
    184           rendering_stats.END_COMP_NAME: {'time': end_comp_time}}
    185 
    186   timestamp = mock_timer.AdvanceAndGet(2, 4)
    187 
    188   tracing_async_slice = async_slice.AsyncSlice(
    189       'benchmark', 'InputLatency', timestamp)
    190 
    191   async_sub_slice = async_slice.AsyncSlice(
    192       'benchmark', rendering_stats.GESTURE_SCROLL_UPDATE_EVENT_NAME, timestamp)
    193   async_sub_slice.args = {'data': data}
    194   async_sub_slice.parent_slice = tracing_async_slice
    195   async_sub_slice.start_thread = start_thread
    196   async_sub_slice.end_thread = end_thread
    197 
    198   tracing_async_slice.sub_slices.append(async_sub_slice)
    199   tracing_async_slice.start_thread = start_thread
    200   tracing_async_slice.end_thread = end_thread
    201   start_thread.AddAsyncSlice(tracing_async_slice)
    202 
    203   # Add scroll update latency info.
    204   scroll_update_data = {
    205       rendering_stats.BEGIN_SCROLL_UPDATE_COMP_NAME: {'time': begin_comp_time},
    206       rendering_stats.FORWARD_SCROLL_UPDATE_COMP_NAME:
    207           {'time': forward_comp_time},
    208       rendering_stats.END_COMP_NAME: {'time': end_comp_time}
    209   }
    210 
    211   scroll_async_slice = async_slice.AsyncSlice(
    212       'benchmark', 'InputLatency', timestamp)
    213 
    214   scroll_async_sub_slice = async_slice.AsyncSlice(
    215       'benchmark', rendering_stats.MAIN_THREAD_SCROLL_UPDATE_EVENT_NAME,
    216       timestamp)
    217   scroll_async_sub_slice.args = {'data': scroll_update_data}
    218   scroll_async_sub_slice.parent_slice = scroll_async_slice
    219   scroll_async_sub_slice.start_thread = start_thread
    220   scroll_async_sub_slice.end_thread = end_thread
    221 
    222   scroll_async_slice.sub_slices.append(scroll_async_sub_slice)
    223   scroll_async_slice.start_thread = start_thread
    224   scroll_async_slice.end_thread = end_thread
    225   start_thread.AddAsyncSlice(scroll_async_slice)
    226 
    227   # Also add some dummy frame statistics so we can feed the resulting timeline
    228   # to RenderingStats.
    229   AddImplThreadRenderingStats(mock_timer, end_thread, False)
    230 
    231   if not ref_latency_stats:
    232     return
    233 
    234   ref_latency_stats.input_event.append(async_sub_slice)
    235   ref_latency_stats.input_event.append(scroll_async_sub_slice)
    236   ref_latency_stats.input_event_latency.append((
    237       rendering_stats.GESTURE_SCROLL_UPDATE_EVENT_NAME,
    238       (data[rendering_stats.END_COMP_NAME]['time'] -
    239        data[rendering_stats.ORIGINAL_COMP_NAME]['time']) / 1000.0))
    240   scroll_update_time = (
    241       scroll_update_data[rendering_stats.END_COMP_NAME]['time'] -
    242       scroll_update_data[rendering_stats.BEGIN_SCROLL_UPDATE_COMP_NAME]['time'])
    243   ref_latency_stats.input_event_latency.append((
    244       rendering_stats.MAIN_THREAD_SCROLL_UPDATE_EVENT_NAME,
    245       scroll_update_time / 1000.0))
    246 
    247 
    248 class RenderingStatsUnitTest(unittest.TestCase):
    249 
    250   def testHasRenderingStats(self):
    251     timeline = model.TimelineModel()
    252     timer = MockTimer()
    253 
    254     # A process without rendering stats
    255     process_without_stats = timeline.GetOrCreateProcess(pid=1)
    256     thread_without_stats = process_without_stats.GetOrCreateThread(tid=11)
    257     process_without_stats.FinalizeImport()
    258     self.assertFalse(rendering_stats.HasRenderingStats(thread_without_stats))
    259 
    260     # A process with rendering stats, but no frames in them
    261     process_without_frames = timeline.GetOrCreateProcess(pid=2)
    262     thread_without_frames = process_without_frames.GetOrCreateThread(tid=21)
    263     process_without_frames.FinalizeImport()
    264     self.assertFalse(rendering_stats.HasRenderingStats(thread_without_frames))
    265 
    266     # A process with rendering stats and frames in them
    267     process_with_frames = timeline.GetOrCreateProcess(pid=3)
    268     thread_with_frames = process_with_frames.GetOrCreateThread(tid=31)
    269     AddImplThreadRenderingStats(timer, thread_with_frames, True, None)
    270     process_with_frames.FinalizeImport()
    271     self.assertTrue(rendering_stats.HasRenderingStats(thread_with_frames))
    272 
    273   def testBothSurfaceFlingerAndDisplayStats(self):
    274     timeline = model.TimelineModel()
    275     timer = MockTimer()
    276 
    277     ref_stats = ReferenceRenderingStats()
    278     ref_stats.AppendNewRange()
    279     surface_flinger = timeline.GetOrCreateProcess(pid=4)
    280     surface_flinger.name = 'SurfaceFlinger'
    281     surface_flinger_thread = surface_flinger.GetOrCreateThread(tid=41)
    282     renderer = timeline.GetOrCreateProcess(pid=2)
    283     browser = timeline.GetOrCreateProcess(pid=3)
    284     browser_main = browser.GetOrCreateThread(tid=31)
    285     browser_main.BeginSlice('webkit.console', 'ActionA',
    286                             timer.AdvanceAndGet(2, 4), '')
    287 
    288     # Create SurfaceFlinger stats and display rendering stats.
    289     for i in xrange(0, 10):
    290       first = (i == 0)
    291       AddSurfaceFlingerStats(timer, surface_flinger_thread, first, ref_stats)
    292       timer.Advance(2, 4)
    293 
    294     for i in xrange(0, 10):
    295       first = (i == 0)
    296       AddDisplayRenderingStats(timer, browser_main, first, None)
    297       timer.Advance(5, 10)
    298 
    299     browser_main.EndSlice(timer.AdvanceAndGet())
    300     timer.Advance(2, 4)
    301 
    302     browser.FinalizeImport()
    303     renderer.FinalizeImport()
    304     timeline_markers = timeline.FindTimelineMarkers(['ActionA'])
    305     timeline_ranges = [bounds.Bounds.CreateFromEvent(marker)
    306                        for marker in timeline_markers]
    307     stats = rendering_stats.RenderingStats(
    308         renderer, browser, surface_flinger, timeline_ranges)
    309 
    310     # Compare rendering stats to reference - Only SurfaceFlinger stats should
    311     # count
    312     self.assertEquals(stats.frame_timestamps, ref_stats.frame_timestamps)
    313     self.assertEquals(stats.frame_times, ref_stats.frame_times)
    314 
    315   def testBothDisplayAndImplStats(self):
    316     timeline = model.TimelineModel()
    317     timer = MockTimer()
    318 
    319     ref_stats = ReferenceRenderingStats()
    320     ref_stats.AppendNewRange()
    321     renderer = timeline.GetOrCreateProcess(pid=2)
    322     browser = timeline.GetOrCreateProcess(pid=3)
    323     browser_main = browser.GetOrCreateThread(tid=31)
    324     browser_main.BeginSlice('webkit.console', 'ActionA',
    325                             timer.AdvanceAndGet(2, 4), '')
    326 
    327     # Create main, impl, and display rendering stats.
    328     for i in xrange(0, 10):
    329       first = (i == 0)
    330       AddImplThreadRenderingStats(timer, browser_main, first, None)
    331       timer.Advance(2, 4)
    332 
    333     for i in xrange(0, 10):
    334       first = (i == 0)
    335       AddDisplayRenderingStats(timer, browser_main, first, ref_stats)
    336       timer.Advance(5, 10)
    337 
    338     browser_main.EndSlice(timer.AdvanceAndGet())
    339     timer.Advance(2, 4)
    340 
    341     browser.FinalizeImport()
    342     renderer.FinalizeImport()
    343     timeline_markers = timeline.FindTimelineMarkers(['ActionA'])
    344     timeline_ranges = [bounds.Bounds.CreateFromEvent(marker)
    345                        for marker in timeline_markers]
    346     stats = rendering_stats.RenderingStats(
    347         renderer, browser, None, timeline_ranges)
    348 
    349     # Compare rendering stats to reference - Only display stats should count
    350     self.assertEquals(stats.frame_timestamps, ref_stats.frame_timestamps)
    351     self.assertEquals(stats.frame_times, ref_stats.frame_times)
    352 
    353   def testRangeWithoutFrames(self):
    354     timer = MockTimer()
    355     timeline = model.TimelineModel()
    356 
    357     # Create a renderer process, with a main thread and impl thread.
    358     renderer = timeline.GetOrCreateProcess(pid=2)
    359     renderer_main = renderer.GetOrCreateThread(tid=21)
    360     renderer_compositor = renderer.GetOrCreateThread(tid=22)
    361 
    362     # Create 10 main and impl rendering stats events for Action A.
    363     renderer_main.BeginSlice('webkit.console', 'ActionA',
    364                              timer.AdvanceAndGet(2, 4), '')
    365     for i in xrange(0, 10):
    366       first = (i == 0)
    367       AddImplThreadRenderingStats(timer, renderer_compositor, first, None)
    368     renderer_main.EndSlice(timer.AdvanceAndGet(2, 4))
    369     timer.Advance(2, 4)
    370 
    371     # Create 5 main and impl rendering stats events not within any action.
    372     for i in xrange(0, 5):
    373       first = (i == 0)
    374       AddImplThreadRenderingStats(timer, renderer_compositor, first, None)
    375 
    376     # Create Action B without any frames. This should trigger
    377     # NotEnoughFramesError when the RenderingStats object is created.
    378     renderer_main.BeginSlice('webkit.console', 'ActionB',
    379                              timer.AdvanceAndGet(2, 4), '')
    380     renderer_main.EndSlice(timer.AdvanceAndGet(2, 4))
    381 
    382     renderer.FinalizeImport()
    383 
    384     timeline_markers = timeline.FindTimelineMarkers(['ActionA', 'ActionB'])
    385     timeline_ranges = [bounds.Bounds.CreateFromEvent(marker)
    386                        for marker in timeline_markers]
    387 
    388     stats = rendering_stats.RenderingStats(
    389         renderer, None, None, timeline_ranges)
    390     self.assertEquals(0, len(stats.frame_timestamps[1]))
    391 
    392   def testFromTimeline(self):
    393     timeline = model.TimelineModel()
    394 
    395     # Create a browser process and a renderer process, and a main thread and
    396     # impl thread for each.
    397     browser = timeline.GetOrCreateProcess(pid=1)
    398     browser_compositor = browser.GetOrCreateThread(tid=12)
    399     renderer = timeline.GetOrCreateProcess(pid=2)
    400     renderer_main = renderer.GetOrCreateThread(tid=21)
    401     renderer_compositor = renderer.GetOrCreateThread(tid=22)
    402 
    403     timer = MockTimer()
    404     renderer_ref_stats = ReferenceRenderingStats()
    405     browser_ref_stats = ReferenceRenderingStats()
    406 
    407     # Create 10 main and impl rendering stats events for Action A.
    408     renderer_main.BeginSlice('webkit.console', 'ActionA',
    409                              timer.AdvanceAndGet(2, 4), '')
    410     renderer_ref_stats.AppendNewRange()
    411     browser_ref_stats.AppendNewRange()
    412     for i in xrange(0, 10):
    413       first = (i == 0)
    414       AddImplThreadRenderingStats(
    415           timer, renderer_compositor, first, renderer_ref_stats)
    416       AddImplThreadRenderingStats(
    417           timer, browser_compositor, first, browser_ref_stats)
    418     renderer_main.EndSlice(timer.AdvanceAndGet(2, 4))
    419 
    420     # Create 5 main and impl rendering stats events not within any action.
    421     for i in xrange(0, 5):
    422       first = (i == 0)
    423       AddImplThreadRenderingStats(timer, renderer_compositor, first, None)
    424       AddImplThreadRenderingStats(timer, browser_compositor, first, None)
    425 
    426     # Create 10 main and impl rendering stats events for Action B.
    427     renderer_main.BeginSlice('webkit.console', 'ActionB',
    428                              timer.AdvanceAndGet(2, 4), '')
    429     renderer_ref_stats.AppendNewRange()
    430     browser_ref_stats.AppendNewRange()
    431     for i in xrange(0, 10):
    432       first = (i == 0)
    433       AddImplThreadRenderingStats(
    434           timer, renderer_compositor, first, renderer_ref_stats)
    435       AddImplThreadRenderingStats(
    436           timer, browser_compositor, first, browser_ref_stats)
    437     renderer_main.EndSlice(timer.AdvanceAndGet(2, 4))
    438 
    439     # Create 10 main and impl rendering stats events for Action A.
    440     renderer_main.BeginSlice('webkit.console', 'ActionA',
    441                              timer.AdvanceAndGet(2, 4), '')
    442     renderer_ref_stats.AppendNewRange()
    443     browser_ref_stats.AppendNewRange()
    444     for i in xrange(0, 10):
    445       first = (i == 0)
    446       AddImplThreadRenderingStats(
    447           timer, renderer_compositor, first, renderer_ref_stats)
    448       AddImplThreadRenderingStats(
    449           timer, browser_compositor, first, browser_ref_stats)
    450     renderer_main.EndSlice(timer.AdvanceAndGet(2, 4))
    451     timer.Advance(2, 4)
    452 
    453     browser.FinalizeImport()
    454     renderer.FinalizeImport()
    455 
    456     timeline_markers = timeline.FindTimelineMarkers(
    457         ['ActionA', 'ActionB', 'ActionA'])
    458     timeline_ranges = [bounds.Bounds.CreateFromEvent(marker)
    459                        for marker in timeline_markers]
    460     stats = rendering_stats.RenderingStats(
    461         renderer, browser, None, timeline_ranges)
    462 
    463     # Compare rendering stats to reference.
    464     self.assertEquals(stats.frame_timestamps,
    465                       browser_ref_stats.frame_timestamps)
    466     self.assertEquals(stats.frame_times, browser_ref_stats.frame_times)
    467     self.assertEquals(stats.approximated_pixel_percentages,
    468                       renderer_ref_stats.approximated_pixel_percentages)
    469     self.assertEquals(stats.checkerboarded_pixel_percentages,
    470                       renderer_ref_stats.checkerboarded_pixel_percentages)
    471 
    472   def testInputLatencyFromTimeline(self):
    473     timeline = model.TimelineModel()
    474 
    475     # Create a browser process and a renderer process.
    476     browser = timeline.GetOrCreateProcess(pid=1)
    477     browser_main = browser.GetOrCreateThread(tid=11)
    478     renderer = timeline.GetOrCreateProcess(pid=2)
    479     renderer_main = renderer.GetOrCreateThread(tid=21)
    480 
    481     timer = MockTimer()
    482     ref_latency = ReferenceInputLatencyStats()
    483 
    484     # Create 10 input latency stats events for Action A.
    485     renderer_main.BeginSlice('webkit.console', 'ActionA',
    486                              timer.AdvanceAndGet(2, 4), '')
    487     for _ in xrange(0, 10):
    488       AddInputLatencyStats(timer, browser_main, renderer_main, ref_latency)
    489     renderer_main.EndSlice(timer.AdvanceAndGet(2, 4))
    490 
    491     # Create 5 input latency stats events not within any action.
    492     timer.Advance(2, 4)
    493     for _ in xrange(0, 5):
    494       AddInputLatencyStats(timer, browser_main, renderer_main, None)
    495 
    496     # Create 10 input latency stats events for Action B.
    497     renderer_main.BeginSlice('webkit.console', 'ActionB',
    498                              timer.AdvanceAndGet(2, 4), '')
    499     for _ in xrange(0, 10):
    500       AddInputLatencyStats(timer, browser_main, renderer_main, ref_latency)
    501     renderer_main.EndSlice(timer.AdvanceAndGet(2, 4))
    502 
    503     # Create 10 input latency stats events for Action A.
    504     renderer_main.BeginSlice('webkit.console', 'ActionA',
    505                              timer.AdvanceAndGet(2, 4), '')
    506     for _ in xrange(0, 10):
    507       AddInputLatencyStats(timer, browser_main, renderer_main, ref_latency)
    508     renderer_main.EndSlice(timer.AdvanceAndGet(2, 4))
    509 
    510     browser.FinalizeImport()
    511     renderer.FinalizeImport()
    512 
    513     latency_events = []
    514 
    515     timeline_markers = timeline.FindTimelineMarkers(
    516         ['ActionA', 'ActionB', 'ActionA'])
    517     timeline_ranges = [bounds.Bounds.CreateFromEvent(marker)
    518                        for marker in timeline_markers]
    519     for timeline_range in timeline_ranges:
    520       if timeline_range.is_empty:
    521         continue
    522       latency_events.extend(rendering_stats.GetLatencyEvents(
    523           browser, timeline_range))
    524 
    525     self.assertEquals(latency_events, ref_latency.input_event)
    526     event_latency_result = rendering_stats.ComputeEventLatencies(latency_events)
    527     self.assertEquals(event_latency_result,
    528                       ref_latency.input_event_latency)
    529 
    530     stats = rendering_stats.RenderingStats(
    531         renderer, browser, None, timeline_ranges)
    532     self.assertEquals(
    533         perf_tests_helper.FlattenList(stats.input_event_latency),
    534         [latency for name, latency in ref_latency.input_event_latency
    535          if name != rendering_stats.MAIN_THREAD_SCROLL_UPDATE_EVENT_NAME])
    536     self.assertEquals(
    537         perf_tests_helper.FlattenList(stats.main_thread_scroll_latency),
    538         [latency for name, latency in ref_latency.input_event_latency
    539          if name == rendering_stats.MAIN_THREAD_SCROLL_UPDATE_EVENT_NAME])
    540     self.assertEquals(
    541         perf_tests_helper.FlattenList(stats.gesture_scroll_update_latency),
    542         [latency for name, latency in ref_latency.input_event_latency
    543          if name == rendering_stats.GESTURE_SCROLL_UPDATE_EVENT_NAME])
    544