def testTracing(self): devtools_client = self._devtools_client if not devtools_client.IsChromeTracingSupported(): self.skipTest('Browser does not support tracing, skipping test.') # Start Chrome tracing. config = tracing_config.TracingConfig() config.enable_chrome_trace = True devtools_client.StartChromeTracing(config) # Stop Chrome tracing and check that the resulting data is valid. builder = trace_data.TraceDataBuilder() devtools_client.StopChromeTracing() devtools_client.CollectChromeTracingData(builder) model.TimelineModel(builder.AsData())
def testHighlight(self): self.assertEquals(self._tab.url, 'about:blank') self._browser.StartTracing(tracing_backend.DEFAULT_TRACE_CATEGORIES) self._tab.Highlight(bitmap.WEB_PAGE_TEST_ORANGE) self._tab.ClearHighlight(bitmap.WEB_PAGE_TEST_ORANGE) trace_data = self._browser.StopTracing() timeline_model = model.TimelineModel(trace_data) renderer_thread = timeline_model.GetRendererThreadFromTabId( self._tab.id) found_video_start_event = False for event in renderer_thread.async_slices: if event.name == '__ClearHighlight.video_capture_start': found_video_start_event = True break self.assertTrue(found_video_start_event)
def testGetFirstRendererThread_singleTab(self): self.assertEqual(len(self.tabs), 1) # We have a single tab/page. config = tracing_config.TracingConfig() config.chrome_trace_config.SetLowOverheadFilter() config.enable_chrome_trace = True self._browser.platform.tracing_controller.StartTracing(config) self._tab.AddTimelineMarker('single-tab-marker') trace_data, errors = self._browser.platform.tracing_controller.StopTracing() self.assertEqual(errors, []) timeline_model = model.TimelineModel(trace_data) # Check that we can find the marker injected into the trace. renderer_thread = timeline_model.GetFirstRendererThread(self._tab.id) markers = list(renderer_thread.IterTimelineMarkers('single-tab-marker')) self.assertEqual(len(markers), 1)
def testStartAndStopTraceMultipleTimes(self): tracing_controller = self._browser.platform.tracing_controller options = tracing_options.TracingOptions() options.enable_chrome_trace = True tracing_controller.Start( options, tracing_category_filter.TracingCategoryFilter()) self.assertFalse( tracing_controller.Start( options, tracing_category_filter.TracingCategoryFilter())) trace_data = tracing_controller.Stop() # Test that trace data is parsable model_module.TimelineModel(trace_data) self.assertFalse(tracing_controller.is_tracing_running) # Calling stop again will raise exception self.assertRaises(Exception, tracing_controller.Stop)
def testImportSamplesMissingArgs(self): events = [ {'name': 'a', 'pid': 52, 'ts': 548, 'cat': 'test', 'tid': 53, 'ph': 'P'}, {'name': 'b', 'pid': 52, 'ts': 548, 'cat': 'test', 'tid': 53, 'ph': 'P'}, {'name': 'c', 'pid': 52, 'ts': 549, 'cat': 'test', 'tid': 53, 'ph': 'P'} ] trace_data = trace_data_module.CreateFromRawChromeEvents(events) m = timeline_model.TimelineModel(trace_data) p = m.GetAllProcesses()[0] t = p.threads[53] self.assertEqual(3, len(t.samples)) self.assertEqual(0, len(m.import_errors))
def testImportErrornousFlowEvent(self): events = [ {'name': 'a', 'cat': 'foo', 'id': 70, 'pid': 52, 'tid': 53, 'ts': 548, 'ph': 's', 'args': {}}, {'name': 'a2', 'cat': 'foo', 'id': 70, 'pid': 52, 'tid': 53, 'ts': 550, 'ph': 's', 'args': {}}, {'name': 'b', 'cat': 'foo', 'id': 73, 'pid': 52, 'tid': 53, 'ts': 570, 'ph': 'f', 'args': {}}, {'name': 'a', 'cat': 'foo', 'id': 72, 'pid': 52, 'tid': 53, 'ts': 560, 'ph': 't', 'args': {}}, ] trace_data = trace_data_module.CreateFromRawChromeEvents(events) m = timeline_model.TimelineModel(trace_data) self.assertEqual(0, len(m.flow_events))
def testImport(self): messages = [_BACKGROUND_MESSAGE, _SAMPLE_MESSAGE] timeline_data = inspector_timeline_data.InspectorTimelineData(messages) m = model.TimelineModel(timeline_data=timeline_data, shift_world_to_zero=False) self.assertEquals(1, len(m.processes)) process = m.processes.values()[0] threads = process.threads self.assertEquals(2, len(threads)) renderer_thread = threads[0] self.assertEquals(1, len(renderer_thread.toplevel_slices)) self.assertEquals('Program', renderer_thread.toplevel_slices[0].name) second_thread = threads['2'] self.assertEquals(1, len(second_thread.toplevel_slices)) self.assertEquals('BeginFrame', second_thread.toplevel_slices[0].name)
def testImport(self): builder = trace_data.TraceDataBuilder() builder.AddEventsTo(trace_data.INSPECTOR_TRACE_PART, [_BACKGROUND_MESSAGE, _SAMPLE_MESSAGE]) m = model.TimelineModel(builder.AsData(), shift_world_to_zero=False) self.assertEquals(1, len(m.processes)) process = m.processes.values()[0] threads = process.threads self.assertEquals(2, len(threads)) renderer_thread = threads[0] self.assertEquals(1, len(renderer_thread.toplevel_slices)) self.assertEquals('Program', renderer_thread.toplevel_slices[0].name) second_thread = threads['2'] self.assertEquals(1, len(second_thread.toplevel_slices)) self.assertEquals('BeginFrame', second_thread.toplevel_slices[0].name)
def ValidateAndMeasurePage(self, page, tab, results): trace_cpu_time_metrics = {} if tab.EvaluateJavaScript('testRunner.tracingCategories'): trace_data = tab.browser.platform.tracing_controller.StopTracing( )[0] # TODO(#763375): Rely on results.telemetry_info.trace_local_path/etc. kwargs = {} if hasattr(results.telemetry_info, 'trace_local_path'): kwargs['file_path'] = results.telemetry_info.trace_local_path kwargs[ 'remote_path'] = results.telemetry_info.trace_remote_path kwargs['upload_bucket'] = results.telemetry_info.upload_bucket kwargs['cloud_url'] = results.telemetry_info.trace_remote_url trace_value = trace.TraceValue(page, trace_data, **kwargs) results.AddValue(trace_value) trace_events_to_measure = tab.EvaluateJavaScript( 'window.testRunner.traceEventsToMeasure') model = model_module.TimelineModel(trace_data) renderer_thread = model.GetRendererThreadFromTabId(tab.id) trace_cpu_time_metrics = _ComputeTraceEventsThreadTimeForBlinkPerf( model, renderer_thread, trace_events_to_measure) log = tab.EvaluateJavaScript( 'document.getElementById("log").innerHTML') for line in log.splitlines(): if line.startswith("FATAL: "): print line continue if not line.startswith('values '): continue parts = line.split() values = [float(v.replace(',', '')) for v in parts[1:-1]] units = parts[-1] metric = page.name.split('.')[0].replace('/', '_') if values: results.AddValue( list_of_scalar_values.ListOfScalarValues( results.current_page, metric, units, values)) else: raise legacy_page_test.MeasurementFailure('Empty test results') break print log self.PrintAndCollectTraceEventMetrics(trace_cpu_time_metrics, results)
def testDumpMemorySuccess(self): # Check that dumping memory before tracing starts raises an exception. self.assertRaises(Exception, self._browser.DumpMemory) # Start tracing with memory dumps enabled. config = tracing_config.TracingConfig() config.chrome_trace_config.category_filter.AddDisabledByDefault( 'disabled-by-default-memory-infra') config.chrome_trace_config.SetMemoryDumpConfig( chrome_trace_config.MemoryDumpConfig()) config.enable_chrome_trace = True self._tracing_controller.StartTracing(config) # Request several memory dumps in a row and test that they were all # successfully created with unique IDs. expected_dump_ids = [] for _ in xrange(self._REQUESTED_DUMP_COUNT): dump_id = self._browser.DumpMemory() self.assertIsNotNone(dump_id) self.assertNotIn(dump_id, expected_dump_ids) expected_dump_ids.append(dump_id) tracing_data = self._tracing_controller.StopTracing() # Check that clock sync data is in tracing data. clock_sync_found = False trace_handles = tracing_data.GetTracesFor(trace_data.CHROME_TRACE_PART) self.assertEqual(len(trace_handles), 1) with open(trace_handles[0].file_path) as f: trace = json.load(f) for event in trace['traceEvents']: if event['name'] == 'clock_sync' or 'ClockSyncEvent' in event[ 'name']: clock_sync_found = True break self.assertTrue(clock_sync_found) # Check that dumping memory after tracing stopped raises an exception. self.assertRaises(Exception, self._browser.DumpMemory) # Test that trace data is parsable. model = model_module.TimelineModel(tracing_data) self.assertGreater(len(model.processes), 0) # Test that the resulting model contains the requested memory dumps in the # correct order (and nothing more). actual_dump_ids = [d.dump_id for d in model.IterGlobalMemoryDumps()] self.assertEqual(actual_dump_ids, expected_dump_ids)
def testBothDrmAndDisplayStats(self): timeline = model.TimelineModel() timer = MockTimer() vblank_timer = MockVblankTimer() ref_stats = ReferenceRenderingStats() ref_stats.AppendNewRange() gpu = timeline.GetOrCreateProcess(pid=6) gpu.name = 'GPU Process' gpu_drm_thread = gpu.GetOrCreateThread(tid=61) renderer = timeline.GetOrCreateProcess(pid=2) browser = timeline.GetOrCreateProcess(pid=3) browser_main = browser.GetOrCreateThread(tid=31) browser_main.BeginSlice('webkit.console', 'ActionA', timer.AdvanceAndGet(2, 4), '') vblank_timer.TvAdvance(2000, 4000) # Create drm flip stats and display rendering stats. for i in xrange(0, 10): first = (i == 0) AddDrmEventFlipStats(timer, vblank_timer, gpu_drm_thread, first, ref_stats) timer.Advance(2, 4) vblank_timer.TvAdvance(2000, 4000) for i in xrange(0, 10): first = (i == 0) AddDisplayRenderingStats(timer, browser_main, first, None) timer.Advance(5, 10) vblank_timer.TvAdvance(5000, 10000) browser_main.EndSlice(timer.AdvanceAndGet()) timer.Advance(2, 4) vblank_timer.TvAdvance(2000, 4000) browser.FinalizeImport() renderer.FinalizeImport() timeline_markers = timeline.FindTimelineMarkers(['ActionA']) records = [ tir_module.TimelineInteractionRecord(e.name, e.start, e.end) for e in timeline_markers ] stats = rendering_stats.RenderingStats(renderer, browser, gpu, records) # Compare rendering stats to reference - Only drm flip stats should # count self.assertEquals(stats.frame_timestamps, ref_stats.frame_timestamps) self.assertEquals(stats.frame_times, ref_stats.frame_times)
def testBrowserProcess(self): trace = trace_data.CreateFromRawChromeEvents([ { "name": "process_name", "args": {"name": "Browser"}, "pid": 5, "ph": "M" }, { "name": "thread_name", "args": {"name": "CrBrowserMain"}, "pid": 5, "tid": 32578, "ph": "M" }]) model = timeline_model.TimelineModel(trace) self.assertEquals(5, model.browser_process.pid)
def ValidateAndMeasurePage(self, _, tab, results): self._results = results trace_result = tab.browser.platform.tracing_controller.StopTracing()[0] trace_value = trace.TraceValue( results.current_page, trace_result, file_path=results.telemetry_info.trace_local_path, remote_path=results.telemetry_info.trace_remote_path, upload_bucket=results.telemetry_info.upload_bucket, cloud_url=results.telemetry_info.trace_remote_url) results.AddValue(trace_value) model = model_module.TimelineModel(trace_result) renderer_thread = model.GetRendererThreadFromTabId(tab.id) records = _CollectRecordsFromRendererThreads(model, renderer_thread) metric = smoothness.SmoothnessMetric() metric.AddResults(model, renderer_thread, records, results)
def __init__(self, options): self._model = model_module.TimelineModel() renderer_process = self._model.GetOrCreateProcess(1) self._renderer_thread = renderer_process.GetOrCreateThread(2) self._renderer_thread.name = 'CrRendererMain' self._foo_thread = renderer_process.GetOrCreateThread(3) self._foo_thread.name = 'CrFoo' self._results_wrapper = tbm_module._TBMResultWrapper() self._results = page_test_results.PageTestResults() self._results.telemetry_info.benchmark_name = 'benchmark' self._results.telemetry_info.benchmark_start_epoch = 123 self._results.telemetry_info.benchmark_descriptions = 'foo' self._story_set = None self._threads_to_records_map = None self._tbm_options = options
def testImportStringWithMissingCloseSquareBracketAndNewline(self): events = [ {'name': 'a', 'args': {}, 'pid': 52, 'ts': 524, 'cat': 'foo', 'tid': 53, 'ph': 'B'}, {'name': 'a', 'args': {}, 'pid': 52, 'ts': 560, 'cat': 'foo', 'tid': 53, 'ph': 'E'} ] tmp = json.dumps(events) self.assertEqual(']', tmp[-1]) # Drop off the trailing ] and add a newline dropped = tmp[:-1] timeline_data = tracing_timeline_data.TracingTimelineData(dropped + '\n') m = timeline_model.TimelineModel(timeline_data=timeline_data) self.assertEqual(1, len(m.GetAllProcesses()))
def ValidateAndMeasurePage(self, page, tab, results): del page # unused timeline_data = tab.browser.platform.tracing_controller.StopTracing() timeline_model = model.TimelineModel(timeline_data) pt_avg = self.ComputeAverageOfDurations( timeline_model, 'LayerTreeHostCommon::ComputeVisibleRectsWithPropertyTrees') results.AddValue( scalar.ScalarValue( results.current_page, 'PT_avg_cost', 'ms', pt_avg, description='Average time spent processing property trees'))
def StopTimelineRecording(self): builder = trace_data_module.TraceDataBuilder() data = self._timeline.Stop() if data: builder.AddEventsTo(trace_data_module.INSPECTOR_TRACE_PART, data) data = self._network.timeline_recorder.Stop() if data: builder.AddEventsTo(trace_data_module.INSPECTOR_TRACE_PART, data) if builder.HasEventsFor(trace_data_module.INSPECTOR_TRACE_PART): self._timeline_model = timeline_model_module.TimelineModel( builder.AsData(), shift_world_to_zero=False) else: self._timeline_model = None
def testArgumentDupeCreatesNonFailingImportError(self): events = [ {'name': 'a', 'args': {'x': 1}, 'pid': 1, 'ts': 520, 'cat': 'foo', 'tid': 1, 'ph': 'B'}, {'name': 'a', 'args': {'x': 2}, 'pid': 1, 'ts': 560, 'cat': 'foo', 'tid': 1, 'ph': 'E'} ] trace_data = trace_data_module.CreateTraceDataFromRawData(events) m = timeline_model.TimelineModel(trace_data) processes = m.GetAllProcesses() t = processes[0].threads[1] slice_a = FindEventNamed(t.all_slices, 'a') self.assertEqual(2, slice_a.args['x']) self.assertEqual(1, len(m.import_errors))
def testOutOfOrderData(self): builder = trace_data.TraceDataBuilder() builder.AddTraceFor(trace_data.INSPECTOR_TRACE_PART, [{ 'startTime': 5295.004, 'endTime': 5305.004, 'data': {}, 'type': 'Program', 'children': [{ 'startTime': 5295.004, 'data': { 'id': 0 }, 'type': 'BeginFrame', }, { 'startTime': 4492.973, 'endTime': 4493.086, 'data': { 'rootNode': -3 }, 'type': 'PaintSetup' }, { 'startTime': 5298.004, 'endTime': 5301.004, 'type': 'Paint', 'frameId': '53228.1', 'data': { 'rootNode': -3, 'clip': [0, 0, 1018, 0, 1018, 764, 0, 764], 'layerId': 10 }, 'children': [] }, { 'startTime': 5301.004, 'endTime': 5305.004, 'data': {}, 'type': 'CompositeLayers', 'children': [] }, { 'startTime': 5305.004, 'data': {}, 'type': 'MarkFirstPaint' }] }]) model.TimelineModel(builder.AsData(), shift_world_to_zero=False)
def testNoDeviceTraceResults(self): """Test expected results when missing device traces.""" model = model_module.TimelineModel() test_thread = model.GetOrCreateProcess(1).GetOrCreateThread(2) service_slice, _ = _CreateGPUSlices(test_thread, 'test_item', 100, 10) _AddSliceToThread(test_thread, service_slice) model.FinalizeImport() metric = gpu_timeline.GPUTimelineMetric() results = self.GetResults(metric, model=model, renderer_thread=test_thread, interaction_records=INTERACTION_RECORDS) for name, source_type in (('swap', None), ('total', 'cpu')): results.AssertHasPageSpecificScalarValue( gpu_timeline.TimelineName(name, source_type, 'max'), 'ms', 10) results.AssertHasPageSpecificScalarValue( gpu_timeline.TimelineName(name, source_type, 'mean'), 'ms', 10) results.AssertHasPageSpecificScalarValue( gpu_timeline.TimelineName(name, source_type, 'stddev'), 'ms', 0) self.assertRaises(AssertionError, results.GetPageSpecificValueNamed, gpu_timeline.TimelineName('total', 'gpu', 'max')) self.assertRaises(AssertionError, results.GetPageSpecificValueNamed, gpu_timeline.TimelineName('total', 'gpu', 'mean')) self.assertRaises(AssertionError, results.GetPageSpecificValueNamed, gpu_timeline.TimelineName('total', 'gpu', 'stddev')) for name in gpu_timeline.TRACKED_GL_CONTEXT_NAME.values(): results.AssertHasPageSpecificScalarValue( gpu_timeline.TimelineName(name, 'cpu', 'max'), 'ms', 0) results.AssertHasPageSpecificScalarValue( gpu_timeline.TimelineName(name, 'cpu', 'mean'), 'ms', 0) results.AssertHasPageSpecificScalarValue( gpu_timeline.TimelineName(name, 'cpu', 'stddev'), 'ms', 0) self.assertRaises(AssertionError, results.GetPageSpecificValueNamed, gpu_timeline.TimelineName(name, 'gpu', 'max')) self.assertRaises(AssertionError, results.GetPageSpecificValueNamed, gpu_timeline.TimelineName(name, 'gpu', 'mean')) self.assertRaises(AssertionError, results.GetPageSpecificValueNamed, gpu_timeline.TimelineName(name, 'gpu', 'stddev'))
def testInstanceCounter(self): events = [ {'name': 'ctr', 'args': {'value': 0}, 'pid': 1, 'ts': 0, 'cat': 'foo', 'tid': 1, 'ph': 'C', 'id': 0}, {'name': 'ctr', 'args': {'value': 10}, 'pid': 1, 'ts': 10, 'cat': 'foo', 'tid': 1, 'ph': 'C', 'id': 0}, {'name': 'ctr', 'args': {'value': 10}, 'pid': 1, 'ts': 10, 'cat': 'foo', 'tid': 1, 'ph': 'C', 'id': 1}, {'name': 'ctr', 'args': {'value': 20}, 'pid': 1, 'ts': 15, 'cat': 'foo', 'tid': 1, 'ph': 'C', 'id': 1}, {'name': 'ctr', 'args': {'value': 30}, 'pid': 1, 'ts': 18, 'cat': 'foo', 'tid': 1, 'ph': 'C', 'id': 1}, {'name': 'ctr', 'args': {'value': 40}, 'pid': 1, 'ts': 20, 'cat': 'bar', 'tid': 1, 'ph': 'C', 'id': 2} ] trace_data = trace_data_module.CreateTraceDataFromRawData(events) m = timeline_model.TimelineModel(trace_data) p = m.GetAllProcesses()[0] ctr = p.counters['foo.ctr[0]'] self.assertEqual('ctr[0]', ctr.name) self.assertEqual('foo', ctr.category) self.assertEqual(2, ctr.num_samples) self.assertEqual(1, ctr.num_series) self.assertEqual([0, 0.01], ctr.timestamps) self.assertEqual([0, 10], ctr.samples) ctr = m.GetAllProcesses()[0].counters['foo.ctr[1]'] self.assertEqual('ctr[1]', ctr.name) self.assertEqual('foo', ctr.category) self.assertEqual(3, ctr.num_samples) self.assertEqual(1, ctr.num_series) self.assertEqual([0.01, 0.015, 0.018], ctr.timestamps) self.assertEqual([10, 20, 30], ctr.samples) ctr = m.GetAllProcesses()[0].counters['bar.ctr[2]'] self.assertEqual('ctr[2]', ctr.name) self.assertEqual('bar', ctr.category) self.assertEqual(1, ctr.num_samples) self.assertEqual(1, ctr.num_series) self.assertEqual([0.02], ctr.timestamps) self.assertEqual([40], ctr.samples)
def testAutoclosingWithEventsOutsideBounds(self): events = [ # Slice that begins before min and ends after max of the other threads. {'name': 'a', 'args': {}, 'pid': 1, 'ts': 0, 'tts': 0, 'cat': 'foo', 'tid': 1, 'ph': 'B'}, {'name': 'b', 'args': {}, 'pid': 1, 'ts': 6, 'tts': 3, 'cat': 'foo', 'tid': 1, 'ph': 'B'}, # Slice that does finish to give an 'end time' to establish a basis {'name': 'c', 'args': {}, 'pid': 1, 'ts': 2, 'tts': 1, 'cat': 'bar', 'tid': 2, 'ph': 'B'}, {'name': 'c', 'args': {}, 'pid': 1, 'ts': 4, 'tts': 2, 'cat': 'bar', 'tid': 2, 'ph': 'E'} ] trace_data = trace_data_module.CreateTraceDataFromRawData(events) m = timeline_model.TimelineModel(trace_data, shift_world_to_zero=False) p = m.GetAllProcesses()[0] t1 = p.threads[1] t1_thread_time_bounds = ( m._thread_time_bounds[t1]) # pylint: disable=protected-access self.assertAlmostEqual(0.000, t1_thread_time_bounds.min) self.assertAlmostEqual(0.003, t1_thread_time_bounds.max) self.assertEqual(2, len(t1.all_slices)) slice_event = FindEventNamed(t1.all_slices, 'a') self.assertEqual('a', slice_event.name) self.assertEqual('foo', slice_event.category) self.assertAlmostEqual(0, slice_event.start) self.assertAlmostEqual(0.006, slice_event.duration) self.assertAlmostEqual(0, slice_event.thread_start) self.assertAlmostEqual(0.003, slice_event.thread_duration) t2 = p.threads[2] t2_thread_time_bounds = ( m._thread_time_bounds[t2]) # pylint: disable=protected-access self.assertAlmostEqual(0.001, t2_thread_time_bounds.min) self.assertAlmostEqual(0.002, t2_thread_time_bounds.max) slice2 = FindEventNamed(t2.all_slices, 'c') self.assertEqual('c', slice2.name) self.assertEqual('bar', slice2.category) self.assertAlmostEqual(0.002, slice2.start) self.assertAlmostEqual(0.002, slice2.duration) self.assertAlmostEqual(0.001, slice2.thread_start) self.assertAlmostEqual(0.001, slice2.thread_duration) self.assertAlmostEqual(0.000, m.bounds.min) self.assertAlmostEqual(0.006, m.bounds.max)
def testGetRendererThreadFromTabId(self): self.assertEquals(self._tab.url, 'about:blank') # Create 3 tabs. The third tab is closed before we call # tracing_controller.StartTracing. first_tab = self._tab second_tab = self._browser.tabs.New() second_tab.Navigate('about:blank') second_tab.WaitForDocumentReadyStateToBeInteractiveOrBetter() third_tab = self._browser.tabs.New() third_tab.Navigate('about:blank') third_tab.WaitForDocumentReadyStateToBeInteractiveOrBetter() third_tab.Close() config = tracing_config.TracingConfig() config.chrome_trace_config.SetLowOverheadFilter() config.enable_chrome_trace = True self._browser.platform.tracing_controller.StartTracing(config) first_tab.ExecuteJavaScript('console.time("first-tab-marker");') first_tab.ExecuteJavaScript('console.timeEnd("first-tab-marker");') second_tab.ExecuteJavaScript('console.time("second-tab-marker");') second_tab.ExecuteJavaScript('console.timeEnd("second-tab-marker");') trace_data = self._browser.platform.tracing_controller.StopTracing() timeline_model = model.TimelineModel(trace_data) # Assert that the renderer_thread of the first tab contains # 'first-tab-marker'. renderer_thread = timeline_model.GetRendererThreadFromTabId( first_tab.id) first_tab_markers = [ renderer_thread.IterAllSlicesOfName('first-tab-marker') ] self.assertEquals(1, len(first_tab_markers)) # Close second tab and assert that the renderer_thread of the second tab # contains 'second-tab-marker'. second_tab.Close() renderer_thread = timeline_model.GetRendererThreadFromTabId( second_tab.id) second_tab_markers = [ renderer_thread.IterAllSlicesOfName('second-tab-marker') ] self.assertEquals(1, len(second_tab_markers)) # Third tab wasn't available when we start tracing, so there is no # renderer_thread corresponding to it in the the trace. self.assertIs(None, timeline_model.GetRendererThreadFromTabId(third_tab.id))
def ValidateAndMeasurePage(self, _, tab, results): self._results = results tab.browser.platform.tracing_controller.telemetry_info = ( results.telemetry_info) trace_result = tab.browser.platform.tracing_controller.StopTracing() # TODO(charliea): This is part of a three-sided Chromium/Telemetry patch # where we're changing the return type of StopTracing from a TraceValue to a # (TraceValue, nonfatal_exception_list) tuple. Once the tuple return value # lands in Chromium, the non-tuple logic should be deleted. if isinstance(trace_result, tuple): trace_result = trace_result[0] trace_value = trace.TraceValue( results.current_page, trace_result, file_path=results.telemetry_info.trace_local_path, remote_path=results.telemetry_info.trace_remote_path, upload_bucket=results.telemetry_info.upload_bucket, cloud_url=results.telemetry_info.trace_remote_url) results.AddValue(trace_value) model = model_module.TimelineModel(trace_result) renderer_thread = model.GetFirstRendererThread(tab.id) records = _CollectRecordsFromRendererThreads(model, renderer_thread) smoothness_metric = smoothness.SmoothnessMetric() smoothness_metric.AddResults(model, renderer_thread, records, results) thread_times_metric = timeline.ThreadTimesTimelineMetric() thread_times_metric.AddResults(model, renderer_thread, records, results) # TBMv2 metrics. mre_result = metric_runner.RunMetric( trace_value.filename, metrics=['renderingMetric'], extra_import_options={'trackDetailedModelStats': True}, report_progress=False, canonical_url=results.telemetry_info.trace_url) for f in mre_result.failures: results.Fail(f.stack) results.ImportHistogramDicts(mre_result.pairs.get('histograms', []), import_immediately=False)
def testRepr(self): # Create a renderer thread. model = model_module.TimelineModel() renderer_main = model.GetOrCreateProcess(1).GetOrCreateThread(2) model.FinalizeImport() s = async_slice.AsyncSlice( 'cat', 'Interaction.Test/is_smooth', timestamp=0, duration=200, start_thread=renderer_main, end_thread=renderer_main, thread_start=30, thread_duration=30) record = tir_module.TimelineInteractionRecord.FromAsyncEvent(s) expected_repr = ( 'TimelineInteractionRecord(label=\'Test\', ' 'start=0.000000, end=200.000000, flags=is_smooth, ' 'async_event=TimelineEvent(name=\'Interaction.Test/is_smooth\',' ' start=0.000000, duration=200, thread_start=30, thread_duration=30))') self.assertEquals(expected_repr, repr(record))
def testHasDrmStats(self): timeline = model.TimelineModel() timer = MockTimer() vblank_timer = MockVblankTimer() # A process without drm stats process_without_stats = timeline.GetOrCreateProcess(pid=5) thread_without_stats = process_without_stats.GetOrCreateThread(tid=51) process_without_stats.FinalizeImport() self.assertFalse(rendering_stats.HasDrmStats(thread_without_stats)) # A process with drm stats and frames in them process_with_frames = timeline.GetOrCreateProcess(pid=6) thread_with_frames = process_with_frames.GetOrCreateThread(tid=61) AddDrmEventFlipStats(timer, vblank_timer, thread_with_frames, True, None) process_with_frames.FinalizeImport() self.assertTrue(rendering_stats.HasDrmStats(thread_with_frames))
def ValidateAndMeasurePage(self, page, tab, results): timeline_data = tab.browser.platform.tracing_controller.StopTracing( )[0] timeline_model = model.TimelineModel(timeline_data) self._power_metric.Stop(page, tab) self._power_metric.AddResults(tab, results) def _IsDone(): return tab.EvaluateJavaScript('isDone') decode_image_events = timeline_model.GetAllEventsOfName( 'ImageFrameGenerator::decode') # FIXME: Remove this when impl-side painting is on everywhere. if not decode_image_events: decode_image_events = timeline_model.GetAllEventsOfName( 'Decode Image') # If it is a real image page, then store only the last-minIterations # decode tasks. if (hasattr( page, 'image_decoding_measurement_limit_results_to_min_iterations') and page.image_decoding_measurement_limit_results_to_min_iterations ): assert _IsDone() min_iterations = tab.EvaluateJavaScript('minIterations') decode_image_events = decode_image_events[-min_iterations:] durations = [d.duration for d in decode_image_events] assert durations, 'Failed to find image decode trace events.' image_decoding_avg = sum(durations) / len(durations) results.AddValue( scalar.ScalarValue( results.current_page, 'ImageDecoding_avg', 'ms', image_decoding_avg, description='Average decode time for images in 4 different ' 'formats: gif, png, jpg, and webp. The image files are ' 'located at chrome/test/data/image_decoding.')) results.AddValue( scalar.ScalarValue( results.current_page, 'ImageLoading_avg', 'ms', tab.EvaluateJavaScript('averageLoadingTimeMs()')))
def testNoSurfaceFlingerStats(self): timeline = model.TimelineModel() timer = MockTimer() ref_stats = ReferenceRenderingStats() ref_stats.AppendNewRange() surface_flinger = timeline.GetOrCreateProcess(pid=4) surface_flinger.name = 'SurfaceFlinger' renderer = timeline.GetOrCreateProcess(pid=2) browser = timeline.GetOrCreateProcess(pid=3) browser_main = browser.GetOrCreateThread(tid=31) browser_main.BeginSlice('webkit.console', 'ActionA', timer.AdvanceAndGet(2, 4), '') for i in xrange(0, 10): first = (i == 0) AddDisplayRenderingStats(timer, browser_main, first, ref_stats) timer.Advance(5, 10) browser_main.EndSlice(timer.AdvanceAndGet()) timer.Advance(2, 4) browser.FinalizeImport() renderer.FinalizeImport() timeline_markers = timeline.FindTimelineMarkers(['ActionA']) records = [ tir_module.TimelineInteractionRecord(e.name, e.start, e.end) for e in timeline_markers ] metadata = [{ 'name': 'metadata', 'value': { 'surface_flinger': { 'refresh_period': 16.6666 } } }] stats = rendering_stats.RenderingStats(renderer, browser, surface_flinger, None, records, metadata) # Compare rendering stats to reference - we should fallback to Display # Compositor stats, in absence of Surface Flinger stats. self.assertEquals(stats.frame_timestamps, ref_stats.frame_timestamps) self.assertEquals(stats.frame_times, ref_stats.frame_times)
def ValidateAndMeasurePage(self, page, tab, results): timeline_data = tab.browser.platform.tracing_controller.StopTracing() # TODO(charliea): This is part of a three-sided Chromium/Telemetry patch # where we're changing the return type of StopTracing from a TraceValue to a # (TraceValue, nonfatal_exception_list) tuple. Once the tuple return value # lands in Chromium, the non-tuple logic should be deleted. if isinstance(timeline_data, tuple): timeline_data = timeline_data[0] timeline_model = model.TimelineModel(timeline_data) self._power_metric.Stop(page, tab) self._power_metric.AddResults(tab, results) def _IsDone(): return tab.EvaluateJavaScript('isDone') decode_image_events = timeline_model.GetAllEventsOfName( 'ImageFrameGenerator::decode') # FIXME: Remove this when impl-side painting is on everywhere. if not decode_image_events: decode_image_events = timeline_model.GetAllEventsOfName('Decode Image') # If it is a real image page, then store only the last-minIterations # decode tasks. if (hasattr( page, 'image_decoding_measurement_limit_results_to_min_iterations') and page.image_decoding_measurement_limit_results_to_min_iterations): assert _IsDone() min_iterations = tab.EvaluateJavaScript('minIterations') decode_image_events = decode_image_events[-min_iterations:] durations = [d.duration for d in decode_image_events] assert durations, 'Failed to find image decode trace events.' image_decoding_avg = sum(durations) / len(durations) results.AddValue(scalar.ScalarValue( results.current_page, 'ImageDecoding_avg', 'ms', image_decoding_avg, description='Average decode time for images in 4 different ' 'formats: gif, png, jpg, and webp. The image files are ' 'located at chrome/test/data/image_decoding.')) results.AddValue(scalar.ScalarValue( results.current_page, 'ImageLoading_avg', 'ms', tab.EvaluateJavaScript('averageLoadingTimeMs()')))
def testBothSurfaceFlingerAndDisplayStats(self): timeline = model.TimelineModel() timer = MockTimer() ref_stats = ReferenceRenderingStats() ref_stats.AppendNewRange() surface_flinger = timeline.GetOrCreateProcess(pid=4) surface_flinger.name = 'SurfaceFlinger' surface_flinger_thread = surface_flinger.GetOrCreateThread(tid=41) renderer = timeline.GetOrCreateProcess(pid=2) browser = timeline.GetOrCreateProcess(pid=3) browser_main = browser.GetOrCreateThread(tid=31) browser_main.BeginSlice('webkit.console', 'ActionA', timer.AdvanceAndGet(2, 4), '') # Create SurfaceFlinger stats and display rendering stats. for i in xrange(0, 10): first = (i == 0) AddSurfaceFlingerStats(timer, surface_flinger_thread, first, ref_stats) timer.Advance(2, 4) for i in xrange(0, 10): first = (i == 0) AddDisplayRenderingStats(timer, browser_main, first, None) timer.Advance(5, 10) browser_main.EndSlice(timer.AdvanceAndGet()) timer.Advance(2, 4) browser.FinalizeImport() renderer.FinalizeImport() timeline_markers = timeline.FindTimelineMarkers(['ActionA']) timeline_ranges = [ bounds.Bounds.CreateFromEvent(marker) for marker in timeline_markers ] stats = rendering_stats.RenderingStats(renderer, browser, surface_flinger, timeline_ranges) # Compare rendering stats to reference - Only SurfaceFlinger stats should # count self.assertEquals(stats.frame_timestamps, ref_stats.frame_timestamps) self.assertEquals(stats.frame_times, ref_stats.frame_times)