blob: 4fea0b853c45cf0ca6044bfe343ebac0cfa9a250 [file] [log] [blame]
# Copyright 2014 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 logging
import StringIO
import unittest
from telemetry.web_perf.metrics import fast_metric
from telemetry.timeline import model as model_module
from telemetry.timeline import async_slice
from telemetry.results import page_measurement_results
from telemetry.web_perf import timeline_interaction_record as tir_module
class RendererThreadHelper(object):
def __init__(self, wall_start, wall_duration, thread_start, thread_duration):
self._model = model_module.TimelineModel()
renderer_process = self._model.GetOrCreateProcess(1)
self._renderer_thread = renderer_process.GetOrCreateThread(2)
self._renderer_thread.name = 'CrRendererMain'
self._renderer_thread.BeginSlice('cat1', 'x.y', wall_start, thread_start)
self._renderer_thread.EndSlice(wall_start + wall_duration,
thread_start + thread_duration)
self._async_slices = []
def AddInteraction(self, logical_name='LogicalName', **kwargs):
# Rename kwargs for AsyncSlice.
kwargs['timestamp'] = kwargs.pop('wall_start')
kwargs['duration'] = kwargs.pop('wall_duration')
self._async_slices.append(async_slice.AsyncSlice(
'cat', 'Interaction.%s/is_fast' % logical_name,
start_thread=self._renderer_thread, end_thread=self._renderer_thread,
**kwargs))
def MeasureFakePage(self, metric):
self._renderer_thread.async_slices.extend(self._async_slices)
self._model.FinalizeImport()
interaction_records = [
tir_module.TimelineInteractionRecord.FromAsyncEvent(s)
for s in self._async_slices]
results = page_measurement_results.PageMeasurementResults()
fake_page = None
results.WillMeasurePage(fake_page)
metric.AddResults(self._model, self._renderer_thread, interaction_records,
results)
return results
class FastMetricTests(unittest.TestCase):
def setUp(self):
self.log_output = StringIO.StringIO()
self.stream_handler = logging.StreamHandler(self.log_output)
logging.getLogger().addHandler(self.stream_handler)
def tearDown(self):
logging.getLogger().removeHandler(self.stream_handler)
self.log_output.close()
def LogOutput(self):
return self.log_output.getvalue()
def ActualValues(self, results):
return sorted(
(v.name, v.units, v.value)
for v in results.all_page_specific_values
)
def testAddResultsWithThreadTime(self):
# Wall time diagram:
# 1 2 3 4
# 01234567890123456789012345678901234567890123456789
# [ x.y ]
# [ Interaction.LogicalName/is_fast ]
renderer_thread_helper = RendererThreadHelper(
wall_start=5, wall_duration=35, thread_start=0, thread_duration=54)
renderer_thread_helper.AddInteraction(
wall_start=32, wall_duration=37, thread_start=51, thread_duration=33)
metric = fast_metric.FastMetric()
results = renderer_thread_helper.MeasureFakePage(metric)
expected_values = [
('fast-cpu_time', 'ms', 3), # 54 - 51; thread overlap
('fast-duration', 'ms', 37), # total interaction wall duration
('fast-idle_time', 'ms', 29), # 37 - ((5 + 35) - 32); interaction wall
# time outside of renderer wall time.
]
self.assertEqual(expected_values, self.ActualValues(results))
def testAddResultsWithoutThreadTime(self):
# Wall time diagram:
# 1 2 3 4
# 01234567890123456789012345678901234567890123456789
# [ x.y ]
# [ Interaction.LogicalName/is_fast ]
renderer_thread_helper = RendererThreadHelper(
wall_start=5, wall_duration=35, thread_start=0, thread_duration=54)
renderer_thread_helper.AddInteraction(
wall_start=32, wall_duration=37) # no thread_start, no thread_duration
metric = fast_metric.FastMetric()
results = renderer_thread_helper.MeasureFakePage(metric)
expected_values = [
# cpu_time is skipped because there is no thread time.
('fast-duration', 'ms', 37), # total interaction wall duration
('fast-idle_time', 'ms', 29), # 37 - ((5 + 35) - 32); interaction wall
# time outside of renderer wall time.
]
self.assertEqual(expected_values, self.ActualValues(results))
self.assertIn('Main thread cpu_time cannot be computed for records',
self.LogOutput())
def testAddResultsWithMultipleInteractions(self):
# Wall time diagram:
# 1 2 3 4
# 01234567890123456789012345678901234567890123456789
# [ x.y ]
# [ Interaction.Foo/is_fast ] [ Interaction.Bar/is_fast ]
renderer_thread_helper = RendererThreadHelper(
wall_start=2, wall_duration=45, thread_start=0, thread_duration=101)
renderer_thread_helper.AddInteraction(
logical_name='Foo',
wall_start=6, wall_duration=27, thread_start=51, thread_duration=33)
renderer_thread_helper.AddInteraction(
logical_name='Bar',
wall_start=38, wall_duration=27, thread_start=90, thread_duration=33)
metric = fast_metric.FastMetric()
results = renderer_thread_helper.MeasureFakePage(metric)
expected_values = [
('fast-cpu_time', 'ms', 44), # thread overlap
('fast-duration', 'ms', 54), # 27 + 27; total interaction wall duration
('fast-idle_time', 'ms', 18), # 27 - ((2 + 45) - 45); interaction wall
# time outside of renderer wall time.
]
self.assertEqual(expected_values, self.ActualValues(results))