329 lines
9.8 KiB
JavaScript
329 lines
9.8 KiB
JavaScript
// 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.runtime.onConnect.addListener(function(port) {
|
|
port.onMessage.addListener(function(data) {
|
|
if (data.message == "start") {
|
|
window.benchmarkConfiguration = data.benchmark;
|
|
Run()
|
|
}
|
|
});
|
|
});
|