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

Side by Side Diff: tools/perf/perf_tools/scroll.js

Issue 11114020: [chrome-remote-control] Interaction objects separate measurement/test code from page scrolling/drag… (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 2 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
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 // Inject this script on any page to measure framerate as the page is scrolled
6 // from top to bottom.
7 //
8 // Usage:
9 // 1. Define a callback that takes a RenderingStats object as a parameter.
10 // 2. To start the test, call new __ScrollTest(callback).
11 // 3a. When the test is complete, the callback will be called.
12 // 3b. If no callback is specified, the results is sent to the console.
13
14 (function() {
15 var getTimeMs = (function() {
16 if (window.performance)
17 return (performance.now ||
18 performance.mozNow ||
19 performance.msNow ||
20 performance.oNow ||
21 performance.webkitNow).bind(window.performance);
22 else
23 return function() { return new Date().getTime(); };
24 })();
25
26 var requestAnimationFrame = (function() {
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 })().bind(window);
36
37 /**
38 * Scrolls a given element down a certain amount to emulate user scrolling.
39 * Uses smooth scrolling capabilities provided by the platform, if available.
40 * @constructor
41 */
42 function SmoothScrollDownGesture(opt_element) {
43 this.element_ = opt_element || document.body;
44 };
45
46 function min(a, b) {
47 if (a > b) {
48 return b;
49 }
50 return a;
51 };
52
53 function getBoundingVisibleRect(el) {
54 r = el.getBoundingClientRect();
55 cur = el;
56 while (cur && cur.parentElement) {
57 r.top += cur.parentElement.offsetTop;
58 r.left += cur.parentElement.offsetLeft;
59 r.height = min(r.height, cur.parentElement.offsetHeight);
60 r.width = min(r.width, cur.parentElement.offsetWidth);
61 cur = cur.parentElement;
62 }
63 return r;
64 };
65
66 function rectsDoIntersect(r1, r2) {
67 return (r1.right >= r2.left &&
68 r1.left <= r2.right &&
69 r1.bottom >= r2.top &&
70 r1.top <= r2.bottom);
71 };
72
73 SmoothScrollDownGesture.prototype.start = function(callback) {
74 this.callback_ = callback;
75 if (chrome &&
76 chrome.gpuBenchmarking &&
77 chrome.gpuBenchmarking.beginSmoothScrollDown) {
78 rect = getBoundingVisibleRect(this.element_);
79 if (chrome.gpuBenchmarking.beginSmoothScrollSupportsPositioning ||
80 rectsDoIntersect(rect, {left: 0,
81 top: 0,
82 right: 1,
83 bottom: 1,
84 height: 1,
85 width: 1})) {
86 chrome.gpuBenchmarking.beginSmoothScrollDown(true, function() {
87 callback();
88 }, rect.left + rect.width / 2, rect.top + rect.height / 2);
89 return;
90 }
91 }
92
93 var SCROLL_DELTA = 100;
94 this.element_.scrollTop += SCROLL_DELTA;
95 requestAnimationFrame(callback);
96 };
97
98 /**
99 * Tracks rendering performance using the gpuBenchmarking.renderingStats API.
100 * @constructor
101 */
102 function GpuBenchmarkingRenderingStats() {
103 }
104
105 GpuBenchmarkingRenderingStats.prototype.start = function() {
106 this.initialStats_ = this.getRenderingStats_();
107 }
108 GpuBenchmarkingRenderingStats.prototype.stop = function() {
109 this.finalStats_ = this.getRenderingStats_();
110 }
111
112 GpuBenchmarkingRenderingStats.prototype.getDeltas = function() {
113 if (!this.initialStats_)
114 throw new Error('Start not called.');
115
116 if (!this.finalStats_)
117 throw new Error('Stop was not called.');
118
119 var stats = this.finalStats_;
120 for (var key in stats)
121 stats[key] -= this.initialStats_[key];
122 return stats;
123 };
124
125 GpuBenchmarkingRenderingStats.prototype.getRenderingStats_ = function() {
126 var stats = chrome.gpuBenchmarking.renderingStats();
127 stats.totalTimeInSeconds = getTimeMs() / 1000;
128 return stats;
129 };
130
131 /**
132 * Tracks rendering performance using requestAnimationFrame.
133 * @constructor
134 */
135 function RafRenderingStats() {
136 this.recording_ = false;
137 this.frameTimes_ = [];
138 }
139
140 RafRenderingStats.prototype.start = function() {
141 if (this.recording_)
142 throw new Error('Already started.');
143 this.recording_ = true;
144 requestAnimationFrame(this.recordFrameTime_.bind(this));
145 }
146
147 RafRenderingStats.prototype.stop = function() {
148 this.recording_ = false;
149 }
150
151 RafRenderingStats.prototype.getDeltas = function() {
152 var results = {};
153 results.numAnimationFrames = this.frameTimes_.length - 1;
154 results.numFramesSentToScreen = results.numAnimationFrames;
155 results.droppedFrameCount = this.getDroppedFrameCount_(this.frameTimes_);
156 results.totalTimeInSeconds = (
157 this.frameTimes_[this.frameTimes_.length - 1] -
158 this.frameTimes_[0]) / 1000;
159 return results;
160 };
161
162 RafRenderingStats.prototype.recordFrameTime_ = function(timestamp) {
163 if (!this.recording_)
164 return;
165
166 this.frameTimes_.push(timestamp);
167 requestAnimationFrame(this.recordFrameTime_.bind(this));
168 };
169
170 RafRenderingStats.prototype.getDroppedFrameCount_ = function(frameTimes) {
171 var droppedFrameCount = 0;
172 for (var i = 1; i < frameTimes.length; i++) {
173 var frameTime = frameTimes[i] - frameTimes[i-1];
174 if (frameTime > 1000 / 55)
175 droppedFrameCount++;
176 }
177 return droppedFrameCount;
178 };
179
180 // This class scrolls a page from the top to the bottom once.
181 //
182 // The page is scrolled down by a set of scroll gestures. These gestures
183 // correspond to a reading gesture on that platform.
184 //
185 // start -> startPass_ -> ...scrolling... -> onGestureComplete_ ->
186 // -> startPass_ -> .. scrolling... -> onGestureComplete_ -> callback_
187 function ScrollTest(opt_callback) {
188 var self = this;
189
190 this.callback_ = opt_callback;
191 }
192
193 ScrollTest.prototype.start = function(opt_element) {
194 // Assign this.element_ here instead of constructor, because the constructor
195 // ensures this method will be called after the document is loaded.
196 this.element_ = opt_element || document.body;
197 // Some pages load more content when you scroll to the bottom. Record
198 // the original element height here and only scroll to that point.
199 this.scrollHeight_ = this.element_.scrollHeight
200 requestAnimationFrame(this.startPass_.bind(this));
201 };
202
203 ScrollTest.prototype.startPass_ = function() {
204 this.element_.scrollTop = 0;
205 if (window.chrome && chrome.gpuBenchmarking &&
206 chrome.gpuBenchmarking.renderingStats)
207 this.renderingStats_ = new GpuBenchmarkingRenderingStats();
208 else
209 this.renderingStats_ = new RafRenderingStats();
210 this.renderingStats_.start();
211
212 this.gesture_ = new SmoothScrollDownGesture(this.element_);
213 this.gesture_.start(this.onGestureComplete_.bind(this));
214 };
215
216 ScrollTest.prototype.onGestureComplete_ = function(timestamp) {
217 // clientHeight is "special" for the body element.
218 var clientHeight;
219 if (this.element_ == document.body)
220 clientHeight = window.innerHeight;
221 else
222 clientHeight = this.element_.clientHeight;
223
224 // If the scrollHeight went down, only scroll to the new scrollHeight.
225 this.scrollHeight_ = Math.min(this.scrollHeight_,
226 this.element_.scrollHeight);
227
228 // -1 to allow for rounding errors on scaled viewports (like mobile).
229 var isPassComplete =
230 this.element_.scrollTop + clientHeight >= this.scrollHeight_ - 1;
231
232 if (!isPassComplete) {
233 this.gesture_.start(this.onGestureComplete_.bind(this));
234 return;
235 }
236
237 this.endPass_();
238
239 // We're done.
240 if (this.callback_)
241 this.callback_(this.renderingStats_.getDeltas());
242 else
243 console.log(this.renderingStats_.getDeltas());
244 };
245
246 ScrollTest.prototype.endPass_ = function() {
247 this.renderingStats_.stop();
248 };
249
250
251 window.__ScrollTest = ScrollTest;
252 })();
OLDNEW
« no previous file with comments | « tools/chrome_remote_control/chrome_remote_control/scroll_interaction.py ('k') | tools/perf/perf_tools/scrolling_benchmark.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698