| Index: tools/telemetry/telemetry/web_perf/metrics/fast_metric_unittest.py
|
| diff --git a/tools/telemetry/telemetry/web_perf/metrics/fast_metric_unittest.py b/tools/telemetry/telemetry/web_perf/metrics/fast_metric_unittest.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..3bd2ca9b46c64d6f802030cce0ef0b646ecce58b
|
| --- /dev/null
|
| +++ b/tools/telemetry/telemetry/web_perf/metrics/fast_metric_unittest.py
|
| @@ -0,0 +1,216 @@
|
| +# 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.results import page_test_results
|
| +from telemetry.timeline import model as model_module
|
| +from telemetry.timeline import async_slice
|
| +from telemetry.web_perf import timeline_interaction_record as tir_module
|
| +from telemetry.web_perf.metrics import fast_metric
|
| +
|
| +
|
| +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 AddEvent(self, category, name, wall_start, wall_duration, thread_start,
|
| + thread_duration):
|
| + self._renderer_thread.BeginSlice(category, name, wall_start, thread_start)
|
| + self._renderer_thread.EndSlice(wall_start + wall_duration,
|
| + thread_start + thread_duration)
|
| +
|
| + 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_test_results.PageTestResults()
|
| + fake_page = None
|
| + results.WillRunPage(fake_page)
|
| + metric.AddResults(self._model, self._renderer_thread, interaction_records,
|
| + results)
|
| + results.DidRunPage(fake_page)
|
| + 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), # (32 + 37) - (5 + 35); interaction wall
|
| + # time outside of renderer wall time.
|
| + ('fast-incremental_marking', 'ms', 0.0),
|
| + ('fast-incremental_marking_outside_idle', 'ms', 0.0),
|
| + ('fast-mark_compactor', 'ms', 0.0),
|
| + ('fast-mark_compactor_outside_idle', 'ms', 0.0),
|
| + ('fast-scavenger', 'ms', 0.0),
|
| + ('fast-scavenger_outside_idle', 'ms', 0.0),
|
| + ('fast-total_garbage_collection', 'ms', 0.0),
|
| + ('fast-total_garbage_collection_outside_idle', 'ms', 0.0)
|
| + ]
|
| + 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), # (32 + 37) - (5 + 35); interaction wall
|
| + # time outside of renderer wall time.
|
| + ('fast-incremental_marking', 'ms', 0.0),
|
| + ('fast-incremental_marking_outside_idle', 'ms', 0.0),
|
| + ('fast-mark_compactor', 'ms', 0.0),
|
| + ('fast-mark_compactor_outside_idle', 'ms', 0.0),
|
| + ('fast-scavenger', 'ms', 0.0),
|
| + ('fast-scavenger_outside_idle', 'ms', 0.0),
|
| + ('fast-total_garbage_collection', 'ms', 0.0),
|
| + ('fast-total_garbage_collection_outside_idle', 'ms', 0.0)
|
| + ]
|
| + 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), # (38 + 27) - (2 + 45); interaction wall
|
| + # time outside of renderer wall time.
|
| + ('fast-incremental_marking', 'ms', 0.0),
|
| + ('fast-incremental_marking_outside_idle', 'ms', 0.0),
|
| + ('fast-mark_compactor', 'ms', 0.0),
|
| + ('fast-mark_compactor_outside_idle', 'ms', 0.0),
|
| + ('fast-scavenger', 'ms', 0.0),
|
| + ('fast-scavenger_outside_idle', 'ms', 0.0),
|
| + ('fast-total_garbage_collection', 'ms', 0.0),
|
| + ('fast-total_garbage_collection_outside_idle', 'ms', 0.0)
|
| + ]
|
| + self.assertEqual(expected_values, self.ActualValues(results))
|
| +
|
| + def testAddResultsWithGarbeCollectionEvents(self):
|
| + # Thread time diagram:
|
| + # 1 2 3 4 5
|
| + # 012345678901234567890123456789012345678901234567890123456789
|
| + # [ x.y ]
|
| + # [ Interaction.Foo/is_fast ]
|
| + # [ Idle ] [Idle] [Idle]
|
| + # [ S ] [S] [ I ] [I] [MC ] [MC]
|
| + renderer_thread_helper = RendererThreadHelper(
|
| + wall_start=1, wall_duration=57, thread_start=1, thread_duration=57)
|
| + renderer_thread_helper.AddInteraction(
|
| + logical_name='Foo',
|
| + wall_start=3, wall_duration=58, thread_start=3, thread_duration=58)
|
| + renderer_thread_helper.AddEvent('v8', 'V8.GCIdleNotification', 3, 7, 3, 7)
|
| + renderer_thread_helper.AddEvent('v8', 'V8.GCIdleNotification', 22, 5, 22, 5)
|
| + renderer_thread_helper.AddEvent('v8', 'V8.GCIdleNotification', 41, 5, 41, 5)
|
| + renderer_thread_helper.AddEvent('v8', 'V8.GCScavenger', 5, 4, 5, 4)
|
| + renderer_thread_helper.AddEvent('v8', 'V8.GCScavenger', 15, 2, 15, 2)
|
| + renderer_thread_helper.AddEvent('v8', 'V8.GCIncrementalMarking', 23, 4, 23,
|
| + 4)
|
| + renderer_thread_helper.AddEvent('v8', 'V8.GCIncrementalMarking', 34, 2, 34,
|
| + 2)
|
| + renderer_thread_helper.AddEvent('v8', 'V8.GCCompactor', 42, 4, 42, 4)
|
| + renderer_thread_helper.AddEvent('v8', 'V8.GCCompactor', 52, 3, 52, 3)
|
| +
|
| + metric = fast_metric.FastMetric()
|
| + results = renderer_thread_helper.MeasureFakePage(metric)
|
| +
|
| + expected_values = [
|
| + ('fast-cpu_time', 'ms', 55), # thread overlap
|
| + ('fast-duration', 'ms', 58), # total interaction wall duration
|
| + ('fast-idle_time', 'ms', 3), # (3 + 58) - (1 + 57); interaction wall
|
| + # time outside of renderer wall time.
|
| + ('fast-incremental_marking', 'ms', 6.0),
|
| + ('fast-incremental_marking_outside_idle', 'ms', 2.0),
|
| + ('fast-mark_compactor', 'ms', 7.0),
|
| + ('fast-mark_compactor_outside_idle', 'ms', 3.0),
|
| + ('fast-scavenger', 'ms', 6.0),
|
| + ('fast-scavenger_outside_idle', 'ms', 2.0),
|
| + ('fast-total_garbage_collection', 'ms', 19.0),
|
| + ('fast-total_garbage_collection_outside_idle', 'ms', 7.0)
|
| + ]
|
| + self.assertEqual(expected_values, self.ActualValues(results))
|
|
|