/*
* 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 COMPUTER, 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 COMPUTER, 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)
{
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)
{
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);
}
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));
print("--------------------------------------------");
for (var category in categoryMeans) {
print("");
print(resultLine(labelWidth, 2, category, meanWidth, categoryMeans[category], categoryStdErrs[category]));
for (var test in testMeansByCategory[category]) {
var shortName = test.replace(/^[^-]*-/, "");
print(resultLine(labelWidth, 4, shortName, meanWidth, testMeansByCategory[category][test], testStdErrsByCategory[category][test]));
}
}
}
initialize();
computeItemTotals();
computeTotals();
computeMeans();
computeStdDevs();
computeStdErrors();
printOutput();