15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// There are tests for computeStatistics() located in LayoutTests/fast/harness/perftests
25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)if (window.testRunner) {
45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    testRunner.waitUntilDone();
55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    testRunner.dumpAsText();
65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)(function () {
95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    var logLines = null;
10926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    var completedIterations = -1;
115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    var callsPerIteration = 1;
125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    var currentTest = null;
135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    var results = [];
145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    var jsHeapResults = [];
15926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    var iterationCount = undefined;
165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    var PerfTestRunner = {};
185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // To make the benchmark results predictable, we replace Math.random with a
205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // 100% deterministic alternative.
215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    PerfTestRunner.randomSeed = PerfTestRunner.initialRandomSeed = 49734321;
225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    PerfTestRunner.resetRandomSeed = function() {
245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        PerfTestRunner.randomSeed = PerfTestRunner.initialRandomSeed
255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    PerfTestRunner.random = Math.random = function() {
285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // Robert Jenkins' 32 bit integer hash function.
295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var randomSeed = PerfTestRunner.randomSeed;
305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        randomSeed = ((randomSeed + 0x7ed55d16) + (randomSeed << 12))  & 0xffffffff;
315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        randomSeed = ((randomSeed ^ 0xc761c23c) ^ (randomSeed >>> 19)) & 0xffffffff;
325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        randomSeed = ((randomSeed + 0x165667b1) + (randomSeed << 5))   & 0xffffffff;
335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        randomSeed = ((randomSeed + 0xd3a2646c) ^ (randomSeed << 9))   & 0xffffffff;
345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        randomSeed = ((randomSeed + 0xfd7046c5) + (randomSeed << 3))   & 0xffffffff;
355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        randomSeed = ((randomSeed ^ 0xb55a4f09) ^ (randomSeed >>> 16)) & 0xffffffff;
365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        PerfTestRunner.randomSeed = randomSeed;
375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return (randomSeed & 0xfffffff) / 0x10000000;
385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    };
395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    PerfTestRunner.now = window.performance && window.performance.now ? function () { return window.performance.now(); } : Date.now;
415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    PerfTestRunner.logInfo = function (text) {
435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (!window.testRunner)
445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            this.log(text);
455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    PerfTestRunner.loadFile = function (path) {
485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var xhr = new XMLHttpRequest();
495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        xhr.open("GET", path, false);
505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        xhr.send(null);
515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return xhr.responseText;
525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    PerfTestRunner.computeStatistics = function (times, unit) {
555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var data = times.slice();
565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // Add values from the smallest to the largest to avoid the loss of significance
585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        data.sort(function(a,b){return a-b;});
595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var middle = Math.floor(data.length / 2);
615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var result = {
625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            min: data[0],
635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            max: data[data.length - 1],
645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            median: data.length % 2 ? data[middle] : (data[middle - 1] + data[middle]) / 2,
655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        };
665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // Compute the mean and variance using Knuth's online algorithm (has good numerical stability).
685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var squareSum = 0;
695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        result.values = times;
705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        result.mean = 0;
715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (var i = 0; i < data.length; ++i) {
725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            var x = data[i];
735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            var delta = x - result.mean;
745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            var sweep = i + 1.0;
755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            result.mean += delta / sweep;
765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            squareSum += delta * (x - result.mean);
775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        result.variance = data.length <= 1 ? 0 : squareSum / (data.length - 1);
795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        result.stdev = Math.sqrt(result.variance);
805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        result.unit = unit || "ms";
815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return result;
835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    PerfTestRunner.logStatistics = function (values, unit, title) {
865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var statistics = this.computeStatistics(values, unit);
875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        this.log("");
885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        this.log(title);
895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (statistics.values)
905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            this.log("values " + statistics.values.join(", ") + " " + statistics.unit);
915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        this.log("avg " + statistics.mean + " " + statistics.unit);
925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        this.log("median " + statistics.median + " " + statistics.unit);
935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        this.log("stdev " + statistics.stdev + " " + statistics.unit);
945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        this.log("min " + statistics.min + " " + statistics.unit);
955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        this.log("max " + statistics.max + " " + statistics.unit);
965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
98926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    function getUsedJSHeap() {
995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return console.memory.usedJSHeapSize;
1005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
1015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    PerfTestRunner.gc = function () {
1035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (window.GCController)
1045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            window.GCController.collect();
1055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        else {
1065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            function gcRec(n) {
1075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                if (n < 1)
1085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    return {};
1095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                var temp = {i: "ab" + i + (i / 100000)};
1105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                temp += "foo";
1115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                gcRec(n-1);
1125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
1135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            for (var i = 0; i < 1000; i++)
1145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                gcRec(10);
1155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
1165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    };
1175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    function logInDocument(text) {
1195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (!document.getElementById("log")) {
1205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            var pre = document.createElement("pre");
1215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            pre.id = "log";
1225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            document.body.appendChild(pre);
1235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
1245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        document.getElementById("log").innerHTML += text + "\n";
1255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        window.scrollTo(0, document.body.height);
1265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
1275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    PerfTestRunner.log = function (text) {
1295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (logLines)
1305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            logLines.push(text);
1315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        else
1325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            logInDocument(text);
1335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
1345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
135d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    PerfTestRunner.logFatalError = function (text) {
1365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        PerfTestRunner.log(text);
1375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        finish();
1385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
1395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    function start(test, runner) {
1415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (!test) {
142d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)            PerfTestRunner.logFatalError("Got a bad test object.");
1435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return;
1445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
1455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        currentTest = test;
146926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        // FIXME: We should be using multiple instances of test runner on Dromaeo as well but it's too slow now.
147926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        // FIXME: Don't hard code the number of in-process iterations to use inside a test runner.
148926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        iterationCount = test.dromaeoIterationCount || (window.testRunner ? 5 : 20);
1495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        logLines = window.testRunner ? [] : null;
150926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        PerfTestRunner.log("Running " + iterationCount + " times");
151926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        if (test.doNotIgnoreInitialRun)
152926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            completedIterations++;
1535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (runner)
1545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            scheduleNextRun(runner);
1555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
1565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    function scheduleNextRun(runner) {
1585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        PerfTestRunner.gc();
1595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        window.setTimeout(function () {
1605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            try {
161926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)                if (currentTest.setup)
162926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)                    currentTest.setup();
163926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
1645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                var measuredValue = runner();
1655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            } catch (exception) {
166d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)                PerfTestRunner.logFatalError("Got an exception while running test.run with name=" + exception.name + ", message=" + exception.message);
1675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return;
1685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
1695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
170926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            completedIterations++;
1715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            try {
1735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                ignoreWarmUpAndLog(measuredValue);
1745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            } catch (exception) {
175d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)                PerfTestRunner.logFatalError("Got an exception while logging the result with name=" + exception.name + ", message=" + exception.message);
1765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return;
1775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
1785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
179926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            if (completedIterations < iterationCount)
1805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                scheduleNextRun(runner);
1815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            else
1825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                finish();
1835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }, 0);
1845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
1855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    function ignoreWarmUpAndLog(measuredValue) {
1875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var labeledResult = measuredValue + " " + PerfTestRunner.unit;
188926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        if (completedIterations <= 0)
1895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            PerfTestRunner.log("Ignoring warm-up run (" + labeledResult + ")");
1905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        else {
1915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            results.push(measuredValue);
192926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            if (window.internals && !currentTest.doNotMeasureMemoryUsage) {
193926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)                jsHeapResults.push(getUsedJSHeap());
1945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
1955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            PerfTestRunner.log(labeledResult);
1965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
1975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
1985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    function finish() {
2005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        try {
2015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (currentTest.description)
2025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                PerfTestRunner.log("Description: " + currentTest.description);
2035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            PerfTestRunner.logStatistics(results, PerfTestRunner.unit, "Time:");
2045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (jsHeapResults.length) {
2055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                PerfTestRunner.logStatistics(jsHeapResults, "bytes", "JS Heap:");
2065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
2075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (logLines)
2085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                logLines.forEach(logInDocument);
2095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (currentTest.done)
2105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                currentTest.done();
2115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        } catch (exception) {
2125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            logInDocument("Got an exception while finalizing the test with name=" + exception.name + ", message=" + exception.message);
2135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
2145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (window.testRunner)
2165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            testRunner.notifyDone();
2175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    PerfTestRunner.prepareToMeasureValuesAsync = function (test) {
2205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        PerfTestRunner.unit = test.unit;
2215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        start(test);
2225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
224926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    PerfTestRunner.measureValueAsync = function (measuredValue) {
225926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        completedIterations++;
2265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        try {
2285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            ignoreWarmUpAndLog(measuredValue);
2295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        } catch (exception) {
230d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)            PerfTestRunner.logFatalError("Got an exception while logging the result with name=" + exception.name + ", message=" + exception.message);
2315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return;
2325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
2335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
234926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        if (completedIterations >= iterationCount)
2355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            finish();
2365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    PerfTestRunner.measureTime = function (test) {
2395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        PerfTestRunner.unit = "ms";
2405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        start(test, measureTimeOnce);
2415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    function measureTimeOnce() {
2445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var start = PerfTestRunner.now();
2455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var returnValue = currentTest.run();
2465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var end = PerfTestRunner.now();
2475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (returnValue - 0 === returnValue) {
249926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            if (returnValue < 0)
250926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)                PerfTestRunner.log("runFunction returned a negative value: " + returnValue);
2515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return returnValue;
2525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
2535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return end - start;
2555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    PerfTestRunner.measureRunsPerSecond = function (test) {
2585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        PerfTestRunner.unit = "runs/s";
2595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        start(test, measureRunsPerSecondOnce);
2605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    function measureRunsPerSecondOnce() {
2635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var timeToRun = 750;
2645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var totalTime = 0;
2655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var numberOfRuns = 0;
2665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        while (totalTime < timeToRun) {
2685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            totalTime += callRunAndMeasureTime(callsPerIteration);
2695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            numberOfRuns += callsPerIteration;
270926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            if (completedIterations < 0 && totalTime < 100)
2715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                callsPerIteration = Math.max(10, 2 * callsPerIteration);
2725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
2735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return numberOfRuns * 1000 / totalTime;
2755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    function callRunAndMeasureTime(callsPerIteration) {
2785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var startTime = PerfTestRunner.now();
2795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (var i = 0; i < callsPerIteration; i++)
2805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            currentTest.run();
2815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return PerfTestRunner.now() - startTime;
2825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    PerfTestRunner.measurePageLoadTime = function(test) {
2865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        test.run = function() {
2875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            var file = PerfTestRunner.loadFile(test.path);
2885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (!test.chunkSize)
2895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                this.chunkSize = 50000;
2905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            var chunks = [];
2925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // The smaller the chunks the more style resolves we do.
2935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // Smaller chunk sizes will show more samples in style resolution.
2945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // Larger chunk sizes will show more samples in line layout.
2955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // Smaller chunk sizes run slower overall, as the per-chunk overhead is high.
2965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            var chunkCount = Math.ceil(file.length / this.chunkSize);
2975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            for (var chunkIndex = 0; chunkIndex < chunkCount; chunkIndex++) {
2985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                var chunk = file.substr(chunkIndex * this.chunkSize, this.chunkSize);
2995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                chunks.push(chunk);
3005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
3015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            PerfTestRunner.logInfo("Testing " + file.length + " byte document in " + chunkCount + " " + this.chunkSize + " byte chunks.");
3035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            var iframe = document.createElement("iframe");
3055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            document.body.appendChild(iframe);
3065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            iframe.sandbox = '';  // Prevent external loads which could cause write() to return before completing the parse.
3085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            iframe.style.width = "600px"; // Have a reasonable size so we're not line-breaking on every character.
3095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            iframe.style.height = "800px";
3105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            iframe.contentDocument.open();
3115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            for (var chunkIndex = 0; chunkIndex < chunks.length; chunkIndex++) {
3135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                iframe.contentDocument.write(chunks[chunkIndex]);
3145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                // Note that we won't cause a style resolve until we've encountered the <body> element.
3155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                // Thus the number of chunks counted above is not exactly equal to the number of style resolves.
3165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                if (iframe.contentDocument.body)
3175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    iframe.contentDocument.body.clientHeight; // Force a full layout/style-resolve.
3185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                else if (iframe.documentElement.localName == 'html')
3195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    iframe.contentDocument.documentElement.offsetWidth; // Force the painting.
3205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
3215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            iframe.contentDocument.close();
3235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            document.body.removeChild(iframe);
3245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        };
3255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        PerfTestRunner.measureTime(test);
3275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
3285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    window.PerfTestRunner = PerfTestRunner;
3305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)})();
331