Add jsbench
[c11concurrency-benchmarks.git] / jsbench-2013.1 / harness.js
diff --git a/jsbench-2013.1/harness.js b/jsbench-2013.1/harness.js
new file mode 100644 (file)
index 0000000..4b9d269
--- /dev/null
@@ -0,0 +1,380 @@
+/*
+ * Copyright (C) 2011, 2012 Purdue University
+ * Written by Gregor Richards
+ * 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
+ */
+
+(function() {
+    // put benchmarks here
+    var benchmarks = ["amazon/chrome", "amazon/chrome-win", "amazon/firefox",
+                      "amazon/firefox-win", "amazon/safari", "facebook/chrome",
+                      "facebook/chrome-win", "facebook/firefox",
+                      "facebook/firefox-win", "facebook/safari",
+                      "google/chrome", "google/chrome-win", "google/firefox",
+                      "google/firefox-win", "google/safari", "twitter/chrome",
+                      "twitter/chrome-win", "twitter/firefox",
+                      "twitter/firefox-win", "twitter/safari", "yahoo/chrome",
+                      "yahoo/chrome-win", "yahoo/firefox", "yahoo/firefox-win",
+                      "yahoo/safari"];
+    var modes = {
+        "*": ["urem"],
+        "amazon/firefox": ["urm"],
+        "amazon/firefox-win": ["urm"],
+        "google/firefox": ["uem"],
+        "twitter/chrome-win": ["rem"]
+    };
+    var minRuns = 23;
+    var keepRuns = 20;
+    var maxRuns = 100;
+    var maxCIM = 0.10;
+
+    // fixups for old engines
+    if (!Array.prototype.reduce) {
+        Array.prototype.reduce = function(f, val) {
+            for (var i = 0; i < this.length; i++) {
+                val = f(val, this[i]);
+            }
+            return val;
+        };
+    }
+
+    // all test results
+    var results = {};
+
+    var curRun = 0;
+    var curBenchmark = 0;
+    var curMode = 0;
+
+    function getModes(bm) {
+        if (bm in modes) return modes[bm];
+        return modes["*"];
+    }
+
+    // call this to either rerun or go to another page and come back
+    function rerun() {
+        try {
+            if (window.sessionStorage) {
+                // store this for the session and go 'round to another page to force uncaching on Chrome
+                sessionStorage.JSBNG_harnessState = JSON.stringify({
+                    results: results,
+                    curRun: curRun,
+                    curBenchmark: curBenchmark,
+                    curMode: curMode
+                });
+                window.location.href = window.location.href.replace(/\/[^\/]*$/, "/reload.html");
+                return;
+            }
+        } catch (ex) {}
+        runBenchmark();
+    }
+
+    // load our current state and run
+    function onload() {
+        var gob = document.getElementById("go");
+        try {
+            if (window.sessionStorage && "JSBNG_harnessState" in sessionStorage) {
+                var state = JSON.parse(sessionStorage.JSBNG_harnessState);
+                results = state.results;
+                curRun = state.curRun;
+                curBenchmark = state.curBenchmark;
+                curMode = state.curMode;
+                setTimeout(runBenchmark, 200);
+                gob.style.display = "none";
+                return;
+            }
+        } catch (ex) {}
+        gob.onclick = function() {
+            gob.style.display = "none";
+            setTimeout(runBenchmark, 200);
+        };
+        if (/#run/.test(window.location.href)) {
+            gob.style.display = "none";
+            setTimeout(runBenchmark, 200);
+        }
+    }
+
+    function runBenchmark() {
+        var output = document.getElementById("output");
+        var bmframe = document.getElementById("bmframe");
+
+        // should we stop?
+        if (curRun < minRuns) {
+            output.innerHTML = (curRun+1) + "/" + minRuns;
+        } else {
+            // check if our S/M is OK
+            var stats = handleResults(false);
+            output.innerHTML = (curRun+1) + " " + stats.cim + " (" + maxCIM + ")";
+            if (curRun >= maxRuns || stats.cim < maxCIM) {
+                bmframe.src = "about:blank";
+                bmframe.style.display = "none";
+                handleResults(true);
+                if (window.sessionStorage) delete sessionStorage.JSBNG_harnessState;
+                return;
+            }
+        }
+
+        // get out our benchmark and mode
+        var benchmark = benchmarks[curBenchmark];
+        var modes = getModes(benchmark);
+        var mode = modes[curMode];
+        if (++curMode >= modes.length) {
+            curMode = 0;
+            curBenchmark++;
+        }
+        if (curBenchmark >= benchmarks.length) {
+            curBenchmark = 0;
+            curRun++;
+        }
+
+        // make sure we have the results space
+        if (!(benchmark in results)) results[benchmark] = {};
+        if (!(mode in results[benchmark])) results[benchmark][mode] = [];
+
+        // set up the receiver
+        if (/v/.test(mode)) {
+            // verification mode, we only care if there's an error
+            window.JSBNG_handleResult = function(res) {
+                if (res.error) {
+                    if (!("errors" in results)) results.errors = [];
+                    results.errors.push(benchmark + "." + mode + ": " + res.msg);
+                }
+                rerun();
+            };
+        } else {
+            window.JSBNG_handleResult = function(res) {
+                if (!res.error) {
+                    results[benchmark][mode].push(res.time);
+                }
+                rerun();
+            };
+        }
+
+        // then load it
+        bmframe.src = benchmark + "/" + mode + ".html";
+    }
+
+    // handle all of our results
+    function handleResults(pr) {
+        var output = document.getElementById("output");
+        function print(str) {
+            output.appendChild(document.createTextNode(str));
+            output.appendChild(document.createElement("br"));
+        }
+        function printarr(arr) {
+            for (var i = 0; i < arr.length; i++) print(arr[i]);
+        }
+        function percent(num) {
+            return (num*100).toFixed(2) + "%";
+        }
+
+        // clear out the intermediate results
+        if (pr) output.innerHTML = "";
+
+        // totals
+        var totals = {
+            mean: 1,
+            stddev: 1,
+            sem: 1,
+            ci: 1,
+            runs: 0
+        };
+
+        // stuff to print later
+        var ptotals = [];
+        var presults = [];
+        var praw = [];
+        var spc = "\u00a0\u00a0";
+        var spc2 = spc + spc;
+
+        // calculate all the real results
+        for (var b = 0; b < benchmarks.length; b++) {
+            var benchmark = benchmarks[b];
+            var modes = getModes(benchmark);
+            if (pr) {
+                presults.push(spc + benchmark + ":");
+                praw.push(spc + benchmark + ":");
+            }
+
+            for (var m = 0; m < modes.length; m++) {
+                var mode = modes[m];
+                var bmresults = results[benchmark][mode].slice(-keepRuns);
+                if (bmresults.length == 0) continue;
+
+                // get the raw results
+                var rr = spc2 + mode + ": [";
+                for (var i = 0; i < bmresults.length; i++) {
+                    if (i != 0) rr += ", ";
+                    rr += bmresults[i];
+                }
+                rr += "]";
+                if (pr) praw.push(rr);
+
+                // now get the stats for this run
+                var bmstats = stats(bmresults);
+
+                // mul it to the totals
+                totals.mean *= bmstats.mean;
+                totals.stddev *= bmstats.stddev;
+                totals.sem *= bmstats.sem;
+                totals.ci *= bmstats.ci;
+                totals.runs++;
+
+                // and output it
+                if (pr) presults.push(spc2 + mode + ": " +
+                    bmstats.mean.toFixed(2) + "ms ± " + percent(bmstats.cim) +
+                    " (stddev=" + percent(bmstats.sm) + ", stderr=" +
+                    percent(bmstats.semm) + ")");
+            }
+
+            if (pr) {
+                presults.push("");
+                praw.push("");
+            }
+        }
+
+        // now calculate the totals
+        var power = 1 / totals.runs;
+        totals.mean = Math.pow(totals.mean, power);
+        totals.stddev = Math.pow(totals.stddev, power);
+        totals.sm = totals.stddev / totals.mean;
+        totals.sem = Math.pow(totals.sem, power);
+        totals.semm = totals.sem / totals.mean;
+        totals.ci = Math.pow(totals.ci, power);
+        totals.cim = totals.ci / totals.mean;
+        ptotals.push("Final results:");
+        ptotals.push(spc + totals.mean.toFixed(2) + "ms ± " + percent(totals.cim) + " (lower is better)");
+        ptotals.push(spc + "Standard deviation = " + percent(totals.sm) + " of mean");
+        ptotals.push(spc + "Standard error = " + percent(totals.semm) + " of mean");
+        if (totals.cim >= maxCIM)
+            ptotals.push(spc + "WARNING: These results are not trustworthy! After " + maxRuns + " runs, 95% confidence interval is still greater than " + percent(maxCIM) + " of the mean!");
+        else
+            ptotals.push(spc + curRun + " runs");
+        ptotals.push("");
+
+        // if there are errors, mark those too
+        if ("errors" in results) {
+            ptotals.push("ERRORS:");
+            for (var i = 0; i < results.errors.length; i++) ptotals.push(spc + results.errors[i]);
+            ptotals.push("");
+        }
+
+        if (pr) {
+            // and print it all out
+            printarr(ptotals);
+            print("Result breakdown:");
+            printarr(presults);
+            print("Raw results:");
+            printarr(praw);
+        }
+
+        return totals;
+    }
+
+    // standard t-distribution for normally distributed samples
+    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];
+
+    // t distribution
+    function tDist(n) {
+        if (n >= tDistribution.length)
+            return tDistribution[tDistribution.length-1];
+        return tDistribution[n];
+    }
+
+    // get statistics
+    function stats(results) {
+        var ret = {};
+
+        function sum(arr) {
+            return arr.reduce(function(p, c) { return p + c; }, 0);
+        }
+
+        // mean
+        ret.mean = sum(results) / results.length;
+
+        // sample stddev
+        ret.stddev = Math.sqrt(
+            sum(
+                results.map(function(e) { return Math.pow(e - ret.mean, 2); })
+            ) / (results.length - 1)
+        );
+
+        // stddev / mean
+        ret.sm = ret.stddev / ret.mean;
+
+        // sample SEM (stderr)
+        ret.sem = ret.stddev / Math.sqrt(results.length);
+
+        // sample SEM/mean
+        ret.semm = ret.sem / ret.mean;
+
+        // sample 95% confidence interval range
+        ret.ci = tDist(results.length) * ret.sem;
+
+        // sample 95% CI / mean
+        ret.cim = ret.ci / ret.mean;
+
+        return ret;
+    }
+
+    window.onload = onload;
+})();