- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / test / data / perf / frame_rate / head.js
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
3 // found in the LICENSE file.
4
5 /**
6  * @fileoverview  Perform various "gestures" and calculate average frame rate.
7  * "Gestures" are recorded scrolling behaviors in terms of time (ms) and
8  * absolute positions.
9  *
10  * How to run a single gesture:
11  *  1) Open a webpage to test (must include this javascript).
12  *  2) Type "__start('name_of_gesture')" in the javascript console.
13  *  3) Wait for gesture to finish.
14  *  4) Type "__calc_results()" in the console to see the test results.
15  *
16  * How to run all gestures:
17  *  1) Open a webpage to test (must include this javascript).
18  *  2) Type "__start_all()" in the javascript console.
19  *  3) Wait for all gestures to finish.
20  *  4) Type "__calc_results_total()" in the console to see the test results.
21  *
22  * How to record a new gesture:
23  *  1) Open a webpage to record from (must include this javascript).
24  *  2) Type "__start_recording()" in the javascript console.
25  *  3) Perform any gestures you wish to record.
26  *  4) Type "__stop()" in the javascript console.
27  *  5) Copy the output from "JSON.stringify(__recording)" in the console.
28  *  6) Paste the output in this file as a new member of __gestures.
29  *  7) Copy the formatting from other gestures.
30  *    Example:
31  *      new_gesture_name: [
32  *        {"time_ms":1, "y":0},
33  *        ... pasted output ...
34  *      ],
35  */
36
37 var __initialized = true;
38 var __running = false;
39 var __running_all = false;
40 var __old_title = "";
41 var __raf_is_live = false;
42 var __raf;
43
44 var __t_start;
45 var __t_last;
46 var __t_est;
47 var __t_frame_intervals;
48
49 var __queued_gesture_functions;
50 var __results;
51
52 var __recording = [];
53 var __advance_gesture;
54
55 // This flag indicates whether the test page contains an animation loop
56 // For more on testing animated pages, see head_animation.js
57 var __animation = false;
58
59 var __gesture_library = {
60   init: [
61     {"time_ms":1, "y":0},
62     {"time_ms":5, "y":10}
63   ],
64   stationary: [
65     {"time_ms":1, "y":0},
66     {"time_ms":5000, "y":0}
67   ],
68   steady: [
69     {"time_ms":1, "y":0},
70     {"time_ms":500, "y":400}
71   ],
72   reading: [
73     {"time_ms":1, "y":0},
74     {"time_ms":842, "y":40},
75     {"time_ms":858, "y":67},
76     {"time_ms":874, "y":94},
77     {"time_ms":890, "y":149},
78     {"time_ms":907, "y":203},
79     {"time_ms":923, "y":257},
80     {"time_ms":939, "y":311},
81     {"time_ms":955, "y":393},
82     {"time_ms":971, "y":542},
83     {"time_ms":987, "y":718},
84     {"time_ms":1003, "y":949},
85     {"time_ms":1033, "y":1071},
86     {"time_ms":1055, "y":1288},
87     {"time_ms":1074, "y":1790},
88     {"time_ms":1090, "y":1898},
89     {"time_ms":1106, "y":2007},
90     {"time_ms":1122, "y":2129},
91     {"time_ms":1138, "y":2278},
92     {"time_ms":1154, "y":2346},
93     {"time_ms":1170, "y":2373}
94   ],
95   mouse_wheel: [
96     {"time_ms":1, "y":0},
97     {"time_ms":163.99, "y":0},
98     {"time_ms":164, "y":53},
99     {"time_ms":227.99, "y":53},
100     {"time_ms":228, "y":106},
101     {"time_ms":259.99, "y":106},
102     {"time_ms":260, "y":160},
103     {"time_ms":292.99, "y":160},
104     {"time_ms":292, "y":213},
105     {"time_ms":307.99, "y":213},
106     {"time_ms":308, "y":266},
107     {"time_ms":324.99, "y":266},
108     {"time_ms":325, "y":320},
109     {"time_ms":340.99, "y":320},
110     {"time_ms":341, "y":373},
111     {"time_ms":356.99, "y":373},
112     {"time_ms":357, "y":426},
113     {"time_ms":372.99, "y":426},
114     {"time_ms":373, "y":480},
115     {"time_ms":388.99, "y":480},
116     {"time_ms":389, "y":533},
117     {"time_ms":404.99, "y":533},
118     {"time_ms":405, "y":586},
119     {"time_ms":420.99, "y":586},
120     {"time_ms":421, "y":639},
121     {"time_ms":437.99, "y":639}
122   ],
123   mac_fling: [
124     {"time_ms":1, "y":0},
125     {"time_ms":212, "y":1},
126     {"time_ms":228, "y":7},
127     {"time_ms":261, "y":59},
128     {"time_ms":277, "y":81},
129     {"time_ms":293, "y":225},
130     {"time_ms":309, "y":305},
131     {"time_ms":325, "y":377},
132     {"time_ms":342, "y":441},
133     {"time_ms":358, "y":502},
134     {"time_ms":374, "y":559},
135     {"time_ms":391, "y":640},
136     {"time_ms":408, "y":691},
137     {"time_ms":424, "y":739},
138     {"time_ms":441, "y":784},
139     {"time_ms":458, "y":827},
140     {"time_ms":523, "y":926},
141     {"time_ms":540, "y":955},
142     {"time_ms":560, "y":1007},
143     {"time_ms":577, "y":1018},
144     {"time_ms":593, "y":1040},
145     {"time_ms":611, "y":1061},
146     {"time_ms":627, "y":1080},
147     {"time_ms":643, "y":1099},
148     {"time_ms":659, "y":1115},
149     {"time_ms":677, "y":1146},
150     {"time_ms":693, "y":1160},
151     {"time_ms":727, "y":1173},
152     {"time_ms":743, "y":1190},
153     {"time_ms":759, "y":1201},
154     {"time_ms":776, "y":1210},
155     {"time_ms":792, "y":1219},
156     {"time_ms":809, "y":1228},
157     {"time_ms":826, "y":1236},
158     {"time_ms":843, "y":1243},
159     {"time_ms":859, "y":1256},
160     {"time_ms":876, "y":1262},
161     {"time_ms":893, "y":1268},
162     {"time_ms":911, "y":1273},
163     {"time_ms":941, "y":1275},
164     {"time_ms":958, "y":1282},
165     {"time_ms":976, "y":1288},
166     {"time_ms":993, "y":1291},
167     {"time_ms":1022, "y":1294},
168     {"time_ms":1055, "y":1302}
169   ],
170 };
171
172 // Stretch the duration of a gesture by a given factor
173 function __gesture_stretch(gesture, stretch_factor) {
174   // clone the gesture
175   var new_gesture = JSON.parse(JSON.stringify(gesture));
176   for (var i = 0; i < new_gesture.length; ++i) {
177     new_gesture[i].time_ms *= stretch_factor;
178   }
179   return new_gesture;
180 }
181
182 // Gesture set to use for testing, initialized with default gesture set.
183 // Redefine in test file to use a different set of gestures.
184 var __gestures = {
185   steady: __gesture_library["steady"],
186 };
187
188 function __init_stats() {
189   __t_last = undefined;
190   __t_est = undefined;
191   __t_frame_intervals = [];
192 }
193 __init_stats();
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
210 function __init_raf() {
211   if ("requestAnimationFrame" in window)
212     __raf = requestAnimationFrame;
213   else if ("webkitRequestAnimationFrame" in window)
214     __raf = webkitRequestAnimationFrame;
215   else if ("mozRequestAnimationFrame" in window)
216     __raf = mozRequestAnimationFrame;
217   else if ("oRequestAnimationFrame" in window)
218     __raf = oRequestAnimationFrame;
219   else if ("msRequestAnimationFrame" in window)
220     __raf = msRequestAnimationFrame;
221   else
222     // No raf implementation available, fake it with 16ms timeouts
223     __raf = function(callback, element) {
224       setTimeout(callback, 16);
225     };
226 }
227 __init_raf();
228
229 function __calc_results() {
230   var M = 0.0;
231   var N = __t_frame_intervals.length;
232
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));
244
245   var R = new Object();
246   R.mean = M;
247   R.sigma = S;
248   return R;
249 }
250
251 function __calc_results_total() {
252   if (!__results) {
253     return {};
254   }
255   var size = __results.gestures.length;
256   var mean = 0;
257   var variance = 0;
258
259   // Remove any intial caching test(s).
260   while (__results.means.length != size) {
261     __results.means.shift();
262     __results.sigmas.shift();
263   }
264   for (var i = 0; i < size; i++) {
265     mean += __results.means[i];
266     variance += __results.sigmas[i] * __results.sigmas[i];
267   }
268   mean /= size;
269   variance /= size;
270   var sigma = Math.sqrt(variance);
271
272   var results = new Object();
273   // GTest expects a comma-separated string for lists.
274   results.gestures = __results.gestures.join(",");
275   results.means = __results.means.join(",");
276   results.sigmas = __results.sigmas.join(",");
277   results.mean = mean;
278   results.sigma = sigma;
279   return results;
280 }
281
282 function __record_frame_time() {
283   var t_now = __get_time();
284   if (window.__t_last) {
285     var t_delta = t_now - __t_last;
286     if (window.__t_est) {
287       __t_est = (0.1 * __t_est) + (0.9 * t_delta);  // low-pass filter
288     } else {
289       __t_est = t_delta;
290     }
291
292     __t_frame_intervals.push(t_delta);
293
294     var fps = 1000.0 / __t_est;
295     document.title = "FPS: " + fps;
296   }
297   __t_last = t_now;
298 }
299
300 // Returns true if a recorded gesture movement occured.
301 function __advance_gesture_recording() {
302   var y = document.body.scrollTop;
303   // Only add a gesture if the scroll position changes.
304   if (__recording.length == 0 || y != __recording[__recording.length - 1].y) {
305     var time_ms = __get_time() - __t_start;
306     __recording.push({ time_ms: time_ms, y: y });
307     return true;
308   }
309   return false;
310 }
311
312 function __scroll_window_to(y) {
313   // Scrolls a window to a new location using window.scrollBy, but avoids
314   // window.scrollTo because of potential animation that may cause. This tracks
315   // the current scrollTop position to avoid forcing layout.
316   //
317   // Returns true if the window actually scrolled.
318   var yfloor = Math.floor(y);
319   if (window.__scrolledTo === undefined) {
320     window.scrollBy(0, yfloor);
321     window.__scrolledTo = yfloor;
322     return true;
323   }
324
325   var delta = yfloor - window.__scrolledTo;
326   if (delta == 0)
327     return false;
328   window.scrollBy(0, delta);
329   window.__scrolledTo = yfloor;
330   return true;
331 }
332
333 // Returns true if a gesture movement occured.
334 function __create_gesture_function(gestures) {
335   var i0 = 0;
336   return function() {
337     if (i0 >= gestures.length) {
338       __stop();
339       return false;
340     }
341     var time_cur = __get_time() - __t_start;
342     if (time_cur <= gestures[i0].time_ms)
343       return false;
344
345     // Skip any keyframes that we missed
346     for (i0; i0 < gestures.length && gestures[i0].time_ms < time_cur; ++i0);
347
348     // This loop overshoots by 1, so move back in time by 1
349     i0--;
350     var i1 = i0 + 1;
351
352     if (i1 < gestures.length) {
353       // If i1 exists, interpolate between i0 and i1 y based on time_cur -
354       // gestures[i0].time_ms
355       var time_since_i0_start = time_cur - gestures[i0].time_ms;
356       var time_between_i0_and_i1 = gestures[i1].time_ms -
357           gestures[i0].time_ms;
358       var percent_into_frame = time_since_i0_start / time_between_i0_and_i1;
359       var y_diff_between_i0_and_i1 = gestures[i1].y - gestures[i0].y;
360       var interpolated_y = gestures[i0].y +
361           (percent_into_frame * y_diff_between_i0_and_i1);
362
363       // Skip all gestures that occured within the same time interval.
364       return __scroll_window_to(interpolated_y);
365     } else {
366       // Only generate a frame if we are at the end of the animation.
367       __stop();
368       return false;
369     }
370   };
371 }
372
373 function __create_repeating_gesture_function(gestures) {
374   var dtime_ms = gestures[gestures.length - 1].time_ms;
375   var dy = gestures[gestures.length - 1].y;
376
377   // Do not repeat gestures that do not change the Y position.
378   if (dy == 0)
379     return __create_gesture_function(gestures);
380
381   // Repeat gestures until a scroll goes out of bounds.
382   // Note: modifies a copy of the given gestures array.
383   gestures = gestures.slice(0);
384   for (var i = 0, y = 0; y >= 0 && y < document.body.scrollHeight; ++i) {
385     y = gestures[i].y + dy;
386     gestures.push({
387       time_ms: gestures[i].time_ms + dtime_ms,
388       y: y,
389     });
390   }
391   return __create_gesture_function(gestures);
392 }
393
394 function __sched_update() {
395   __raf(function() {
396     __raf_is_live = true;
397     // In case __raf falls back to using setTimeout, we must schedule the next
398     // update before rendering the current update to help maintain the
399     // regularity of update frame_intervals.
400     __sched_update();
401     if (__running) {
402       // Only update the FPS if a gesture movement occurs. Otherwise, the frame
403       // rate average becomes inaccurate after any pause.
404       if (__advance_gesture())
405         __record_frame_time();
406       else
407         __t_last = __get_time();
408     }
409   }, document.body);
410 }
411
412 function __start_recording() {
413   __start(__advance_gesture_recording);
414 }
415
416 function __make_body_composited() {
417   document.body.style.webkitTransform = "translateZ(0)";
418 }
419
420 function __start(gesture_function) {
421   if (__running)
422     return;
423   // Attempt to create a gesture function from a string name.
424   if (typeof gesture_function == "string") {
425     if (!__gestures[gesture_function]) {
426       if (!__gesture_library[gesture_function])
427         throw new Error("Unrecognized gesture name");
428       else
429         gesture_function = __create_repeating_gesture_function(
430                             __gesture_library[gesture_function]);
431     }
432     else
433       gesture_function = __create_repeating_gesture_function(
434                             __gestures[gesture_function]);
435   }
436   else if (typeof gesture_function != "function")
437     throw new Error("Argument is not a function or gesture name");
438
439   __old_title = document.title;
440   __advance_gesture = gesture_function;
441   __t_start = __get_time();
442   __running = true;
443   if (!__raf_is_live && !__animation) {
444     __sched_update();
445   }
446 }
447
448 function __start_all() {
449   __queued_gesture_functions = [];
450   __results = {
451     gestures: [],
452     means: [],
453     sigmas: [],
454   };
455
456   for (var gesture in __gestures) {
457     __results.gestures.push(gesture);
458     __queued_gesture_functions.push(gesture);
459   }
460   __running_all = true;
461   // Run init gesture once to cache the webpage layout for subsequent tests.
462   __start("init");
463 }
464
465 function __stop() {
466   __running = false;
467   document.title = __old_title;
468   window.__scrolledTo = undefined;
469
470   if (__running_all) {
471     var results = __calc_results();
472     __results.means.push(results.mean);
473     __results.sigmas.push(results.sigma);
474
475     if (__queued_gesture_functions.length > 0) {
476       document.body.scrollTop = 0;
477       __init_stats();
478       __start(__queued_gesture_functions.shift());
479     } else {
480       __running_all = false;
481     }
482   }
483 }
484
485 function __reset() {
486   __running = false;
487   __running_all = false;
488   document.title = __old_title;
489   document.body.scrollTop = 0;
490   __init_stats();
491 }
492
493 function __force_compositor() {
494   document.body.style.webkitTransform = "translateZ(0)";
495 }