OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 /** | 5 /** |
6 * @fileoverview Perform various "gestures" and calculate average frame rate. | 6 * @fileoverview Perform various "gestures" and calculate average frame rate. |
7 * "Gestures" are recorded scrolling behaviors in terms of time (ms) and | 7 * "Gestures" are recorded scrolling behaviors in terms of time (ms) and |
8 * absolute positions. | 8 * absolute positions. |
9 * | 9 * |
10 * How to run a single gesture: | 10 * How to run a single gesture: |
(...skipping 23 matching lines...) Expand all Loading... |
34 * ], | 34 * ], |
35 */ | 35 */ |
36 | 36 |
37 var __initialized = true; | 37 var __initialized = true; |
38 var __running = false; | 38 var __running = false; |
39 var __running_all = false; | 39 var __running_all = false; |
40 var __old_title = ""; | 40 var __old_title = ""; |
41 var __raf_is_live = false; | 41 var __raf_is_live = false; |
42 var __raf; | 42 var __raf; |
43 | 43 |
| 44 var __t_start; |
44 var __t_last; | 45 var __t_last; |
45 var __t_est; | 46 var __t_est; |
46 var __t_est_total; | 47 var __t_frame_intervals; |
47 var __t_est_squared_total; | |
48 var __t_count; | |
49 var __t_start; | |
50 | 48 |
51 var __queued_gesture_functions; | 49 var __queued_gesture_functions; |
52 var __results; | 50 var __results; |
53 | 51 |
54 var __recording = []; | 52 var __recording = []; |
55 var __advance_gesture; | 53 var __advance_gesture; |
56 | 54 |
57 // This flag indicates whether the test page contains an animation loop | 55 // This flag indicates whether the test page contains an animation loop |
58 // For more on testing animated pages, see head_animation.js | 56 // For more on testing animated pages, see head_animation.js |
59 var __animation = false; | 57 var __animation = false; |
60 | 58 |
61 var __gesture_library = { | 59 var __gesture_library = { |
62 init: [ | 60 init: [ |
63 {"time_ms":1, "y":0}, | 61 {"time_ms":1, "y":0}, |
64 {"time_ms":5, "y":10} | 62 {"time_ms":5, "y":10} |
65 ], | 63 ], |
66 stationary: [ | 64 stationary: [ |
67 {"time_ms":1, "y":0}, | 65 {"time_ms":1, "y":0}, |
68 {"time_ms":5000, "y":0} | 66 {"time_ms":5000, "y":0} |
69 ], | 67 ], |
| 68 steady: [ |
| 69 {"time_ms":1, "y":0}, |
| 70 {"time_ms":500, "y":400} |
| 71 ], |
70 reading: [ | 72 reading: [ |
71 {"time_ms":1, "y":0}, | 73 {"time_ms":1, "y":0}, |
72 {"time_ms":842, "y":40}, | 74 {"time_ms":842, "y":40}, |
73 {"time_ms":858, "y":67}, | 75 {"time_ms":858, "y":67}, |
74 {"time_ms":874, "y":94}, | 76 {"time_ms":874, "y":94}, |
75 {"time_ms":890, "y":149}, | 77 {"time_ms":890, "y":149}, |
76 {"time_ms":907, "y":203}, | 78 {"time_ms":907, "y":203}, |
77 {"time_ms":923, "y":257}, | 79 {"time_ms":923, "y":257}, |
78 {"time_ms":939, "y":311}, | 80 {"time_ms":939, "y":311}, |
79 {"time_ms":955, "y":393}, | 81 {"time_ms":955, "y":393}, |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
173 var new_gesture = JSON.parse(JSON.stringify(gesture)); | 175 var new_gesture = JSON.parse(JSON.stringify(gesture)); |
174 for (var i = 0; i < new_gesture.length; ++i) { | 176 for (var i = 0; i < new_gesture.length; ++i) { |
175 new_gesture[i].time_ms *= stretch_factor; | 177 new_gesture[i].time_ms *= stretch_factor; |
176 } | 178 } |
177 return new_gesture; | 179 return new_gesture; |
178 } | 180 } |
179 | 181 |
180 // Gesture set to use for testing, initialized with default gesture set. | 182 // Gesture set to use for testing, initialized with default gesture set. |
181 // Redefine in test file to use a different set of gestures. | 183 // Redefine in test file to use a different set of gestures. |
182 var __gestures = { | 184 var __gestures = { |
183 none: __gesture_library["stationary"], | 185 steady: __gesture_library["steady"], |
184 steady: __gesture_library["init"], | |
185 reading: __gesture_library["reading"], | |
186 mouse_wheel: __gesture_library["mouse_wheel"], | |
187 mac_fling: __gesture_library["mac_fling"], | |
188 }; | 186 }; |
189 | 187 |
190 function __init_stats() { | 188 function __init_stats() { |
191 __t_last = undefined; | 189 __t_last = undefined; |
192 __t_est = undefined; | 190 __t_est = undefined; |
193 __t_est_total = 0; | 191 __t_frame_intervals = []; |
194 __t_est_squared_total = 0; | |
195 __t_count = 0; | |
196 } | 192 } |
197 __init_stats(); | 193 __init_stats(); |
198 | 194 |
| 195 var __cur_chrome_interval; |
| 196 function __init_time() { |
| 197 if (chrome.Interval) { |
| 198 __cur_chrome_interval = new chrome.Interval(); |
| 199 __cur_chrome_interval.start(); |
| 200 } |
| 201 } |
| 202 __init_time(); |
| 203 |
| 204 function __get_time() { |
| 205 if (__cur_chrome_interval) |
| 206 return __cur_chrome_interval.microseconds() / 1000; |
| 207 return new Date().getTime(); |
| 208 } |
| 209 |
199 function __init_raf() { | 210 function __init_raf() { |
200 if ("requestAnimationFrame" in window) | 211 if ("requestAnimationFrame" in window) |
201 __raf = requestAnimationFrame; | 212 __raf = requestAnimationFrame; |
202 else if ("webkitRequestAnimationFrame" in window) | 213 else if ("webkitRequestAnimationFrame" in window) |
203 __raf = webkitRequestAnimationFrame; | 214 __raf = webkitRequestAnimationFrame; |
204 else if ("mozRequestAnimationFrame" in window) | 215 else if ("mozRequestAnimationFrame" in window) |
205 __raf = mozRequestAnimationFrame; | 216 __raf = mozRequestAnimationFrame; |
206 else if ("oRequestAnimationFrame" in window) | 217 else if ("oRequestAnimationFrame" in window) |
207 __raf = oRequestAnimationFrame; | 218 __raf = oRequestAnimationFrame; |
208 else if ("msRequestAnimationFrame" in window) | 219 else if ("msRequestAnimationFrame" in window) |
209 __raf = msRequestAnimationFrame; | 220 __raf = msRequestAnimationFrame; |
210 else | 221 else |
211 // No raf implementation available, fake it with 16ms timeouts | 222 // No raf implementation available, fake it with 16ms timeouts |
212 __raf = function(callback, element) { | 223 __raf = function(callback, element) { |
213 setTimeout(callback, 16); | 224 setTimeout(callback, 16); |
214 } | 225 }; |
215 } | 226 } |
216 __init_raf(); | 227 __init_raf(); |
217 | 228 |
218 function __calc_results() { | 229 function __calc_results() { |
219 var M = __t_est_total / __t_count; | 230 var M = 0.0; |
220 var X = __t_est_squared_total / __t_count; | 231 var N = __t_frame_intervals.length; |
221 var V = X - M * M; | 232 |
222 var S = Math.sqrt(V); | 233 for (var i = 0; i < N; i++) |
| 234 M += __t_frame_intervals[i]; |
| 235 M = M / N; |
| 236 |
| 237 var V = 0.0; |
| 238 for (var i = 0; i < N; i++) { |
| 239 var v = __t_frame_intervals[i] - M; |
| 240 V += v * v; |
| 241 } |
| 242 |
| 243 var S = Math.sqrt(V / (N - 1)); |
223 | 244 |
224 var R = new Object(); | 245 var R = new Object(); |
225 R.mean = 1000.0 / M; | 246 R.mean = M; |
226 R.sigma = R.mean - 1000.0 / (M + S); | 247 R.sigma = S; |
227 return R; | 248 return R; |
228 } | 249 } |
229 | 250 |
230 function __calc_results_total() { | 251 function __calc_results_total() { |
231 if (!__results) { | 252 if (!__results) { |
232 return; | 253 return {}; |
233 } | 254 } |
234 var size = __results.gestures.length; | 255 var size = __results.gestures.length; |
235 var mean = 0; | 256 var mean = 0; |
236 var variance = 0; | 257 var variance = 0; |
237 var sigma; | |
238 | 258 |
239 // Remove any intial caching test(s). | 259 // Remove any intial caching test(s). |
240 while (__results.means.length != size) { | 260 while (__results.means.length != size) { |
241 __results.means.shift(); | 261 __results.means.shift(); |
242 __results.sigmas.shift(); | 262 __results.sigmas.shift(); |
243 } | 263 } |
244 for (var i = 0; i < size; i++) { | 264 for (var i = 0; i < size; i++) { |
245 mean += __results.means[i]; | 265 mean += __results.means[i]; |
246 variance += __results.sigmas[i] * __results.sigmas[i]; | 266 variance += __results.sigmas[i] * __results.sigmas[i]; |
247 } | 267 } |
248 mean /= size; | 268 mean /= size; |
249 variance /= size; | 269 variance /= size; |
250 sigma = Math.sqrt(variance); | 270 var sigma = Math.sqrt(variance); |
251 | 271 |
252 var results = new Object(); | 272 var results = new Object(); |
253 // GTest expects a comma-separated string for lists. | 273 // GTest expects a comma-separated string for lists. |
254 results.gestures = __results.gestures.join(","); | 274 results.gestures = __results.gestures.join(","); |
255 results.means = __results.means.join(","); | 275 results.means = __results.means.join(","); |
256 results.sigmas = __results.sigmas.join(","); | 276 results.sigmas = __results.sigmas.join(","); |
257 results.mean = mean; | 277 results.mean = mean; |
258 results.sigma = sigma; | 278 results.sigma = sigma; |
259 return results; | 279 return results; |
260 } | 280 } |
261 | 281 |
262 function __update_fps() { | 282 function __record_frame_time() { |
263 var t_now = new Date().getTime(); | 283 var t_now = __get_time(); |
264 if (window.__t_last) { | 284 if (window.__t_last) { |
265 var t_delta = t_now - __t_last; | 285 var t_delta = t_now - __t_last; |
266 if (window.__t_est) { | 286 if (window.__t_est) { |
267 __t_est = (0.1 * __t_est) + (0.9 * t_delta); // low-pass filter | 287 __t_est = (0.1 * __t_est) + (0.9 * t_delta); // low-pass filter |
268 } else { | 288 } else { |
269 __t_est = t_delta; | 289 __t_est = t_delta; |
270 } | 290 } |
| 291 |
| 292 __t_frame_intervals.push(t_delta); |
| 293 |
271 var fps = 1000.0 / __t_est; | 294 var fps = 1000.0 / __t_est; |
272 document.title = "FPS: " + (fps | 0); | 295 document.title = "FPS: " + fps; |
273 | |
274 __t_est_total += t_delta; | |
275 __t_est_squared_total += t_delta * t_delta; | |
276 __t_count++; | |
277 } | 296 } |
278 __t_last = t_now; | 297 __t_last = t_now; |
279 } | 298 } |
280 | 299 |
281 // Returns true if a recorded gesture movement occured. | 300 // Returns true if a recorded gesture movement occured. |
282 function __advance_gesture_recording() { | 301 function __advance_gesture_recording() { |
283 var y = document.body.scrollTop; | 302 var y = document.body.scrollTop; |
284 // Only add a gesture if the scroll position changes. | 303 // Only add a gesture if the scroll position changes. |
285 if (__recording.length == 0 || y != __recording[__recording.length - 1].y) { | 304 if (__recording.length == 0 || y != __recording[__recording.length - 1].y) { |
286 var time_ms = new Date().getTime() - __t_start; | 305 var time_ms = __get_time() - __t_start; |
287 __recording.push({ time_ms: time_ms, y: y }); | 306 __recording.push({ time_ms: time_ms, y: y }); |
288 return true; | 307 return true; |
289 } | 308 } |
290 return false; | 309 return false; |
291 } | 310 } |
292 | 311 |
293 function __scroll_window_to(y) { | 312 function __scroll_window_to(y) { |
294 // Scrolls a window to a new location using window.scrollBy, but avoids | 313 // Scrolls a window to a new location using window.scrollBy, but avoids |
295 // window.scrollTo because of potential animation that may cause. This tracks | 314 // window.scrollTo because of potential animation that may cause. This tracks |
296 // the current scrollTop position to avoid forcing layout. | 315 // the current scrollTop position to avoid forcing layout. |
(...skipping 15 matching lines...) Expand all Loading... |
312 } | 331 } |
313 | 332 |
314 // Returns true if a gesture movement occured. | 333 // Returns true if a gesture movement occured. |
315 function __create_gesture_function(gestures) { | 334 function __create_gesture_function(gestures) { |
316 var i0 = 0; | 335 var i0 = 0; |
317 return function() { | 336 return function() { |
318 if (i0 >= gestures.length) { | 337 if (i0 >= gestures.length) { |
319 __stop(); | 338 __stop(); |
320 return false; | 339 return false; |
321 } | 340 } |
322 var time_cur = new Date().getTime() - __t_start; | 341 var time_cur = __get_time() - __t_start; |
323 if (time_cur <= gestures[i0].time_ms) | 342 if (time_cur <= gestures[i0].time_ms) |
324 return false; | 343 return false; |
325 | 344 |
326 // Skip any keyframes that we missed | 345 // Skip any keyframes that we missed |
327 for (i0; i0 < gestures.length && gestures[i0].time_ms < time_cur; ++i0); | 346 for (i0; i0 < gestures.length && gestures[i0].time_ms < time_cur; ++i0); |
328 | 347 |
329 // This loop overshoots by 1, so move back in time by 1 | 348 // This loop overshoots by 1, so move back in time by 1 |
330 i0--; | 349 i0--; |
331 var i1 = i0 + 1; | 350 var i1 = i0 + 1; |
332 | 351 |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
370 }); | 389 }); |
371 } | 390 } |
372 return __create_gesture_function(gestures); | 391 return __create_gesture_function(gestures); |
373 } | 392 } |
374 | 393 |
375 function __sched_update() { | 394 function __sched_update() { |
376 __raf(function() { | 395 __raf(function() { |
377 __raf_is_live = true; | 396 __raf_is_live = true; |
378 // In case __raf falls back to using setTimeout, we must schedule the next | 397 // In case __raf falls back to using setTimeout, we must schedule the next |
379 // update before rendering the current update to help maintain the | 398 // update before rendering the current update to help maintain the |
380 // regularity of update intervals. | 399 // regularity of update frame_intervals. |
381 __sched_update(); | 400 __sched_update(); |
382 if (__running) { | 401 if (__running) { |
383 // Only update the FPS if a gesture movement occurs. Otherwise, the frame | 402 // Only update the FPS if a gesture movement occurs. Otherwise, the frame |
384 // rate average becomes inaccurate after any pause. | 403 // rate average becomes inaccurate after any pause. |
385 if (__advance_gesture()) | 404 if (__advance_gesture()) |
386 __update_fps(); | 405 __record_frame_time(); |
387 else | 406 else |
388 __t_last = new Date().getTime(); | 407 __t_last = __get_time(); |
389 } | 408 } |
390 }, document.body); | 409 }, document.body); |
391 } | 410 } |
392 | 411 |
393 function __start_recording() { | 412 function __start_recording() { |
394 __start(__advance_gesture_recording); | 413 __start(__advance_gesture_recording); |
395 } | 414 } |
396 | 415 |
397 function __make_body_composited() { | 416 function __make_body_composited() { |
398 document.body.style.webkitTransform = "translateZ(0)"; | 417 document.body.style.webkitTransform = "translateZ(0)"; |
(...skipping 13 matching lines...) Expand all Loading... |
412 } | 431 } |
413 else | 432 else |
414 gesture_function = __create_repeating_gesture_function( | 433 gesture_function = __create_repeating_gesture_function( |
415 __gestures[gesture_function]); | 434 __gestures[gesture_function]); |
416 } | 435 } |
417 else if (typeof gesture_function != "function") | 436 else if (typeof gesture_function != "function") |
418 throw new Error("Argument is not a function or gesture name"); | 437 throw new Error("Argument is not a function or gesture name"); |
419 | 438 |
420 __old_title = document.title; | 439 __old_title = document.title; |
421 __advance_gesture = gesture_function; | 440 __advance_gesture = gesture_function; |
422 __t_start = new Date().getTime(); | 441 __t_start = __get_time(); |
423 __running = true; | 442 __running = true; |
424 if (!__raf_is_live && !__animation) { | 443 if (!__raf_is_live && !__animation) { |
425 __sched_update(); | 444 __sched_update(); |
426 } | 445 } |
427 } | 446 } |
428 | 447 |
429 function __start_all() { | 448 function __start_all() { |
430 __queued_gesture_functions = []; | 449 __queued_gesture_functions = []; |
431 __results = { | 450 __results = { |
432 gestures: [], | 451 gestures: [], |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
467 __running = false; | 486 __running = false; |
468 __running_all = false; | 487 __running_all = false; |
469 document.title = __old_title; | 488 document.title = __old_title; |
470 document.body.scrollTop = 0; | 489 document.body.scrollTop = 0; |
471 __init_stats(); | 490 __init_stats(); |
472 } | 491 } |
473 | 492 |
474 function __force_compositor() { | 493 function __force_compositor() { |
475 document.body.style.webkitTransform = "translateZ(0)"; | 494 document.body.style.webkitTransform = "translateZ(0)"; |
476 } | 495 } |
OLD | NEW |