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.
9 from telemetry
import benchmark
10 from telemetry
.core
import util
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
14 from telemetry
.value
import scalar
16 from measurements
import timeline_controller
17 from metrics
import speedindex
20 class _ServiceWorkerTimelineMetric(object):
21 def AddResultsOfCounters(self
, process
, counter_regex_string
, results
):
22 counter_filter
= re
.compile(counter_regex_string
)
23 for counter_name
, counter
in process
.counters
.iteritems():
24 if not counter_filter
.search(counter_name
):
27 total
= sum(counter
.totals
)
29 # Results objects cannot contain the '.' character, so remove that here.
30 sanitized_counter_name
= counter_name
.replace('.', '_')
32 results
.AddValue(scalar
.ScalarValue(
33 results
.current_page
, sanitized_counter_name
, 'count', total
))
34 results
.AddValue(scalar
.ScalarValue(
35 results
.current_page
, sanitized_counter_name
+ '_avg', 'count',
36 total
/ float(len(counter
.totals
))))
38 def AddResultsOfEvents(
39 self
, process
, thread_regex_string
, event_regex_string
, results
):
40 thread_filter
= re
.compile(thread_regex_string
)
41 event_filter
= re
.compile(event_regex_string
)
43 for thread
in process
.threads
.itervalues():
44 thread_name
= thread
.name
.replace('/', '_')
45 if not thread_filter
.search(thread_name
):
49 for event
in thread
.IterAllEvents():
50 event_name
= event
.name
.replace('.', '_')
51 if event_filter
.search(event_name
):
52 filtered_events
.append(event
)
54 async_events_by_name
= collections
.defaultdict(list)
55 sync_events_by_name
= collections
.defaultdict(list)
56 for event
in filtered_events
:
57 if isinstance(event
, async_slice_module
.AsyncSlice
):
58 async_events_by_name
[event
.name
].append(event
)
59 elif isinstance(event
, slice_module
.Slice
):
60 sync_events_by_name
[event
.name
].append(event
)
62 for event_name
, event_group
in async_events_by_name
.iteritems():
63 times
= [e
.duration
for e
in event_group
]
64 self
._AddResultOfEvent
(thread_name
, event_name
, times
, results
)
66 for event_name
, event_group
in sync_events_by_name
.iteritems():
67 times
= [e
.self_time
for e
in event_group
]
68 self
._AddResultOfEvent
(thread_name
, event_name
, times
, results
)
70 def _AddResultOfEvent(self
, thread_name
, event_name
, times
, results
):
72 biggest_jank
= max(times
)
74 # Results objects cannot contain the '.' character, so remove that here.
75 sanitized_event_name
= event_name
.replace('.', '_')
77 full_name
= thread_name
+ '|' + sanitized_event_name
78 results
.AddValue(scalar
.ScalarValue(
79 results
.current_page
, full_name
, 'ms', total
))
80 results
.AddValue(scalar
.ScalarValue(
81 results
.current_page
, full_name
+ '_max', 'ms', biggest_jank
))
82 results
.AddValue(scalar
.ScalarValue(
83 results
.current_page
, full_name
+ '_avg', 'ms', total
/ len(times
)))
86 class _ServiceWorkerMeasurement(page_test
.PageTest
):
87 """Measure Speed Index and TRACE_EVENTs"""
90 super(_ServiceWorkerMeasurement
, self
).__init
__()
91 self
._timeline
_controller
= timeline_controller
.TimelineController()
92 self
._speed
_index
= speedindex
.SpeedIndexMetric()
93 self
._page
_open
_times
= collections
.defaultdict(int)
95 def CustomizeBrowserOptions(self
, options
):
96 options
.AppendExtraBrowserArgs([
97 '--enable-experimental-web-platform-features'
100 def WillNavigateToPage(self
, page
, tab
):
101 self
._timeline
_controller
.SetUp(page
, tab
)
102 self
._timeline
_controller
.Start(tab
)
103 self
._speed
_index
.Start(page
, tab
)
105 def ValidateAndMeasurePage(self
, page
, tab
, results
):
106 tab
.WaitForDocumentReadyStateToBeComplete(40)
107 self
._timeline
_controller
.Stop(tab
, results
)
109 # Retrieve TRACE_EVENTs
110 timeline_metric
= _ServiceWorkerTimelineMetric()
111 browser_process
= self
._timeline
_controller
.model
.browser_process
112 filter_text
= '(RegisterServiceWorker|'\
113 'UnregisterServiceWorker|'\
115 'FindRegistrationForDocument|'\
116 'DispatchFetchEvent)'
117 timeline_metric
.AddResultsOfEvents(
118 browser_process
, 'IOThread', filter_text
, results
)
121 def SpeedIndexIsFinished():
122 return self
._speed
_index
.IsFinished(tab
)
123 util
.WaitFor(SpeedIndexIsFinished
, 60)
124 self
._speed
_index
.Stop(page
, tab
)
125 # Distinguish the first and second load from the subsequent loads
127 chart_prefix
= 'page_load'
128 self
._page
_open
_times
[url
] += 1
129 if self
._page
_open
_times
[url
] == 1:
130 chart_prefix
+= '_1st'
131 elif self
._page
_open
_times
[url
] == 2:
132 chart_prefix
+= '_2nd'
134 chart_prefix
+= '_later'
135 self
._speed
_index
.AddResults(tab
, results
, chart_prefix
)
138 class _ServiceWorkerMicroBenchmarkMeasurement(page_test
.PageTest
):
139 """Measure JS land values and TRACE_EVENTs"""
142 super(_ServiceWorkerMicroBenchmarkMeasurement
, self
).__init
__()
143 self
._timeline
_controller
= timeline_controller
.TimelineController()
145 def CustomizeBrowserOptions(self
, options
):
146 options
.AppendExtraBrowserArgs([
147 '--enable-experimental-web-platform-features'
150 def WillNavigateToPage(self
, page
, tab
):
151 self
._timeline
_controller
.SetUp(page
, tab
)
152 self
._timeline
_controller
.Start(tab
)
154 def ValidateAndMeasurePage(self
, page
, tab
, results
):
155 tab
.WaitForJavaScriptExpression('window.done', 40)
156 self
._timeline
_controller
.Stop(tab
, results
)
158 # Measure JavaScript-land
159 json
= tab
.EvaluateJavaScript('window.results || {}')
160 for key
, value
in json
.iteritems():
161 results
.AddValue(scalar
.ScalarValue(
162 results
.current_page
, key
, value
['units'], value
['value']))
164 # Retrieve TRACE_EVENTs
165 timeline_metric
= _ServiceWorkerTimelineMetric()
166 browser_process
= self
._timeline
_controller
.model
.browser_process
167 filter_text
= '(RegisterServiceWorker|'\
168 'UnregisterServiceWorker|'\
170 'FindRegistrationForDocument|'\
171 'DispatchFetchEvent)'
172 timeline_metric
.AddResultsOfEvents(
173 browser_process
, 'IOThread', filter_text
, results
)
176 # TODO(simonhatch): Temporarily disabling (http://crbug.com/433943)
178 class ServiceWorkerPerfTest(benchmark
.Benchmark
):
179 """Performance test on public applications using ServiceWorker"""
180 test
= _ServiceWorkerMeasurement
181 page_set
= page_sets
.ServiceWorkerPageSet
185 return 'service_worker.service_worker'
188 # Disabled due to redness on the tree. crbug.com/442752
189 # TODO(horo): Enable after the reference build newer than M39 will be rolled.
190 @benchmark.Disabled('reference')
191 class ServiceWorkerMicroBenchmarkPerfTest(benchmark
.Benchmark
):
192 """This test measures the performance of pages using ServiceWorker.
194 As a page set, two benchamrk pages (many registration, many concurrent
195 fetching) and one application (Trained-to-thrill:
196 https://jakearchibald.github.io/trained-to-thrill/) are included. Execution
197 time of these pages will be shown as Speed Index, and TRACE_EVENTs are
198 subsidiary information to know more detail performance regression.
200 test
= _ServiceWorkerMicroBenchmarkMeasurement
201 page_set
= page_sets
.ServiceWorkerMicroBenchmarkPageSet
204 return 'service_worker.service_worker_micro_benchmark'