SunSpider/resources/sunspider-compare-results.js
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     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 
       
    26 function sunspiderCompareResults(output1, output2)
       
    27 {
       
    28     var count1 = output1.length;
       
    29     var count2 = output2.length;
       
    30 
       
    31     var itemTotals1 = {};
       
    32     itemTotals1.length = count1;
       
    33     
       
    34     var total1 = 0;
       
    35     var categoryTotals1 = {};
       
    36     var testTotalsByCategory1 = {};
       
    37     
       
    38     var mean1 = 0;
       
    39     var categoryMeans1 = {};
       
    40     var testMeansByCategory1 = {};
       
    41     
       
    42     var stdDev1 = 0;
       
    43     var categoryStdDevs1 = {};
       
    44     var testStdDevsByCategory1 = {};
       
    45     
       
    46     var stdErr1 = 0;
       
    47     var categoryStdErrs1 = {};
       
    48     var testStdErrsByCategory1 = {};
       
    49     
       
    50     var itemTotals2 = {};
       
    51     itemTotals2.length = count2;
       
    52     
       
    53     var total2 = 0;
       
    54     var categoryTotals2 = {};
       
    55     var testTotalsByCategory2 = {};
       
    56     
       
    57     var mean2 = 0;
       
    58     var categoryMeans2 = {};
       
    59     var testMeansByCategory2 = {};
       
    60     
       
    61     var stdDev2 = 0;
       
    62     var categoryStdDevs2 = {};
       
    63     var testStdDevsByCategory2 = {};
       
    64     
       
    65     var stdErr2 = 0;
       
    66     var categoryStdErrs2 = {};
       
    67     var testStdErrsByCategory2 = {};
       
    68     
       
    69     function initialize()
       
    70     {
       
    71         itemTotals1 = {total: []};
       
    72         
       
    73         for (var i = 0; i < categories.length; i++) {
       
    74             var category = categories[i];
       
    75             itemTotals1[category] = [];
       
    76             categoryTotals1[category] = 0;
       
    77             testTotalsByCategory1[category] = {};
       
    78             categoryMeans1[category] = 0;
       
    79             testMeansByCategory1[category] = {};
       
    80             categoryStdDevs1[category] = 0;
       
    81             testStdDevsByCategory1[category] = {};
       
    82             categoryStdErrs1[category] = 0;
       
    83             testStdErrsByCategory1[category] = {};
       
    84         }
       
    85         
       
    86         for (var i = 0; i < tests.length; i++) {
       
    87             var test = tests[i];
       
    88             itemTotals1[test] = [];
       
    89             var category = test.replace(/-.*/, "");
       
    90             testTotalsByCategory1[category][test] = 0;
       
    91             testMeansByCategory1[category][test] = 0;
       
    92             testStdDevsByCategory1[category][test] = 0;
       
    93             testStdErrsByCategory1[category][test] = 0;
       
    94         }
       
    95         
       
    96         for (var i = 0; i < count1; i++) {
       
    97             itemTotals1["total"][i] = 0;
       
    98             for (var category in categoryTotals1) {
       
    99                 itemTotals1[category][i] = 0;
       
   100                 for (var test in testTotalsByCategory1[category]) {
       
   101                     itemTotals1[test][i] = 0;
       
   102                 }
       
   103             }
       
   104         }
       
   105         
       
   106         itemTotals2 = {total: []};
       
   107         
       
   108         for (var i = 0; i < categories.length; i++) {
       
   109             var category = categories[i];
       
   110             itemTotals2[category] = [];
       
   111             categoryTotals2[category] = 0;
       
   112             testTotalsByCategory2[category] = {};
       
   113             categoryMeans2[category] = 0;
       
   114             testMeansByCategory2[category] = {};
       
   115             categoryStdDevs2[category] = 0;
       
   116             testStdDevsByCategory2[category] = {};
       
   117             categoryStdErrs2[category] = 0;
       
   118             testStdErrsByCategory2[category] = {};
       
   119         }
       
   120         
       
   121         for (var i = 0; i < tests.length; i++) {
       
   122             var test = tests[i];
       
   123             itemTotals2[test] = [];
       
   124             var category = test.replace(/-.*/, "");
       
   125             testTotalsByCategory2[category][test] = 0;
       
   126             testMeansByCategory2[category][test] = 0;
       
   127             testStdDevsByCategory2[category][test] = 0;
       
   128             testStdErrsByCategory2[category][test] = 0;
       
   129         }
       
   130         
       
   131         for (var i = 0; i < count2; i++) {
       
   132             itemTotals2["total"][i] = 0;
       
   133             for (var category in categoryTotals2) {
       
   134                 itemTotals2[category][i] = 0;
       
   135                 for (var test in testTotalsByCategory2[category]) {
       
   136                     itemTotals2[test][i] = 0;
       
   137                 }
       
   138             }
       
   139         }
       
   140         
       
   141     }
       
   142     
       
   143     function computeItemTotals(output, itemTotals)
       
   144     {
       
   145         for (var i = 0; i < output.length; i++) {
       
   146             var result = output[i];
       
   147             for (var test in result) {
       
   148                 var time = result[test];
       
   149                 var category = test.replace(/-.*/, "");
       
   150                 itemTotals["total"][i] += time;
       
   151                 itemTotals[category][i] += time;
       
   152                 itemTotals[test][i] += time;
       
   153             }
       
   154         }
       
   155     }
       
   156     
       
   157     function computeTotals(output, categoryTotals, testTotalsByCategory)
       
   158     {
       
   159         var total = 0;
       
   160         
       
   161         for (var i = 0; i < output.length; i++) {
       
   162             var result = output[i];
       
   163             for (var test in result) {
       
   164                 var time = result[test];
       
   165                 var category = test.replace(/-.*/, "");
       
   166                 total += time;
       
   167                 categoryTotals[category] += time;
       
   168                 testTotalsByCategory[category][test] += time;
       
   169             }
       
   170         }
       
   171         
       
   172         return total;
       
   173     }
       
   174     
       
   175     function computeMeans(count, total, categoryTotals, categoryMeans, testTotalsByCategory, testMeansByCategory)
       
   176     {
       
   177         var mean = total / count;
       
   178         for (var category in categoryTotals) {
       
   179             categoryMeans[category] = categoryTotals[category] / count;
       
   180             for (var test in testTotalsByCategory[category]) {
       
   181                 testMeansByCategory[category][test] = testTotalsByCategory[category][test] / count;
       
   182             }
       
   183         }
       
   184         return mean;
       
   185     }
       
   186     
       
   187     function standardDeviation(mean, items)
       
   188     {
       
   189         var deltaSquaredSum = 0;
       
   190         for (var i = 0; i < items.length; i++) {
       
   191             var delta = items[i] - mean;
       
   192             deltaSquaredSum += delta * delta;
       
   193         }
       
   194         variance = deltaSquaredSum / (items.length - 1);
       
   195         return Math.sqrt(variance);
       
   196     }
       
   197     
       
   198     function computeStdDevs(mean, itemTotals, categoryStdDevs, categoryMeans, testStdDevsByCategory, testMeansByCategory)
       
   199     {
       
   200         var stdDev = standardDeviation(mean, itemTotals["total"]);
       
   201         for (var category in categoryStdDevs) {
       
   202             categoryStdDevs[category] = standardDeviation(categoryMeans[category], itemTotals[category]);
       
   203         }
       
   204         for (var category in categoryStdDevs) {
       
   205             for (var test in testStdDevsByCategory[category]) {
       
   206                 testStdDevsByCategory[category][test] = standardDeviation(testMeansByCategory[category][test], itemTotals[test]);
       
   207             }
       
   208         }
       
   209         return stdDev;
       
   210     }
       
   211     
       
   212     function computeStdErrors(count, stdDev, categoryStdErrs, categoryStdDevs, testStdErrsByCategory, testStdDevsByCategory)
       
   213     {
       
   214         var sqrtCount = Math.sqrt(count);
       
   215         
       
   216         var stdErr = stdDev / sqrtCount;
       
   217         for (var category in categoryStdErrs) {
       
   218             categoryStdErrs[category] = categoryStdDevs[category] / sqrtCount;
       
   219         }
       
   220         for (var category in categoryStdDevs) {
       
   221             for (var test in testStdErrsByCategory[category]) {
       
   222                 testStdErrsByCategory[category][test] = testStdDevsByCategory[category][test] / sqrtCount;
       
   223             }
       
   224         }
       
   225         
       
   226         return stdErr;
       
   227     }
       
   228     
       
   229     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];
       
   230     var tMax = tDistribution.length;
       
   231     var tLimit = 1.96;
       
   232     
       
   233     function tDist(n)
       
   234     {
       
   235         if (n > tMax)
       
   236             return tLimit;
       
   237         return tDistribution[n];
       
   238     }
       
   239     
       
   240     
       
   241     function formatMean(meanWidth, mean, stdErr, count)
       
   242     {
       
   243         var meanString = mean.toFixed(1).toString();
       
   244         while (meanString.length < meanWidth) {
       
   245             meanString = " " + meanString;
       
   246         }
       
   247         
       
   248         var error = "+/- " + ((tDist(count) * stdErr / mean) * 100).toFixed(1) + "% ";
       
   249         
       
   250         return meanString + "ms " + error;
       
   251     }
       
   252     
       
   253     function computeLabelWidth()
       
   254     {
       
   255         var width = "Total".length;
       
   256         for (var category in categoryMeans1) {
       
   257             if (category.length + 2 > width)
       
   258                 width = category.length + 2;
       
   259         }
       
   260         for (var i = 0; i < tests.length; i++) {
       
   261             var shortName = tests[i].replace(/^[^-]*-/, "");
       
   262             if (shortName.length + 4 > width)
       
   263                 width = shortName.length + 4;
       
   264         }
       
   265         
       
   266         return width;
       
   267     }
       
   268     
       
   269     function computeMeanWidth(mean, categoryMeans, testMeansByCategory)
       
   270     {
       
   271         var width = mean.toFixed(1).toString().length;
       
   272         for (var category in categoryMeans) {
       
   273             var candidate = categoryMeans[category].toFixed(1).toString().length;
       
   274             if (candidate > width)
       
   275                 width = candidate;
       
   276             for (var test in testMeansByCategory[category]) {
       
   277                 var candidate = testMeansByCategory[category][test].toFixed(1).toString().length;
       
   278                 if (candidate > width)
       
   279                     width = candidate;
       
   280             }
       
   281         }
       
   282         
       
   283         return width;
       
   284     }
       
   285     
       
   286     function pad(str, n)
       
   287     {
       
   288         while (str.length < n) {
       
   289             str += " ";
       
   290         }
       
   291         return str;
       
   292     }
       
   293     
       
   294     function resultLine(labelWidth, indent, label, meanWidth1, mean1, stdErr1, meanWidth2, mean2, stdErr2)
       
   295     {
       
   296         result = pad("", indent);    
       
   297         result += label + ": ";
       
   298         result = pad(result, labelWidth + 2);
       
   299         
       
   300         var t = (mean1 - mean2) / (Math.sqrt((stdErr1 * stdErr1) + (stdErr2 * stdErr2)));
       
   301         var df = count1 + count2 - 2;
       
   302         
       
   303         var statisticallySignificant = (Math.abs(t) > tDist(df+1));
       
   304         var diff = mean2 - mean1;
       
   305         var percentage = 100 * diff / mean1;
       
   306         var isFaster = diff < 0;
       
   307         var probablySame = (percentage < 0.1) && !statisticallySignificant;
       
   308         var ratio = isFaster ? (mean1 / mean2) : (mean2 / mean1);
       
   309         var fixedRatio = (ratio < 1.2) ? ratio.toFixed(3).toString() : ((ratio < 10) ? ratio.toFixed(2).toString() : ratio.toFixed(1).toString());
       
   310         var formattedRatio = isFaster ? fixedRatio + "x as fast" : "*" + fixedRatio + "x as slow*";
       
   311 
       
   312         var diffSummary;
       
   313         var diffDetail;
       
   314         
       
   315         if (probablySame) {
       
   316             diffSummary = "-";
       
   317             diffDetail = "";
       
   318         } else if (!statisticallySignificant) {
       
   319             diffSummary = "??";
       
   320             diffDetail =  "    not conclusive: might be " + formattedRatio;
       
   321         } else {
       
   322             diffSummary = formattedRatio;
       
   323             diffDetail = "    significant"; 
       
   324         }
       
   325         
       
   326         return result + pad(diffSummary, 18) + formatMean(meanWidth1, mean1, stdErr1, count1) + "  " + formatMean(meanWidth2, mean2, stdErr2, count2) + diffDetail;
       
   327     }
       
   328     
       
   329     function printOutput()
       
   330     {
       
   331         var labelWidth = computeLabelWidth();
       
   332         var meanWidth1 = computeMeanWidth(mean1, categoryMeans1, testMeansByCategory1);
       
   333         var meanWidth2 = computeMeanWidth(mean2, categoryMeans2, testMeansByCategory2);
       
   334         
       
   335         print("\n");
       
   336         var header = "TEST";
       
   337         while (header.length < labelWidth)
       
   338             header += " ";
       
   339         header += "  COMPARISON            FROM                 TO             DETAILS";
       
   340         print(header);
       
   341         print("");
       
   342         print("=============================================================================");
       
   343         print("");
       
   344         print(resultLine(labelWidth, 0, "** TOTAL **", meanWidth1, mean1, stdErr1, meanWidth2, mean2, stdErr2));
       
   345         print("");
       
   346         print("=============================================================================");
       
   347         
       
   348         for (var category in categoryMeans1) {
       
   349             print("");
       
   350             print(resultLine(labelWidth, 2, category,
       
   351                              meanWidth1, categoryMeans1[category], categoryStdErrs1[category],
       
   352                              meanWidth2, categoryMeans2[category], categoryStdErrs2[category]));
       
   353             for (var test in testMeansByCategory1[category]) {
       
   354                 var shortName = test.replace(/^[^-]*-/, "");
       
   355                 print(resultLine(labelWidth, 4, shortName, 
       
   356                                  meanWidth1, testMeansByCategory1[category][test], testStdErrsByCategory1[category][test],
       
   357                                  meanWidth2, testMeansByCategory2[category][test], testStdErrsByCategory2[category][test]));
       
   358             }
       
   359         }
       
   360     }
       
   361     
       
   362     initialize();
       
   363     
       
   364     computeItemTotals(output1, itemTotals1);
       
   365     computeItemTotals(output2, itemTotals2);
       
   366 
       
   367     total1 = computeTotals(output1, categoryTotals1, testTotalsByCategory1);
       
   368     total2 = computeTotals(output2, categoryTotals2, testTotalsByCategory2);
       
   369 
       
   370     mean1 = computeMeans(count1, total1, categoryTotals1, categoryMeans1, testTotalsByCategory1, testMeansByCategory1);
       
   371     mean2 = computeMeans(count2, total2, categoryTotals2, categoryMeans2, testTotalsByCategory2, testMeansByCategory2);
       
   372 
       
   373     stdDev1 = computeStdDevs(mean1, itemTotals1, categoryStdDevs1, categoryMeans1, testStdDevsByCategory1, testMeansByCategory1);
       
   374     stdDev2 = computeStdDevs(mean2, itemTotals2, categoryStdDevs2, categoryMeans2, testStdDevsByCategory2, testMeansByCategory2);
       
   375 
       
   376     stdErr1 = computeStdErrors(count1, stdDev1, categoryStdErrs1, categoryStdDevs1, testStdErrsByCategory1, testStdDevsByCategory1);
       
   377     stdErr2 = computeStdErrors(count2, stdDev2, categoryStdErrs2, categoryStdDevs2, testStdErrsByCategory2, testStdDevsByCategory2);
       
   378 
       
   379     printOutput();
       
   380 }