edit
[c11concurrency-benchmarks.git] / jsbench-2013.1 / harness.js
1 /*
2  * Copyright (C) 2011, 2012 Purdue University
3  * Written by Gregor Richards
4  * All rights reserved.
5  * 
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  * 
9  * 1. Redistributions of source code must retain the above copyright notice,
10  *    this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  *    this list of conditions and the following disclaimer in the documentation
13  *    and/or other materials provided with the distribution.
14  * 
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 (function() {
29     // put benchmarks here
30     var benchmarks = ["amazon/chrome", "amazon/chrome-win", "amazon/firefox",
31                       "amazon/firefox-win", "amazon/safari", "facebook/chrome",
32                       "facebook/chrome-win", "facebook/firefox",
33                       "facebook/firefox-win", "facebook/safari",
34                       "google/chrome", "google/chrome-win", "google/firefox",
35                       "google/firefox-win", "google/safari", "twitter/chrome",
36                       "twitter/chrome-win", "twitter/firefox",
37                       "twitter/firefox-win", "twitter/safari", "yahoo/chrome",
38                       "yahoo/chrome-win", "yahoo/firefox", "yahoo/firefox-win",
39                       "yahoo/safari"];
40     var modes = {
41         "*": ["urem"],
42         "amazon/firefox": ["urm"],
43         "amazon/firefox-win": ["urm"],
44         "google/firefox": ["uem"],
45         "twitter/chrome-win": ["rem"]
46     };
47     var minRuns = 23;
48     var keepRuns = 20;
49     var maxRuns = 100;
50     var maxCIM = 0.10;
51
52     // fixups for old engines
53     if (!Array.prototype.reduce) {
54         Array.prototype.reduce = function(f, val) {
55             for (var i = 0; i < this.length; i++) {
56                 val = f(val, this[i]);
57             }
58             return val;
59         };
60     }
61
62     // all test results
63     var results = {};
64
65     var curRun = 0;
66     var curBenchmark = 0;
67     var curMode = 0;
68
69     function getModes(bm) {
70         if (bm in modes) return modes[bm];
71         return modes["*"];
72     }
73
74     // call this to either rerun or go to another page and come back
75     function rerun() {
76         try {
77             if (window.sessionStorage) {
78                 // store this for the session and go 'round to another page to force uncaching on Chrome
79                 sessionStorage.JSBNG_harnessState = JSON.stringify({
80                     results: results,
81                     curRun: curRun,
82                     curBenchmark: curBenchmark,
83                     curMode: curMode
84                 });
85                 window.location.href = window.location.href.replace(/\/[^\/]*$/, "/reload.html");
86                 return;
87             }
88         } catch (ex) {}
89         runBenchmark();
90     }
91
92     // load our current state and run
93     function onload() {
94         var gob = document.getElementById("go");
95         try {
96             if (window.sessionStorage && "JSBNG_harnessState" in sessionStorage) {
97                 var state = JSON.parse(sessionStorage.JSBNG_harnessState);
98                 results = state.results;
99                 curRun = state.curRun;
100                 curBenchmark = state.curBenchmark;
101                 curMode = state.curMode;
102                 setTimeout(runBenchmark, 200);
103                 gob.style.display = "none";
104                 return;
105             }
106         } catch (ex) {}
107         gob.onclick = function() {
108             gob.style.display = "none";
109             setTimeout(runBenchmark, 200);
110         };
111         if (/#run/.test(window.location.href)) {
112             gob.style.display = "none";
113             setTimeout(runBenchmark, 200);
114         }
115     }
116
117     function runBenchmark() {
118         var output = document.getElementById("output");
119         var bmframe = document.getElementById("bmframe");
120
121         // should we stop?
122         if (curRun < minRuns) {
123             output.innerHTML = (curRun+1) + "/" + minRuns;
124         } else {
125             // check if our S/M is OK
126             var stats = handleResults(false);
127             output.innerHTML = (curRun+1) + " " + stats.cim + " (" + maxCIM + ")";
128             if (curRun >= maxRuns || stats.cim < maxCIM) {
129                 bmframe.src = "about:blank";
130                 bmframe.style.display = "none";
131                 handleResults(true);
132                 if (window.sessionStorage) delete sessionStorage.JSBNG_harnessState;
133                 return;
134             }
135         }
136
137         // get out our benchmark and mode
138         var benchmark = benchmarks[curBenchmark];
139         var modes = getModes(benchmark);
140         var mode = modes[curMode];
141         if (++curMode >= modes.length) {
142             curMode = 0;
143             curBenchmark++;
144         }
145         if (curBenchmark >= benchmarks.length) {
146             curBenchmark = 0;
147             curRun++;
148         }
149
150         // make sure we have the results space
151         if (!(benchmark in results)) results[benchmark] = {};
152         if (!(mode in results[benchmark])) results[benchmark][mode] = [];
153
154         // set up the receiver
155         if (/v/.test(mode)) {
156             // verification mode, we only care if there's an error
157             window.JSBNG_handleResult = function(res) {
158                 if (res.error) {
159                     if (!("errors" in results)) results.errors = [];
160                     results.errors.push(benchmark + "." + mode + ": " + res.msg);
161                 }
162                 rerun();
163             };
164         } else {
165             window.JSBNG_handleResult = function(res) {
166                 if (!res.error) {
167                     results[benchmark][mode].push(res.time);
168                 }
169                 rerun();
170             };
171         }
172
173         // then load it
174         bmframe.src = benchmark + "/" + mode + ".html";
175     }
176
177     // handle all of our results
178     function handleResults(pr) {
179         var output = document.getElementById("output");
180         function print(str) {
181             output.appendChild(document.createTextNode(str));
182             output.appendChild(document.createElement("br"));
183         }
184         function printarr(arr) {
185             for (var i = 0; i < arr.length; i++) print(arr[i]);
186         }
187         function percent(num) {
188             return (num*100).toFixed(2) + "%";
189         }
190
191         // clear out the intermediate results
192         if (pr) output.innerHTML = "";
193
194         // totals
195         var totals = {
196             mean: 1,
197             stddev: 1,
198             sem: 1,
199             ci: 1,
200             runs: 0
201         };
202
203         // stuff to print later
204         var ptotals = [];
205         var presults = [];
206         var praw = [];
207         var spc = "\u00a0\u00a0";
208         var spc2 = spc + spc;
209
210         // calculate all the real results
211         for (var b = 0; b < benchmarks.length; b++) {
212             var benchmark = benchmarks[b];
213             var modes = getModes(benchmark);
214             if (pr) {
215                 presults.push(spc + benchmark + ":");
216                 praw.push(spc + benchmark + ":");
217             }
218
219             for (var m = 0; m < modes.length; m++) {
220                 var mode = modes[m];
221                 var bmresults = results[benchmark][mode].slice(-keepRuns);
222                 if (bmresults.length == 0) continue;
223
224                 // get the raw results
225                 var rr = spc2 + mode + ": [";
226                 for (var i = 0; i < bmresults.length; i++) {
227                     if (i != 0) rr += ", ";
228                     rr += bmresults[i];
229                 }
230                 rr += "]";
231                 if (pr) praw.push(rr);
232
233                 // now get the stats for this run
234                 var bmstats = stats(bmresults);
235
236                 // mul it to the totals
237                 totals.mean *= bmstats.mean;
238                 totals.stddev *= bmstats.stddev;
239                 totals.sem *= bmstats.sem;
240                 totals.ci *= bmstats.ci;
241                 totals.runs++;
242
243                 // and output it
244                 if (pr) presults.push(spc2 + mode + ": " +
245                     bmstats.mean.toFixed(2) + "ms ± " + percent(bmstats.cim) +
246                     " (stddev=" + percent(bmstats.sm) + ", stderr=" +
247                     percent(bmstats.semm) + ")");
248             }
249
250             if (pr) {
251                 presults.push("");
252                 praw.push("");
253             }
254         }
255
256         // now calculate the totals
257         var power = 1 / totals.runs;
258         totals.mean = Math.pow(totals.mean, power);
259         totals.stddev = Math.pow(totals.stddev, power);
260         totals.sm = totals.stddev / totals.mean;
261         totals.sem = Math.pow(totals.sem, power);
262         totals.semm = totals.sem / totals.mean;
263         totals.ci = Math.pow(totals.ci, power);
264         totals.cim = totals.ci / totals.mean;
265         ptotals.push("Final results:");
266         ptotals.push(spc + totals.mean.toFixed(2) + "ms ± " + percent(totals.cim) + " (lower is better)");
267         ptotals.push(spc + "Standard deviation = " + percent(totals.sm) + " of mean");
268         ptotals.push(spc + "Standard error = " + percent(totals.semm) + " of mean");
269         if (totals.cim >= maxCIM)
270             ptotals.push(spc + "WARNING: These results are not trustworthy! After " + maxRuns + " runs, 95% confidence interval is still greater than " + percent(maxCIM) + " of the mean!");
271         else
272             ptotals.push(spc + curRun + " runs");
273         ptotals.push("");
274
275         // if there are errors, mark those too
276         if ("errors" in results) {
277             ptotals.push("ERRORS:");
278             for (var i = 0; i < results.errors.length; i++) ptotals.push(spc + results.errors[i]);
279             ptotals.push("");
280         }
281
282         if (pr) {
283             // and print it all out
284             printarr(ptotals);
285             print("Result breakdown:");
286             printarr(presults);
287             print("Raw results:");
288             printarr(praw);
289         }
290
291         return totals;
292     }
293
294     // standard t-distribution for normally distributed samples
295     var tDistribution = [NaN, NaN, 12.71, 4.30, 3.18, 2.78, 2.57, 2.45, 2.36,
296     2.31, 2.26, 2.23, 2.20, 2.18, 2.16, 2.14, 2.13, 2.12, 2.11, 2.10, 2.09,
297     2.09, 2.08, 2.07, 2.07, 2.06, 2.06, 2.06, 2.05, 2.05, 2.05, 2.04, 2.04,
298     2.04, 2.03, 2.03, 2.03, 2.03, 2.03, 2.02, 2.02, 2.02, 2.02, 2.02, 2.02,
299     2.02, 2.01, 2.01, 2.01, 2.01, 2.01, 2.01, 2.01, 2.01, 2.01, 2.00, 2.00,
300     2.00, 2.00, 2.00, 2.00, 2.00, 2.00, 2.00, 2.00, 2.00, 2.00, 2.00, 2.00,
301     2.00, 1.99, 1.99, 1.99, 1.99, 1.99, 1.99, 1.99, 1.99, 1.99, 1.99, 1.99,
302     1.99, 1.99, 1.99, 1.99, 1.99, 1.99, 1.99, 1.99, 1.99, 1.99, 1.99, 1.99,
303     1.99, 1.99, 1.99, 1.99, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98,
304     1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98,
305     1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98,
306     1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98,
307     1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98,
308     1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.98, 1.97, 1.97, 1.97, 1.97, 1.97,
309     1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97,
310     1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97,
311     1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97,
312     1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97,
313     1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97,
314     1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97,
315     1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97,
316     1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97,
317     1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97,
318     1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97,
319     1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97,
320     1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97,
321     1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97,
322     1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97,
323     1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97,
324     1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97,
325     1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97,
326     1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97,
327     1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97,
328     1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97,
329     1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97,
330     1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97,
331     1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97,
332     1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97,
333     1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97,
334     1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.97, 1.96];
335
336     // t distribution
337     function tDist(n) {
338         if (n >= tDistribution.length)
339             return tDistribution[tDistribution.length-1];
340         return tDistribution[n];
341     }
342
343     // get statistics
344     function stats(results) {
345         var ret = {};
346
347         function sum(arr) {
348             return arr.reduce(function(p, c) { return p + c; }, 0);
349         }
350
351         // mean
352         ret.mean = sum(results) / results.length;
353
354         // sample stddev
355         ret.stddev = Math.sqrt(
356             sum(
357                 results.map(function(e) { return Math.pow(e - ret.mean, 2); })
358             ) / (results.length - 1)
359         );
360
361         // stddev / mean
362         ret.sm = ret.stddev / ret.mean;
363
364         // sample SEM (stderr)
365         ret.sem = ret.stddev / Math.sqrt(results.length);
366
367         // sample SEM/mean
368         ret.semm = ret.sem / ret.mean;
369
370         // sample 95% confidence interval range
371         ret.ci = tDist(results.length) * ret.sem;
372
373         // sample 95% CI / mean
374         ret.cim = ret.ci / ret.mean;
375
376         return ret;
377     }
378
379     window.onload = onload;
380 })();