| Index: tools/page_cycler/webpagereplay/extension/background.js
|
| diff --git a/tools/page_cycler/webpagereplay/extension/background.js b/tools/page_cycler/webpagereplay/extension/background.js
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..207979e88605cfd3238f85721bf7e6794b8c0dd6
|
| --- /dev/null
|
| +++ b/tools/page_cycler/webpagereplay/extension/background.js
|
| @@ -0,0 +1,328 @@
|
| +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +// start.js sends a "start" message to set this.
|
| +window.benchmarkConfiguration = {};
|
| +
|
| +// The callback (e.g. report writer) is set via AddBenchmarckCallback.
|
| +window.benchmarkCallback;
|
| +
|
| +// Url to load before loading target page.
|
| +var kWaitUrl = "http://wprwprwpr/web-page-replay-generate-200";
|
| +
|
| +// Constant StatCounter Names
|
| +var kTcpReadBytes = "tcp.read_bytes";
|
| +var kTcpWriteBytes = "tcp.write_bytes";
|
| +var kRequestCount = "HttpNetworkTransaction.Count";
|
| +var kConnectCount = "tcp.connect";
|
| +
|
| +function CHECK(expr, comment) {
|
| + if (!expr) {
|
| + console.log(comment);
|
| + alert(comment);
|
| + }
|
| +}
|
| +
|
| +function Result() {
|
| + var me_ = this;
|
| + this.url = "";
|
| + this.firstPaintTime = 0;
|
| + this.readBytesKB = 0;
|
| + this.writeBytesKB = 0;
|
| + this.numRequests = 0;
|
| + this.numConnects = 0;
|
| + this.timing = {}; // window.performance.timing
|
| + this.getTotalTime = function() {
|
| + var totalTime = 0
|
| + if (me_.timing.navigationStart && me_.timing.loadEventEnd) {
|
| + totalTime = me_.timing.loadEventEnd - me_.timing.navigationStart;
|
| + }
|
| + CHECK(totalTime >= 0);
|
| + return totalTime;
|
| + }
|
| +}
|
| +
|
| +// Collect all the results for a session (i.e. different pages).
|
| +function ResultsCollection() {
|
| + var results_ = [];
|
| + var pages_ = [];
|
| + var pageResults_ = {};
|
| +
|
| + this.addResult = function(result) {
|
| + results_.push(result);
|
| + var url = result.url;
|
| + if (!(url in pageResults_)) {
|
| + pages_.push(url);
|
| + pageResults_[url] = [];
|
| + }
|
| + pageResults_[url].push(result);
|
| + }
|
| +
|
| + this.getPages = function() {
|
| + return pages_;
|
| + }
|
| +
|
| + this.getResults = function() {
|
| + return results_;
|
| + }
|
| +
|
| + this.getTotalTimes = function() {
|
| + return results_.map(function (t) { return t.getTotalTime(); });
|
| + }
|
| +}
|
| +
|
| +// Load a url in the default tab and record the time.
|
| +function PageLoader(url, resultReadyCallback) {
|
| + var me_ = this;
|
| + var url_ = url;
|
| + var resultReadyCallback_ = resultReadyCallback;
|
| +
|
| + // If it record mode, wait a little longer for lazy loaded resources.
|
| + var postLoadGraceMs_ = window.isRecordMode ? 5000 : 0;
|
| + var loadInterval_ = window.loadInterval;
|
| + var checkInterval_ = window.checkInterval;
|
| + var timeout_ = window.timeout;
|
| + var maxLoadChecks_ = window.maxLoadChecks;
|
| +
|
| + var preloadFunc_;
|
| + var timeoutId_;
|
| + var isFinished_;
|
| + var result_;
|
| +
|
| + var initialReadBytes_;
|
| + var initialWriteBytes_;
|
| + var initialRequestCount_;
|
| + var initialConnectCount_;
|
| +
|
| + this.result = function() { return result_; };
|
| +
|
| + this.run = function() {
|
| + timeoutId_ = null;
|
| + isFinished_ = false;
|
| + result_ = null;
|
| + initialReadBytes_ = chrome.benchmarking.counter(kTcpReadBytes);
|
| + initialWriteBytes_ = chrome.benchmarking.counter(kTcpWriteBytes);
|
| + initialRequestCount_ = chrome.benchmarking.counter(kRequestCount);
|
| + initialConnectCount_ = chrome.benchmarking.counter(kConnectCount);
|
| +
|
| + if (me_.preloadFunc_) {
|
| + me_.preloadFunc_(me_.load_);
|
| + } else {
|
| + me_.load_();
|
| + }
|
| + };
|
| +
|
| + this.setClearAll = function() {
|
| + me_.preloadFunc_ = me_.clearAll_;
|
| + };
|
| +
|
| + this.setClearConnections = function() {
|
| + me_.preloadFunc_ = me_.clearConnections_;
|
| + };
|
| +
|
| + this.clearAll_ = function(callback) {
|
| + chrome.tabs.getSelected(null, function(tab) {
|
| + chrome.tabs.update(tab.id, {"url": kWaitUrl}, function() {
|
| + chrome.benchmarking.clearHostResolverCache();
|
| + chrome.benchmarking.clearPredictorCache();
|
| + chrome.benchmarking.closeConnections();
|
| + var dataToRemove = {
|
| + "appcache": true,
|
| + "cache": true,
|
| + "cookies": true,
|
| + "downloads": true,
|
| + "fileSystems": true,
|
| + "formData": true,
|
| + "history": true,
|
| + "indexedDB": true,
|
| + "localStorage": true,
|
| + "passwords": true,
|
| + "pluginData": true,
|
| + "webSQL": true
|
| + };
|
| + // Add any items new to the API.
|
| + for (var prop in chrome.browsingData) {
|
| + var dataName = prop.replace("remove", "");
|
| + if (dataName && dataName != prop) {
|
| + dataName = dataName.charAt(0).toLowerCase() +
|
| + dataName.substr(1);
|
| + if (!dataToRemove.hasOwnProperty(dataName)) {
|
| + console.log("New browsingData API item: " + dataName);
|
| + dataToRemove[dataName] = true;
|
| + }
|
| + }
|
| + }
|
| + chrome.browsingData.remove({}, dataToRemove, callback);
|
| + });
|
| + });
|
| + };
|
| +
|
| + this.clearConnections_ = function(callback) {
|
| + chrome.benchmarking.closeConnections();
|
| + callback();
|
| + };
|
| +
|
| + this.load_ = function() {
|
| + console.log("LOAD started: " + url_);
|
| + setTimeout(function() {
|
| + chrome.extension.onRequest.addListener(me_.finishLoad_);
|
| + timeoutId_ = setTimeout(function() {
|
| + me_.finishLoad_({"loadTimes": null, "timing": null});
|
| + }, timeout_);
|
| + chrome.tabs.getSelected(null, function(tab) {
|
| + chrome.tabs.update(tab.id, {"url": url_});
|
| + });
|
| + }, loadInterval_);
|
| + };
|
| +
|
| + this.finishLoad_ = function(msg) {
|
| + if (!isFinished_) {
|
| + isFinished_ = true;
|
| + clearTimeout(timeoutId_);
|
| + chrome.extension.onRequest.removeListener(me_.finishLoad_);
|
| + me_.saveResult_(msg.loadTimes, msg.timing);
|
| + }
|
| + };
|
| +
|
| + this.saveResult_ = function(loadTimes, timing) {
|
| + result_ = new Result()
|
| + result_.url = url_;
|
| + if (!loadTimes || !timing) {
|
| + console.log("LOAD INCOMPLETE: " + url_);
|
| + } else {
|
| + console.log("LOAD complete: " + url_);
|
| + result_.timing = timing;
|
| + var baseTime = timing.navigationStart;
|
| + CHECK(baseTime);
|
| + result_.firstPaintTime = Math.max(0,
|
| + Math.round((1000.0 * loadTimes.firstPaintTime) - baseTime));
|
| + }
|
| + result_.readBytesKB = (chrome.benchmarking.counter(kTcpReadBytes) -
|
| + initialReadBytes_) / 1024;
|
| + result_.writeBytesKB = (chrome.benchmarking.counter(kTcpWriteBytes) -
|
| + initialWriteBytes_) / 1024;
|
| + result_.numRequests = (chrome.benchmarking.counter(kRequestCount) -
|
| + initialRequestCount_);
|
| + result_.numConnects = (chrome.benchmarking.counter(kConnectCount) -
|
| + initialConnectCount_);
|
| + setTimeout(function() { resultReadyCallback_(me_); }, postLoadGraceMs_);
|
| + };
|
| +}
|
| +
|
| +// Load page sets and prepare performance results.
|
| +function SessionLoader(resultsReadyCallback) {
|
| + var me_ = this;
|
| + var resultsReadyCallback_ = resultsReadyCallback;
|
| + var pageSets_ = benchmarkConfiguration.pageSets;
|
| + var iterations_ = window.iterations;
|
| + var retries_ = window.retries;
|
| +
|
| + var pageLoaders_ = [];
|
| + var resultsCollection_ = new ResultsCollection();
|
| + var loaderIndex_ = 0;
|
| + var retryIndex_ = 0;
|
| + var iterationIndex_ = 0;
|
| +
|
| + this.run = function() {
|
| + me_.createLoaders_();
|
| + me_.loadPage_();
|
| + }
|
| +
|
| + this.getResultsCollection = function() {
|
| + return resultsCollection_;
|
| + }
|
| +
|
| + this.createLoaders_ = function() {
|
| + // Each url becomes one benchmark.
|
| + for (var i = 0; i < pageSets_.length; i++) {
|
| + for (var j = 0; j < pageSets_[i].length; j++) {
|
| + // Remove extra space at the beginning or end of a url.
|
| + var url = pageSets_[i][j].trim();
|
| + // Alert about and ignore blank page which does not get loaded.
|
| + if (url == "about:blank") {
|
| + alert("blank page loaded!");
|
| + } else if (!url.match(/https?:\/\//)) {
|
| + // Alert about url that is not in scheme http:// or https://.
|
| + alert("Skipping url without http:// or https://: " + url);
|
| + } else {
|
| + var loader = new PageLoader(url, me_.handleResult_)
|
| + if (j == 0) {
|
| + // Clear all browser data for the first page in a sub list.
|
| + loader.setClearAll();
|
| + } else {
|
| + // Otherwise, only clear the connections.
|
| + loader.setClearConnections();
|
| + }
|
| + pageLoaders_.push(loader);
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| + this.loadPage_ = function() {
|
| + console.log("LOAD url " + (loaderIndex_ + 1) + " of " +
|
| + pageLoaders_.length +
|
| + ", iteration " + (iterationIndex_ + 1) + " of " +
|
| + iterations_);
|
| + pageLoaders_[loaderIndex_].run();
|
| + }
|
| +
|
| + this.handleResult_ = function(loader) {
|
| + var result = loader.result();
|
| + resultsCollection_.addResult(result);
|
| + var totalTime = result.getTotalTime();
|
| + if (!totalTime && retryIndex_ < retries_) {
|
| + retryIndex_++;
|
| + console.log("LOAD retry, " + retryIndex_);
|
| + } else {
|
| + retryIndex_ = 0;
|
| + console.log("RESULTS url " + (loaderIndex_ + 1) + " of " +
|
| + pageLoaders_.length +
|
| + ", iteration " + (iterationIndex_ + 1) + " of " +
|
| + iterations_ + ": " + totalTime);
|
| + loaderIndex_++;
|
| + if (loaderIndex_ >= pageLoaders_.length) {
|
| + iterationIndex_++;
|
| + if (iterationIndex_ < iterations_) {
|
| + loaderIndex_ = 0;
|
| + } else {
|
| + resultsReadyCallback_(me_);
|
| + return;
|
| + }
|
| + }
|
| + }
|
| + me_.loadPage_();
|
| + }
|
| +}
|
| +
|
| +function AddBenchmarkCallback(callback) {
|
| + window.benchmarkCallback = callback;
|
| +}
|
| +
|
| +function Run() {
|
| + window.checkInterval = 500;
|
| + window.loadInterval = 1000;
|
| + window.timeout = 20000; // max ms before killing page.
|
| + window.retries = 0;
|
| + window.isRecordMode = benchmarkConfiguration.isRecordMode;
|
| + if (window.isRecordMode) {
|
| + window.iterations = 1;
|
| + window.timeout = 40000;
|
| + window.retries = 2;
|
| + } else {
|
| + window.iterations = benchmarkConfiguration["iterations"] || 3;
|
| + }
|
| + var sessionLoader = new SessionLoader(benchmarkCallback);
|
| + console.log("pageSets: " + JSON.stringify(benchmarkConfiguration.pageSets));
|
| + sessionLoader.run();
|
| +}
|
| +
|
| +chrome.extension.onConnect.addListener(function(port) {
|
| + port.onMessage.addListener(function(data) {
|
| + if (data.message == "start") {
|
| + window.benchmarkConfiguration = data.benchmark;
|
| + Run()
|
| + }
|
| + });
|
| +});
|
|
|