sunspider-compare-results.js 17 KB

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