1/*
2 * Copyright (C) 2007 Apple Inc.  All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26var count = output.length;
27
28var itemTotals = {};
29itemTotals.length = count;
30
31var total = 0;
32var categoryTotals = {};
33var testTotalsByCategory = {};
34
35var mean = 0;
36var categoryMeans = {};
37var testMeansByCategory = {};
38
39var stdDev = 0;
40var categoryStdDevs = {};
41var testStdDevsByCategory = {};
42
43var stdErr = 0;
44var categoryStdErrs = {};
45var testStdErrsByCategory = {};
46
47function initialize()
48{
49    itemTotals = {total: []};
50
51    for (var i = 0; i < categories.length; i++) {
52        var category = categories[i];
53        itemTotals[category] = [];
54        categoryTotals[category] = 0;
55        testTotalsByCategory[category] = {};
56        categoryMeans[category] = 0;
57        testMeansByCategory[category] = {};
58        categoryStdDevs[category] = 0;
59        testStdDevsByCategory[category] = {};
60        categoryStdErrs[category] = 0;
61        testStdErrsByCategory[category] = {};
62    }
63
64    for (var i = 0; i < tests.length; i++) {
65        var test = tests[i];
66        itemTotals[test] = [];
67        var category = test.replace(/-.*/, "");
68        testTotalsByCategory[category][test] = 0;
69        testMeansByCategory[category][test] = 0;
70        testStdDevsByCategory[category][test] = 0;
71        testStdErrsByCategory[category][test] = 0;
72    }
73
74    for (var i = 0; i < count; i++) {
75        itemTotals["total"][i] = 0;
76        for (var category in categoryTotals) {
77            itemTotals[category][i] = 0;
78            for (var test in testTotalsByCategory[category]) {
79                itemTotals[test][i] = 0;
80            }
81        }
82    }
83}
84
85function computeItemTotals()
86{
87    for (var i = 0; i < output.length; i++) {
88        var result = output[i];
89        for (var test in result) {
90            var time = result[test];
91            var category = test.replace(/-.*/, "");
92            itemTotals["total"][i] += time;
93            itemTotals[category][i] += time;
94            itemTotals[test][i] += time;
95        }
96    }
97}
98
99function computeTotals()
100{
101    for (var i = 0; i < output.length; i++) {
102        var result = output[i];
103        for (var test in result) {
104            var time = result[test];
105            var category = test.replace(/-.*/, "");
106            total += time;
107            categoryTotals[category] += time;
108            testTotalsByCategory[category][test] += time;
109        }
110    }
111}
112
113function computeMeans()
114{
115    mean = total / count;
116    for (var category in categoryTotals) {
117        categoryMeans[category] = categoryTotals[category] / count;
118        for (var test in testTotalsByCategory[category]) {
119            testMeansByCategory[category][test] = testTotalsByCategory[category][test] / count;
120        }
121    }
122}
123
124function standardDeviation(mean, items)
125{
126    var deltaSquaredSum = 0;
127    for (var i = 0; i < items.length; i++) {
128        var delta = items[i] - mean;
129        deltaSquaredSum += delta * delta;
130    }
131    variance = deltaSquaredSum / (items.length - 1);
132    return Math.sqrt(variance);
133}
134
135function computeStdDevs()
136{
137    stdDev = standardDeviation(mean, itemTotals["total"]);
138    for (var category in categoryStdDevs) {
139        categoryStdDevs[category] = standardDeviation(categoryMeans[category], itemTotals[category]);
140    }
141    for (var category in categoryStdDevs) {
142        for (var test in testStdDevsByCategory[category]) {
143            testStdDevsByCategory[category][test] = standardDeviation(testMeansByCategory[category][test], itemTotals[test]);
144        }
145    }
146}
147
148function computeStdErrors()
149{
150    var sqrtCount = Math.sqrt(count);
151
152    stdErr = stdDev / sqrtCount;
153    for (var category in categoryStdErrs) {
154        categoryStdErrs[category] = categoryStdDevs[category] / sqrtCount;
155    }
156    for (var category in categoryStdDevs) {
157        for (var test in testStdErrsByCategory[category]) {
158            testStdErrsByCategory[category][test] = testStdDevsByCategory[category][test] / sqrtCount;
159        }
160    }
161
162}
163
164var 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];
165var tMax = tDistribution.length;
166var tLimit = 1.96;
167
168function tDist(n)
169{
170    if (n > tMax)
171        return tLimit;
172    return tDistribution[n];
173}
174
175
176function formatResult(meanWidth, mean, stdErr, n)
177{
178    var meanString = mean.toFixed(1).toString();
179    while (meanString.length < meanWidth) {
180        meanString = " " + meanString;
181    }
182
183    if (n == 1)
184        return meanString + "ms";
185
186    return meanString + "ms +/- " + ((tDist(n) * stdErr / mean) * 100).toFixed(1) + "%";
187}
188
189function computeLabelWidth()
190{
191    var width = "Total".length;
192    for (var category in categoryMeans) {
193        if (category.length + 2 > width)
194            width = category.length + 2;
195    }
196    for (var i = 0; i < tests.length; i++) {
197        var shortName = tests[i].replace(/^[^-]*-/, "");
198        if (shortName.length + 4 > width)
199            width = shortName.length + 4;
200    }
201
202    return width;
203}
204
205function computeMeanWidth()
206{
207    var width = mean.toFixed(1).toString().length;
208    for (var category in categoryMeans) {
209        var candidate = categoryMeans[category].toFixed(2).toString().length;
210        if (candidate > width)
211            width = candidate;
212        for (var test in testMeansByCategory[category]) {
213            var candidate = testMeansByCategory[category][test].toFixed(2).toString().length;
214            if (candidate > width)
215                width = candidate;
216        }
217    }
218
219    return width;
220}
221
222function resultLine(labelWidth, indent, label, meanWidth, mean, stdErr)
223{
224    var result = "";
225    for (i = 0; i < indent; i++) {
226        result += " ";
227    }
228
229    result += label + ": ";
230
231    for (i = 0; i < (labelWidth - (label.length + indent)); i++) {
232        result += " ";
233    }
234
235    return result + formatResult(meanWidth, mean, stdErr, count);
236}
237
238function printOutput()
239{
240    var labelWidth = computeLabelWidth();
241    var meanWidth = computeMeanWidth();
242
243    print("\n");
244    print("============================================");
245    if (count == 1)
246        print("RESULTS");
247    else
248        print("RESULTS (means and 95% confidence intervals)");
249    print("--------------------------------------------");
250    print(resultLine(labelWidth, 0, "Total", meanWidth, mean, stdErr));
251    print("--------------------------------------------");
252    for (var category in categoryMeans) {
253        print("");
254        print(resultLine(labelWidth, 2, category, meanWidth, categoryMeans[category], categoryStdErrs[category]));
255        for (var test in testMeansByCategory[category]) {
256            var shortName = test.replace(/^[^-]*-/, "");
257            print(resultLine(labelWidth, 4, shortName, meanWidth, testMeansByCategory[category][test], testStdErrsByCategory[category][test]));
258        }
259    }
260}
261
262initialize();
263computeItemTotals();
264computeTotals();
265computeMeans();
266computeStdDevs();
267computeStdErrors();
268printOutput();
269