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.
5 // start.js sends a "start" message to set this.
6 window.benchmarkConfiguration = {};
8 // The callback (e.g. report writer) is set via AddBenchmarckCallback.
9 window.benchmarkCallback;
11 // Url to load before loading target page.
12 var kWaitUrl = "http://wprwprwpr/web-page-replay-generate-200";
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";
20 function CHECK(expr, comment) {
30 this.firstPaintTime = 0;
32 this.writeBytesKB = 0;
35 this.timing = {}; // window.performance.timing
36 this.getTotalTime = function() {
38 if (me_.timing.navigationStart && me_.timing.loadEventEnd) {
39 totalTime = me_.timing.loadEventEnd - me_.timing.navigationStart;
41 CHECK(totalTime >= 0);
46 // Collect all the results for a session (i.e. different pages).
47 function ResultsCollection() {
50 var pageResults_ = {};
52 this.addResult = function(result) {
53 results_.push(result);
55 if (!(url in pageResults_)) {
57 pageResults_[url] = [];
59 pageResults_[url].push(result);
62 this.getPages = function() {
66 this.getResults = function() {
70 this.getTotalTimes = function() {
71 return results_.map(function (t) { return t.getTotalTime(); });
75 // Load a url in the default tab and record the time.
76 function PageLoader(url, resultReadyCallback) {
79 var resultReadyCallback_ = resultReadyCallback;
81 // If it record mode, wait a little longer for lazy loaded resources.
82 var postLoadGraceMs_ = window.isRecordMode ? 5000 : 0;
83 var loadInterval_ = window.loadInterval;
84 var checkInterval_ = window.checkInterval;
85 var timeout_ = window.timeout;
86 var maxLoadChecks_ = window.maxLoadChecks;
93 var initialReadBytes_;
94 var initialWriteBytes_;
95 var initialRequestCount_;
96 var initialConnectCount_;
98 this.result = function() { return result_; };
100 this.run = function() {
104 initialReadBytes_ = chrome.benchmarking.counter(kTcpReadBytes);
105 initialWriteBytes_ = chrome.benchmarking.counter(kTcpWriteBytes);
106 initialRequestCount_ = chrome.benchmarking.counter(kRequestCount);
107 initialConnectCount_ = chrome.benchmarking.counter(kConnectCount);
109 if (me_.preloadFunc_) {
110 me_.preloadFunc_(me_.load_);
116 this.setClearAll = function() {
117 me_.preloadFunc_ = me_.clearAll_;
120 this.setClearConnections = function() {
121 me_.preloadFunc_ = me_.clearConnections_;
124 this.clearAll_ = function(callback) {
125 chrome.tabs.getSelected(null, function(tab) {
126 chrome.tabs.update(tab.id, {"url": kWaitUrl}, function() {
127 chrome.benchmarking.clearHostResolverCache();
128 chrome.benchmarking.clearPredictorCache();
129 chrome.benchmarking.closeConnections();
139 "localStorage": true,
144 // Add any items new to the API.
145 for (var prop in chrome.browsingData) {
146 var dataName = prop.replace("remove", "");
147 if (dataName && dataName != prop) {
148 dataName = dataName.charAt(0).toLowerCase() +
150 if (!dataToRemove.hasOwnProperty(dataName)) {
151 console.log("New browsingData API item: " + dataName);
152 dataToRemove[dataName] = true;
156 chrome.browsingData.remove({}, dataToRemove, callback);
161 this.clearConnections_ = function(callback) {
162 chrome.benchmarking.closeConnections();
166 this.load_ = function() {
167 console.log("LOAD started: " + url_);
168 setTimeout(function() {
169 chrome.extension.onRequest.addListener(me_.finishLoad_);
170 timeoutId_ = setTimeout(function() {
171 me_.finishLoad_({"loadTimes": null, "timing": null});
173 chrome.tabs.getSelected(null, function(tab) {
174 chrome.tabs.update(tab.id, {"url": url_});
179 this.finishLoad_ = function(msg) {
182 clearTimeout(timeoutId_);
183 chrome.extension.onRequest.removeListener(me_.finishLoad_);
184 me_.saveResult_(msg.loadTimes, msg.timing);
188 this.saveResult_ = function(loadTimes, timing) {
189 result_ = new Result()
191 if (!loadTimes || !timing) {
192 console.log("LOAD INCOMPLETE: " + url_);
194 console.log("LOAD complete: " + url_);
195 result_.timing = timing;
196 var baseTime = timing.navigationStart;
198 result_.firstPaintTime = Math.max(0,
199 Math.round((1000.0 * loadTimes.firstPaintTime) - baseTime));
201 result_.readBytesKB = (chrome.benchmarking.counter(kTcpReadBytes) -
202 initialReadBytes_) / 1024;
203 result_.writeBytesKB = (chrome.benchmarking.counter(kTcpWriteBytes) -
204 initialWriteBytes_) / 1024;
205 result_.numRequests = (chrome.benchmarking.counter(kRequestCount) -
206 initialRequestCount_);
207 result_.numConnects = (chrome.benchmarking.counter(kConnectCount) -
208 initialConnectCount_);
209 setTimeout(function() { resultReadyCallback_(me_); }, postLoadGraceMs_);
213 // Load page sets and prepare performance results.
214 function SessionLoader(resultsReadyCallback) {
216 var resultsReadyCallback_ = resultsReadyCallback;
217 var pageSets_ = benchmarkConfiguration.pageSets;
218 var iterations_ = window.iterations;
219 var retries_ = window.retries;
221 var pageLoaders_ = [];
222 var resultsCollection_ = new ResultsCollection();
223 var loaderIndex_ = 0;
225 var iterationIndex_ = 0;
227 this.run = function() {
228 me_.createLoaders_();
232 this.getResultsCollection = function() {
233 return resultsCollection_;
236 this.createLoaders_ = function() {
237 // Each url becomes one benchmark.
238 for (var i = 0; i < pageSets_.length; i++) {
239 for (var j = 0; j < pageSets_[i].length; j++) {
240 // Remove extra space at the beginning or end of a url.
241 var url = pageSets_[i][j].trim();
242 // Alert about and ignore blank page which does not get loaded.
243 if (url == "about:blank") {
244 alert("blank page loaded!");
245 } else if (!url.match(/https?:\/\//)) {
246 // Alert about url that is not in scheme http:// or https://.
247 alert("Skipping url without http:// or https://: " + url);
249 var loader = new PageLoader(url, me_.handleResult_)
251 // Clear all browser data for the first page in a sub list.
252 loader.setClearAll();
254 // Otherwise, only clear the connections.
255 loader.setClearConnections();
257 pageLoaders_.push(loader);
263 this.loadPage_ = function() {
264 console.log("LOAD url " + (loaderIndex_ + 1) + " of " +
265 pageLoaders_.length +
266 ", iteration " + (iterationIndex_ + 1) + " of " +
268 pageLoaders_[loaderIndex_].run();
271 this.handleResult_ = function(loader) {
272 var result = loader.result();
273 resultsCollection_.addResult(result);
274 var totalTime = result.getTotalTime();
275 if (!totalTime && retryIndex_ < retries_) {
277 console.log("LOAD retry, " + retryIndex_);
280 console.log("RESULTS url " + (loaderIndex_ + 1) + " of " +
281 pageLoaders_.length +
282 ", iteration " + (iterationIndex_ + 1) + " of " +
283 iterations_ + ": " + totalTime);
285 if (loaderIndex_ >= pageLoaders_.length) {
287 if (iterationIndex_ < iterations_) {
290 resultsReadyCallback_(me_);
299 function AddBenchmarkCallback(callback) {
300 window.benchmarkCallback = callback;
304 window.checkInterval = 500;
305 window.loadInterval = 1000;
306 window.timeout = 20000; // max ms before killing page.
308 window.isRecordMode = benchmarkConfiguration.isRecordMode;
309 if (window.isRecordMode) {
310 window.iterations = 1;
311 window.timeout = 40000;
314 window.iterations = benchmarkConfiguration["iterations"] || 3;
316 var sessionLoader = new SessionLoader(benchmarkCallback);
317 console.log("pageSets: " + JSON.stringify(benchmarkConfiguration.pageSets));
321 chrome.runtime.onConnect.addListener(function(port) {
322 port.onMessage.addListener(function(data) {
323 if (data.message == "start") {
324 window.benchmarkConfiguration = data.benchmark;