pageloader exgtension for firefox, b=367559 r=robcee

git-svn-id: svn://10.0.0.236/trunk@219349 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
rhelmer%mozilla.com 2007-02-01 20:56:13 +00:00
parent cb5309cce4
commit 2991de3ced
10 changed files with 389 additions and 0 deletions

View File

@ -0,0 +1,6 @@
all:
zip -r pageloader.xpi chrome chrome.manifest install.rdf
check:
./test/chrome/content/report.js
./test/chrome/content/pageloader.js

View File

@ -0,0 +1,13 @@
This is a pageloader extension for Firefox. It cycles through a list of URLs
specified in a text file by the user (one URL per line), and reports statistics
and raw data about the time each page took to load.
This data is dumped to the console, so the browser.dom.window.dump.enabled pref
(boolean) must be set to "true", and on Windows Firefox must be run with the
"-console" command line switch.
This test is intended to be run standalone from a chrome URL, e.g.:
firefox -chrome chrome://pageloader/content/pageloader.xul
The window will close and the data will be dumped to the console when the
test has completed.

View File

@ -0,0 +1 @@
content pageloader chrome/content/

View File

@ -0,0 +1,3 @@
window {
background-color: #0088CC;
}

View File

@ -0,0 +1,148 @@
var NUM_CYCLES = 5;
var pages;
var pageIndex;
var results;
var start_time;
var end_time;
var cycle;
var report;
function plInit() {
try {
pageIndex = 0;
cycle = 0;
results = new Object();
if (! pages) {
pages = plLoadURLsFromFile();
}
if (pages.length == 0) {
alert('no pages to test');
plStop(true);
}
report = new Report(pages);
plLoadPage();
} catch(e) {
alert(e);
plStop(true);
}
}
function plLoadPage() {
try {
start_time = new Date();
p = pages[pageIndex];
var startButton = document.getElementById('plStartButton');
startButton.setAttribute('disabled', 'true');
this.content = document.getElementById('contentPageloader');
this.content.addEventListener('load', plLoadHandler, true);
this.content.loadURI(p);
} catch (e) {
alert(e);
plStop(true);
}
}
function plLoadHandler(evt) {
if (evt.type == 'load') {
window.setTimeout('reallyHandle()', 500);
} else {
alert('Unknown event type: '+evt.type);
plStop(true);
}
}
function reallyHandle() {
if (pageIndex < pages.length) {
try {
end_time = new Date();
var pageName = pages[pageIndex];
results[pageName] = (end_time - start_time);
start_time = new Date();
dump(pageName+" took "+results[pageName]+"\n");
plReport();
pageIndex++;
plLoadPage();
} catch(e) {
alert(e);
plStop(true);
}
} else {
plStop(false);
}
}
function plReport() {
try {
var reportNode = document.getElementById('report');
var pageName = pages[pageIndex];
var time = results[pageName];
report.recordTime(pageIndex, time);
} catch(e) {
alert(e);
plStop(false);
}
}
function plStop(force) {
try {
pageIndex = 0;
results = new Object;
if (force == false) {
if (cycle < NUM_CYCLES) {
cycle++;
plLoadPage();
return;
} else {
dump(report.getReport()+"\n");
}
}
var startButton = document.getElementById('plStartButton');
startButton.setAttribute('disabled', 'false');
this.content.removeEventListener('load', plLoadHandler, true);
//goQuitApplication();
} catch(e) {
alert(e);
}
}
/* Returns array */
function plLoadURLsFromFile() {
try {
const nsIFilePicker = Components.interfaces.nsIFilePicker;
var fp = Components.classes["@mozilla.org/filepicker;1"]
.createInstance(nsIFilePicker);
fp.init(window, "Dialog Title", nsIFilePicker.modeOpen);
fp.appendFilters(nsIFilePicker.filterAll | nsIFilePicker.filterText);
var rv = fp.show();
if (rv == nsIFilePicker.returnOK)
{
var file = fp.file;
var data = "";
var fstream =
Components.classes["@mozilla.org/network/file-input-stream;1"]
.createInstance(Components.interfaces.nsIFileInputStream);
var sstream = Components.classes["@mozilla.org/scriptableinputstream;1"]
.createInstance(Components.interfaces.nsIScriptableInputStream);
fstream.init(file, -1, 0, 0);
sstream.init(fstream);
var str = sstream.read(4096);
while (str.length > 0) {
data += str;
str = sstream.read(4096);
}
sstream.close();
fstream.close();
var p = data.split("\n");
// discard result of final split (EOF)
p.pop()
return p;
}
} catch (e) {
alert(e);
}
}

View File

@ -0,0 +1,14 @@
<?xml version="1.0"?>
<?xml-stylesheet href="pageloader.css" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/x-javascript" src="chrome://global/content/globalOverlay.js"/>
<script type="application/x-javascript" src="report.js"></script>
<script type="application/x-javascript" src="pageloader.js"></script>
<box align="center">
<button id="plStartButton" label="start" onclick="plInit(false);" />
</box>
<box align="center">
<browser id="contentPageloader" src="about:blank"
type="content" flex="1" align="center" width="1024" height="768"/>
</box>
</window>

View File

@ -0,0 +1,112 @@
// Constructor
function Report(pages) {
this.pages = pages;
this.timeVals = new Array(pages.length); // matrix of times
for (var i = 0; i < this.timeVals.length; ++i) {
this.timeVals[i] = new Array;
}
}
// returns an object with the following properties:
// min : min value of array elements
// max : max value of array elements
// mean : mean value of array elements
// vari : variance computation
// stdd : standard deviation, sqrt(vari)
// indexOfMax : index of max element (the element that is
// removed from the mean computation)
Report.prototype.getArrayStats = function(ary) {
var r = {};
r.min = ary[0];
r.max = ary[0];
r.indexOfMax = 0;
var sum = 0;
for (var i = 0; i < ary.length; ++i) {
if (ary[i] < r.min) {
r.min = ary[i];
} else if (ary[i] > r.max) {
r.max = ary[i];
r.indexOfMax = i;
}
sum = sum + ary[i];
}
// median
sorted_ary = ary.concat();
sorted_ary.sort();
// remove longest run
sorted_ary.pop();
if (sorted_ary.length%2) {
r.median = sorted_ary[(sorted_ary.length-1)/2];
}else{
var n = Math.floor(sorted_ary.length / 2);
r.median = (sorted_ary[n] + sorted_ary[n + 1]) / 2;
}
// ignore max value when computing mean and stddev
r.mean = (sum - r.max) / (ary.length - 1);
r.vari = 0;
for (var i = 0; i < ary.length; ++i) {
if (i == r.indexOfMax)
continue;
var d = r.mean - ary[i];
r.vari = r.vari + d * d;
}
r.vari = r.vari / (ary.length - 1);
r.stdd = Math.sqrt(r.vari);
return r;
}
Report.prototype.getReport = function() {
var all = new Array();
var counter = 0;
for (var i = 0; i < this.timeVals.length; ++i) {
for (var j = 0; j < this.timeVals[i].length; ++j) {
all[counter] = this.timeVals[i][j];
++counter;
}
}
// avg and avg median are cumulative for all the pages
var avgs = new Array();
var medians = new Array();
for (var i = 0; i < this.timeVals.length; ++i) {
avgs[i] = this.getArrayStats(this.timeVals[i]).mean;
medians[i] = this.getArrayStats(this.timeVals[i]).median;
}
var avg = this.getArrayStats(avgs).mean;
var avgmed = this.getArrayStats(medians).mean;
var r = this.getArrayStats(all);
var report = '';
report +=
"(tinderbox dropping follows)\n"+
"_x_x_mozilla_page_load,"+avgmed+","+r.max+","+r.min+"\n"+
"_x_x_mozilla_page_load_details,avgmedian|"+avgmed+"|average|"+avg.toFixed(2)+"|minimum|"+r.min+"|maximum|"+r.max+"|stddev|"+r.stdd.toFixed(2)+":"
for (var i = 0; i < this.timeVals.length; ++i) {
r = this.getArrayStats(this.timeVals[i]);
report +=
'|'+
i+';'+
pages[i]+';'+
r.median+';'+
r.mean+';'+
r.min+';'+
r.max
for (var j = 0; j < this.timeVals[i].length; ++j) {
report +=
';'+this.timeVals[i][j]
}
}
return report;
}
Report.prototype.recordTime = function(pageIndex, ms) {
this.timeVals[pageIndex].push(ms);
}

View File

@ -0,0 +1,27 @@
<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>pageloader@mozilla.org</em:id>
<em:version>0.5</em:version>
<em:type>2</em:type>
<!-- Target Application this extension can install into,
with minimum and maximum supported versions. -->
<em:targetApplication>
<Description>
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
<em:minVersion>1.0+</em:minVersion>
<em:maxVersion>4.0</em:maxVersion>
</Description>
</em:targetApplication>
<!-- Front End MetaData -->
<em:name>PageLoader</em:name>
<em:description>A pageloader extension.</em:description>
<em:creator>Robert Helmer</em:creator>
<em:homepageURL>http://www.roberthelmer.com/</em:homepageURL>
</Description>
</RDF>

View File

@ -0,0 +1,46 @@
#!/usr/bin/js
// mock objects
function alert(str) {
print(str);
}
function dump(str) {
print(str);
}
window = new Object();
document = new Object();
document.createEvent = function(str) {
obj = new Object();
obj.initMouseEvent = function() {}
return obj;
}
document.getElementById = function(str) {
obj = new Object();
if (str == 'contentPageloader') {
obj.content = new Object();
obj.content.addEventListener = function() {}
obj.content.removeEventListener = function() {}
obj.content.loadURI = function() {}
return obj.content;
} else if (str == 'plStartButton') {
obj.startButton = new Object();
obj.startButton.setAttribute = function(key, value) {}
return obj.startButton;
}
}
evt = new Object();
evt.type = 'load';
window.setTimeout = function() {}
this.content = document.getElementById('content');
// dummy data
pages = ['http://google.com'];
load(['chrome/content/pageloader.js']);
load(['chrome/content/report.js']);
plInit(true);
plInit(false);
for (cycle = 0; cycle < NUM_CYCLES*2; cycle++) {
plLoadHandler(evt);
}

View File

@ -0,0 +1,19 @@
#!/usr/bin/js
load(['chrome/content/report.js']);
pages = [
'http://www.google.com',
'http://www.yahoo.com',
'http://www.msn.com',
];
cycle_time = 5;
report = new Report(pages);
for (var c=0; c < cycle_time; c++) {
for (var p=0; p < pages.length; p++) {
report.recordTime(p, c+1);
}
}
print(report.getReport());