diff -r 000000000000 -r 6474c204b198 browser/metro/base/tests/mochiperf/head.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/browser/metro/base/tests/mochiperf/head.js Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,269 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Load common code from ../mochitest/head.js +let mochitestDir = getRootDirectory(gTestPath).replace('/mochiperf', '/mochitest'); +Services.scriptloader.loadSubScript(mochitestDir + "head.js", this); + +// Misc. constants +const kInfoHeader = "PERF-TEST | "; +const kDeclareId = "DECLARE "; +const kResultsId = "RESULTS "; + +// Mochitest log data format version +const kDataSetVersion = "1"; + +/* + * PerfTest - helper library for simple mochitest based performance tests. + */ + +var PerfTest = { + _userStartTime: 0, + _userStopTime: 0, + + /****************************************************** + * Declare and results + */ + + /* + * declareTest + * + * Declare a test which the graph server will pick up and track. + * Must be called by every test on startup. Graph server will + * search for result data between this declaration and the next. + * + * @param aUUID string for this particular test, case sensitive. + * @param aName The name of the test. + * @param aCategory Top level test calegory. For example 'General', + * 'Graphics', 'Startup', 'Jim's Tests'. + * @param aSubCategory (optional) sub category name with aCategory. + * @param aDescription A detailed description (sentence or two) of + * what the test does. + */ + declareTest: function declareTest(aUUID, aName, aCategory, aSubCategory, aDescription) { + this._uid = aUUID; + this._print(kDeclareId, this._toJsonStr({ + id: aUUID, + version: kDataSetVersion, + name: aName, + category: aCategory, + subcategory: aSubCategory, + description: aDescription, + buildid: Services.appinfo.appBuildID, + })); + }, + + /* + * declareNumericalResult + * + * Declare a simple numerical result. + * + * @param aValue numerical value to record + * @param aDescription string describing the value to display on the y axis. + */ + declareNumericalResult: function declareNumericalResult(aValue, aDescription) { + this._print(kResultsId, this._toJsonStr({ + id: this._uid, + version: kDataSetVersion, + results: { + r0: { + value: aValue, + desc: aDescription + } + }, + })); + }, + + /* + * declareFrameRateResult + * + * Declare a frame rate for a result. + * + * @param aFrameCount numerical frame count + * @param aRunMs run time in miliseconds + * @param aDescription string describing the value to display on the y axis. + */ + declareFrameRateResult: function declareFrameRateResult(aFrameCount, aRunMs, aDescription) { + this._print(kResultsId, this._toJsonStr({ + id: this._uid, + version: kDataSetVersion, + results: { + r0: { + value: (aFrameCount / (aRunMs / 1000.0)), + desc: aDescription + } + }, + })); + }, + + /* + * declareNumericalResults + * + * Declare a set of numerical results. + * + * @param aArray an array of datapoint objects of the form: + * + * [ { value: (value), desc: "description/units" }, .. ] + * + * optional values: + * shareAxis - the 0 based index of a previous data point this point + * should share a y axis with. + */ + declareNumericalResults: function declareNumericalResults(aArray) { + let collection = new Object(); + for (let idx = 0; idx < aArray.length; idx++) { + collection['r' + idx] = { value: aArray[idx].value, desc: aArray[idx].desc }; + if (aArray[idx].shareAxis != undefined) { + collection['r' + idx].shareAxis = aArray[idx].shareAxis; + } + } + let dataset = { + id: this._uid, + version: kDataSetVersion, + results: collection + }; + this._print(kResultsId, this._toJsonStr(dataset)); + }, + + /****************************************************** + * Perf tests + */ + + perfBoundsCheck: function perfBoundsCheck(aLow, aHigh, aValue, aTestMessage) { + ok(aValue < aLow || aValue > aHigh, aTestMessage); + }, + + /****************************************************** + * Math utilities + */ + + computeMedian: function computeMedian(aArray, aOptions) { + aArray.sort(function (a, b) { + return a - b; + }); + + var idx = Math.floor(aArray.length / 2); + + if(aArray.length % 2) { + return aArray[idx]; + } else { + return (aArray[idx-1] + aArray[idx]) / 2; + } + }, + + computeAverage: function computeAverage(aArray, aOptions) { + let idx; + let count = 0, total = 0; + let highIdx = -1, lowIdx = -1; + let high = 0, low = 0; + if (aOptions.stripOutliers) { + for (idx = 0; idx < aArray.length; idx++) { + if (high < aArray[idx]) { + highIdx = idx; + high = aArray[idx]; + } + if (low > aArray[idx]) { + lowIdx = idx; + low = aArray[idx]; + } + } + } + for (idx = 0; idx < aArray.length; idx++) { + if (idx != high && idx != low) { + total += aArray[idx]; + count++; + } + } + return total / count; + }, + + computeHighLowBands: function computeHighLow(aArray, aPercentage) { + let bandCount = Math.ceil(aArray.length * aPercentage); + let lowGroup = 0, highGroup = 0; + let idx; + + function compareNumbers(a, b) { + return a - b; + } + aArray.sort(compareNumbers); + for (idx = 0; idx < bandCount; idx++) { + lowGroup += aArray[idx]; + } + let top = aArray.length - 1; + for (idx = top; idx > (top - bandCount); idx--) { + highGroup += aArray[idx]; + } + return { + low: lowGroup / bandCount, + high: highGroup / bandCount, + ave: this.computeAverage(aArray, {}) + }; + }, + + /****************************************************** + * Internal + */ + + _print: function _print() { + let str = kInfoHeader; + for (let idx = 0; idx < arguments.length; idx++) { + str += arguments[idx]; + } + info(str); + }, + + _toJsonStr: function _toJsonStr(aTable) { + return window.JSON.stringify(aTable); + }, +}; + +/* + * StopWatch - timing helper + */ + +function StopWatch(aStart) { + if (aStart) { + this.start(); + } +} + +StopWatch.prototype = { + /* + * Start timing. Resets existing clock. + */ + start: function start() { + this.reset(); + this._userStartTime = window.performance.now(); + }, + + /* + * Stop timing. + */ + stop: function stop() { + this._userStopTime = window.performance.now(); + return this.time(); + }, + + /* + * Resets both start and end time. + */ + reset: function reset() { + this._userStartTime = this._userStopTime = 0; + }, + + /* + * Returns the total time ellapsed in milliseconds. Returns zero if + * no time has been accumulated. + */ + time: function time() { + if (!this._userStartTime) { + return 0; + } + if (!this._userStopTime) { + return (window.performance.now() - this._userStartTime); + } + return this._userStopTime - this._userStartTime; + }, +};