OLD | NEW |
1 # Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
| 5 import collections |
5 import page_sets | 6 import page_sets |
| 7 import re |
| 8 |
| 9 from measurements import timeline_controller |
6 from telemetry import benchmark | 10 from telemetry import benchmark |
7 from telemetry.page import page_test | 11 from telemetry.page import page_test |
| 12 from telemetry.timeline import async_slice as async_slice_module |
| 13 from telemetry.timeline import slice as slice_module |
8 from telemetry.value import scalar | 14 from telemetry.value import scalar |
9 | 15 |
| 16 class _ServiceWorkerTimelineMetric(object): |
| 17 def AddResultsOfCounters(self, process, counter_regex_string, results): |
| 18 counter_filter = re.compile(counter_regex_string) |
| 19 for counter_name, counter in process.counters.iteritems(): |
| 20 if not counter_filter.search(counter_name): |
| 21 continue |
| 22 |
| 23 total = sum(counter.totals) |
| 24 |
| 25 # Results objects cannot contain the '.' character, so remove that here. |
| 26 sanitized_counter_name = counter_name.replace('.', '_') |
| 27 |
| 28 results.AddValue(scalar.ScalarValue( |
| 29 results.current_page, sanitized_counter_name, 'count', total)) |
| 30 results.AddValue(scalar.ScalarValue( |
| 31 results.current_page, sanitized_counter_name + '_avg', 'count', |
| 32 total / float(len(counter.totals)))) |
| 33 |
| 34 def AddResultsOfEvents( |
| 35 self, process, thread_regex_string, event_regex_string, results): |
| 36 thread_filter = re.compile(thread_regex_string) |
| 37 event_filter = re.compile(event_regex_string) |
| 38 |
| 39 for thread in process.threads.itervalues(): |
| 40 thread_name = thread.name.replace('/', '_') |
| 41 if not thread_filter.search(thread_name): |
| 42 continue |
| 43 |
| 44 filtered_events = [] |
| 45 for event in thread.IterAllEvents(): |
| 46 event_name = event.name.replace('.', '_') |
| 47 if event_filter.search(event_name): |
| 48 filtered_events.append(event) |
| 49 |
| 50 async_events_by_name = collections.defaultdict(list) |
| 51 sync_events_by_name = collections.defaultdict(list) |
| 52 for event in filtered_events: |
| 53 if isinstance(event, async_slice_module.AsyncSlice): |
| 54 async_events_by_name[event.name].append(event) |
| 55 elif isinstance(event, slice_module.Slice): |
| 56 sync_events_by_name[event.name].append(event) |
| 57 |
| 58 for event_name, event_group in async_events_by_name.iteritems(): |
| 59 times = [e.duration for e in event_group] |
| 60 self._AddResultOfEvent(thread_name, event_name, times, results) |
| 61 |
| 62 for event_name, event_group in sync_events_by_name.iteritems(): |
| 63 times = [e.self_time for e in event_group] |
| 64 self._AddResultOfEvent(thread_name, event_name, times, results) |
| 65 |
| 66 def _AddResultOfEvent(self, thread_name, event_name, times, results): |
| 67 total = sum(times) |
| 68 biggest_jank = max(times) |
| 69 |
| 70 # Results objects cannot contain the '.' character, so remove that here. |
| 71 sanitized_event_name = event_name.replace('.', '_') |
| 72 |
| 73 full_name = thread_name + '|' + sanitized_event_name |
| 74 results.AddValue(scalar.ScalarValue( |
| 75 results.current_page, full_name, 'ms', total)) |
| 76 results.AddValue(scalar.ScalarValue( |
| 77 results.current_page, full_name + '_max', 'ms', biggest_jank)) |
| 78 results.AddValue(scalar.ScalarValue( |
| 79 results.current_page, full_name + '_avg', 'ms', total / len(times))) |
10 | 80 |
11 class _ServiceWorkerMeasurement(page_test.PageTest): | 81 class _ServiceWorkerMeasurement(page_test.PageTest): |
| 82 def __init__(self, *args, **kwargs): |
| 83 super(_ServiceWorkerMeasurement, self).__init__(*args, **kwargs) |
| 84 self._timeline_controller = timeline_controller.TimelineController() |
| 85 |
12 def CustomizeBrowserOptions(self, options): | 86 def CustomizeBrowserOptions(self, options): |
13 options.AppendExtraBrowserArgs([ | 87 options.AppendExtraBrowserArgs([ |
14 '--enable-experimental-web-platform-features' | 88 '--enable-experimental-web-platform-features' |
15 ]) | 89 ]) |
16 | 90 |
| 91 def WillNavigateToPage(self, page, tab): |
| 92 self._timeline_controller.SetUp(page, tab) |
| 93 self._timeline_controller.Start(tab) |
| 94 |
17 def ValidateAndMeasurePage(self, _, tab, results): | 95 def ValidateAndMeasurePage(self, _, tab, results): |
18 tab.WaitForJavaScriptExpression('window.done', 40) | 96 tab.WaitForJavaScriptExpression('window.done', 40) |
| 97 self._timeline_controller.Stop(tab) |
| 98 |
| 99 # Measure JavaScript-land |
19 json = tab.EvaluateJavaScript('window.results') | 100 json = tab.EvaluateJavaScript('window.results') |
20 for key, value in json.iteritems(): | 101 for key, value in json.iteritems(): |
21 results.AddValue(scalar.ScalarValue( | 102 results.AddValue(scalar.ScalarValue( |
22 results.current_page, key, value['units'], value['value'])) | 103 results.current_page, key, value['units'], value['value'])) |
23 | 104 |
| 105 # Retrieve TRACE_EVENTs |
| 106 timeline_metric = _ServiceWorkerTimelineMetric() |
| 107 browser_process = self._timeline_controller.model.browser_process |
| 108 filter_text = '(RegisterServiceWorker|'\ |
| 109 'UnregisterServiceWorker|'\ |
| 110 'ProcessAllocate|'\ |
| 111 'FindRegistrationForDocument|'\ |
| 112 'PrepareForMainResource|'\ |
| 113 'DispatchFetchEvent)' |
| 114 timeline_metric.AddResultsOfEvents( |
| 115 browser_process, 'IOThread', filter_text , results) |
24 | 116 |
25 @benchmark.Disabled | 117 @benchmark.Disabled |
26 class ServiceWorkerPerfTest(benchmark.Benchmark): | 118 class ServiceWorkerPerfTest(benchmark.Benchmark): |
27 test = _ServiceWorkerMeasurement | 119 test = _ServiceWorkerMeasurement |
28 page_set = page_sets.ServiceWorkerPageSet | 120 page_set = page_sets.ServiceWorkerPageSet |
OLD | NEW |