Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3)

Side by Side Diff: tools/telemetry/telemetry/web_perf/metrics/smoothness.py

Issue 1313243003: [Telemetry] Introduce SummarizableValue. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 logging 5 import logging
6 6
7 from telemetry.util import perf_tests_helper 7 from telemetry.util import perf_tests_helper
8 from telemetry.util import statistics 8 from telemetry.util import statistics
9 from telemetry.value import improvement_direction
9 from telemetry.value import list_of_scalar_values 10 from telemetry.value import list_of_scalar_values
10 from telemetry.value import scalar 11 from telemetry.value import scalar
11 from telemetry.web_perf.metrics import rendering_stats 12 from telemetry.web_perf.metrics import rendering_stats
12 from telemetry.web_perf.metrics import timeline_based_metric 13 from telemetry.web_perf.metrics import timeline_based_metric
13 14
14 15
15 NOT_ENOUGH_FRAMES_MESSAGE = ( 16 NOT_ENOUGH_FRAMES_MESSAGE = (
16 'Not enough frames for smoothness metrics (at least two are required).\n' 17 'Not enough frames for smoothness metrics (at least two are required).\n'
17 'Issues that have caused this in the past:\n' 18 'Issues that have caused this in the past:\n'
18 '- Browser bugs that prevents the page from redrawing\n' 19 '- Browser bugs that prevents the page from redrawing\n'
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
134 max_frame_delay = round(max(normalized_frame_lengths)) 135 max_frame_delay = round(max(normalized_frame_lengths))
135 frame_lengths = normalized_frame_lengths 136 frame_lengths = normalized_frame_lengths
136 else: 137 else:
137 none_value_reason = NOT_ENOUGH_FRAMES_MESSAGE 138 none_value_reason = NOT_ENOUGH_FRAMES_MESSAGE
138 139
139 return ( 140 return (
140 scalar.ScalarValue( 141 scalar.ScalarValue(
141 page, 'avg_surface_fps', 'fps', avg_surface_fps, 142 page, 'avg_surface_fps', 'fps', avg_surface_fps,
142 description='Average frames per second as measured by the ' 143 description='Average frames per second as measured by the '
143 'platform\'s SurfaceFlinger.', 144 'platform\'s SurfaceFlinger.',
144 none_value_reason=none_value_reason), 145 none_value_reason=none_value_reason,
146 improvement_direction=improvement_direction.UP),
145 scalar.ScalarValue( 147 scalar.ScalarValue(
146 page, 'jank_count', 'janks', jank_count, 148 page, 'jank_count', 'janks', jank_count,
147 description='Number of changes in frame rate as measured by the ' 149 description='Number of changes in frame rate as measured by the '
148 'platform\'s SurfaceFlinger.', 150 'platform\'s SurfaceFlinger.',
149 none_value_reason=none_value_reason), 151 none_value_reason=none_value_reason,
152 improvement_direction=improvement_direction.DOWN),
150 scalar.ScalarValue( 153 scalar.ScalarValue(
151 page, 'max_frame_delay', 'vsyncs', max_frame_delay, 154 page, 'max_frame_delay', 'vsyncs', max_frame_delay,
152 description='Largest frame time as measured by the platform\'s ' 155 description='Largest frame time as measured by the platform\'s '
153 'SurfaceFlinger.', 156 'SurfaceFlinger.',
154 none_value_reason=none_value_reason), 157 none_value_reason=none_value_reason,
158 improvement_direction=improvement_direction.DOWN),
155 list_of_scalar_values.ListOfScalarValues( 159 list_of_scalar_values.ListOfScalarValues(
156 page, 'frame_lengths', 'vsyncs', frame_lengths, 160 page, 'frame_lengths', 'vsyncs', frame_lengths,
157 description='Frame time in vsyncs as measured by the platform\'s ' 161 description='Frame time in vsyncs as measured by the platform\'s '
158 'SurfaceFlinger.', 162 'SurfaceFlinger.',
159 none_value_reason=none_value_reason) 163 none_value_reason=none_value_reason,
164 improvement_direction=improvement_direction.DOWN)
160 ) 165 )
161 166
162 def _ComputeLatencyMetric(self, page, stats, name, list_of_latency_lists): 167 def _ComputeLatencyMetric(self, page, stats, name, list_of_latency_lists):
163 """Returns Values for the mean and discrepancy for given latency stats.""" 168 """Returns Values for the mean and discrepancy for given latency stats."""
164 mean_latency = None 169 mean_latency = None
165 latency_discrepancy = None 170 latency_discrepancy = None
166 none_value_reason = None 171 none_value_reason = None
167 if self._HasEnoughFrames(stats.frame_timestamps): 172 if self._HasEnoughFrames(stats.frame_timestamps):
168 latency_list = perf_tests_helper.FlattenList(list_of_latency_lists) 173 latency_list = perf_tests_helper.FlattenList(list_of_latency_lists)
169 if len(latency_list) == 0: 174 if len(latency_list) == 0:
170 return () 175 return ()
171 mean_latency = round(statistics.ArithmeticMean(latency_list), 3) 176 mean_latency = round(statistics.ArithmeticMean(latency_list), 3)
172 latency_discrepancy = ( 177 latency_discrepancy = (
173 round(statistics.DurationsDiscrepancy(latency_list), 4)) 178 round(statistics.DurationsDiscrepancy(latency_list), 4))
174 else: 179 else:
175 none_value_reason = NOT_ENOUGH_FRAMES_MESSAGE 180 none_value_reason = NOT_ENOUGH_FRAMES_MESSAGE
176 return ( 181 return (
177 scalar.ScalarValue( 182 scalar.ScalarValue(
178 page, 'mean_%s' % name, 'ms', mean_latency, 183 page, 'mean_%s' % name, 'ms', mean_latency,
179 description='Arithmetic mean of the raw %s values' % name, 184 description='Arithmetic mean of the raw %s values' % name,
180 none_value_reason=none_value_reason), 185 none_value_reason=none_value_reason,
186 improvement_direction=improvement_direction.DOWN),
181 scalar.ScalarValue( 187 scalar.ScalarValue(
182 page, '%s_discrepancy' % name, 'ms', latency_discrepancy, 188 page, '%s_discrepancy' % name, 'ms', latency_discrepancy,
183 description='Discrepancy of the raw %s values' % name, 189 description='Discrepancy of the raw %s values' % name,
184 none_value_reason=none_value_reason) 190 none_value_reason=none_value_reason,
191 improvement_direction=improvement_direction.DOWN)
185 ) 192 )
186 193
187 def _ComputeFirstGestureScrollUpdateLatencies(self, page, stats): 194 def _ComputeFirstGestureScrollUpdateLatencies(self, page, stats):
188 """Returns a ListOfScalarValuesValues of gesture scroll update latencies. 195 """Returns a ListOfScalarValuesValues of gesture scroll update latencies.
189 196
190 Returns a Value for the first gesture scroll update latency for each 197 Returns a Value for the first gesture scroll update latency for each
191 interaction record in |stats|. 198 interaction record in |stats|.
192 """ 199 """
193 none_value_reason = None 200 none_value_reason = None
194 first_gesture_scroll_update_latencies = [round(latencies[0], 4) 201 first_gesture_scroll_update_latencies = [round(latencies[0], 4)
195 for latencies in stats.gesture_scroll_update_latency 202 for latencies in stats.gesture_scroll_update_latency
196 if len(latencies)] 203 if len(latencies)]
197 if (not self._HasEnoughFrames(stats.frame_timestamps) or 204 if (not self._HasEnoughFrames(stats.frame_timestamps) or
198 not first_gesture_scroll_update_latencies): 205 not first_gesture_scroll_update_latencies):
199 first_gesture_scroll_update_latencies = None 206 first_gesture_scroll_update_latencies = None
200 none_value_reason = NOT_ENOUGH_FRAMES_MESSAGE 207 none_value_reason = NOT_ENOUGH_FRAMES_MESSAGE
201 return list_of_scalar_values.ListOfScalarValues( 208 return list_of_scalar_values.ListOfScalarValues(
202 page, 'first_gesture_scroll_update_latency', 'ms', 209 page, 'first_gesture_scroll_update_latency', 'ms',
203 first_gesture_scroll_update_latencies, 210 first_gesture_scroll_update_latencies,
204 description='First gesture scroll update latency measures the time it ' 211 description='First gesture scroll update latency measures the time it '
205 'takes to process the very first gesture scroll update ' 212 'takes to process the very first gesture scroll update '
206 'input event. The first scroll gesture can often get ' 213 'input event. The first scroll gesture can often get '
207 'delayed by work related to page loading.', 214 'delayed by work related to page loading.',
208 none_value_reason=none_value_reason) 215 none_value_reason=none_value_reason,
216 improvement_direction=improvement_direction.DOWN)
209 217
210 def _ComputeQueueingDuration(self, page, stats): 218 def _ComputeQueueingDuration(self, page, stats):
211 """Returns a Value for the frame queueing durations.""" 219 """Returns a Value for the frame queueing durations."""
212 queueing_durations = None 220 queueing_durations = None
213 none_value_reason = None 221 none_value_reason = None
214 if 'frame_queueing_durations' in stats.errors: 222 if 'frame_queueing_durations' in stats.errors:
215 none_value_reason = stats.errors['frame_queueing_durations'] 223 none_value_reason = stats.errors['frame_queueing_durations']
216 elif self._HasEnoughFrames(stats.frame_timestamps): 224 elif self._HasEnoughFrames(stats.frame_timestamps):
217 queueing_durations = perf_tests_helper.FlattenList( 225 queueing_durations = perf_tests_helper.FlattenList(
218 stats.frame_queueing_durations) 226 stats.frame_queueing_durations)
219 if len(queueing_durations) == 0: 227 if len(queueing_durations) == 0:
220 queueing_durations = None 228 queueing_durations = None
221 none_value_reason = 'No frame queueing durations recorded.' 229 none_value_reason = 'No frame queueing durations recorded.'
222 else: 230 else:
223 none_value_reason = NOT_ENOUGH_FRAMES_MESSAGE 231 none_value_reason = NOT_ENOUGH_FRAMES_MESSAGE
224 return list_of_scalar_values.ListOfScalarValues( 232 return list_of_scalar_values.ListOfScalarValues(
225 page, 'queueing_durations', 'ms', queueing_durations, 233 page, 'queueing_durations', 'ms', queueing_durations,
226 description='The frame queueing duration quantifies how out of sync ' 234 description='The frame queueing duration quantifies how out of sync '
227 'the compositor and renderer threads are. It is the amount ' 235 'the compositor and renderer threads are. It is the amount '
228 'of wall time that elapses between a ' 236 'of wall time that elapses between a '
229 'ScheduledActionSendBeginMainFrame event in the compositor ' 237 'ScheduledActionSendBeginMainFrame event in the compositor '
230 'thread and the corresponding BeginMainFrame event in the ' 238 'thread and the corresponding BeginMainFrame event in the '
231 'main thread.', 239 'main thread.',
232 none_value_reason=none_value_reason) 240 none_value_reason=none_value_reason,
241 improvement_direction=improvement_direction.DOWN)
233 242
234 def _ComputeFrameTimeMetric(self, page, stats): 243 def _ComputeFrameTimeMetric(self, page, stats):
235 """Returns Values for the frame time metrics. 244 """Returns Values for the frame time metrics.
236 245
237 This includes the raw and mean frame times, as well as the percentage of 246 This includes the raw and mean frame times, as well as the percentage of
238 frames that were hitting 60 fps. 247 frames that were hitting 60 fps.
239 """ 248 """
240 frame_times = None 249 frame_times = None
241 mean_frame_time = None 250 mean_frame_time = None
242 percentage_smooth = None 251 percentage_smooth = None
243 none_value_reason = None 252 none_value_reason = None
244 if self._HasEnoughFrames(stats.frame_timestamps): 253 if self._HasEnoughFrames(stats.frame_timestamps):
245 frame_times = perf_tests_helper.FlattenList(stats.frame_times) 254 frame_times = perf_tests_helper.FlattenList(stats.frame_times)
246 mean_frame_time = round(statistics.ArithmeticMean(frame_times), 3) 255 mean_frame_time = round(statistics.ArithmeticMean(frame_times), 3)
247 # We use 17ms as a somewhat looser threshold, instead of 1000.0/60.0. 256 # We use 17ms as a somewhat looser threshold, instead of 1000.0/60.0.
248 smooth_threshold = 17.0 257 smooth_threshold = 17.0
249 smooth_count = sum(1 for t in frame_times if t < smooth_threshold) 258 smooth_count = sum(1 for t in frame_times if t < smooth_threshold)
250 percentage_smooth = float(smooth_count) / len(frame_times) * 100.0 259 percentage_smooth = float(smooth_count) / len(frame_times) * 100.0
251 else: 260 else:
252 none_value_reason = NOT_ENOUGH_FRAMES_MESSAGE 261 none_value_reason = NOT_ENOUGH_FRAMES_MESSAGE
253 return ( 262 return (
254 list_of_scalar_values.ListOfScalarValues( 263 list_of_scalar_values.ListOfScalarValues(
255 page, 'frame_times', 'ms', frame_times, 264 page, 'frame_times', 'ms', frame_times,
256 description='List of raw frame times, helpful to understand the ' 265 description='List of raw frame times, helpful to understand the '
257 'other metrics.', 266 'other metrics.',
258 none_value_reason=none_value_reason), 267 none_value_reason=none_value_reason,
268 improvement_direction=improvement_direction.DOWN),
259 scalar.ScalarValue( 269 scalar.ScalarValue(
260 page, 'mean_frame_time', 'ms', mean_frame_time, 270 page, 'mean_frame_time', 'ms', mean_frame_time,
261 description='Arithmetic mean of frame times.', 271 description='Arithmetic mean of frame times.',
262 none_value_reason=none_value_reason), 272 none_value_reason=none_value_reason,
273 improvement_direction=improvement_direction.DOWN),
263 scalar.ScalarValue( 274 scalar.ScalarValue(
264 page, 'percentage_smooth', 'score', percentage_smooth, 275 page, 'percentage_smooth', 'score', percentage_smooth,
265 description='Percentage of frames that were hitting 60 fps.', 276 description='Percentage of frames that were hitting 60 fps.',
266 none_value_reason=none_value_reason) 277 none_value_reason=none_value_reason,
278 improvement_direction=improvement_direction.DOWN)
267 ) 279 )
268 280
269 def _ComputeFrameTimeDiscrepancy(self, page, stats): 281 def _ComputeFrameTimeDiscrepancy(self, page, stats):
270 """Returns a Value for the absolute discrepancy of frame time stamps.""" 282 """Returns a Value for the absolute discrepancy of frame time stamps."""
271 283
272 frame_discrepancy = None 284 frame_discrepancy = None
273 none_value_reason = None 285 none_value_reason = None
274 if self._HasEnoughFrames(stats.frame_timestamps): 286 if self._HasEnoughFrames(stats.frame_timestamps):
275 frame_discrepancy = round(statistics.TimestampsDiscrepancy( 287 frame_discrepancy = round(statistics.TimestampsDiscrepancy(
276 stats.frame_timestamps), 4) 288 stats.frame_timestamps), 4)
277 else: 289 else:
278 none_value_reason = NOT_ENOUGH_FRAMES_MESSAGE 290 none_value_reason = NOT_ENOUGH_FRAMES_MESSAGE
279 return scalar.ScalarValue( 291 return scalar.ScalarValue(
280 page, 'frame_time_discrepancy', 'ms', frame_discrepancy, 292 page, 'frame_time_discrepancy', 'ms', frame_discrepancy,
281 description='Absolute discrepancy of frame time stamps, where ' 293 description='Absolute discrepancy of frame time stamps, where '
282 'discrepancy is a measure of irregularity. It quantifies ' 294 'discrepancy is a measure of irregularity. It quantifies '
283 'the worst jank. For a single pause, discrepancy ' 295 'the worst jank. For a single pause, discrepancy '
284 'corresponds to the length of this pause in milliseconds. ' 296 'corresponds to the length of this pause in milliseconds. '
285 'Consecutive pauses increase the discrepancy. This metric ' 297 'Consecutive pauses increase the discrepancy. This metric '
286 'is important because even if the mean and 95th ' 298 'is important because even if the mean and 95th '
287 'percentile are good, one long pause in the middle of an ' 299 'percentile are good, one long pause in the middle of an '
288 'interaction is still bad.', 300 'interaction is still bad.',
289 none_value_reason=none_value_reason) 301 none_value_reason=none_value_reason,
302 improvement_direction=improvement_direction.DOWN)
290 303
291 def _ComputeMeanPixelsApproximated(self, page, stats): 304 def _ComputeMeanPixelsApproximated(self, page, stats):
292 """Add the mean percentage of pixels approximated. 305 """Add the mean percentage of pixels approximated.
293 306
294 This looks at tiles which are missing or of low or non-ideal resolution. 307 This looks at tiles which are missing or of low or non-ideal resolution.
295 """ 308 """
296 mean_pixels_approximated = None 309 mean_pixels_approximated = None
297 none_value_reason = None 310 none_value_reason = None
298 if self._HasEnoughFrames(stats.frame_timestamps): 311 if self._HasEnoughFrames(stats.frame_timestamps):
299 mean_pixels_approximated = round(statistics.ArithmeticMean( 312 mean_pixels_approximated = round(statistics.ArithmeticMean(
300 perf_tests_helper.FlattenList( 313 perf_tests_helper.FlattenList(
301 stats.approximated_pixel_percentages)), 3) 314 stats.approximated_pixel_percentages)), 3)
302 else: 315 else:
303 none_value_reason = NOT_ENOUGH_FRAMES_MESSAGE 316 none_value_reason = NOT_ENOUGH_FRAMES_MESSAGE
304 return scalar.ScalarValue( 317 return scalar.ScalarValue(
305 page, 'mean_pixels_approximated', 'percent', mean_pixels_approximated, 318 page, 'mean_pixels_approximated', 'percent', mean_pixels_approximated,
306 description='Percentage of pixels that were approximated ' 319 description='Percentage of pixels that were approximated '
307 '(checkerboarding, low-resolution tiles, etc.).', 320 '(checkerboarding, low-resolution tiles, etc.).',
308 none_value_reason=none_value_reason) 321 none_value_reason=none_value_reason,
322 improvement_direction=improvement_direction.DOWN)
309 323
310 def _ComputeMeanPixelsCheckerboarded(self, page, stats): 324 def _ComputeMeanPixelsCheckerboarded(self, page, stats):
311 """Add the mean percentage of pixels checkerboarded. 325 """Add the mean percentage of pixels checkerboarded.
312 326
313 This looks at tiles which are only missing. 327 This looks at tiles which are only missing.
314 It does not take into consideration tiles which are of low or 328 It does not take into consideration tiles which are of low or
315 non-ideal resolution. 329 non-ideal resolution.
316 """ 330 """
317 mean_pixels_checkerboarded = None 331 mean_pixels_checkerboarded = None
318 none_value_reason = None 332 none_value_reason = None
319 if self._HasEnoughFrames(stats.frame_timestamps): 333 if self._HasEnoughFrames(stats.frame_timestamps):
320 if rendering_stats.CHECKERBOARDED_PIXEL_ERROR in stats.errors: 334 if rendering_stats.CHECKERBOARDED_PIXEL_ERROR in stats.errors:
321 none_value_reason = stats.errors[ 335 none_value_reason = stats.errors[
322 rendering_stats.CHECKERBOARDED_PIXEL_ERROR] 336 rendering_stats.CHECKERBOARDED_PIXEL_ERROR]
323 else: 337 else:
324 mean_pixels_checkerboarded = round(statistics.ArithmeticMean( 338 mean_pixels_checkerboarded = round(statistics.ArithmeticMean(
325 perf_tests_helper.FlattenList( 339 perf_tests_helper.FlattenList(
326 stats.checkerboarded_pixel_percentages)), 3) 340 stats.checkerboarded_pixel_percentages)), 3)
327 else: 341 else:
328 none_value_reason = NOT_ENOUGH_FRAMES_MESSAGE 342 none_value_reason = NOT_ENOUGH_FRAMES_MESSAGE
329 return scalar.ScalarValue( 343 return scalar.ScalarValue(
330 page, 'mean_pixels_checkerboarded', 'percent', 344 page, 'mean_pixels_checkerboarded', 'percent',
331 mean_pixels_checkerboarded, 345 mean_pixels_checkerboarded,
332 description='Percentage of pixels that were checkerboarded.', 346 description='Percentage of pixels that were checkerboarded.',
333 none_value_reason=none_value_reason) 347 none_value_reason=none_value_reason,
348 improvement_direction=improvement_direction.DOWN)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698