/* * Copyright (C) 2007 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ var count = output.length; var itemTotals = {}; itemTotals.length = count; var total = 0; var categoryTotals = {}; var testTotalsByCategory = {}; var mean = 0; var categoryMeans = {}; var testMeansByCategory = {}; var stdDev = 0; var categoryStdDevs = {}; var testStdDevsByCategory = {}; var stdErr = 0; var categoryStdErrs = {}; var testStdErrsByCategory = {}; function initialize() { itemTotals = {total: []}; for (var i = 0; i < categories.length; i++) { var category = categories[i]; itemTotals[category] = []; categoryTotals[category] = 0; testTotalsByCategory[category] = {}; categoryMeans[category] = 0; testMeansByCategory[category] = {}; categoryStdDevs[category] = 0; testStdDevsByCategory[category] = {}; categoryStdErrs[category] = 0; testStdErrsByCategory[category] = {}; } for (var i = 0; i < tests.length; i++) { var test = tests[i]; itemTotals[test] = []; var category = test.replace(/-.*/, ""); testTotalsByCategory[category][test] = 0; testMeansByCategory[category][test] = 0; testStdDevsByCategory[category][test] = 0; testStdErrsByCategory[category][test] = 0; } for (var i = 0; i < count; i++) { itemTotals["total"][i] = 0; for (var category in categoryTotals) { itemTotals[category][i] = 0; for (var test in testTotalsByCategory[category]) { itemTotals[test][i] = 0; } } } } function computeItemTotals() { for (var i = 0; i < output.length; i++) { var result = output[i]; for (var test in result) { var time = result[test]; var category = test.replace(/-.*/, ""); itemTotals["total"][i] += time; itemTotals[category][i] += time; itemTotals[test][i] += time; } } } function computeTotals() { for (var i = 0; i < output.length; i++) { var result = output[i]; for (var test in result) { var time = result[test]; var category = test.replace(/-.*/, ""); total += time; categoryTotals[category] += time; testTotalsByCategory[category][test] += time; } } } function computeMeans() { mean = total / count; for (var category in categoryTotals) { categoryMeans[category] = categoryTotals[category] / count; for (var test in testTotalsByCategory[category]) { testMeansByCategory[category][test] = testTotalsByCategory[category][test] / count; } } } function standardDeviation(mean, items) { var deltaSquaredSum = 0; for (var i = 0; i < items.length; i++) { var delta = items[i] - mean; deltaSquaredSum += delta * delta; } variance = deltaSquaredSum / (items.length - 1); return Math.sqrt(variance); } function computeStdDevs() { stdDev = standardDeviation(mean, itemTotals["total"]); for (var category in categoryStdDevs) { categoryStdDevs[category] = standardDeviation(categoryMeans[category], itemTotals[category]); } for (var category in categoryStdDevs) { for (var test in testStdDevsByCategory[category]) { testStdDevsByCategory[category][test] = standardDeviation(testMeansByCategory[category][test], itemTotals[test]); } } } function computeStdErrors() { var sqrtCount = Math.sqrt(count); stdErr = stdDev / sqrtCount; for (var category in categoryStdErrs) { categoryStdErrs[category] = categoryStdDevs[category] / sqrtCount; } for (var category in categoryStdDevs) { for (var test in testStdErrsByCategory[category]) { testStdErrsByCategory[category][test] = testStdDevsByCategory[category][test] / sqrtCount; } } } var tDistribution = [NaN, NaN, 12.71, 4.30, 3.18, 2.78, 2.57, 2.45, 2.36, 2.31, 2.26, 2.23, 2.20, 2.18, 2.16, 2.14, 2.13, 2.12, 2.11, 2.10, 2.09, 2.09, 2.08, 2.07, 2.07, 2.06, 2.06, 2.06, 2.05, 2.05, 2.05, 2.04, 2.04, 2.04, 2.03, 2.03, 2.03, 2.03, 2.03, 2.02, 2.02, 2.02, 2.02, 2.02, 2.02, 2.02, 2.01, 2.01, 2.01, 2.01, 2.01, 2.01, 2.01, 2.01, 2.01, 2.00, 2.00, 2.00, 2.00, 2.00, 2.00, 2.00, 2.00, 2.00, 2.00, 2.00, 2.00, 2.00, 2.00, 2.00, 1.99, 1.99, 1.99, 1.99, 1.99, 1.99, 1.99, 1.99, 1.99, 1.99, 1.99, 1.99, 1.99, 1.99, 1.99, 1.99, 1.99, 1.99, 1.99, 1.99, 1.99, 1.99, 1.99, 1.99, 1.99, 1.99, 1.99, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.96]; var tMax = tDistribution.length; var tLimit = 1.96; function tDist(n) { if (n > tMax) return tLimit; return tDistribution[n]; } function formatResult(meanWidth, mean, stdErr, n, mode) { // NaN mean means that the test did not run correctly. if (mean != mean) { var result = ""; for (var i = 0; i < meanWidth - 3; ++i) result += " "; if (mode == "test") result += "ERROR: Invalid test run."; else result += "ERROR: Some tests failed."; return result; } var meanString = mean.toFixed(1).toString(); while (meanString.length < meanWidth) { meanString = " " + meanString; } if (n == 1) return meanString + "ms"; return meanString + "ms +/- " + ((tDist(n) * stdErr / mean) * 100).toFixed(1) + "%"; } function computeLabelWidth() { var width = "Total".length; for (var category in categoryMeans) { if (category.length + 2 > width) width = category.length + 2; } for (var i = 0; i < tests.length; i++) { var shortName = tests[i].replace(/^[^-]*-/, ""); if (shortName.length + 4 > width) width = shortName.length + 4; } return width; } function computeMeanWidth() { var width = mean.toFixed(1).toString().length; for (var category in categoryMeans) { var candidate = categoryMeans[category].toFixed(2).toString().length; if (candidate > width) width = candidate; for (var test in testMeansByCategory[category]) { var candidate = testMeansByCategory[category][test].toFixed(2).toString().length; if (candidate > width) width = candidate; } } return width; } function resultLine(labelWidth, indent, label, meanWidth, mean, stdErr, mode) { var result = ""; for (i = 0; i < indent; i++) { result += " "; } result += label + ": "; for (i = 0; i < (labelWidth - (label.length + indent)); i++) { result += " "; } return result + formatResult(meanWidth, mean, stdErr, count, mode); } function printOutput() { var labelWidth = computeLabelWidth(); var meanWidth = computeMeanWidth(); print("\n"); print("============================================"); if (count == 1) print("RESULTS"); else print("RESULTS (means and 95% confidence intervals)"); print("--------------------------------------------"); print(resultLine(labelWidth, 0, "Total", meanWidth, mean, stdErr, "total")); print("--------------------------------------------"); for (var category in categoryMeans) { print(""); print(resultLine(labelWidth, 2, category, meanWidth, categoryMeans[category], categoryStdErrs[category], "category")); for (var test in testMeansByCategory[category]) { var shortName = test.replace(/^[^-]*-/, ""); print(resultLine(labelWidth, 4, shortName, meanWidth, testMeansByCategory[category][test], testStdErrsByCategory[category][test], "test")); } } } initialize(); computeItemTotals(); computeTotals(); computeMeans(); computeStdDevs(); computeStdErrors(); printOutput();