# HG changeset patch # User Jeff Hammel # Date 1329179046 28800 # Node ID 3f290bcae11ab10fd28eecd88fb3051b7b280057 # Parent 7bad4b7281f251ea23514123a2f8ad37070aac39# Parent beca399c3a16ef1831f7f887c608a5ef2224b564 wtf diff -r 7bad4b7281f2 -r 3f290bcae11a README --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/README Mon Feb 13 16:24:06 2012 -0800 @@ -0,0 +1,81 @@ +Pageload Test Component +======================= + +Usage: + + ./firefox -tp file:///path/to/manifest.txt [-tpargs...] + +See ./firefox -help for other arguments. + + +Manifest file format +==================== + +Comments in the manifest file start with a #. Each line may be: + +* a URL (absolute or relative to the manifest) + +This URL is added to the list of tests. + +* one or more flags, followed by whitespace, followed by a URL + +The only flag supported currently is '%', which indicates that +a test will do its own timing. (See Self-timing Tests below.) + +* "include" followed by whitespace, followed by a URL + +Parse the given manifest file. + +Self-timing Tests +================= + +Most timing tests are interested in timing how long it takes the page +to load; that is, from the start of page loading until the 'load' +event is dispatched. By default, this is what the pageloader will +time. However, if a test URL has the % flag, the test is expected to +report its own timing. For this purpose, the pageloader will provide +a function named "tpRecordTime" in the test's global object that it +should call once it has performed whatever timing it wants to do. +The given value will be used as the timing result for this test. + +Output format +============= + +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 -r 7bad4b7281f2 -r 3f290bcae11a chrome.manifest --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/chrome.manifest Mon Feb 13 16:24:06 2012 -0800 @@ -0,0 +1,4 @@ +content pageloader chrome/ +component {8AF052F5-8EFE-4359-8266-E16498A82E8B} components/tp-cmdline.js +contract @mozilla.org/commandlinehandler/general-startup;1?type=tp {8AF052F5-8EFE-4359-8266-E16498A82E8B} +category command-line-handler m-tp @mozilla.org/commandlinehandler/general-startup;1?type=tp diff -r 7bad4b7281f2 -r 3f290bcae11a chrome/MozillaFileLogger.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/chrome/MozillaFileLogger.js Mon Feb 13 16:24:06 2012 -0800 @@ -0,0 +1,153 @@ +/** + * MozillaFileLogger, a log listener that can write to a local file. + */ + +var ipcMode = false; // running in e10s build and need to use IPC? +try { + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + var ipcsanity = Components.classes["@mozilla.org/preferences-service;1"] + .getService(Components.interfaces.nsIPrefBranch); + ipcsanity.setIntPref("mochitest.ipcmode", 0); +} catch (e) { + ipcMode = true; +} + +function contentDispatchEvent(type, data, sync) { + if (typeof(data) === "undefined") { + data = {}; + } + + var element = document.createEvent("datacontainerevent"); + element.initEvent("contentEvent", true, false); + element.setData("sync", sync); + element.setData("type", type); + element.setData("data", JSON.stringify(data)); + document.dispatchEvent(element); +} + +function contentSyncEvent(type, data) { + contentDispatchEvent(type, data, 1); +} + +function contentAsyncEvent(type, data) { + contentDispatchEvent(type, data, 0); +} + +try { + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + + if (Cc === undefined) { + var Cc = Components.classes; + var Ci = Components.interfaces; + } +} catch (ex) {} //running in ipcMode-chrome + +try { + const FOSTREAM_CID = "@mozilla.org/network/file-output-stream;1"; + const LF_CID = "@mozilla.org/file/local;1"; + + // File status flags. It is a bitwise OR of the following bit flags. + // Only one of the first three flags below may be used. + const PR_READ_ONLY = 0x01; // Open for reading only. + const PR_WRITE_ONLY = 0x02; // Open for writing only. + const PR_READ_WRITE = 0x04; // Open for reading and writing. + + // If the file does not exist, the file is created. + // If the file exists, this flag has no effect. + const PR_CREATE_FILE = 0x08; + + // The file pointer is set to the end of the file prior to each write. + const PR_APPEND = 0x10; + + // If the file exists, its length is truncated to 0. + const PR_TRUNCATE = 0x20; + + // If set, each write will wait for both the file data + // and file status to be physically updated. + const PR_SYNC = 0x40; + + // If the file does not exist, the file is created. If the file already + // exists, no action and NULL is returned. + const PR_EXCL = 0x80; +} catch (ex) { + // probably not running in the test harness +} + +/** Init the file logger with the absolute path to the file. + It will create and append if the file already exists **/ +var MozillaFileLogger = {}; + + +MozillaFileLogger.init = function(path) { + if (ipcMode) { + contentAsyncEvent("LoggerInit", {"filename": path}); + return; + } + + try { + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + } catch (ex) {} //running in ipcMode-chrome + + MozillaFileLogger._file = Cc[LF_CID].createInstance(Ci.nsILocalFile); + MozillaFileLogger._file.initWithPath(path); + MozillaFileLogger._foStream = Cc[FOSTREAM_CID].createInstance(Ci.nsIFileOutputStream); + MozillaFileLogger._foStream.init(this._file, PR_WRITE_ONLY | PR_CREATE_FILE | PR_APPEND, + 0664, 0); +} + +MozillaFileLogger.getLogCallback = function() { + if (ipcMode) { + return function(msg) { + contentAsyncEvent("Logger", {"num": msg.num, "level": msg.level, "info": msg.info.join(' ')}); + } + } + + return function (msg) { + try { + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + } catch(ex) {} //running in ipcMode-chrome + + var data = msg.num + " " + msg.level + " " + msg.info.join(' ') + "\n"; + if (MozillaFileLogger._foStream) + MozillaFileLogger._foStream.write(data, data.length); + + if (data.indexOf("SimpleTest FINISH") >= 0) { + MozillaFileLogger.close(); + } + } +} + +// This is only used from chrome space by the reftest harness +MozillaFileLogger.log = function(msg) { + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + if (MozillaFileLogger._foStream) + MozillaFileLogger._foStream.write(msg, msg.length); +} + +MozillaFileLogger.close = function() { + if (ipcMode) { + contentAsyncEvent("LoggerClose"); + return; + } + + try { + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + } catch(ex) {} //running in ipcMode-chrome + + if(MozillaFileLogger._foStream) + MozillaFileLogger._foStream.close(); + + MozillaFileLogger._foStream = null; + MozillaFileLogger._file = null; +} + +if (ipcMode == false) { + try { + var prefs = Components.classes['@mozilla.org/preferences-service;1'] + .getService(Components.interfaces.nsIPrefBranch2); + var filename = prefs.getCharPref('talos.logfile'); + MozillaFileLogger.init(filename); + } catch (ex) {} //pref does not exist, return empty string +} + + diff -r 7bad4b7281f2 -r 3f290bcae11a chrome/memory.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/chrome/memory.js Mon Feb 13 16:24:06 2012 -0800 @@ -0,0 +1,95 @@ + +var gChildProcess = true; +var gMemCallback = null; + + +/* + * Initialize memory collector. Determine if we have a child process. + */ +function initializeMemoryCollector(callback, args) { + gMemCallback = function() { return callback(args); }; + + var os = Components.classes["@mozilla.org/observer-service;1"]. + getService(Components.interfaces.nsIObserverService); + + os.addObserver(function () { + var os = Components.classes["@mozilla.org/observer-service;1"]. + getService(Components.interfaces.nsIObserverService); + + memTimer.cancel(); + memTimer = null; + + os.removeObserver(arguments.callee, "child-memory-reporter-update", false); + os.addObserver(collectAndReport, "child-memory-reporter-update", false); + gMemCallback(); + }, "child-memory-reporter-update", false); + + /* + * Assume we have a child process, but if timer fires before we call the observer + * we will assume there is no child process. + */ + var event = { + notify: function(timer) { + memTimer = null; + gChildProcess = false; + gMemCallback(); + } + } + + memTimer = Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer); + memTimer.initWithCallback(event, 10000, Components.interfaces.nsITimer.TYPE_ONE_SHOT); + + os.notifyObservers(null, "child-memory-reporter-request", null); +} + +/* + * Collect memory from all processes and callback when done collecting. + */ +function collectMemory(callback, args) { + gMemCallback = function() { return callback(args); }; + + if (gChildProcess) { + var os = Components.classes["@mozilla.org/observer-service;1"]. + getService(Components.interfaces.nsIObserverService); + + os.notifyObservers(null, "child-memory-reporter-request", null); + } else { + collectAndReport(null, null, null); + } +} + +function collectAndReport(aSubject, aTopic, aData) { + dumpLine(collectRSS()); + gMemCallback(); +} + +function collectRSS() { + var mgr = Components.classes["@mozilla.org/memory-reporter-manager;1"]. + getService(Components.interfaces.nsIMemoryReporterManager); + var e = mgr.enumerateReporters(); + text = ""; + while (e.hasMoreElements()) { + var reporter = e.getNext().QueryInterface(Components.interfaces.nsIMemoryReporter); + if (reporter.path == 'resident') { + procName = reporter.process; + if (procName == '') + procName = "Main"; + + //For content process it is in the format "Content ()", we just want Content + procName = procName.split(' ')[0]; + text += "RSS: " + procName + ": " + reporter.amount + "\n"; + } + } + return text; +} + +/* + * Cleanup and stop memory collector. + */ +function stopMemCollector() { + if (gChildProcess) { + var os = Cc["@mozilla.org/observer-service;1"]. + getService(Ci.nsIObserverService); + os.removeObserver(collectAndReport, "child-memory-reporter-update"); + } +} diff -r 7bad4b7281f2 -r 3f290bcae11a chrome/pageloader.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/chrome/pageloader.js Mon Feb 13 16:24:06 2012 -0800 @@ -0,0 +1,706 @@ +/* -*- 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 ***** */ + +try { + if (Cc === undefined) { + var Cc = Components.classes; + var Ci = Components.interfaces; + } +} catch (ex) {} + +var NUM_CYCLES = 5; + +var pageFilterRegexp = null; +var reportFormat = "js"; +var useBrowser = true; +var winWidth = 1024; +var winHeight = 768; + +var doRenderTest = false; + +var pages; +var pageIndex; +var start_time; +var cycle; +var report; +var renderReport; +var noisy = false; +var timeout = -1; +var delay = 250; +var timeoutEvent = -1; +var running = false; +var forceCC = true; +var reportRSS = false; + +var useMozAfterPaint = false; +var gPaintWindow = window; +var gPaintListener = false; + +//when TEST_DOES_OWN_TIMING, we need to store the time from the page as MozAfterPaint can be slower than pageload +var gTime = -1; +var gStartTime = -1; + +var content; + +var TEST_DOES_OWN_TIMING = 1; + +var browserWindow = null; + +// the io service +var gIOS = null; + +function plInit() { + if (running) { + return; + } + running = true; + + cycle = 0; + + 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.noisy) noisy = true; + if (args.timeout) timeout = parseInt(args.timeout); + if (args.delay) delay = parseInt(args.delay); + if (args.mozafterpaint) useMozAfterPaint = true; + if (args.rss) reportRSS = true; + + forceCC = !args.noForceCC; + doRenderTest = args.doRender; + + if (forceCC && + !window.QueryInterface(Components.interfaces.nsIInterfaceRequestor) + .getInterface(Components.interfaces.nsIDOMWindowUtils) + .garbageCollect) { + forceCC = false; + } + + gIOS = Cc["@mozilla.org/network/io-service;1"] + .getService(Ci.nsIIOService); + if (args.offline) + gIOS.offline = true; + var fileURI = gIOS.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); + var pageUrls = pages.map(function(p) { return p.url.spec.toString(); }); + report = new Report(pageUrls); + + if (doRenderTest) + renderReport = new Report(pageUrls); + + 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,all,dialog=no,width=" + winWidth + ",height=" + winHeight, blank); + + gPaintWindow = browserWindow; + // 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(); + + // Load the frame script for e10s / IPC message support + if (content.getAttribute("remote") == "true") { + let contentScript = "data:,function _contentLoadHandler(e) { " + + " if (e.originalTarget.defaultView == content) { " + + " content.wrappedJSObject.tpRecordTime = function(t, s) { sendAsyncMessage('PageLoader:RecordTime', { time: t, startTime: s }); }; "; + if (useMozAfterPaint) { + contentScript += "" + + "function _contentPaintHandler() { " + + " var utils = content.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIDOMWindowUtils); " + + " if (utils.isMozAfterPaintPending) { " + + " addEventListener('MozAfterPaint', function(e) { " + + " removeEventListener('MozAfterPaint', arguments.callee, true); " + + " sendAsyncMessage('PageLoader:MozAfterPaint', {}); " + + " }, true); " + + " } else { " + + " sendAsyncMessage('PageLoader:MozAfterPaint', {}); " + + " } " + + "}; " + + "content.wrappedJSObject.setTimeout(_contentPaintHandler, 0); "; + } else { + contentScript += " sendAsyncMessage('PageLoader:Load', {}); "; + } + contentScript += "" + + " }" + + "} " + + "addEventListener('load', _contentLoadHandler, true); "; + content.messageManager.loadFrameScript(contentScript, false); + } + if (reportRSS) { + initializeMemoryCollector(plLoadPage, 100); + } else { + setTimeout(plLoadPage, 100); + } + }, 500); + }; + + browserWindow.addEventListener('load', browserLoadFunc, true); + } else { + gPaintWindow = window; + window.resizeTo(winWidth, winHeight); + + content = document.getElementById('contentPageloader'); + + if (reportRSS) { + initializeMemoryCollector(plLoadPage, delay); + } else { + setTimeout(plLoadPage, delay); + } + } + } catch(e) { + dumpLine(e); + plStop(true); + } +} + +function plPageFlags() { + return pages[pageIndex].flags; +} + +// load the current page, start timing +var removeLastAddedListener = null; +var removeLastAddedMsgListener = null; +function plLoadPage() { + var pageName = pages[pageIndex].url.spec; + + if (removeLastAddedListener) + removeLastAddedListener(); + + if (removeLastAddedMsgListener) + removeLastAddedMsgListener(); + + if (plPageFlags() & TEST_DOES_OWN_TIMING) { + // if the page does its own timing, use a capturing handler + // to make sure that we can set up the function for content to call + + content.addEventListener('load', plLoadHandlerCapturing, true); + removeLastAddedListener = function() { + content.removeEventListener('load', plLoadHandlerCapturing, true); + if (useMozAfterPaint) { + content.removeEventListener("MozAfterPaint", plPaintedCapturing, true); + gPaintHandler = false; + } + }; + } else { + // if the page doesn't do its own timing, use a bubbling handler + // to make sure that we're called after the page's own onload() handling + + // XXX we use a capturing event here too -- load events don't bubble up + // to the element. See bug 390263. + content.addEventListener('load', plLoadHandler, true); + removeLastAddedListener = function() { + content.removeEventListener('load', plLoadHandler, true); + if (useMozAfterPaint) { + gPaintWindow.removeEventListener("MozAfterPaint", plPainted, true); + gPaintHandler = false; + } + }; + } + + // If the test browser is remote (e10s / IPC) we need to use messages to watch for page load + if (content.getAttribute("remote") == "true") { + content.messageManager.addMessageListener('PageLoader:Load', plLoadHandlerMessage); + content.messageManager.addMessageListener('PageLoader:RecordTime', plRecordTimeMessage); + if (useMozAfterPaint) + content.messageManager.addMessageListener('PageLoader:MozAfterPaint', plPaintHandler); + removeLastAddedMsgListener = function() { + content.messageManager.removeMessageListener('PageLoader:Load', plLoadHandlerMessage); + content.messageManager.removeMessageListener('PageLoader:RecordTime', plRecordTimeMessage); + if (useMozAfterPaint) + content.messageManager.removeMessageListener('PageLoader:MozAfterPaint', plPaintHandler); + }; + } + + if (timeout > 0) { + timeoutEvent = setTimeout('loadFail()', timeout); + } + if (reportRSS) { + collectMemory(startAndLoadURI, pageName); + } else { + startAndLoadURI(pageName); + } +} + +function startAndLoadURI(pageName) { + start_time = Date.now(); + content.loadURI(pageName); +} + +function loadFail() { + var pageName = pages[pageIndex].url.spec; + dumpLine("__FAILTimeout exceeded on " + pageName + "__FAIL") + plStop(true); +} + +function plNextPage() { + if (pageIndex < pages.length-1) { + pageIndex++; + + if (forceCC) { + var tccstart = new Date(); + window.QueryInterface(Components.interfaces.nsIInterfaceRequestor) + .getInterface(Components.interfaces.nsIDOMWindowUtils) + .garbageCollect(); + var tccend = new Date(); + report.recordCCTime(tccend - tccstart); + } + + setTimeout(plLoadPage, delay); + } else { + plStop(false); + } +} + +function plRecordTime(time) { + var pageName = pages[pageIndex].url.spec; + var i = pageIndex + if (i < pages.length-1) { + i++; + } else { + i = 0; + } + var nextName = pages[i].url.spec; + report.recordTime(pageIndex, time); + if (noisy) { + dumpLine("Cycle " + (cycle+1) + ": loaded " + pageName + " (next: " + nextName + ")"); + } +} + +function plLoadHandlerCapturing(evt) { + // make sure we pick up the right load event + if (evt.type != 'load' || + evt.originalTarget.defaultView.frameElement) + return; + + //set the tpRecordTime function (called from test pages we load to store a global time. + content.contentWindow.wrappedJSObject.tpRecordTime = function (time, startTime) { + gTime = time; + gStartTime = startTime; + setTimeout(plWaitForPaintingCapturing, 0); + } + + content.removeEventListener('load', plLoadHandlerCapturing, true); + + setTimeout(plWaitForPaintingCapturing, 0); +} + +function plWaitForPaintingCapturing() { + if (gPaintListener) + return; + + var utils = gPaintWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor) + .getInterface(Components.interfaces.nsIDOMWindowUtils); + + if (utils.isMozAfterPaintPending && useMozAfterPaint) { + if (gPaintListener == false) + gPaintWindow.addEventListener("MozAfterPaint", plPaintedCapturing, true); + gPaintListener = true; + return; + } + + _loadHandlerCapturing(); +} + +function plPaintedCapturing() { + gPaintWindow.removeEventListener("MozAfterPaint", plPaintedCapturing, true); + gPaintListener = false; + _loadHandlerCapturing(); +} + +function _loadHandlerCapturing() { + if (timeout > 0) { + clearTimeout(timeoutEvent); + } + + if (!(plPageFlags() & TEST_DOES_OWN_TIMING)) { + dumpLine("tp: Capturing onload handler used with page that doesn't do its own timing?"); + plStop(true); + } + + if (useMozAfterPaint) { + if (gStartTime != null && gStartTime >= 0) { + gTime = (new Date()) - gStartTime; + gStartTime = -1; + } + } + + // set up the function for content to call + if (gTime >= 0) { + plRecordTime(gTime); + gTime = -1; + setTimeout(plNextPage, delay); + }; +} + +// the onload handler +function plLoadHandler(evt) { + // make sure we pick up the right load event + if (evt.type != 'load' || + evt.originalTarget.defaultView.frameElement) + return; + + content.removeEventListener('load', plLoadHandler, true); + setTimeout(waitForPainted, 0); +} + +// This is called after we have received a load event, now we wait for painted +function waitForPainted() { + + var utils = gPaintWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor) + .getInterface(Components.interfaces.nsIDOMWindowUtils); + + if (!utils.isMozAfterPaintPending || !useMozAfterPaint) { + _loadHandler(); + return; + } + + if (gPaintListener == false) + gPaintWindow.addEventListener("MozAfterPaint", plPainted, true); + gPaintListener = true; +} + +function plPainted() { + gPaintWindow.removeEventListener("MozAfterPaint", plPainted, true); + gPaintListener = false; + _loadHandler(); +} + +function _loadHandler() { + if (timeout > 0) { + clearTimeout(timeoutEvent); + } + var docElem; + if (browserWindow) + docElem = browserWindow.frames["content"].document.documentElement; + else + docElem = content.contentDocument.documentElement; + var width; + if ("getBoundingClientRect" in docElem) { + width = docElem.getBoundingClientRect().width; + } else if ("offsetWidth" in docElem) { + width = docElem.offsetWidth; + } + + var end_time = Date.now(); + var time = (end_time - start_time); + + // does this page want to do its own timing? + // if so, we shouldn't be here + if (plPageFlags() & TEST_DOES_OWN_TIMING) { + dumpLine("tp: Bubbling onload handler used with page that does its own timing?"); + plStop(true); + } + + plRecordTime(time); + + if (doRenderTest) + runRenderTest(); + + plNextPage(); +} + +// the onload handler used for remote (e10s) browser +function plLoadHandlerMessage(message) { + _loadHandlerMessage(); +} + +// the mozafterpaint handler for remote (e10s) browser +function plPaintHandler(message) { + _loadHandlerMessage(); +} + +// the core handler for remote (e10s) browser +function _loadHandlerMessage() { + if (timeout > 0) { + clearTimeout(timeoutEvent); + } + + var time = -1; + + // does this page want to do its own timing? + if ((plPageFlags() & TEST_DOES_OWN_TIMING)) { + if (typeof(gStartTime) != "number") + gStartTime = Date.parse(gStartTime); + + if (gTime >= 0) { + if (useMozAfterPaint && gStartTime >= 0) { + gTime = Date.now() - gStartTime; + gStartTime = -1; + } else if (useMozAfterPaint) { + gTime = -1; + } + time = gTime; + gTime = -1; + } + + } else { + var end_time = Date.now(); + time = (end_time - start_time); + } + + if (time >= 0) { + plRecordTime(time); + if (doRenderTest) + runRenderTest(); + + plNextPage(); + } +} + +// the record time handler used for remote (e10s) browser +function plRecordTimeMessage(message) { + gTime = message.json.time; + if (useMozAfterPaint) { + gStartTime = message.json.startTime; + } + _loadHandlerMessage(); +} + +function runRenderTest() { + const redrawsPerSample = 500; + + if (!Ci.nsIDOMWindowUtils) + return; + + var win; + + if (browserWindow) + win = content.contentWindow; + else + win = window; + var wu = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils); + + 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) { + if (reportRSS) { + collectMemory(plStopAll, force); + } else { + plStopAll(force); + } +} + +function plStopAll(force) { + try { + if (force == false) { + pageIndex = 0; + if (cycle < NUM_CYCLES-1) { + cycle++; + setTimeout(plLoadPage, delay); + return; + } + + var formats = reportFormat.split(","); + + if (!renderReport) { + for each (var fmt in formats) + dumpLine(report.getReport(fmt)); + } + else { + dumpLine ("*************** Render report *******************"); + for each (var fmt in formats) + dumpLine(renderReport.getReport(fmt)); + } + } + } catch (e) { + dumpLine(e); + } + + if (reportRSS) { + stopMemCollector(); + } + + if (content) { + content.removeEventListener('load', plLoadHandlerCapturing, true); + content.removeEventListener('load', plLoadHandler, true); + if (useMozAfterPaint) + content.removeEventListener("MozAfterPaint", plPaintedCapturing, true); + content.removeEventListener("MozAfterPaint", plPainted, true); + + if (content.getAttribute("remote") == "true") { + content.messageManager.removeMessageListener('PageLoader:Load', plLoadHandlerMessage); + content.messageManager.removeMessageListener('PageLoader:RecordTime', plRecordTimeMessage); + if (useMozAfterPaint) + content.messageManager.removeMessageListener('PageLoader:MozAfterPaint', plPaintHandler); + + content.messageManager.loadFrameScript("data:,removeEventListener('load', _contentLoadHandler, true);", false); + } + } + + if (MozillaFileLogger) + MozillaFileLogger.close(); + + goQuitApplication(); +} + +/* Returns array */ +function plLoadURLsFromURI(manifestUri) { + var fstream = Cc["@mozilla.org/network/file-input-stream;1"] + .createInstance(Ci.nsIFileInputStream); + var uriFile = manifestUri.QueryInterface(Ci.nsIFileURL); + + fstream.init(uriFile.file, -1, 0, 0); + var lstream = fstream.QueryInterface(Ci.nsILineInputStream); + + var d = []; + + var lineNo = 0; + var line = {value:null}; + var more; + do { + lineNo++; + more = lstream.readLine(line); + var s = line.value; + + // strip comments + s = s.replace(/#.*/, ''); + + // strip leading and trailing whitespace + s = s.replace(/^\s*/, '').replace(/\s*$/, ''); + + if (!s) + continue; + + var flags = 0; + var urlspec = s; + + // split on whitespace, and figure out if we have any flags + var items = s.split(/\s+/); + if (items[0] == "include") { + if (items.length != 2) { + dumpLine("tp: Error on line " + lineNo + " in " + manifestUri.spec + ": include must be followed by the manifest to include!"); + return null; + } + + var subManifest = gIOS.newURI(items[1], null, manifestUri); + if (subManifest == null) { + dumpLine("tp: invalid URI on line " + manifestUri.spec + ":" + lineNo + " : '" + line.value + "'"); + return null; + } + + var subItems = plLoadURLsFromURI(subManifest); + if (subItems == null) + return null; + d = d.concat(subItems); + } else { + if (items.length == 2) { + if (items[0].indexOf("%") != -1) + flags |= TEST_DOES_OWN_TIMING; + + urlspec = items[1]; + } else if (items.length != 1) { + dumpLine("tp: Error on line " + lineNo + " in " + manifestUri.spec + ": whitespace must be %-escaped!"); + return null; + } + + var url = gIOS.newURI(urlspec, null, manifestUri); + + if (pageFilterRegexp && !pageFilterRegexp.test(url.spec)) + continue; + + d.push({ url: url, + flags: flags }); + } + } while (more); + + return d; +} + +function dumpLine(str) { + if (MozillaFileLogger) + MozillaFileLogger.log(str + "\n"); + dump(str); + dump("\n"); +} diff -r 7bad4b7281f2 -r 3f290bcae11a chrome/pageloader.xul --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/chrome/pageloader.xul Mon Feb 13 16:24:06 2012 -0800 @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + diff -r 7bad4b7281f2 -r 3f290bcae11a chrome/quit.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/chrome/quit.js Mon Feb 13 16:24:06 2012 -0800 @@ -0,0 +1,110 @@ +/* -*- 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) + { + } + 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'; + } + + try + { + appService.quit(forceQuit); + } + catch(ex) + { + throw('goQuitApplication: ' + ex); + } + + return true; +} + diff -r 7bad4b7281f2 -r 3f290bcae11a chrome/report.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/chrome/report.js Mon Feb 13 16:24:06 2012 -0800 @@ -0,0 +1,268 @@ +/* -*- 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(); + } + this.totalCCTime = 0; + this.showTotalCCTime = false; +} + +// 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; +} + +function compareNumbers(a, b) { + return a - b; +} + +// 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 + if (ary.length > 1) { + sorted_ary = ary.concat(); + sorted_ary.sort(compareNumbers); + // 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); + if (n >= sorted_ary.length) + r.median = sorted_ary[n]; + else + r.median = (sorted_ary[n-1] + sorted_ary[n]) / 2; + } + }else{ + r.median = ary[0]; + } + + // 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; +} + +function strPadFixed(n, len, left) { + return strPad(n.toFixed(0), len, left); +} + +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(this.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: this.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(this.pages[i].substr(prefixLen), 40, false) + + strPadFixed(stats.mean) + + strPadFixed(stats.stdd) + + strPadFixed(stats.min) + + strPadFixed(stats.max) + + this.timeVals[i] + + "\n"; + } + if (this.showTotalCCTime) { + report += "Cycle collection: " + this.totalCCTime + "\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\n"; + report += "|i|pagename|median|mean|min|max|runs|\n"; + + for (var i = 0; i < this.timeVals.length; i++) { + var r = getArrayStats(this.timeVals[i]); + report += '|'+ + i + ';'+ + this.pages[i].substr(prefixLen) + ';'+ + r.median + ';'+ + r.mean + ';'+ + r.min + ';'+ + r.max + ';'+ + this.timeVals[i].join(";") + + "\n"; + } + report += "__end_tp_report\n"; + if (this.showTotalCCTime) { + report += "__start_cc_report\n"; + report += "_x_x_mozilla_cycle_collect," + this.totalCCTime + "\n"; + report += "__end_cc_report\n"; + } + var now = (new Date()).getTime(); + report += "__startTimestamp" + now + "__endTimestamp\n"; //timestamp for determning shutdown time, used by talos + } else { + report = "Unknown report format"; + } + + return report; +} + +Report.prototype.recordTime = function(pageIndex, ms) { + this.timeVals[pageIndex].push(ms); +} + +Report.prototype.recordCCTime = function(ms) { + this.totalCCTime += ms; + this.showTotalCCTime = true; +} diff -r 7bad4b7281f2 -r 3f290bcae11a components/tp-cmdline.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/components/tp-cmdline.js Mon Feb 13 16:24:06 2012 -0800 @@ -0,0 +1,197 @@ +/* ***** 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.offline = cmdLine.handleFlag("tpoffline", false); + args.noisy = cmdLine.handleFlag("tpnoisy", false); + args.timeout = cmdLine.handleFlagWithParam("tptimeout", false); + args.delay = cmdLine.handleFlagWithParam("tpdelay", false); + args.noForceCC = cmdLine.handleFlag("tpnoforcecc", false); + args.mozafterpaint = cmdLine.handleFlag("tpmozafterpaint", false); + args.rss = cmdLine.handleFlag("rss", 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" + + " -tpoffline Force offline mode\n" + + " -tpnoisy Dump the name of the last loaded page to console\n" + + " -tptimeout Max amount of time given for a page to load, quit if exceeded\n" + + " -tpdelay Amount of time to wait between each pageload\n" + + " -tpnoforcecc Don't force cycle collection between each pageload\n" + + " -tpmozafterpaint Measure Time after recieving MozAfterPaint event instead of load event\n" + + " -rss Dump RSS after each page is loaded\n" + +}; + + +var PageLoaderCmdLineFactory = +{ + createInstance : function(outer, iid) + { + if (outer != null) { + throw Components.results.NS_ERROR_NO_AGGREGATION; + } + + return new PageLoaderCmdLineHandler().QueryInterface(iid); + } +}; + +function NSGetFactory(cid) { + if (!cid.equals(TP_CMDLINE_CLSID)) + throw Components.results.NS_ERROR_NOT_IMPLEMENTED; + + return PageLoaderCmdLineFactory; +} + +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) + { + return NSGetFactory(cid); + }, + + canUnload : function(compMgr) + { + return true; + } +}; + + +function NSGetModule(compMgr, fileSpec) { + return PageLoaderCmdLineModule; +} diff -r 7bad4b7281f2 -r 3f290bcae11a install.rdf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/install.rdf Mon Feb 13 16:24:06 2012 -0800 @@ -0,0 +1,20 @@ + + + + + pageloader@mozilla.org + 1.0 + + + toolkit@mozilla.org + 2.0b3pre + * + + + + PageLoader extension + Cycles through pages and measures load times + Vladimir Vukicevic + +