1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/browser/metro/base/tests/mochiperf/head.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,269 @@ 1.4 +/* Any copyright is dedicated to the Public Domain. 1.5 + http://creativecommons.org/publicdomain/zero/1.0/ */ 1.6 + 1.7 +"use strict"; 1.8 + 1.9 +// Load common code from ../mochitest/head.js 1.10 +let mochitestDir = getRootDirectory(gTestPath).replace('/mochiperf', '/mochitest'); 1.11 +Services.scriptloader.loadSubScript(mochitestDir + "head.js", this); 1.12 + 1.13 +// Misc. constants 1.14 +const kInfoHeader = "PERF-TEST | "; 1.15 +const kDeclareId = "DECLARE "; 1.16 +const kResultsId = "RESULTS "; 1.17 + 1.18 +// Mochitest log data format version 1.19 +const kDataSetVersion = "1"; 1.20 + 1.21 +/* 1.22 + * PerfTest - helper library for simple mochitest based performance tests. 1.23 + */ 1.24 + 1.25 +var PerfTest = { 1.26 + _userStartTime: 0, 1.27 + _userStopTime: 0, 1.28 + 1.29 + /****************************************************** 1.30 + * Declare and results 1.31 + */ 1.32 + 1.33 + /* 1.34 + * declareTest 1.35 + * 1.36 + * Declare a test which the graph server will pick up and track. 1.37 + * Must be called by every test on startup. Graph server will 1.38 + * search for result data between this declaration and the next. 1.39 + * 1.40 + * @param aUUID string for this particular test, case sensitive. 1.41 + * @param aName The name of the test. 1.42 + * @param aCategory Top level test calegory. For example 'General', 1.43 + * 'Graphics', 'Startup', 'Jim's Tests'. 1.44 + * @param aSubCategory (optional) sub category name with aCategory. 1.45 + * @param aDescription A detailed description (sentence or two) of 1.46 + * what the test does. 1.47 + */ 1.48 + declareTest: function declareTest(aUUID, aName, aCategory, aSubCategory, aDescription) { 1.49 + this._uid = aUUID; 1.50 + this._print(kDeclareId, this._toJsonStr({ 1.51 + id: aUUID, 1.52 + version: kDataSetVersion, 1.53 + name: aName, 1.54 + category: aCategory, 1.55 + subcategory: aSubCategory, 1.56 + description: aDescription, 1.57 + buildid: Services.appinfo.appBuildID, 1.58 + })); 1.59 + }, 1.60 + 1.61 + /* 1.62 + * declareNumericalResult 1.63 + * 1.64 + * Declare a simple numerical result. 1.65 + * 1.66 + * @param aValue numerical value to record 1.67 + * @param aDescription string describing the value to display on the y axis. 1.68 + */ 1.69 + declareNumericalResult: function declareNumericalResult(aValue, aDescription) { 1.70 + this._print(kResultsId, this._toJsonStr({ 1.71 + id: this._uid, 1.72 + version: kDataSetVersion, 1.73 + results: { 1.74 + r0: { 1.75 + value: aValue, 1.76 + desc: aDescription 1.77 + } 1.78 + }, 1.79 + })); 1.80 + }, 1.81 + 1.82 + /* 1.83 + * declareFrameRateResult 1.84 + * 1.85 + * Declare a frame rate for a result. 1.86 + * 1.87 + * @param aFrameCount numerical frame count 1.88 + * @param aRunMs run time in miliseconds 1.89 + * @param aDescription string describing the value to display on the y axis. 1.90 + */ 1.91 + declareFrameRateResult: function declareFrameRateResult(aFrameCount, aRunMs, aDescription) { 1.92 + this._print(kResultsId, this._toJsonStr({ 1.93 + id: this._uid, 1.94 + version: kDataSetVersion, 1.95 + results: { 1.96 + r0: { 1.97 + value: (aFrameCount / (aRunMs / 1000.0)), 1.98 + desc: aDescription 1.99 + } 1.100 + }, 1.101 + })); 1.102 + }, 1.103 + 1.104 + /* 1.105 + * declareNumericalResults 1.106 + * 1.107 + * Declare a set of numerical results. 1.108 + * 1.109 + * @param aArray an array of datapoint objects of the form: 1.110 + * 1.111 + * [ { value: (value), desc: "description/units" }, .. ] 1.112 + * 1.113 + * optional values: 1.114 + * shareAxis - the 0 based index of a previous data point this point 1.115 + * should share a y axis with. 1.116 + */ 1.117 + declareNumericalResults: function declareNumericalResults(aArray) { 1.118 + let collection = new Object(); 1.119 + for (let idx = 0; idx < aArray.length; idx++) { 1.120 + collection['r' + idx] = { value: aArray[idx].value, desc: aArray[idx].desc }; 1.121 + if (aArray[idx].shareAxis != undefined) { 1.122 + collection['r' + idx].shareAxis = aArray[idx].shareAxis; 1.123 + } 1.124 + } 1.125 + let dataset = { 1.126 + id: this._uid, 1.127 + version: kDataSetVersion, 1.128 + results: collection 1.129 + }; 1.130 + this._print(kResultsId, this._toJsonStr(dataset)); 1.131 + }, 1.132 + 1.133 + /****************************************************** 1.134 + * Perf tests 1.135 + */ 1.136 + 1.137 + perfBoundsCheck: function perfBoundsCheck(aLow, aHigh, aValue, aTestMessage) { 1.138 + ok(aValue < aLow || aValue > aHigh, aTestMessage); 1.139 + }, 1.140 + 1.141 + /****************************************************** 1.142 + * Math utilities 1.143 + */ 1.144 + 1.145 + computeMedian: function computeMedian(aArray, aOptions) { 1.146 + aArray.sort(function (a, b) { 1.147 + return a - b; 1.148 + }); 1.149 + 1.150 + var idx = Math.floor(aArray.length / 2); 1.151 + 1.152 + if(aArray.length % 2) { 1.153 + return aArray[idx]; 1.154 + } else { 1.155 + return (aArray[idx-1] + aArray[idx]) / 2; 1.156 + } 1.157 + }, 1.158 + 1.159 + computeAverage: function computeAverage(aArray, aOptions) { 1.160 + let idx; 1.161 + let count = 0, total = 0; 1.162 + let highIdx = -1, lowIdx = -1; 1.163 + let high = 0, low = 0; 1.164 + if (aOptions.stripOutliers) { 1.165 + for (idx = 0; idx < aArray.length; idx++) { 1.166 + if (high < aArray[idx]) { 1.167 + highIdx = idx; 1.168 + high = aArray[idx]; 1.169 + } 1.170 + if (low > aArray[idx]) { 1.171 + lowIdx = idx; 1.172 + low = aArray[idx]; 1.173 + } 1.174 + } 1.175 + } 1.176 + for (idx = 0; idx < aArray.length; idx++) { 1.177 + if (idx != high && idx != low) { 1.178 + total += aArray[idx]; 1.179 + count++; 1.180 + } 1.181 + } 1.182 + return total / count; 1.183 + }, 1.184 + 1.185 + computeHighLowBands: function computeHighLow(aArray, aPercentage) { 1.186 + let bandCount = Math.ceil(aArray.length * aPercentage); 1.187 + let lowGroup = 0, highGroup = 0; 1.188 + let idx; 1.189 + 1.190 + function compareNumbers(a, b) { 1.191 + return a - b; 1.192 + } 1.193 + aArray.sort(compareNumbers); 1.194 + for (idx = 0; idx < bandCount; idx++) { 1.195 + lowGroup += aArray[idx]; 1.196 + } 1.197 + let top = aArray.length - 1; 1.198 + for (idx = top; idx > (top - bandCount); idx--) { 1.199 + highGroup += aArray[idx]; 1.200 + } 1.201 + return { 1.202 + low: lowGroup / bandCount, 1.203 + high: highGroup / bandCount, 1.204 + ave: this.computeAverage(aArray, {}) 1.205 + }; 1.206 + }, 1.207 + 1.208 + /****************************************************** 1.209 + * Internal 1.210 + */ 1.211 + 1.212 + _print: function _print() { 1.213 + let str = kInfoHeader; 1.214 + for (let idx = 0; idx < arguments.length; idx++) { 1.215 + str += arguments[idx]; 1.216 + } 1.217 + info(str); 1.218 + }, 1.219 + 1.220 + _toJsonStr: function _toJsonStr(aTable) { 1.221 + return window.JSON.stringify(aTable); 1.222 + }, 1.223 +}; 1.224 + 1.225 +/* 1.226 + * StopWatch - timing helper 1.227 + */ 1.228 + 1.229 +function StopWatch(aStart) { 1.230 + if (aStart) { 1.231 + this.start(); 1.232 + } 1.233 +} 1.234 + 1.235 +StopWatch.prototype = { 1.236 + /* 1.237 + * Start timing. Resets existing clock. 1.238 + */ 1.239 + start: function start() { 1.240 + this.reset(); 1.241 + this._userStartTime = window.performance.now(); 1.242 + }, 1.243 + 1.244 + /* 1.245 + * Stop timing. 1.246 + */ 1.247 + stop: function stop() { 1.248 + this._userStopTime = window.performance.now(); 1.249 + return this.time(); 1.250 + }, 1.251 + 1.252 + /* 1.253 + * Resets both start and end time. 1.254 + */ 1.255 + reset: function reset() { 1.256 + this._userStartTime = this._userStopTime = 0; 1.257 + }, 1.258 + 1.259 + /* 1.260 + * Returns the total time ellapsed in milliseconds. Returns zero if 1.261 + * no time has been accumulated. 1.262 + */ 1.263 + time: function time() { 1.264 + if (!this._userStartTime) { 1.265 + return 0; 1.266 + } 1.267 + if (!this._userStopTime) { 1.268 + return (window.performance.now() - this._userStartTime); 1.269 + } 1.270 + return this._userStopTime - this._userStartTime; 1.271 + }, 1.272 +};