diff --git a/mozilla/layout/Makefile.in b/mozilla/layout/Makefile.in index 987ff7299a3..3ccf70077f9 100644 --- a/mozilla/layout/Makefile.in +++ b/mozilla/layout/Makefile.in @@ -73,6 +73,7 @@ DIRS += build ifdef ENABLE_TESTS DIRS += tools/reftest +DIRS += tools/pageloader ifndef MOZ_ENABLE_LIBXUL TOOL_DIRS += html/tests endif diff --git a/mozilla/layout/tools/pageloader/Makefile.in b/mozilla/layout/tools/pageloader/Makefile.in new file mode 100644 index 00000000000..8aefb9d9ceb --- /dev/null +++ b/mozilla/layout/tools/pageloader/Makefile.in @@ -0,0 +1,51 @@ +# vim: set shiftwidth=8 tabstop=8 autoindent noexpandtab copyindent: +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla's pageloader test +# +# The Initial Developer of the Original Code is the Mozilla Foundation. +# Portions created by the Initial Developer are Copyright (C) 2007 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Vladimir Vukicevic +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = layout + +EXTRA_COMPONENTS= \ + tp-cmdline.js \ + $(NULL) + +include $(topsrcdir)/config/rules.mk diff --git a/mozilla/layout/tools/pageloader/README b/mozilla/layout/tools/pageloader/README new file mode 100644 index 00000000000..e72bed5c0dc --- /dev/null +++ b/mozilla/layout/tools/pageloader/README @@ -0,0 +1,53 @@ +Pageload Test Component +======================= + +Usage: + + ./firefox -tp file:///path/to/manifest.txt [-tpargs...] + +See ./firefox -help for other arguments. + +The manifest file should contain a list of URLs or URL fragments, one +per line. Empty lines or lines starting with # are ignored. If URL +fragments are specified, then -tpprefix must be used to give a prefix +to prepend to each line in the manifest to turn it into a complete +URL. + +The result is a dump to stdout via dump() -- +browser.dom.window.dump.enabled must be set to true in the profile. A +number of output formats can be specified via the -tpformat command +line option, currently 'js', 'text', and 'tinderbox' are supported. + +Sample 'js' format output: + +([({page:"1280x1024-PNG/index.html", value:133, stddev:20.049937655763422}),({page:"bugzilla.mozilla.org/index.html", value:233, stddev:36.66606060105176}),({page:"espn.go.com/index.html", value:117.6, stddev:1.2}),({page:"home.netscape.com/index.html", value:97.8, stddev:47.41898354035017}),]) + +Sample 'text' format output: + +============================================================ + Page mean stdd min max raw + 0 1280x1024-PNG/index.html 133 20 121 297 297,173,122,121,124,125 + 1 bugzilla.mozilla.org/index.html 233 37 192 395 395,273,223,192,198,279 + 2 espn.go.com/index.html 118 1 116 254 254,117,116,119,119,117 + 3 home.netscape.com/index.html 98 47 3 124 3,121,120,124,124,121 +============================================================ + +Sample 'tinderbox' format output: + +__start_tp_report +_x_x_mozilla_page_load,778.5,NaN,NaN +_x_x_mozilla_page_load_details,avgmedian|778.5|average|766.75|minimum|NaN|maximum|NaN|stddev|NaN|0;file:///c:/proj/mozilla-cvs/perf/tp2/base/www.cnn.com/index.html;778.5;766.75;722;1027;1027;788;777;722;780|... +__end_tp_report + +Note that the minimum, maximum, stddev are not calculated; they're +always reported as NaN. (They were the minimum and maximum values of +any sampled value, and the standard deviation across all sampled +values -- not very useful.) + +TODO +==== + +* Command line option to choose whether to run with or without browser chrome. Currently runs without. + +* Tinderbox-dropping style output + * better yet would be to teach tinderbox about JSON diff --git a/mozilla/layout/tools/pageloader/jar.mn b/mozilla/layout/tools/pageloader/jar.mn new file mode 100644 index 00000000000..39a81788dca --- /dev/null +++ b/mozilla/layout/tools/pageloader/jar.mn @@ -0,0 +1,6 @@ +pageloader.jar: +% content pageloader %content/ +* content/quit.js (quit.js) +* content/pageloader.js (pageloader.js) + content/pageloader.xul (pageloader.xul) +* content/report.js (report.js) diff --git a/mozilla/layout/tools/pageloader/pageloader.js b/mozilla/layout/tools/pageloader/pageloader.js new file mode 100644 index 00000000000..0ca0c1b5377 --- /dev/null +++ b/mozilla/layout/tools/pageloader/pageloader.js @@ -0,0 +1,300 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is tp. + * + * The Initial Developer of the Original Code is + * Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Rob Helmer + * Vladimir Vukicevic + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const Cc = Components.classes; +const Ci = Components.interfaces; + +var NUM_CYCLES = 5; + +var pageFilterRegexp = null; +var reportFormat = "js"; +var useBrowser = true; +var winWidth = 1024; +var winHeight = 768; +var urlPrefix = null; + +var doRenderTest = false; + +var pages; +var pageIndex; +var results; +var start_time; +var cycle; +var report; +var renderReport; +var running = false; + +var content; + +var browserWindow = null; + +function plInit() { + if (running) { + return; + } + running = true; + + cycle = 0; + results = {}; + + try { + var args = window.arguments[0].wrappedJSObject; + + var manifestURI = args.manifest; + var startIndex = 0; + var endIndex = -1; + if (args.startIndex) startIndex = parseInt(args.startIndex); + if (args.endIndex) endIndex = parseInt(args.endIndex); + if (args.numCycles) NUM_CYCLES = parseInt(args.numCycles); + if (args.format) reportFormat = args.format; + if (args.width) winWidth = parseInt(args.width); + if (args.height) winHeight = parseInt(args.height); + if (args.filter) pageFilterRegexp = new RegExp(args.filter); + if (args.prefix) urlPrefix = args.prefix; + doRenderTest = args.doRender; + + var ios = Cc["@mozilla.org/network/io-service;1"] + .getService(Ci.nsIIOService); + if (args.offline) + ios.offline = true; + var fileURI = ios.newURI(manifestURI, null, null); + pages = plLoadURLsFromURI(fileURI); + + if (!pages) { + dumpLine('tp: could not load URLs, quitting'); + plStop(true); + } + + if (pages.length == 0) { + dumpLine('tp: no pages to test, quitting'); + plStop(true); + } + + if (startIndex < 0) + startIndex = 0; + if (endIndex == -1 || endIndex >= pages.length) + endIndex = pages.length-1; + if (startIndex > endIndex) { + dumpLine("tp: error: startIndex >= endIndex"); + plStop(true); + } + + pages = pages.slice(startIndex,endIndex+1); + report = new Report(pages); + + if (doRenderTest) + renderReport = new Report(pages); + + pageIndex = 0; + + if (args.useBrowserChrome) { + var wwatch = Cc["@mozilla.org/embedcomp/window-watcher;1"] + .getService(Ci.nsIWindowWatcher); + var blank = Cc["@mozilla.org/supports-string;1"] + .createInstance(Ci.nsISupportsString); + blank.data = "about:blank"; + browserWindow = wwatch.openWindow + (null, "chrome://browser/content/", "_blank", + "chrome,dialog=no,width=" + winWidth + ",height=" + winHeight, blank); + + // get our window out of the way + window.resizeTo(10,10); + + var browserLoadFunc = function (ev) { + browserWindow.removeEventListener('load', browserLoadFunc, true); + + // do this half a second after load, because we need to be + // able to resize the window and not have it get clobbered + // by the persisted values + setTimeout(function () { + browserWindow.resizeTo(winWidth, winHeight); + browserWindow.moveTo(0, 0); + browserWindow.focus(); + + content = browserWindow.getBrowser(); + content.addEventListener('load', plLoadHandler, true); + setTimeout(plLoadPage, 100); + }, 500); + }; + + browserWindow.addEventListener('load', browserLoadFunc, true); + } else { + window.resizeTo(winWidth, winHeight); + + content = document.getElementById('contentPageloader'); + content.addEventListener('load', plLoadHandler, true); + + setTimeout(plLoadPage, 0); + } + } catch(e) { + dumpLine(e); + plStop(true); + } +} + +function plLoadPage() { + start_time = Date.now(); + content.loadURI(pages[pageIndex]); +} + +function plLoadHandler(evt) { + // make sure we pick up the right load event + if (evt.type != 'load' || + (!evt.originalTarget instanceof Ci.nsIDOMHTMLDocument || + evt.originalTarget.defaultView.frameElement)) + return; + + var end_time = Date.now(); + var time = (end_time - start_time); + + var pageName = pages[pageIndex]; + + results[pageName] = time; + report.recordTime(pageIndex, time); + + if (doRenderTest) + runRenderTest(); + + if (pageIndex < pages.length-1) { + pageIndex++; + setTimeout(plLoadPage, 0); + } else { + plStop(false); + } +} + +function runRenderTest() { + const redrawsPerSample = 5; + const renderCycles = 10; + + if (!Ci.nsIDOMWindowUtils) + return; + + var win; + + if (browserWindow) + win = content.contentWindow; + else + win = window; + var wu = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils); + + for (var i = 0; i < renderCycles; i++) { + var start = Date.now(); + for (var j = 0; j < redrawsPerSample; j++) + wu.redraw(); + var end = Date.now(); + + renderReport.recordTime(pageIndex, end - start); + } +} + +function plStop(force) { + try { + if (force == false) { + pageIndex = 0; + results = {}; + if (cycle < NUM_CYCLES-1) { + cycle++; + setTimeout(plLoadPage, 0); + return; + } + + var formats = reportFormat.split(","); + + for each (var fmt in formats) + dumpLine(report.getReport(fmt)); + + if (renderReport) { + dumpLine ("*************** Render report *******************"); + for each (var fmt in formats) + dumpLine(renderReport.getReport(fmt)); + } + } + } catch (e) { + dumpLine(e); + } + + if (content) + content.removeEventListener('load', plLoadHandler, true); + + goQuitApplication(); +} + +/* Returns array */ +function plLoadURLsFromURI(uri) { + var data = ""; + var fstream = Cc["@mozilla.org/network/file-input-stream;1"] + .createInstance(Ci.nsIFileInputStream); + var sstream = Cc["@mozilla.org/scriptableinputstream;1"] + .createInstance(Ci.nsIScriptableInputStream); + var uriFile = uri.QueryInterface(Ci.nsIFileURL); + fstream.init(uriFile.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"); + + // get rid of things that start with # (comments), + // or that don't have the load string, if given + p = p.filter(function(s) { + if (s == "" || s.indexOf("#") == 0) + return false; + if (pageFilterRegexp && !pageFilterRegexp.test(s)) + return false; + return true; + }); + + // stick urlPrefix to the start if necessary + if (urlPrefix) + p = p.map(function(s) { return urlPrefix + s; }); + + return p; +} + +function dumpLine(str) { + dump(str); + dump("\n"); +} diff --git a/mozilla/layout/tools/pageloader/pageloader.xul b/mozilla/layout/tools/pageloader/pageloader.xul new file mode 100644 index 00000000000..cc33d4bb1ba --- /dev/null +++ b/mozilla/layout/tools/pageloader/pageloader.xul @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + diff --git a/mozilla/layout/tools/pageloader/quit.js b/mozilla/layout/tools/pageloader/quit.js new file mode 100644 index 00000000000..ab3b0fdf8c2 --- /dev/null +++ b/mozilla/layout/tools/pageloader/quit.js @@ -0,0 +1,129 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is The Original Code is Mozilla Automated Testing Code + * + * The Initial Developer of the Original Code is + * Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 2005 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): Bob Clary + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + From mozilla/toolkit/content + These files did not have a license +*/ + +function canQuitApplication() +{ + var os = Components.classes["@mozilla.org/observer-service;1"] + .getService(Components.interfaces.nsIObserverService); + if (!os) + { + return true; + } + + try + { + var cancelQuit = Components.classes["@mozilla.org/supports-PRBool;1"] + .createInstance(Components.interfaces.nsISupportsPRBool); + os.notifyObservers(cancelQuit, "quit-application-requested", null); + + // Something aborted the quit process. + if (cancelQuit.data) + { + return false; + } + } + catch (ex) + { + } + os.notifyObservers(null, "quit-application-granted", null); + return true; +} + +function goQuitApplication() +{ + if (!canQuitApplication()) + { + return false; + } + + const kAppStartup = '@mozilla.org/toolkit/app-startup;1'; + const kAppShell = '@mozilla.org/appshell/appShellService;1'; + var appService; + var forceQuit; + + if (kAppStartup in Components.classes) + { + appService = Components.classes[kAppStartup]. + getService(Components.interfaces.nsIAppStartup); + forceQuit = Components.interfaces.nsIAppStartup.eForceQuit; + } + else if (kAppShell in Components.classes) + { + appService = Components.classes[kAppShell]. + getService(Components.interfaces.nsIAppShellService); + forceQuit = Components.interfaces.nsIAppShellService.eForceQuit; + } + else + { + throw 'goQuitApplication: no AppStartup/appShell'; + } + + var windowManager = Components. + classes['@mozilla.org/appshell/window-mediator;1'].getService(); + + var windowManagerInterface = windowManager. + QueryInterface(Components.interfaces.nsIWindowMediator); + + var enumerator = windowManagerInterface.getEnumerator(null); + + while (enumerator.hasMoreElements()) + { + var domWindow = enumerator.getNext(); + if (("tryToClose" in domWindow) && !domWindow.tryToClose()) + { + return false; + } + domWindow.close(); + } + + try + { + appService.quit(forceQuit); + } + catch(ex) + { + throw('goQuitApplication: ' + ex); + } + + return true; +} + diff --git a/mozilla/layout/tools/pageloader/report.js b/mozilla/layout/tools/pageloader/report.js new file mode 100644 index 00000000000..0496b19cefb --- /dev/null +++ b/mozilla/layout/tools/pageloader/report.js @@ -0,0 +1,227 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is tp. + * + * The Initial Developer of the Original Code is + * Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * Rob Helmer + * Vladimir Vukicevic + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// 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(); + } +} + +// given an array of strings, finds the longest common prefix +function findCommonPrefixLength(strs) { + if (strs.length < 2) + return 0; + + var len = 0; + do { + var newlen = len + 1; + var newprefix = null; + var failed = false; + for (var i = 0; i < strs.length; i++) { + if (newlen > strs[i].length) { + failed = true; + break; + } + + var s = strs[i].substr(0, newlen); + if (newprefix == null) { + newprefix = s; + } else if (newprefix != s) { + failed = true; + break; + } + } + + if (failed) + break; + + len++; + } while (true); + return len; +} + +// 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) +function getArrayStats(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 + if (ary.length > 1) + r.mean = (sum - r.max) / (ary.length - 1); + else + r.mean = ary[0]; + + 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; + } + + if (ary.length > 1) { + r.vari = r.vari / (ary.length - 1); + r.stdd = Math.sqrt(r.vari); + } else { + r.vari = 0.0; + r.stdd = 0.0; + } + return r; +} + +function strPad(o, len, left) { + var str = o.toString(); + if (!len) + len = 6; + if (left == null) + left = true; + + if (str.length < len) { + len -= str.length; + while (--len) { + if (left) + str = " " + str; + else + str += " "; + } + } + + str += " "; + return str; +} + +Report.prototype.getReport = function(format) { + // 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] = getArrayStats(this.timeVals[i]).mean; + medians[i] = getArrayStats(this.timeVals[i]).median; + } + var avg = getArrayStats(avgs).mean; + var avgmed = getArrayStats(medians).mean; + + var report; + + var prefixLen = findCommonPrefixLength(pages); + + if (format == "js") { + // output "simple" js format; + // array of { page: "str", value: 123.4, stddev: 23.3 } objects + report = "(["; + for (var i = 0; i < this.timeVals.length; i++) { + var stats = getArrayStats(this.timeVals[i]); + report += uneval({ page: pages[i].substr(prefixLen), value: stats.mean, stddev: stats.stdd}); + report += ","; + } + report += "])"; + } else if (format == "jsfull") { + // output "full" js format, with raw values + } else if (format == "text") { + // output text format suitable for dumping + report = "============================================================\n"; + report += " " + strPad("Page", 40, false) + strPad("mean") + strPad("stdd") + strPad("min") + strPad("max") + "raw" + "\n"; + for (var i = 0; i < this.timeVals.length; i++) { + var stats = getArrayStats(this.timeVals[i]); + report += strPad(i, 4, true) + strPad(pages[i].substr(prefixLen), 40, false) + strPad(stats.mean.toFixed(0)) + strPad(stats.stdd.toFixed(0)) + strPad(stats.min.toFixed(0)) + strPad(stats.max.toFixed(0)) + this.timeVals[i] + "\n"; + } + report += "============================================================\n"; + } else if (format == "tinderbox") { + report = "__start_tp_report\n"; + report += "_x_x_mozilla_page_load,"+avgmed+",NaN,NaN\n"; // max and min are just 0, ignored + report += "_x_x_mozilla_page_load_details,avgmedian|"+avgmed+"|average|"+avg.toFixed(2)+"|minimum|NaN|maximum|NaN|stddev|NaN"; + + for (var i = 0; i < this.timeVals.length; i++) { + var r = getArrayStats(this.timeVals[i]); + report += '|'+ + i + ';'+ + pages[i].substr(prefixLen) + ';'+ + r.median + ';'+ + r.mean + ';'+ + r.min + ';'+ + r.max + ';'+ + this.timeVals[i].join(";") + + "\n"; + } + report += "__end_tp_report\n"; + } else { + report = "Unknown report format"; + } + + return report; +} + +Report.prototype.recordTime = function(pageIndex, ms) { + this.timeVals[pageIndex].push(ms); +} diff --git a/mozilla/layout/tools/pageloader/tp-cmdline.js b/mozilla/layout/tools/pageloader/tp-cmdline.js new file mode 100644 index 00000000000..2c545e922bb --- /dev/null +++ b/mozilla/layout/tools/pageloader/tp-cmdline.js @@ -0,0 +1,188 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is DOM Inspector. + * + * The Initial Developer of the Original Code is + * Christopher A. Aillon . + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Christopher A. Aillon + * L. David Baron, Mozilla Corporation (modified for reftest) + * Vladimir Vukicevic, Mozilla Corporation (modified for tp) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// This only implements nsICommandLineHandler, since it needs +// to handle multiple arguments. + +const TP_CMDLINE_CONTRACTID = "@mozilla.org/commandlinehandler/general-startup;1?type=tp"; +const TP_CMDLINE_CLSID = Components.ID('{8AF052F5-8EFE-4359-8266-E16498A82E8B}'); +const CATMAN_CONTRACTID = "@mozilla.org/categorymanager;1"; +const nsISupports = Components.interfaces.nsISupports; + +const nsICategoryManager = Components.interfaces.nsICategoryManager; +const nsICommandLine = Components.interfaces.nsICommandLine; +const nsICommandLineHandler = Components.interfaces.nsICommandLineHandler; +const nsIComponentRegistrar = Components.interfaces.nsIComponentRegistrar; +const nsISupportsString = Components.interfaces.nsISupportsString; +const nsIWindowWatcher = Components.interfaces.nsIWindowWatcher; + +function PageLoaderCmdLineHandler() {} +PageLoaderCmdLineHandler.prototype = +{ + /* nsISupports */ + QueryInterface : function handler_QI(iid) { + if (iid.equals(nsISupports)) + return this; + + if (nsICommandLineHandler && iid.equals(nsICommandLineHandler)) + return this; + + throw Components.results.NS_ERROR_NO_INTERFACE; + }, + + /* nsICommandLineHandler */ + handle : function handler_handle(cmdLine) { + var args = {}; + try { + var uristr = cmdLine.handleFlagWithParam("tp", false); + if (uristr == null) + return; + try { + args.manifest = cmdLine.resolveURI(uristr).spec; + } catch (e) { + return; + } + + args.numCycles = cmdLine.handleFlagWithParam("tpcycles", false); + args.startIndex = cmdLine.handleFlagWithParam("tpstart", false); + args.endIndex = cmdLine.handleFlagWithParam("tpend", false); + args.filter = cmdLine.handleFlagWithParam("tpfilter", false); + args.format = cmdLine.handleFlagWithParam("tpformat", false); + args.useBrowserChrome = cmdLine.handleFlag("tpchrome", false); + args.doRender = cmdLine.handleFlag("tprender", false); + args.width = cmdLine.handleFlagWithParam("tpwidth", false); + args.height = cmdLine.handleFlagWithParam("tpheight", false); + args.prefix = cmdLine.handleFlagWithParam("tpprefix", false); + args.offline = cmdLine.handleFlag("tpoffline", false); + } + catch (e) { + return; + } + + // get our data through xpconnect + args.wrappedJSObject = args; + + var wwatch = Components.classes["@mozilla.org/embedcomp/window-watcher;1"] + .getService(nsIWindowWatcher); + wwatch.openWindow(null, "chrome://pageloader/content/pageloader.xul", "_blank", + "chrome,dialog=no,all", args); + cmdLine.preventDefault = true; + }, + + helpInfo : + " -tp Run pageload perf tests on given manifest\n" + + " -tpfilter str Only include pages from manifest that contain str (regexp)\n" + + " -tpcycles n Loop through pages n times\n" + + " -tpstart n Start at index n in the manifest\n" + + " -tpend n End with index n in the manifest\n" + + " -tpformat f1,f2,.. Report format(s) to use\n" + + " -tpchrome Test with normal browser chrome\n" + + " -tprender Run render-only benchmark for each page\n" + + " -tpwidth width Width of window\n" + + " -tpheight height Height of window\n" + + " -tpprefix prefix Add 'prefix' to the start of each line in the manifest\n" + + " -tpoffline Force offline mode\n" +}; + + +var PageLoaderCmdLineFactory = +{ + createInstance : function(outer, iid) + { + if (outer != null) { + throw Components.results.NS_ERROR_NO_AGGREGATION; + } + + return new PageLoaderCmdLineHandler().QueryInterface(iid); + } +}; + + +var PageLoaderCmdLineModule = +{ + registerSelf : function(compMgr, fileSpec, location, type) + { + compMgr = compMgr.QueryInterface(nsIComponentRegistrar); + + compMgr.registerFactoryLocation(TP_CMDLINE_CLSID, + "PageLoader CommandLine Service", + TP_CMDLINE_CONTRACTID, + fileSpec, + location, + type); + + var catman = Components.classes[CATMAN_CONTRACTID].getService(nsICategoryManager); + catman.addCategoryEntry("command-line-handler", + "m-tp", + TP_CMDLINE_CONTRACTID, true, true); + }, + + unregisterSelf : function(compMgr, fileSpec, location) + { + compMgr = compMgr.QueryInterface(nsIComponentRegistrar); + + compMgr.unregisterFactoryLocation(TP_CMDLINE_CLSID, fileSpec); + catman = Components.classes[CATMAN_CONTRACTID].getService(nsICategoryManager); + catman.deleteCategoryEntry("command-line-handler", + "m-tp", true); + }, + + getClassObject : function(compMgr, cid, iid) + { + if (cid.equals(TP_CMDLINE_CLSID)) { + return PageLoaderCmdLineFactory; + } + + if (!iid.equals(Components.interfaces.nsIFactory)) { + throw Components.results.NS_ERROR_NOT_IMPLEMENTED; + } + + throw Components.results.NS_ERROR_NO_INTERFACE; + }, + + canUnload : function(compMgr) + { + return true; + } +}; + + +function NSGetModule(compMgr, fileSpec) { + return PageLoaderCmdLineModule; +}