зеркало из https://github.com/mozilla/pjs.git
pageloader exgtension for firefox, b=367559 r=robcee
This commit is contained in:
Родитель
bd8172f849
Коммит
7b512dea98
|
@ -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
|
|
@ -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.
|
|
@ -0,0 +1 @@
|
|||
content pageloader chrome/content/
|
|
@ -0,0 +1,3 @@
|
|||
window {
|
||||
background-color: #0088CC;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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);
|
||||
}
|
|
@ -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>
|
|
@ -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);
|
||||
}
|
|
@ -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());
|
Загрузка…
Ссылка в новой задаче