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

Side by Side Diff: tools/page_cycler/webpagereplay/extension/background.js

Issue 9956045: Add Web Page Replay test to page cycler. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Ready for review. Created 8 years, 8 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 // start.js sends a "start" message to set this.
6 window.benchmarkConfiguration = {};
7
8 // The callback (e.g. report writer) is set via AddBenchmarckCallback.
9 window.benchmarkCallback;
10
11 // Url to load before loading target page.
12 var kWaitUrl = "http://wprwprwpr/web-page-replay-generate-200";
tonyg 2012/04/13 14:32:21 This extension is very closely coupled with WPR. I
slamm_google 2012/04/13 23:43:36 The extension is what couples WPR and the page cyc
tonyg 2012/04/16 15:34:32 OK, fair enough. I'm just sad to see duplication b
slamm_google 2012/04/16 23:43:07 Perhaps it could be made into a generic WPR extens
James Simonsen 2012/04/17 03:30:19 The only thing I really liked about the old one we
tonyg 2012/04/17 11:04:45 Makes sense. I like the idea of porting those scen
13
14 // Constant StatCounter Names
15 var kTcpReadBytes = "tcp.read_bytes";
16 var kTcpWriteBytes = "tcp.write_bytes";
17 var kRequestCount = "HttpNetworkTransaction.Count";
18 var kConnectCount = "tcp.connect";
19
20 function CHECK(expr, comment) {
21 if (!expr) {
22 console.log(comment);
23 alert(comment);
24 }
25 }
26
27 // Return a list of values for an attribute (e.g. [x.attr for x in array]).
28 Array.attrValues = function(array, attr, default_value) {
29 var values = [];
30 for (var i = 0, len = array.length; i < len; i++) {
31 if (attr in array[i]) {
32 values.push(array[i][attr]);
33 } else {
34 values.push(default_value);
35 }
36 }
37 return values;
38 };
39
40 // Returns the sum of all values in the array.
41 Array.sum = function(array) {
42 var sum = 0;
43 for (var i = array.length - 1; i >= 0; i--) {
44 sum += array[i];
45 }
46 return sum;
47 };
48
49 // Map WebTiming properties to Result attribute names.
tonyg 2012/04/13 14:32:21 Why bother with this map. Wouldn't it be more clea
slamm_google 2012/04/13 23:43:36 I copied this from the perftracker code. A better
tonyg 2012/04/16 15:34:32 Yeah, I like the idea of dropping the map. The pe
slamm_google 2012/04/16 23:43:07 The map is gone. The code is much easier to unders
50 window.loggedTimings = {
51 fetchStart: 'start_load_time',
52 domainLookupEnd: 'dns_time',
53 connectEnd: 'connect_time',
54 responseStart: 'first_byte_time',
55 responseEnd: 'last_byte_time',
56 domInteractive: 'doc_load_time',
57 domContentLoadedEventEnd: 'dcl_time',
58 loadEventEnd: 'total_time',
59 };
60
61 function Result() {
62 this.url = "";
63 this.paint_time = 0;
64 this.read_bytes_kb = 0;
65 this.write_bytes_kb = 0;
66 this.num_requests = 0;
67 this.num_connects = 0;
68 this.num_sessions = 0;
69 // The values of window.loggedTimings are also added as attributes.
70 }
71
72 // Collect all the results for a session (i.e. different pages).
73 function ResultsCollection() {
74 var results_ = [];
75 var pages_ = [];
76 var pageResults_ = {};
77
78 this.addResult = function(result) {
79 results_.push(result);
80 var url = result.url;
81 if (!(url in pageResults_)) {
82 pages_.push(url);
83 pageResults_[url] = [];
84 }
85 pageResults_[url].push(result);
86 }
87
88 this.getPages = function() {
89 return pages_;
90 }
91
92 this.getResults = function() {
93 return results_;
94 }
95
96 this.getTotalTimes = function() {
97 var default_time = 0;
98 return Array.attrValues(results_, "total_time", default_time);
99 }
100 }
101
102 // Load a url in the default tab and record the time.
103 function PageLoader(url, resultReadyCallback) {
104 var me_ = this;
105 var url_ = url;
106 var resultReadyCallback_ = resultReadyCallback;
107
108 // If it record mode, wait a little longer for lazy loaded resources.
109 var postLoadGraceMs_ = window.isRecordMode ? 5000 : 0;
110 var loadInterval_ = window.loadInterval;
111 var checkInterval_ = window.checkInterval;
112 var timeout_ = window.timeout;
113 var maxLoadChecks_ = window.maxLoadChecks;
114
115 var preloadFunc_;
116 var timeoutId_;
117 var isFinished_;
118 var result_;
119
120 var initialReadBytes_;
121 var initialWriteBytes_;
122 var initialRequestCount_;
123 var initialConnectCount_;
124
125 this.result = function() { return result_; };
126
127 this.run = function() {
128 timeoutId_ = null;
129 isFinished_ = false;
130 result_ = null;
131 initialReadBytes_ = chrome.benchmarking.counter(kTcpReadBytes);
132 initialWriteBytes_ = chrome.benchmarking.counter(kTcpWriteBytes);
133 initialRequestCount_ = chrome.benchmarking.counter(kRequestCount);
134 initialConnectCount_ = chrome.benchmarking.counter(kConnectCount);
135
136 if (me_.preloadFunc_) {
137 me_.preloadFunc_(me_.load_);
138 } else {
139 me_.load_();
140 }
141 };
142
143 this.setClearAll = function() {
144 me_.preloadFunc_ = me_.clearAll_;
145 };
146
147 this.setClearConnections = function() {
148 me_.preloadFunc_ = me_.clearConnections_;
149 };
150
151 this.clearAll_ = function(callback) {
152 chrome.tabs.getSelected(null, function(tab) {
153 chrome.tabs.update(tab.id, {"url": kWaitUrl});
154 });
155 var isDone = false;
156 chrome.browsingData.remove({}, {
157 "appcache": true,
tonyg 2012/04/13 14:32:21 Is there a way to tell browsingData to remove ever
slamm_google 2012/04/13 23:43:36 I did not see a way. I even left a few things off
tonyg 2012/04/16 15:34:32 If there's no way to do them all, at least do as m
slamm_google 2012/04/16 23:43:07 I added the full list again and they work fine --
158 "cache": true,
159 "cookies": true,
160 "localStorage": true,
161 "pluginData": true,
162 "webSQL": true
163 }, callback);
164 chrome.benchmarking.clearHostResolverCache();
165 chrome.benchmarking.clearPredictorCache();
166 chrome.benchmarking.closeConnections();
167 };
168
169 this.clearConnections_ = function(callback) {
170 chrome.benchmarking.closeConnections();
171 callback();
172 };
173
174 this.load_ = function() {
175 console.log("LOAD started: " + url_);
176 setTimeout(function() {
177 chrome.extension.onRequest.addListener(me_.finishLoad_);
178 timeoutId_ = setTimeout(function() {
179 me_.finishLoad_({"loadTimes": null, "timing": null});
180 }, timeout_);
181 chrome.tabs.getSelected(null, function(tab) {
182 chrome.tabs.update(tab.id, {"url": url_});
183 });
184 }, loadInterval_);
185 };
186
187 this.finishLoad_ = function(msg) {
188 if (!isFinished_) {
189 isFinished_ = true;
190 clearTimeout(timeoutId_);
191 chrome.extension.onRequest.removeListener(me_.finishLoad_);
192 me_.saveResult_(msg.loadTimes, msg.timing);
193 }
194 };
195
196 this.saveResult_ = function(loadTimes, timing) {
197 result_ = new Result()
198 result_.url = url_;
199 if (!loadTimes || !timing) {
200 console.log("LOAD INCOMPLETE: " + url_);
201 } else {
202 console.log("LOAD complete: " + url_);
203 var baseTime = timing.navigationStart;
204 CHECK(baseTime);
205 for (var prop in loggedTimings) {
206 if (prop in timing) {
207 result_[loggedTimings[prop]] = Math.max(0, timing[prop] - baseTime);
208 }
209 }
210 result_.paint_time = Math.max(0,
211 Math.round((1000.0 * loadTimes.firstPaintTime) - baseTime));
212 }
213 result_.read_bytes_kb = (chrome.benchmarking.counter(kTcpReadBytes) -
214 initialReadBytes_) / 1024;
215 result_.write_bytes_kb = (chrome.benchmarking.counter(kTcpWriteBytes) -
216 initialWriteBytes_) / 1024;
217 result_.num_requests = (chrome.benchmarking.counter(kRequestCount) -
218 initialRequestCount_);
219 result_.num_connects = (chrome.benchmarking.counter(kConnectCount) -
220 initialConnectCount_);
221 setTimeout(function() { resultReadyCallback_(me_); }, postLoadGraceMs_);
222 };
223 }
224
225 // Load page sets and prepare performance results.
226 function SessionLoader(resultsReadyCallback) {
227 var me_ = this;
228 var resultsReadyCallback_ = resultsReadyCallback;
229 var pageSets_ = benchmarkConfiguration.pageSets;
230 var iterations_ = window.iterations;
231 var retries_ = window.retries;
232
233 var pageLoaders_ = [];
234 var resultsCollection_ = new ResultsCollection();
235 var loaderIndex_ = 0;
236 var retryIndex_ = 0;
237 var iterationIndex_ = 0;
238
239 this.run = function() {
240 me_.createLoaders_();
241 me_.loadPage_();
242 }
243
244 this.getResultsCollection = function() {
245 return resultsCollection_;
246 }
247
248 this.createLoaders_ = function() {
249 // Each url becomes one benchmark.
250 for (var i = 0; i < pageSets_.length; i++) {
251 for (var j = 0; j < pageSets_[i].length; j++) {
252 // Remove extra space at the beginning or end of a url.
253 var url = pageSets_[i][j].trim();
254 // Alert about and ignore blank page which does not get loaded.
255 if (url == "about:blank") {
256 alert("blank page loaded!");
257 } else if (!url.match(/https?:\/\//)) {
258 // Alert about url that is not in scheme http:// or https://.
259 alert("Skipping url without http:// or https://: " + url);
260 } else {
261 var loader = new PageLoader(url, me_.handleResult_)
262 if (j == 0) {
263 // Clear all browser data for the first page in a sub list.
264 loader.setClearAll();
265 } else {
266 // Otherwise, only clear the connections.
267 loader.setClearConnections();
268 }
269 pageLoaders_.push(loader);
270 }
271 }
272 }
273 }
274
275 this.loadPage_ = function() {
276 console.log("LOAD url " + (loaderIndex_ + 1) + " of " +
277 pageLoaders_.length +
278 ", iteration " + (iterationIndex_ + 1) + " of " +
279 iterations_);
280 pageLoaders_[loaderIndex_].run();
281 }
282
283 this.handleResult_ = function(loader) {
284 var result = loader.result();
285 resultsCollection_.addResult(result);
286 var totalTime = result["total_time"] || 0;
287 if (!totalTime && retryIndex_ < retries_) {
288 retryIndex_++;
289 console.log("LOAD retry, " + retryIndex_);
290 } else {
291 retryIndex_ = 0;
292 console.log("RESULTS url " + (loaderIndex_ + 1) + " of " +
293 pageLoaders_.length +
294 ", iteration " + (iterationIndex_ + 1) + " of " +
295 iterations_ + ": " + result["total_time"]);
296 loaderIndex_++;
297 if (loaderIndex_ >= pageLoaders_.length) {
298 iterationIndex_++;
299 if (iterationIndex_ < iterations_) {
300 loaderIndex_ = 0;
301 } else {
302 resultsReadyCallback_(me_);
303 return;
304 }
305 }
306 }
307 me_.loadPage_();
308 }
309 }
310
311 function AddBenchmarkCallback(callback) {
312 window.benchmarkCallback = callback;
313 }
314
315 function Run() {
316 window.checkInterval = 500;
317 window.loadInterval = 1000;
318 window.timeout = 20000; // max ms before killing page.
319 window.retries = 0;
320 window.isRecordMode = benchmarkConfiguration.isRecordMode;
321 if (window.isRecordMode) {
322 window.iterations = 1;
323 window.timeout = 40000;
324 window.retries = 2;
325 } else {
326 window.iterations = benchmarkConfiguration["iterations"] || 3;
327 }
328 var sessionLoader = new SessionLoader(benchmarkCallback);
329 console.log("pageSets: " + JSON.stringify(benchmarkConfiguration.pageSets));
330 sessionLoader.run();
331 }
332
333 chrome.extension.onConnect.addListener(function(port) {
334 port.onMessage.addListener(function(data) {
335 if (data.message == "start") {
336 window.benchmarkConfiguration = data.benchmark;
337 Run()
338 }
339 });
340 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698