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

Side by Side Diff: chrome/test/data/scroll/scroll.js

Issue 10836202: Refactor/rewrite scroll.js, reporting results as renderingStats objects. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Initial commit. Created 8 years, 4 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | chrome/test/functional/perf.py » ('j') | chrome/test/functional/perf.py » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 // Inject this script on any page to measure framerate as the page is scrolled 5 // Inject this script on any page to measure framerate as the page is scrolled
6 // twice from top to bottom. 6 // from top to bottom.
7 // 7 //
8 // USAGE: 8 // USAGE:
9 // 1. To start the scrolling, invoke __scroll_test(). 9 // 1. Define a callback that takes the results array as a parameter.
10 // 2. Wait for __scrolling_complete to be true 10 // 2. To start the test, instantiate a new ScrollTest().
11 // 3. Read __frame_times array. 11 // 3a. When the test is complete, the callback will be called.
12 // 3b. If no callback is specified, the results will be sent in
13 // JSON format through window.domAutomationController.
14 // 3c. If there is no domAC, the results are sent to the console.
12 15
16 window.performance = window.performance || {};
nduca 2012/08/14 00:24:34 Its probably bad that we're mutating the window ob
dtu 2012/08/16 02:31:10 Done.
17 performance.now = (function() {
18 return performance.now ||
19 performance.mozNow ||
20 performance.msNow ||
21 performance.oNow ||
22 performance.webkitNow ||
23 function() { return new Date().getTime(); };
24 })();
13 25
14 // Function that sets a callback called when the next frame is rendered. 26 window.requestAnimationFrame = (function(){
nduca 2012/08/14 00:24:34 same comment about mutating
dtu 2012/08/16 02:31:10 Done.
15 var __set_frame_callback; 27 return window.requestAnimationFrame ||
28 window.webkitRequestAnimationFrame ||
29 window.mozRequestAnimationFrame ||
30 window.oRequestAnimationFrame ||
31 window.msRequestAnimationFrame ||
32 function(callback) {
33 window.setTimeout(callback, 1000 / 60);
34 };
35 })();
16 36
17 // Function that scrolls the page. 37 var __isGmailTest = false;
18 var __scroll_by;
19 38
20 // Element that can be scrolled. Must provide scrollTop property. 39 function BenchmarkingScrollStats() {
nduca 2012/08/14 00:24:34 GpuBenchmarkingScrollStats
dtu 2012/08/16 02:31:10 Done.
21 var __scrollable_element; 40 this.results = [];
22
23 // Amount of scrolling at each frame.
24 var __scroll_delta = 100;
25
26 // Number of scrolls to perform.
27 var __num_scrolls = 2;
28
29 // Current scroll position.
30 var __ypos;
31
32 // Time of previous scroll callback execution.
33 var __start_time = 0;
34
35 // True when all scrolling has completed.
36 var __scrolling_complete = false;
37
38 // Array of frame times for each scroll in __num_scrolls.
39 var __frame_times = [[]];
40
41 // Set this to true when scrolling in Gmail.
42 var __is_gmail_test = false;
43
44
45 // Initializes the platform-independent frame callback scheduler function.
46 function __init_set_frame_callback() {
47 __set_frame_callback = window.requestAnimationFrame ||
48 window.mozRequestAnimationFrame ||
49 window.msRequestAnimationFrame ||
50 window.oRequestAnimationFrame ||
51 window.webkitRequestAnimationFrame;
52 } 41 }
53 42
43 BenchmarkingScrollStats.prototype.getRenderingStats = function() {
nduca 2012/08/14 00:24:34 doesn't seem like it needs to be a member function
dtu 2012/08/16 02:31:10 Is it better in JavaScript to put it outside? RafS
44 var stats = chrome.gpuBenchmarking.renderingStats();
45 stats.totalTimeInSeconds = window.performance.now() / 1000;
nduca 2012/08/14 00:24:34 timestampWhenObtained?
dtu 2012/08/16 02:31:10 As is, it is more consistent with totalPaintTimeIn
46 return stats;
47 };
54 48
55 // Initializes the most realistic scrolling method. 49 BenchmarkingScrollStats.prototype.getStatsDiff = function(old_stats) {
56 function __init_scroll_by() { 50 var stats = this.getRenderingStats();
57 if (__is_gmail_test) { 51 for (var key in stats)
58 __scroll_by = function(x, y) { 52 stats[key] -= old_stats[key];
59 __scrollable_element.scrollByLines(1); 53 return stats;
60 }; 54 };
61 } else if (window.chrome && window.chrome.benchmarking && 55
62 window.chrome.benchmarking.smoothScrollBy) { 56 BenchmarkingScrollStats.prototype.startScroll = function(timestamp) {
63 __scroll_by = window.chrome.benchmarking.smoothScrollBy; 57 this.initialStats = this.getRenderingStats();
58 };
59
60 BenchmarkingScrollStats.prototype.endStep = function(timestamp) {}
61
62 BenchmarkingScrollStats.prototype.endScroll = function() {
63 this.results.push(this.getStatsDiff(this.initialStats));
nduca 2012/08/14 00:24:34 do we need to support more than one results?
dtu 2012/08/16 02:31:10 Done.
64 };
65
66 BenchmarkingScrollStats.prototype.getResults = function() {
67 return this.results;
68 };
69
70 function RAFScrollStats() {
nduca 2012/08/14 00:24:34 this class should set up its own raf loop that rec
dtu 2012/08/16 02:31:10 Done. Huh, hadn't even occurred to me. That makes
71 this.results = [];
72 }
73
74 RAFScrollStats.prototype.getDroppedFrameCount = function(frameTimes) {
75 var droppedFrameCount = 0;
76 for (var i = 1; i < frameTimes.length; i++) {
77 var frameTime = frameTimes[i] - frameTimes[i-1];
78 if (frameTime > 1000 / 55)
79 droppedFrameCount++;
80 }
81 return droppedFrameCount;
82 };
83
84 RAFScrollStats.prototype.startScroll = function(timestamp) {
85 this.frameTimes = [timestamp];
86 };
87
88 RAFScrollStats.prototype.endStep = function(timestamp) {
89 this.frameTimes.push(timestamp);
90 };
91
92 RAFScrollStats.prototype.endScroll = function() {
93 var scrollResult = {};
94 scrollResult.numAnimationFrames = this.frameTimes.length - 1;
95 scrollResult.droppedFrameCount = this.getDroppedFrameCount(this.frameTimes);
96 scrollResult.totalTimeInSeconds =
97 (this.frameTimes[this.frameTimes.length - 1] - this.frameTimes[0]) / 1000;
98 this.results.push(scrollResult);
99 };
100
101 RAFScrollStats.prototype.getResults = function() {
102 return this.results;
103 };
104
105 // In the terminology of this class, a "step" is when the page
106 // is being scrolled. processStep is run between the steps.
107 // i.e. startScroll -> startStep -> scroll -> endStep ->
108 // processStep -> startStep -> scroll -> endStep -> endScroll
109 function ScrollTest(callback) {
110 var self = this;
111
112 this.TOTAL_ITERATIONS = 2;
113 this.SCROLL_DELTA = 100;
114
115 this.callback = callback;
116 this.iteration = 0;
117
118 if (window.chrome && chrome.gpuBenchmarking)
119 this.scrollStats = new BenchmarkingScrollStats();
nduca 2012/08/14 00:24:34 seems like this should be a private var, and just
dtu 2012/08/16 02:31:10 Not sure what you're saying. A getter is not neede
120 else
121 this.scrollStats = new RAFScrollStats;
nduca 2012/08/14 00:24:34 any reason for not ()?
dtu 2012/08/16 02:31:10 Done.
122
123 if (__isGmailTest) {
nduca 2012/08/14 00:24:34 feels like this could be a construction time varia
dtu 2012/08/16 02:31:10 Done.
124 gmonkey.load('2.0', function(api) {
125 self.start(api.getScrollableElement());
126 });
64 } else { 127 } else {
65 __scroll_by = window.scrollBy; 128 if (document.readyState == 'complete')
129 this.start();
130 else
131 window.addEventListener('load', function() { self.start(); });
66 } 132 }
67 } 133 }
68 134
135 ScrollTest.prototype.scroll = function(x, y) {
136 if (__isGmailTest)
137 this.element.scrollByLines(1);
138 else
139 window.scrollBy(x, y);
140 };
69 141
70 // Scrolls page down and reschedules itself until it hits the bottom. 142 ScrollTest.prototype.start = function(element) {
71 // Collects stats along the way. 143 this.element = element || document.body;
72 function __do_scroll(now_time) { 144 window.requestAnimationFrame(this.startScroll.bind(this));
73 __scroll_by(0, __scroll_delta); 145 };
74 __set_frame_callback(function(now_time) {
75 if (__start_time) {
76 if (__scrollable_element.scrollTop > __ypos) {
77 // Scroll in progress, push a frame.
78 __frame_times[__frame_times.length-1].push(now_time - __start_time);
79 } else {
80 // Scroll complete, either scroll again or finish.
81 if (__frame_times.length < __num_scrolls) {
82 __scrollable_element.scrollTop = 0;
83 __frame_times.push([]);
84 } else {
85 console.log('frame_times', '' + __frame_times);
86 __scrolling_complete = true;
87 return;
88 }
89 }
90 }
91 __ypos = __scrollable_element.scrollTop;
92 __start_time = now_time;
93 __do_scroll();
94 });
95 }
96 146
147 ScrollTest.prototype.startScroll = function(timestamp) {
148 this.element.scrollTop = 0;
149 this.scrollStats.startScroll(timestamp);
150 this.startStep();
151 };
97 152
98 function __start_scroll(scrollable_element) { 153 ScrollTest.prototype.startStep = function() {
99 __scrollable_element = scrollable_element; 154 this.scroll(0, this.SCROLL_DELTA);
100 __init_scroll_by(); 155 window.requestAnimationFrame(this.processStep.bind(this));
101 __set_frame_callback(__do_scroll); 156 };
102 }
103 157
158 ScrollTest.prototype.endStep = function(timestamp) {
159 this.scrollStats.endStep(timestamp);
nduca 2012/08/14 00:24:34 remove this
dtu 2012/08/16 02:31:10 Done.
160 };
104 161
105 // Performs the scroll test. 162 ScrollTest.prototype.endScroll = function() {
106 function __scroll_test() { 163 this.scrollStats.endScroll();
107 __init_set_frame_callback(); 164 this.iteration++;
108 if (__is_gmail_test) { 165 };
109 gmonkey.load("2.0", function(api) { 166
110 __start_scroll(api.getScrollableElement()); 167 ScrollTest.prototype.sendResults = function() {
111 }); 168 var results = this.scrollStats.getResults();
112 } else { 169 if (this.callback)
113 if (window.performance.timing.loadEventStart) { 170 this.callback(results);
114 __start_scroll(document.body); // Page already loaded. 171 else if (window.domAutomationController)
nduca 2012/08/14 00:24:34 Does anything still use this send case? I wonder i
dtu 2012/08/16 02:31:10 Done. On the Python side that looks like: __Scroll
115 } else { 172 window.domAutomationController.send(JSON.stringify(results));
116 window.addEventListener('load', function() { 173 else
117 __start_scroll(document.body); // Page hasn't loaded yet, schedule. 174 console.log(results);
118 }); 175 };
119 } 176
177 ScrollTest.prototype.processStep = function(timestamp) {
178 this.endStep(timestamp);
nduca 2012/08/14 00:24:34 seems like we should remove this. RAF loop that dr
dtu 2012/08/16 02:31:10 Done.
179
180 // clientHeight is "special" for the body element.
181 if (this.element == document.body)
182 var clientHeight = window.innerHeight;
183 else
184 var clientHeight = this.element.clientHeight;
185
186 var isScrollComplete =
187 this.element.scrollTop + clientHeight >= this.element.scrollHeight;
188 if (isScrollComplete) {
189 this.endScroll();
190
191 var isTestComplete = this.iteration >= this.TOTAL_ITERATIONS;
192 if (isTestComplete)
193 this.sendResults();
194 else
195 window.requestAnimationFrame(this.startScroll.bind(this));
196
197 return;
120 } 198 }
121 } 199
200 this.startStep();
201 };
OLDNEW
« no previous file with comments | « no previous file | chrome/test/functional/perf.py » ('j') | chrome/test/functional/perf.py » ('J')

Powered by Google App Engine
This is Rietveld 408576698